java - parse - JAXBContext.newInstance variations
xml to java (1)
Estoy experimentando con las diversas formas de método newInstance en la clase JAXBContext (estoy usando la implementación predeterminada de Sun JAXB que se envía con Oracle JDK 1.7).
No está claro para mí cuándo está bien pasar simplemente al método newInstance las clases concretas frente a la clase ObjectFactory . Debo señalar que estoy usando JAXB puramente para analizar archivos XML, es decir, solo en la dirección XML-> Java.
Aquí está el código absolutamente mínimo que demuestra mi punto:
archivo xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema elementFormDefault="qualified"
xmlns ="http://www.w3.org/2001/XMLSchema"
xmlns:a ="http://www.example.org/A"
targetNamespace="http://www.example.org/A">
<element name="root" type="a:RootType"></element>
<complexType name="RootType">
<sequence>
<element name="value" type="string"></element>
</sequence>
</complexType>
</schema>
Dado el XSD anterior, las siguientes invocaciones JAXBInstance.newInstance logran crear un contexto que pueda analizar un archivo a.xml de muestra:
- jc = JAXBContext.newInstance ("ejemplo.a");
- jc = JAXBContext.newInstance (ejemplo.a.ObjectFactory.class);
- jc = JAXBContext.newInstance (example.a.RootType.class, example.a.ObjectFactory.class);
Sin embargo, al pasar solo el ejemplo.a.RootType.class , falla con javax.xml.bind.UnmarshalException en tiempo de ejecución:
jc = JAXBContext.newInstance(example.a.RootType.class); // this fails at runtime.
¿Alguien puede arrojar algo de luz? La razón por la que estoy experimentando con estas variaciones de JAXBContext :: newInstance es que he tropezado con este problema donde la respuesta aceptada incluía la opción de "crear el contexto JAXB basado en clases individuales en lugar de fábricas de objetos". La muestra a.xml y el código JAXB Java que estoy usando siguen al final de la publicación.
muestra a.xml utilizada
<?xml version="1.0" encoding="UTF-8"?>
<a:root xmlns:a="http://www.example.org/A"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.org/A A.xsd">
<a:value>foo</a:value>
</a:root>
Código de análisis JAXB
public static void main (String args[]) throws JAXBException, FileNotFoundException {
JAXBContext jc = null;
message("using package context (press any key:)");
jc = JAXBContext.newInstance("example.a");
work(jc); // SUCCEEDS
message("using Object factory (press any key):");
jc = JAXBContext.newInstance(example.a.ObjectFactory.class);
work(jc); // SUCCEEDS
message("using class enumeration (press any key):");
try {
jc = JAXBContext.newInstance(example.a.RootType.class);
work(jc); // FAILS
} catch (javax.xml.bind.UnmarshalException e) {
e.printStackTrace();
}
message("using class enumeration and Object factory too (press any key):");
jc = JAXBContext.newInstance(example.a.RootType.class, example.a.ObjectFactory.class);
work(jc); // SUCCEEDS
}
private static void work(JAXBContext jc) throws JAXBException, FileNotFoundException {
Unmarshaller u = jc.createUnmarshaller();
RootType root = ((JAXBElement<RootType>)u.unmarshal( new FileInputStream( "a.xml" ))).getValue();
System.out.println( root.getValue() );
}
Modelo JAXB generado a partir de esquema XML
Al crear un JAXBContext
partir de un modelo generado a partir de un esquema XML, siempre recomiendo hacerlo en el nombre del paquete de las clases generadas.
JAXBContext jc = JAXBContext.newInstance("example.a");
Es incluso mejor utilizar un newInstance
método de newInstance
que toma un parámetro ClassLoader
. Esto te ahorrará dolor cuando pases de un entorno Java SE a Java EE.
JAXBContext jc = JAXBContext.newInstance("example.a", example.a.ObjectFactory.class.getClassLoader());
Cuando crea el JAXBContext
en el nombre del paquete, JAXB impl supone que generó el modelo a partir de un esquema XML y extrae la clase ObjectFactory
, ya que siempre genera la clase anotada con @XmlRegistry
con este nombre.
A partir de un modelo de Java
Esto es cuando recomiendo que las personas usen los newInstance
métodos de newInstance
que toman clases. Cuando se JAXBContext
un JAXBContext
de clases JAXB, no hay nada especial acerca de una clase llamada ObjectFactory
. El rol de ObjectFactory
podría ser jugado por cualquier clase anotada con @XmlRegistry
por lo que no se busca automáticamente. Esta es la razón por la cual su caso de uso funcionó cuando hizo referencia ObjectFactory
y falló cuando no lo hizo.