Unmarshalling liste générique avec JAXB
J'ai un service qui retourne ce XML:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<status>success</status>
<result>
<project>
<id>id1</id>
<owner>owner1</owner>
</project>
<project>
<id>id2</id>
<owner>owner2</owner>
</project>
</result>
ou
<?xml version="1.0" encoding="UTF-8"?>
<response>
<status>success</status>
<result>
<user>
<id>id1</id>
<name>name1</name>
</user>
<user>
<id>id2</id>
<name>name2</name>
</user>
</result>
Je veux unmarshall le XML récupéré à l'aide de ces classes:
Résultat:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
@XmlElement
protected String status;
@XmlElementWrapper(name = "result")
@XmlElement
protected List<T> result;
}
Projet:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Project {
@XmlElement
public String id;
@XmlElement
public String owner;
}
Utilisateur:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class User {
@XmlElement
public String id;
@XmlElement
public String name;
}
Premier pas de solution de travail
JAXBContext context = JAXBContext.newInstance(Response.class, Project.class, User.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
StreamSource source = new StreamSource(new File("responseProject.xml"));
Response<Project> responseProject = (Response<Project>)unmarshaller.unmarshal(source);
System.out.println(responseProject.getStatus());
for (Project project:responseProject.getResult()) System.out.println(project);
source = new StreamSource(new File("responseUser.xml"));
Response<User> responseUser = (Response<User>)unmarshaller.unmarshal(source);
System.out.println(responseUser.getStatus());
for (User user:responseUser.getResult()) System.out.println(user);
- Je obtenir une liste vide.
Deuxième ne fonctionne pas solution
Inspiré par cet article http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html j'ai modifié la classe de Réponse:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
@XmlElement
protected String status;
@XmlAnyElement(lax=true)
protected List<T> result;
}
Et puis testé avec ce code:
Response<Project> responseProject = unmarshal(unmarshaller, Project.class, "responseProject.xml");
System.out.println(responseProject.getStatus());
for (Project project:responseProject.getResult()) System.out.println(project);
private static <T> Response<T> unmarshal(Unmarshaller unmarshaller, Class<T> clazz, String xmlLocation) throws JAXBException {
StreamSource xml = new StreamSource(xmlLocation);
@SuppressWarnings("unchecked")
Response<T> wrapper = (Response<T>) unmarshaller.unmarshal(xml, Response.class).getValue();
return wrapper;
}
Et je bénéficier de cette exception, la lecture de la réponse de la liste:
Exception in thread "main" java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to org.test.Project
Note: je ne peux pas modifier le XML d'origine. Il y a plus d'autres types de Projet et de l'Utilisateur.
L'exemple suivant permettra de: blog.bdoughan.com/2012/11/...
Bonjour Blaise, j'ai déjà trouvé votre article, nice btw, mais j'obtiens une exception d'essayer de lire la liste: Exception in thread "main" java.lang.ClassCastException: com.soleil.org.apache.xerces.interne.dom.ElementNSImpl ne peut pas être lancé pour org.test.Projet, je mettrai à jour la question avec l'essayé la solution.
Vous devez vous assurer que le
Essayez de triage d'une instance de l'objet de votre modèle. Puis de le comparer avec l'entrée que vous utilisez pour voir si elles correspondent?
Fait ce travail, je vous remercie! Je vais poster une réponse.
Bonjour Blaise, j'ai déjà trouvé votre article, nice btw, mais j'obtiens une exception d'essayer de lire la liste: Exception in thread "main" java.lang.ClassCastException: com.soleil.org.apache.xerces.interne.dom.ElementNSImpl ne peut pas être lancé pour org.test.Projet, je mettrai à jour la question avec l'essayé la solution.
Vous devez vous assurer que le
JAXBContext
est conscient de toutes les classes, et que chacun des éléments de la collection est annoté avec @XmlRootElement
.Essayez de triage d'une instance de l'objet de votre modèle. Puis de le comparer avec l'entrée que vous utilisez pour voir si elles correspondent?
Fait ce travail, je vous remercie! Je vais poster une réponse.
OriginalL'auteur Fedy2 | 2013-11-09
Vous devez vous connecter pour publier un commentaire.
Grâce à Blaise Doughan et de son article, que j'ai trouvé la solution.
Nous avons d'abord besoin de la classe Wrapper fournie dans l'article:
Puis j'ai modifié la classe de Réponse pour l'utiliser:
Enfin la unmarshalling code:
J'ai ajouté de la classe Wrapper pour la classe de contexte de liste.
Alternativement, vous pouvez ajouter cette annotation à la classe de Réponse:
OriginalL'auteur Fedy2
À l'aide de @XmlSeeAlso({Project.class, User.class}) sur Réponse classes a l'inconvénient de produire des déchets informations sur chaque entité dans la liste: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="compteutilisateur"
OriginalL'auteur Michał Ziobro