XStream me dando dor de cabeça para ler XML

Pessoal,

Estou usando o XStream para ler um XML relativamente muito fácil. Implementei todos os beans e para criar o XML a partir dos JavaBeans criados, fuinciona perfeitamente. Porém, quando eu tenho o XML obtido externamente, ele da um erro muito louco. Já vasculhei o Google para ver se alguém tinha passado por isso, e acabei não achando nada. Estou recorrendo a vocês para ver se alguém já enfrentou algo parecido com isso.

Bom vamos lá. O XML que eu tenho que ler é o da API do Twitter. É igual a esse abaixo:

<?xml version="1.0" encoding="UTF-8"?>
<statuses type="array">
<status>
  <created_at>Tue Mar 24 23:15:16 +0000 2009</created_at>
  <id>1384672137</id>
  <text>zzzzzZZZzzzzz zzz ZZZZzzzzzz.  ZzzZzzzzzzzZzzzz. Zzzzz zz.   Zzzzz</text>
  <source>&lt;a href=&quot;http://www.atebits.com/software/tweetie/&quot;&gt;Tweetie&lt;/a&gt;</source>

  <truncated>false</truncated>
  <in_reply_to_status_id></in_reply_to_status_id>
  <in_reply_to_user_id></in_reply_to_user_id>
  <favorited>false</favorited>
  <in_reply_to_screen_name></in_reply_to_screen_name>
  <user>
    <id>16428990</id>

    <name>Alex </name>
    <screen_name>Xlex</screen_name>
    <location>Amsterdam</location>
    <description>Hi ! I'm Alex . Im an artist , designer , and a musician. Oh and i LOVE to twittt !!!!!!!!</description>
    <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/61499379/photo-3c_normal.JPG</profile_image_url>
    <url></url>

    <protected>false</protected>
    <followers_count>583</followers_count>
  </user>
</status>
<status>
  <created_at>Tue Mar 24 23:14:50 +0000 2009</created_at>
  <id>1384669752</id>
  <text>Going to sleep, feeling so lonely :( so diprest. SleepSweet Twitterrrr !</text>

  <source>&lt;a href="http://www.atebits.com/software/tweetie/"&gt;Tweetie&lt;/a&gt;</source>
  <truncated>false</truncated>
  <in_reply_to_status_id></in_reply_to_status_id>
  <in_reply_to_user_id></in_reply_to_user_id>
  <favorited>false</favorited>
  <in_reply_to_screen_name></in_reply_to_screen_name>

  <user>
    <id>16428990</id>
    <name>Alex </name>
    <screen_name>Xlex</screen_name>
    <location>Amsterdam</location>
    <description>Hi ! I'm Alex . Im an artist , designer , and a musician. Oh and i LOVE to twittt !!!!!!!!</description>

    <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/61499379/photo-3c_normal.JPG</profile_image_url>
    <url></url>
    <protected>false</protected>
    <followers_count>583</followers_count>
  </user>
</status>
<status>
  <created_at>Tue Mar 24 22:14:10 +0000 2009</created_at>

  <id>1384364371</id>
  <text>Vai nessa, monkey boy: http://tinyurl.com/c4v65s</text>
  <source>&lt;a href="http://twitterfox.net/"&gt;TwitterFox&lt;/a&gt;</source>
  <truncated>false</truncated>
  <in_reply_to_status_id></in_reply_to_status_id>
  <in_reply_to_user_id></in_reply_to_user_id>

  <favorited>false</favorited>
  <in_reply_to_screen_name></in_reply_to_screen_name>
  <user>
    <id>8524192</id>
    <name>Eust&#225;quio Rangel</name>
    <screen_name>taq</screen_name>

    <location>S&#227;o Jos&#233; do Rio Preto, SP, Bra</location>
    <description>http://eustaquiorangel.com/me</description>
    <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/56074459/taqblack_normal.jpg</profile_image_url>
    <url>http://eustaquiorangel.com</url>
    <protected>false</protected>

    <followers_count>456</followers_count>
  </user>
</status>
</statuses>

Meus Beans estão implementados assim:

package com.jforbidtwitt.xml.beans;

import java.util.ArrayList;
import java.util.List;

public class Statuses {
	
	private String type;
	private List<Status> status = new ArrayList<Status>();
	
	public String getType() {
		return type;
	}
	
	public void setType(String type) {
		this.type = type;
	}
	
	public void add(Status status) {
		this.status.add(status);
	}
	
	public List<Status> getContent() {
		return this.status;
	}
}

[code]package com.jforbidtwitt.xml.beans;

public class Status {

private String created_at;
private String id;
private String text;
private String source;
private boolean truncated;
private String in_reply_to_status_id;
private String in_reply_to_user_id;
private boolean favorited;
private String in_reply_to_screen_name;
private User user;

public User getUser() {
	return user;
}

public void setUser(User user) {
	this.user = user;
}

public String getCreated_at() {
	return created_at;
}

public void setCreated_at(String created_at) {
	this.created_at = created_at;
}

public String getId() {
	return id;
}

public void setId(String id) {
	this.id = id;
}

public String getText() {
	return text;
}

public void setText(String text) {
	this.text = text;
}

public String getSource() {
	return source;
}

public void setSource(String source) {
	this.source = source;
}

public boolean isTruncated() {
	return truncated;
}

public void setTruncated(boolean truncated) {
	this.truncated = truncated;
}

public String getIn_reply_to_status_id() {
	return in_reply_to_status_id;
}

public void setIn_reply_to_status_id(String in_reply_to_status_id) {
	this.in_reply_to_status_id = in_reply_to_status_id;
}

public String getIn_reply_to_user_id() {
	return in_reply_to_user_id;
}

public void setIn_reply_to_user_id(String in_reply_to_user_id) {
	this.in_reply_to_user_id = in_reply_to_user_id;
}

public boolean isFavorited() {
	return favorited;
}

public void setFavorited(boolean favorited) {
	this.favorited = favorited;
}

public String getIn_reply_to_screen_name() {
	return in_reply_to_screen_name;
}

public void setIn_reply_to_screen_name(String in_reply_to_screen_name) {
	this.in_reply_to_screen_name = in_reply_to_screen_name;
}

}
[/code]

[code]package com.jforbidtwitt.xml.beans;

public class User {

private String name;
private String screen_name;
private String location;
private String description;
private String profile_image_url;
private String url;
private boolean protect;
private int followers_count;

public String getName() {
	return name;
}

public void setName(String name) {
	this.name = name;
}

public String getScreen_name() {
	return screen_name;
}

public void setScreen_name(String screen_name) {
	this.screen_name = screen_name;
}

public String getLocation() {
	return location;
}

public void setLocation(String location) {
	this.location = location;
}

public String getDescription() {
	return description;
}

public void setDescription(String description) {
	this.description = description;
}

public String getProfile_image_url() {
	return profile_image_url;
}

public void setProfile_image_url(String profile_image_url) {
	this.profile_image_url = profile_image_url;
}

public String getUrl() {
	return url;
}

public void setUrl(String url) {
	this.url = url;
}

public boolean isProtect() {
	return protect;
}

public void setProtect(boolean protect) {
	this.protect = protect;
}

public int getFollowers_count() {
	return followers_count;
}

public void setFollowers_count(int followers_count) {
	this.followers_count = followers_count;
}

}
[/code]

E para ler o XML estou fazendo assim:

[code]package com.jforbidtwitt.xml;

import com.jforbidtwitt.xml.beans.Status;
import com.jforbidtwitt.xml.beans.Statuses;
import com.jforbidtwitt.xml.beans.User;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

public class XMLRead {

public static Statuses readXML(String xml) {
	System.out.println();
	XStream xs = new XStream(new DomDriver());
	xs.alias("statuses", Statuses.class);
	xs.alias("status", Status.class);
	xs.alias("user", User.class);
	xs.aliasAttribute(Statuses.class, "type", "type");
	xs.addImplicitCollection(Statuses.class, "status");
	xs.aliasField("protect", User.class, "protected");
	
	Statuses res = (Statuses) xs.fromXML(xml);
	System.out.println(res);
	
	return res;
}

}[/code]

E finalmente, porém muito importante, o erro cabuloso que o XStream gera:

Alguém consegue ter alguma luz nesse túnel sombrio?

Obrigado

Só atualizando o post. Como eu não consegui ainda usar o XStream para ler essa XML, fui para o JDOM mesmo e fiz o parse “manual”. Funcionou muito bem o método que implementei pra realizar o parser usando o JDOM. Abaixo está o método implementado usando o JDOM. Mas mesmo assim, que souber como arrumar o erro do XStream, por favor, eu ainda gostaria de usar o XStream.

public class JDOMRead implements XMLRead {

	@SuppressWarnings("unchecked")
	@Override
	public Statuses readXML(String XML) throws NullXMLException {
		
		if (XML == null) {
			throw new NullXMLException("A XML passada como parâmetro não pode ser nula.");
		}
		
		SAXBuilder parser = new SAXBuilder();
        
        try {
            Document doc = parser.build(new StringReader(XML));
            Element root = doc.getRootElement();
            List<Element> status = root.getChildren("status");

            Iterator<Element> i = status.iterator();

            Statuses statuses = new Statuses();
            Status st = null;
            User user = null;

            while(i.hasNext()) {
                Element s = i.next();
                st = new Status();

                st.setCreated_at(s.getChildText("created_at"));
                st.setFavorited(Boolean.parseBoolean(s.getChildText("favorited")));
                st.setId(s.getChildText("id>"));
                st.setIn_reply_to_screen_name(s.getChildText("in_reply_to_screen_name"));
                st.setIn_reply_to_user_id(s.getChildText("in_reply_to_user_id"));
                st.setIn_reply_to_status_id(s.getChildText("in_reply_to_status_id"));
                st.setSource(s.getChildText("source"));
                st.setText(s.getChildText("text"));
                st.setTruncated(Boolean.parseBoolean(s.getChildText("truncated")));

                user = new User();
                user.setDescription(s.getChild("user").getChildText("description"));
                user.setFollowers_count(Integer.parseInt(s.getChild("user").getChildText("followers_count")));
                user.setId(s.getChild("user").getChildText("id"));
                user.setLocation(s.getChild("user").getChildText("location"));
                user.setName(s.getChild("user").getChildText("name"));
                user.setProfile_image_url(s.getChild("user").getChildText("profile_image_url"));
                user.setProtect(Boolean.parseBoolean(s.getChild("user").getChildText("protected")));
                user.setScreen_name(s.getChild("user").getChildText("screen_name"));
                user.setUrl(s.getChild("user").getChildText("url"));

                st.setUser(user);

                statuses.add(st);
            }

            return statuses;

        }
        catch (JDOMException e) {
            e.printStackTrace();
            return null;
        }
        catch (IOException e) {
            e.printStackTrace();
            return null;
        }
	}
}

Mais de 1 ano depois, mas está aí caso possa ajudar alguém:

Quem faz a mágica é a classe “XmlFriendlyReplacer”.

Em situação igual a deste problema, um “conflito” foi resolvido quando modifiquei em meu código o equivalente ao nome do atributo e status (em seu codigo) para algo diferente do alias da classe. Ou seja, escolha um nome diferente para o atributo status da classe Statuses (linha 09) não esquecendo de atualizar tambem na linha 18 da classe XMLRead.

Tive um problema semelhante. A solução que apliquei foi utilizar a anotação “@XStreamImplicit”:

public class Statuses {

private String type;  

@XStreamImplicit
private List<Status> status = new ArrayList<Status>();