Problemas com XStream

16 respostas
A

Bom dia Pessoal,

Eu te juro que procurei muito sobre XStream antes de vir encher o saco de vocês é que eu to batendo cabeça e não consigo terminar a leitura de um XML, cada hora tenho um problema diferente.

Eu preciso ler um XML parecido com este:

<?xml version="1.0" encoding="utf-8"?>
<MigrationEstimationReport>
  <UserEstimationList>
    <EntityName>[email removido]</EntityName>
    <StoreEstimationList>
      <StoreName>[email removido]</StoreName>
      <EstimationStatus value="Fail" />
      <EmailEstimationStatus>
        <EstimationStatus value="Fail" />
        <StartTime>2011-05-25T18:36:00.000Z</StartTime>
        <EndTime>2011-05-25T18:36:05.000Z</EndTime>
      </EmailEstimationStatus>
    </StoreEstimationList>
  </UserEstimationList>
  <UserEstimationList>
    <EntityName>[email removido]</EntityName>
    <StoreEstimationList>
      <StoreName>[email removido]</StoreName>
      <EstimationStatus value="Fail" />
      <EmailEstimationStatus>
        <EstimationStatus value="Fail" />
        <StartTime>2011-05-25T18:36:05.000Z</StartTime>
        <EndTime>2011-05-25T18:36:07.000Z</EndTime>
      </EmailEstimationStatus>
    </StoreEstimationList>
  </UserEstimationList>
  <UserEstimationList>
    <EntityName>[email removido]</EntityName>
    <StoreEstimationList>
      <StoreName>[email removido]</StoreName>
      <EstimationStatus value="Success" />
      <EmailEstimationStatus>
        <EstimationStatus value="Success" />
        <FolderList>
          <FolderName>Itens Enviados</FolderName>
          <FolderStatus value="Success" />
          <TotalCount value="571" />
        </FolderList>
        <FolderList>
          <FolderName>Lixeira</FolderName>
          <FolderStatus value="Success" />
          <TotalCount value="3" />
        </FolderList>
        <TotalCount value="574" />
        <StartTime>2011-05-25T18:36:07.000Z</StartTime>
        <EndTime>2011-05-25T18:36:12.000Z</EndTime>
      </EmailEstimationStatus>
    </StoreEstimationList>
  </UserEstimationList>
  </MigrationEstimationReport>

Para isso refiz TODA hierarquia de classe como eu li para e falaram pra fazer depois fui criar os aliases no meu método que acabou ficando algo assim

public void readXML(String path) throws IOException, ClassNotFoundException {
		
		FileReader fileReader = new FileReader(path);
		BufferedReader in = new BufferedReader(fileReader);
        XStream stream = new XStream(new DomDriver());
        stream.alias("MigrationEstimationReport", MigrationEstimationReport.class);
        stream.alias("UserEstimationList",  UserEstimationList.class);
        stream.alias("EntityName", EntityName.class);
        stream.alias("StoreEstimationList", StoreEstimationList.class);
        stream.alias("EmailEstimationStatus", EmailEstimationStatus.class);
        stream.alias("EstimationStatus", EstimationStatus.class);
        stream.alias("StartTime", StartTime.class);
        stream.alias("EndTime", EndTime.class);
        stream.alias("TotalCount", TotalCount.class);
        stream.alias("FolderList", FolderList.class);       
        List<UserEstimationList> userEstimationList = (List<UserEstimationList>) stream.fromXML(in);
        

        String str;
        while((str = in.readLine()) != null){
        	System.out.println(str);
        }
        in.close();
		//return estimationXML;
	}

No começo estava tendo problemas com classes não mapeadas mas agora estou tendo um problema no resultado do UserEstimationList

Exception in thread "main" com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$DuplicateFieldException: UserEstimationList
---- Debugging information ----
duplicate-field     : UserEstimationList
class               : com.gammeestimation.model.MigrationEstimationReport
required-type       : com.gammeestimation.model.MigrationEstimationReport
path                : /MigrationEstimationReport/UserEstimationList[2]
-------------------------------
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$SeenFields.add(AbstractReflectionConverter.java:322)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:234)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:162)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:82)
	at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:63)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:76)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:60)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:137)
	at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:33)
	at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:923)
	at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:909)
	at com.thoughtworks.xstream.XStream.fromXML(XStream.java:853)
	at com.gammeestimation.main.ReadXML.readXML(ReadXML.java:39)
	at com.gammeestimation.main.EstimationMain.main(EstimationMain.java:14)

Vou copiar também as classes modelos,

[size=7]
public class MigrationEstimationReport {
	
	
	private List<UserEstimationList> UserEstimationList;

	public List<UserEstimationList> getUserEstimationList() {
		return UserEstimationList;
	}

	public void setUserEstimationList(List<UserEstimationList> userEstimationList) {
		this.UserEstimationList = userEstimationList;
	}

}
public class UserEstimationList {

	private List<EntityName> EntityName;
	private List<StoreEstimationList> StoreEstimationList;
	
	
	public List<EntityName> getEntityName() {
		return EntityName;
	}
	public void setEntityName(List<EntityName> entityName) {
		EntityName = entityName;
	}
	public List<StoreEstimationList> getStoreEstimationList() {
		return StoreEstimationList;
	}
	public void setStoreEstimationList(List<StoreEstimationList> storeEstimationList) {
		this.StoreEstimationList = storeEstimationList;
	}
}
[/size] [/code]

Desculpem por criar um topico tão cheio de código, eu odeio ver topicos assim mas estou sem ideia como resolver.

Obrigado!

16 Respostas

romarcio

Da uma lida nesse tutorial que eu montei: http://mballem.wordpress.com/2011/05/12/manipulando-arquivo-xml-–-parte-iii-xstream/
Vai lá na sessão 5. Gerando o XML através de anotações Lê ela, e se possivel faz o exemplo que eu criei, que dai você vai entender como funciona a coisa toda.
Pode também fazer isso sem uso de anotações, mas é mais trabalhoso.

A

Romarcio,

Obrigado pelo link, no exemplo consegui fazer show de bola agora na prática :blush:

Acho o que meu problema está na hora de montar o objeto para UserEstimationList, ele está se perdendo ai :frowning:

romarcio

Na classe MigrationEstimationReport você precisa criar uma lista de UserEstimationList e colocar a anotação @XStreamImplicit

@XStreamAlias("MigrationEstimationReport") public class MigrationEstimationReport { @XStreamImplicit(itemFieldName = "UserEstimationList") private List<UserEstimationList> userEstimationList; ... }

A

Então para todos os filhos eu precisarei colocar esta logica?

romarcio

alejacquet:
Então para todos os filhos eu precisarei colocar esta logica?

Apenas quando você tiver uma lista de uma classe dentro de outra.
Isso aconteceu apenas 2 vezes nesse seu xml.
Dentro da classe MigrationEstimationReport, você tem uma lista de UserEstimationList. E dentro da classe EmailEstimationStatus, você tem uma lista de FolderList.

romarcio

Você deve criar classes apenas do que é classe.
Por exemplo:

<MigrationEstimationReport>  
  <UserEstimationList>  
    <EntityName>[email removido]</EntityName>  
    <StoreEstimationList>  
      <StoreName>[email removido]</StoreName>  
      <EstimationStatus value="Fail" />  
      <EmailEstimationStatus>  
        <EstimationStatus value="Fail" />  
        <StartTime>2011-05-25T18:36:00.000Z</StartTime>  
        <EndTime>2011-05-25T18:36:05.000Z</EndTime>  
      </EmailEstimationStatus>  
    </StoreEstimationList>  
  </UserEstimationList>
</MigrationEstimationReport>

MigrationEstimationReport é uma classe que possui um atributo que é uma lista de UserEstimationList que também é uma classe.
UserEstimationList é uma classe que possui os atributos EntityName que deve ser uma String e o atributo StoreEstimationList que é uma classe.
StoreEstimationList é uma classe que possui os atributos StoreName, EstimationStatus que parecem ser String e o atributo EmailEstimationStatus que é uma classe
EmailEstimationStatus é uma classe que possui os atributos StartTime, EndTime e EstimationStatus e na última tag do seu modelo completo mostra que também tem um atributo FolderList que é uma lista da classe FolderList que possui outros atributos.

A

Ok, remanjei as Classes fiquei com o seguinte

@XStreamAlias("MigrationEstimationReport")  
public class MigrationEstimationReport {

	@XStreamImplicit(itemFieldName = "UserEstimationList")  
	private List<UserEstimationList> UserEstimationList;

}

public class UserEstimationList {
	
	@XStreamAlias("EntityName")
	private String EntityName;
	
	@XStreamImplicit(itemFieldName = "StoreEstimationList")  
	private List<StoreEstimationList> StoreEstimationList;
	

public class StoreEstimationList {
	@XStreamAlias("StoreName")
	private String StoreName;

	@XStreamAlias("EstimationStatus")
	private String EstimationStatus;
	
	@XStreamImplicit(itemFieldName = "EmailEstimationStatus")
	private List<EmailEstimationStatus> EmailEstimationStatus;

public class EmailEstimationStatus {
	@XStreamAlias("EstimationStatus")
	private String EstimationStatus;

	@XStreamImplicit(itemFieldName = "FolderList")
	private List<FolderList> FolderList;
	
	@XStreamAlias("TotalCount")
	private String TotalCount;
	
	@XStreamAlias("StartTime")
	private String StartTime;
	
	@XStreamAlias("EndTime")
	private String EndTime;


public class FolderList {
	@XStreamAlias("FolderName")
	private String FolderName;
	
	@XStreamAlias("FolderStatus")
	private String FolderStatus;
	
	@XStreamAlias("TotalCount")
	private String TotalCount;
	

	public void readXML(String path) throws IOException, ClassNotFoundException {
		
		FileReader fileReader = new FileReader(path);
		BufferedReader in = new BufferedReader(fileReader);
        XStream stream = new XStream(new DomDriver());
        stream.processAnnotations(MigrationEstimationReport.class);
        stream.processAnnotations(UserEstimationList.class);
        stream.processAnnotations(StoreEstimationList.class);
        stream.processAnnotations(EmailEstimationStatus.class);
        stream.processAnnotations(FolderList.class);
        List<UserEstimationList> userEstimationList = (List<UserEstimationList>) stream.fromXML(in);

Isso tudo resultou em

Exception in thread main java.lang.ClassCastException: com.gammeestimation.model.MigrationEstimationReport cannot be cast to java.util.List

at com.gammeestimation.main.ReadXML.readXML(ReadXML.java:28)

at com.gammeestimation.main.EstimationMain.main(EstimationMain.java:14)
A

AEEE

Agora consegui

MigrationEstimationReport migrationReport = (MigrationEstimationReport) stream.fromXML(in);
System.out.println(migrationReport.getUserEstimationList().get(1).getEntityName());

Eu estava tentando pegar o list no lugar errado, MUUIITOOO OBRIGADO Romarcio!!!

A

Só estou com um pequeno problema…

Como retorno um valor que está no seguinte parametro

<EstimationStatus value=“Success” />

Toda vez que tento puxar ele volta em branco,

romarcio

Isso mesmo, só uma coisa, na última parte onde usa o método stream.processAnnotations(MigrationEstimationReport.class);
pode deixar só esse e eliminar os outros que você colocou. Pq através deste e das anotações ele faz o resto.

Sobre a pergunta, não sei te responder. Dei uma pesquisa no site oficial mas não encontrei nada a respeito.
Tem uma anotação que parecia ser para isso, mas testei e não funcionou (@XStreamAsAttribute)

Talvez para ler esses atributos das tags, vc não vai conseguir usando o XStream.

A

Boa noite pessoal,

Estou com problemas no xstream para retornar a seguinte parte do xml

&lt;FolderList&gt;
          &lt;FolderName&gt;Itens Enviados&lt;/FolderName&gt;
          &lt;FolderStatus value="Success" /&gt;
          &lt;TotalCount value="571" /&gt;
        &lt;/FolderList&gt;

public class FolderList {
	@XStreamAlias("FolderName")
	private String FolderName;
	
	@XStreamAlias("FolderStatus")
	private String FolderStatus;
	
	@XStreamAlias("TotalCount")
	private String TotalCount;

Aparentemente ele não consegue identificar os valores que são passados nos values... Eu consigo chegar até o nó mas ele nao retorna nada alguem tem alguma ideia?

romarcio

Consegui ler o atributo TotalCount que tem na classe EmailEstimationStatus. Porém se faço a mesma coisa para ler o que tem na classe FolderList, da erro:

Fiz assim, criei uma classe para o atributo TotalCount e uma classe TotalCountConverter para converter o atributo.

public class TotalCount {

    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

public class TotalCountConverter implements Converter {

    public void marshal(Object o, HierarchicalStreamWriter hierarchicalStreamWriter, MarshallingContext marshallingContext) {
        TotalCount totalCount = (TotalCount) o;

        hierarchicalStreamWriter.addAttribute( "value", totalCount.getValue() );
    }

    public Object unmarshal(HierarchicalStreamReader hierarchicalStreamReader, UnmarshallingContext unmarshallingContext) {
        TotalCount totalCount = new TotalCount();

        totalCount.setValue(hierarchicalStreamReader.getAttribute("value"));

        hierarchicalStreamReader.moveUp();

        return totalCount;
    }

    public boolean canConvert(Class aClass) {
        return aClass.equals(TotalCount.class);
    }

Dai na classe EmailEstimationStatus eu passo o atributo TotalCount de String para o tipo TotalCount.
E uso a anotação XStreamConverter para indicar qual classe ira converter esse atributo

@XStreamAlias("EmailEstimationStatus")
public class EmailEstimationStatus {
    ...

    @XStreamAlias("TotalCount")
    @XStreamConverter(value = TotalCountConverter.class)
    private TotalCount totalCount;

    ...

Porém não entendi por que na classe FolderList da erro se faço a mesma coisa.
Tenta descobrir isso.
Para os outros atributos que tem esse campo value na tag, deve ser feito o mesmo procedimento, criar uma classe e depois uma classe converter para eles.

A

Fiz exatamente como você passou mas tive o seguinte erro

Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl cannot be cast to org.w3c.dom.Element : com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl cannot be cast to org.w3c.dom.Element
---- Debugging information ----
message             : com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl cannot be cast to org.w3c.dom.Element
cause-exception     : java.lang.ClassCastException
cause-message       : com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl cannot be cast to org.w3c.dom.Element
class               : com.gammeestimation.model.MigrationEstimationReport
required-type       : com.gammeestimation.model.MigrationEstimationReport
path                : /MigrationEstimationReport

...
-------------------------------
A

Tentei fazer semelhante para o EstimationStatus que é o principal

public class EmailEstimationStatus {

	@XStreamAlias("EstimationStatus")
	@XStreamConverter(value = EstimationStatusConverter.class)
	private EstimationStatus EstimationStatus;

	@XStreamImplicit(itemFieldName = "FolderList")
	private List&lt;FolderList&gt; FolderList;
	
	@XStreamAlias("TotalCount")  
	private String TotalCount;
	
	@XStreamAlias("StartTime")
	private String StartTime;
	
	@XStreamAlias("EndTime")
	private String EndTime;


public class EstimationStatus {
	private String value;

	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}
}


package com.gammeestimation.model;

import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

public class EstimationStatusConverter implements Converter {

	@Override
	public boolean canConvert(Class arg0) {
		return arg0.equals(EstimationStatus.class);  
	}

	@Override
	public void marshal(Object arg0, HierarchicalStreamWriter arg1, MarshallingContext arg2) {
		EstimationStatus estimationStatus = (EstimationStatus) arg0;
		arg1.addAttribute("value", estimationStatus.getValue());
		
	}

	@Override
	public Object unmarshal(HierarchicalStreamReader arg0, UnmarshallingContext arg1) {
		EstimationStatus estimationStatus = new EstimationStatus();
		estimationStatus.setValue(arg0.getAttribute("value"));
		arg0.moveUp();
		return estimationStatus;
	}

}

	public static void main(String[] args) {
		try {
			MigrationEstimationReport migrationReport = new ReadXML().readXML("test.xml");
			List&lt;UserEstimationList&gt; userEstimationList = migrationReport.getUserEstimationList();
			System.out.println(userEstimationList.get(1).getStoreEstimationList().get(0).getEmailEstimationStatus().get(0).getEstimationStatus());

Mas tive um resultado diferente do outro

Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: UserEstimationList : UserEstimationList : UserEstimationList : UserEstimationList
---- Debugging information ----
message             : UserEstimationList : UserEstimationList
cause-exception     : com.thoughtworks.xstream.mapper.CannotResolveClassException
cause-message       : UserEstimationList : UserEstimationList
class               : com.gammeestimation.model.MigrationEstimationReport
required-type       : com.gammeestimation.model.UserEstimationList
path                : /MigrationEstimationReport/UserEstimationList[2]
-------------------------------
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:89)
	at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:63)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:76)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:60)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:225)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:162)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:82)
romarcio

Erro parecido com os que eu tive aqui quando tento usar um atributo em mais de uma classe.

Não consegui achar o motivo disto. Acho que seria melhor você tentar usar a API JDOM, é mais trabalhosa, mas mais manipulavel que esse XStream.

A

Vou criar outro codigo parecido mas não vou desistir!

Muitisssiimo obrigado cara!

Criado 26 de maio de 2011
Ultima resposta 26 de mai. de 2011
Respostas 16
Participantes 2