java - without - it is missing an @xmlrootelement annotation
No @XmlRootElement generado por JAXB (14)
¡En caso de que mi experiencia con este problema le dé a alguien un Eureka! momento ... Agregaré lo siguiente:
También estaba obteniendo este problema cuando usaba un archivo xsd que había generado usando la opción de menú "Generar xsd desde documento de instancia" de IntelliJ.
Cuando acepté todos los valores predeterminados de esta herramienta, generó un archivo xsd que, cuando se usaba con jaxb, generaba archivos Java sin @XmlRootElement
. En el tiempo de ejecución cuando traté de reunirme obtuve la misma excepción que se discutió en esta pregunta.
Volví a la herramienta IntellJ y vi la opción predeterminada en el menú desplegable "Tipo de diseño" (que por supuesto no entendí ... y todavía no lo hago si soy sincero) fue:
Tipo de Desgin:
"elementos locales / tipos complejos globales"
Cambié esto a
"elementos / tipos locales"
, ahora generó un xsd (sustancialmente) diferente, que produjo @XmlRootElement
cuando se usó con jaxb. No puedo decir que entiendo las entradas y salidas, pero funcionó para mí.
Intento generar clases Java a partir de la versión 4.5 de FpML (Lenguaje de marcado de productos financieros). Se genera una tonelada de código, pero no puedo usarlo. Tratando de serializar un documento simple, entiendo esto:
javax.xml.bind.MarshalException
- with linked exception: [com.sun.istack.SAXException2: unable
to marshal type
"org.fpml._2008.fpml_4_5.PositionReport"
as an element because it is missing an
@XmlRootElement annotation]
De hecho, ninguna clase tiene la anotación @XmlRootElement, entonces ¿qué puedo estar haciendo mal ?. Estoy apuntando xjc (JAXB 2.1) a fpml-main-4-5.xsd, que luego incluye todos los tipos.
¿Intentó cambiar su xsd así?
<!-- create-logical-system -->
<xs:element name="methodCall">
<xs:complexType>
...
</xs:complexType>
</xs:element>
@XmlRootElement no es necesario para desasignar, si se usa la forma de 2 parámetros de Unmarshaller # unmarshall.
Entonces, si en vez de hacer:
UserType user = (UserType) unmarshaller.unmarshal(new StringReader(responseString));
uno debería hacer:
JAXBElement<UserType> userElement = unmarshaller.unmarshal(someSource, UserType.class);
UserType user = userElement.getValue();
El último código no requerirá la anotación @XmlRootElement en el nivel de clase UserType.
Como sabes, la respuesta es usar ObjectFactory (). Aquí hay una muestra del código que funcionó para mí :)
ObjectFactory myRootFactory = new ObjectFactory();
MyRootType myRootType = myRootFactory.createMyRootType();
try {
File file = new File("./file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(MyRoot.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
//output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
JABXElement<MyRootType> myRootElement = myRootFactory.createMyRoot(myRootType);
jaxbMarshaller.marshal(myRootElement, file);
jaxbMarshaller.marshal(myRootElement, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
Como se insinuó en una de las respuestas anteriores, no obtendrá un XMLRootElement en su elemento raíz si en el XSD su tipo está definido como un tipo con nombre, ya que ese tipo con nombre podría usarse en otro lugar en su XSD. Intente crear un tipo anónimo, es decir, en lugar de:
<xsd:element name="myRootElement" type="MyRootElementType" />
<xsd:complexType name="MyRootElementType">
...
</xsd:complexType>
tendrías:
<xsd:element name="myRootElement">
<xsd:complexType>
...
<xsd:complexType>
</xsd:element>
Con una compilación Maven, puede agregar la anotación @XmlRootElement
con el jaxb2-basics-annotate
" jaxb2-basics-annotate
".
Ver más información: ver
Configure Maven para generar clases a partir de un Esquema XML usando JAXB
Después de buscar durante dos días, encontré la solución para el problema. Puede usar la clase ObjectFactory como solución alternativa para las clases que no tienen @XmlRootElement . ObjectFactory ha sobrecargado los métodos para envolverlo alrededor de JAXBElement. Método: 1 hace la creación simple del objeto y Método: 2 envolverá el objeto con @JAXBElement . Siempre utilizar el método: 2 para evitar javax.xml.bind.MarshalException - con la excepción vinculada falta una anotación @XmlRootElement
Método 1
public GetCountry createGetCountry() {
return new GetCountry();
}
Método: 2
@XmlElementDecl(namespace = "my/name/space", name = "getCountry")
public JAXBElement<GetCountry> createGetCountry(GetCountry value) {
return new JAXBElement<GetCountry>(_GetCountry_QNAME, GetCountry.class, null, value);
}
Muestra del código de trabajo:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
WebServiceTemplate springWSTemplate = context.getBean(WebServiceTemplate.class);
GetCountry request = new GetCountry();
request.setGuid("1f3e1771-3049-49f5-95e6-dc3732c3227b");
JAXBElement<GetCountryResponse> jaxbResponse = (JAXBElement<GetCountryResponse>)springWSTemplate .marshalSendAndReceive(new ObjectFactory().createGetCountry(request));
GetCountryResponse response = jaxbResponse.getValue();
Esto se menciona en la parte inferior de la publicación del blog ya vinculada anteriormente, pero esto funciona como un regalo para mí:
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(new JAXBElement<MyClass>(new QName("uri","local"), MyClass.class, myClassInstance), System.out);
La respuesta de Joe (Joe Jun 26 ''09 a las 17:26) lo hace por mí. La respuesta simple es que la ausencia de una anotación @XmlRootElement no es un problema si clasifica un JAXBElement. Lo que me confundió es que ObjectFactory generado tiene 2 métodos createMyRootElement: el primero no toma parámetros y le da el objeto desenvuelto, el segundo toma el objeto desenvuelto y lo devuelve envuelto en un JAXBElement, y establece que JAXBElement funciona bien. Este es el código básico que utilicé (soy nuevo en esto, por lo que me disculpo si el código no está formateado correctamente en esta respuesta), en gran parte descifrado del texto del enlace :
ObjectFactory objFactory = new ObjectFactory();
MyRootElement root = objFactory.createMyRootElement();
...
// Set root properties
...
if (!writeDocument(objFactory.createMyRootElement(root), output)) {
System.err.println("Failed to marshal XML document");
}
...
private boolean writeDocument(JAXBElement document, OutputStream output) {
Class<?> clazz = document.getValue().getClass();
try {
JAXBContext context =
JAXBContext.newInstance(clazz.getPackage().getName());
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(document, output);
return true;
} catch (JAXBException e) {
e.printStackTrace(System.err);
return false;
}
}
Los contenedores JAXBElement funcionan para casos donde @XmlRootElement
no genera @XmlRootElement
. Estas envolturas están disponibles en la clase ObjectFactory
generada por maven-jaxb2-plugin
. Por ejemplo:
public class HelloWorldEndpoint {
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "person")
@ResponsePayload
public JAXBElement<Greeting> sayHello(@RequestPayload JAXBElement<Person> request) {
Person person = request.getValue();
String greeting = "Hello " + person.getFirstName() + " " + person.getLastName() + "!";
Greeting greet = new Greeting();
greet.setGreeting(greeting);
ObjectFactory factory = new ObjectFactory();
JAXBElement<Greeting> response = factory.createGreeting(greet);
return response;
}
}
Para solucionarlo, debe configurar un enlace xml antes de compilar con wsimport, configurando generateElementProperty como falso.
<jaxws:bindings wsdlLocation="LOCATION_OF_WSDL"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<jaxws:enableWrapperStyle>false</jaxws:enableWrapperStyle>
<jaxws:bindings node="wsdl:definitions/wsdl:types/xs:schema[@targetNamespace=''NAMESPACE_OF_WSDL'']">
<jxb:globalBindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xjc:generateElementProperty>false</xjc:generateElementProperty>
</jxb:globalBindings>
</jaxws:bindings>
</jaxws:bindings>
Para vincular lo que otros ya han indicado o insinuado, las reglas por las cuales JAXB XJC decide si se debe colocar o no la anotación @XmlRootElement
en una clase generada no son triviales ( consulte este artículo ).
@XmlRootElement
existe porque el tiempo de ejecución JAXB requiere cierta información para ordenar / deshacer un determinado objeto, específicamente el nombre del elemento XML y el espacio de nombres. No puedes simplemente pasar cualquier objeto viejo al Marshaller. @XmlRootElement
proporciona esta información.
La anotación es solo una conveniencia, sin embargo, JAXB no lo requiere. La alternativa es usar objetos envoltorios JAXBElement
, que proporcionan la misma información que @XmlRootElement
, pero en forma de un objeto, en lugar de una anotación.
Sin embargo, los objetos de JAXBElement
son difíciles de construir, ya que necesita conocer el nombre del elemento XML y el espacio de nombres, lo que generalmente no sucede con la lógica empresarial.
Afortunadamente, cuando XJC genera un modelo de clase, también genera una clase llamada ObjectFactory
. Esto es parcialmente compatible con JAXB v1, pero también está ahí como lugar para que XJC ponga métodos de fábrica generados que crean envoltorios JAXBElement
alrededor de sus propios objetos. Maneja el nombre XML y el espacio de nombres para usted, por lo que no necesita preocuparse por ello. Solo necesita mirar a través de los métodos de ObjectFactory
(y para el esquema grande, puede haber cientos de ellos) para encontrar el que necesita.
Puede solucionar este problema utilizando el enlace de Cómo generar clases @XmlRootElement para Tipos base en XSD? .
Aquí hay un ejemplo con Maven
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.3.1</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>src/main/resources/xsd</schemaDirectory>
<packageName>com.mycompany.schemas</packageName>
<bindingFiles>bindings.xjb</bindingFiles>
<extension>true</extension>
</configuration>
</plugin>
Aquí está el contenido del archivo binding.xjb
<?xml version="1.0"?>
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc= "http://java.sun.com/xml/ns/jaxb/xjc"
jxb:extensionBindingPrefixes="xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jxb:bindings schemaLocation="path/to/myschema.xsd" node="/xs:schema">
<jxb:globalBindings>
<xjc:simple/>
</jxb:globalBindings>
</jxb:bindings>
</jxb:bindings>
Tampoco funciona para nosotros. Pero sí encontramos un artículo ampliamente citado que agrega ALGUNOS antecedentes ... Lo vincularé aquí por el bien de la siguiente persona: http://weblogs.java.net/blog/kohsuke/archive/2006/03/why_does_jaxb_p.html