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

R

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:

R

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?

R

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.

R

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,

R

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?

R

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)
R

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