quand est-ce que JAXB est unmarshaller.unmarshal renvoie un JAXBElement ou un MySchemaObject?
j'ai deux codes, dans deux projets java différents, faisant presque la même chose (démonter l'entrée d'un service web selon un fichier xsd).
Mais, dans un cas, je devrais écrire ceci: (Entrée est un espace réservé de nom) ( élément est OMElement d'entrée )
ClassLoader clInput = input.ObjectFactory.class.getClassLoader();
JAXBContext jc = JAXBContext.newInstance("input", clInput);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Input input = (Input)unmarshaller.unmarshal( element.getXMLStreamReader() );
et dans l'autre lib je dois utiliser JAXBElement.getValue (), parce que C'est un JAXBElement qui est retourné, et qu'un cast simple (Input) s'écrase simplement:
Input input = (Input)unmarshaller.unmarshal( element.getXMLStreamReader() ).getValue();
savez-vous ce qui mène à une telle différence ?
5 réponses
Si l'élément racine unique correspond à une classe Java alors une instance de cette classe sera retourné, et si ce n'est un JAXBElement
sera retourné.
si vous voulez vous assurer que vous obtenez toujours une instance de l'objet domaine, vous pouvez utiliser le JAXBInstrospector
. Ci-dessous est un exemple.
Démo
package forum10243679;
import java.io.StringReader;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
public class Demo {
private static final String XML = "<root/>";
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBIntrospector jaxbIntrospector = jc.createJAXBIntrospector();
Object object = unmarshaller.unmarshal(new StringReader(XML));
System.out.println(object.getClass());
System.out.println(jaxbIntrospector.getValue(object).getClass());
Object jaxbElement = unmarshaller.unmarshal(new StreamSource(new StringReader(XML)), Root.class);
System.out.println(jaxbElement.getClass());
System.out.println(jaxbIntrospector.getValue(jaxbElement).getClass());
}
}
Sortie
class forum10243679.Root
class forum10243679.Root
class javax.xml.bind.JAXBElement
class forum10243679.Root
cela dépend de la présence de xmlrootelement annotation sur la classe de votre élément racine.
si vous générez vos classes JAXB à partir D'un XSD, les règles suivantes s'appliquent:
- si le type de l'élément racine est un type anonyme - > xmlrootelement l'annotation est ajoutée à la classe générée
- si le type de l'élément racine est un type de niveau supérieur - > xmlrootelement annotation est omis de la classe générée
pour cette raison, je choisis souvent des types anonymes pour les éléments racine.
vous pouvez personnaliser le nom de classe de ce type anonyme avec un fichier de personnalisation. Par exemple: créer une reliure.fichier xjc comme ceci:
<jxb:bindings version="1.0"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jxb:bindings schemaLocation="yourXsd.xsd" node="/xs:schema">
<jxb:bindings node="//xs:element[@name='yourRootElement']">
<jxb:class name="YourRootElementType"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
vous devez ajouter à votre classe générée par JAXB @XMLRootElement
- il devrait avoir l'espace de nom:
@XmlRootElement(namespace="http://your.namespace.com/", name="yourRootElement")
jetez un coup d'oeil à la question connexe (il y a beaucoup de bons conseils): Classe Cast Exception lors de l'essai de unmarshall xml?
Modifier les classes java générées, Je ne suis pas d'accord. Ne pas autoriser tous les formats xsd possibles, Je ne suis pas d'accord.
Merci pour toutes vos explications d'un des liens, c'est le code que j'ai écrit afin de prendre soin de ces deux cas, l'utilisation de l'Annotation à l'Introspection. Il fonctionne pour la sortie ainsi que l'entrée, et est (à mon goût) plus générique:
public class JaxbWrapper {
private static boolean isXmlRootElement(Class classT){
Annotation[] annotations = classT.getAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof XmlRootElement){
return true;
}
}
return false;
}
public static Object unmarshall(Class classObjectFactory, Class classObject, XMLStreamReader xmlStreamReader){
Package pack = classObjectFactory.getPackage();
String strPackageName = pack.getName();
Object returnObject = null;
try {
JAXBContext jc = JAXBContext.newInstance(strPackageName, classObjectFactory.getClassLoader());
Unmarshaller unmarshaller = jc.createUnmarshaller();
returnObject = unmarshaller.unmarshal( xmlStreamReader );
boolean bIsRootedElement = isXmlRootElement(classObject);
if(!bIsRootedElement)
{
JAXBElement jaxbElement = (JAXBElement) returnObject;
returnObject = jaxbElement.getValue();
}
}
catch (JAXBException e) {
/*...*/
}
return returnObject;
}
private static void writeToXml(Class classObjectFactory, Object obj, XMLStreamWriter xmlStreamWriter){
Package pack = classObjectFactory.getPackage();
String strPackageName = pack.getName();
try {
JAXBContext jc = JAXBContext.newInstance(strPackageName, classObjectFactory.getClassLoader());
Marshaller marshaller = jc.createMarshaller();
marshaller.marshal(obj, xmlStreamWriter);
}
catch(JAXBException e) {
/*...*/
}
}
public static String marshall(Class classObjectFactory, Class classObject, Object obj){
Object objectToMarshall = obj;
boolean bIsRootedElement = isXmlRootElement(classObject);
if(!bIsRootedElement)
{
Package pack = classObjectFactory.getPackage();
String strPackageName = pack.getName();
String strClassName = classObject.getName();
QName qName = new QName(strPackageName, strClassName);
JAXBElement jaxbElement = new JAXBElement(qName, classObject, null, obj);
objectToMarshall = jaxbElement;
}
StringWriter sw = new StringWriter();
XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
XMLStreamWriter xmlStreamWriter = null;
try {
xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(sw);
writeToXml(classObjectFactory, objectToMarshall, xmlStreamWriter);
xmlStreamWriter.flush();
xmlStreamWriter.close();
}
catch (XMLStreamException e) {
/*...*/
}
return sw.toString();
}
}
j'ai le même problème. JAXB unmarshaller.unmarshal retourne un JAXBElement<MyObject>
au lieu du MyObject
désiré .
j'ai trouvé et enlevé @XmlElementDecl
. Le problème est résolu.