Hemos estado utilizando JAXB 2.1 durante mucho tiempo en nuestro sistema. Tenemos una plataforma que se construye con Ant y genera un conjunto de paquetes que se implementan en un tiempo de ejecución OSGi. Usamos Java SE 6.Dos clases tienen el mismo nombre de tipo XML "objectFactory"
Utilizamos JAXB durante el proceso de compilación para generar tipos de datos de diferentes esquemas. Esas clases se empaquetan en los paquetes y se usan en tiempo de ejecución para serializar/deserializar el contenido. Además, utilizamos JAXB en nuestra plataforma en tiempo de ejecución para generar tipos de datos de otros esquemas proporcionados por el usuario (es una especie de plataforma MDA).
En el tiempo de ejecución de OSGi tenemos un paquete que tiene las jarras JAXB y exporta los paquetes necesarios. Creamos una instancia de JAXBContext con la ruta de contexto de todas las fábricas de objetos generadas, por lo que podemos ordenar/deshacer todos nuestros tipos de datos.
Eso ha estado funcionando hasta ahora, pero ahora estamos intentando actualizar a la última versión estable de JAXB (2.2.4) y estamos teniendo problemas al intentar crear el contexto en tiempo de ejecución. Obtenemos la siguiente excepción:
Two classes have the same XML type name "objectFactory". Use @XmlType.name and @XmlType.namespace to assign different names to them.
this problem is related to the following location:
at some.package.ObjectFactory
this problem is related to the following location:
at some.other.package.ObjectFactory
at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:436)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:277)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1100)
at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:143)
at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:110)
at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:191)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:187)
... 76 more
El error dos clases tienen el mismo nombre de tipo XML "objectFactory" se imprime para cada una de las factorías de objetos generados durante el proceso de construcción.
Hemos visto varias publicaciones en SO con el mismo error pero aplicando a los tipos generados, no a la fábrica de objetos. Creemos que JAXB puede no estar identificando la clase ObjectFactory como una fábrica de objetos sino como un tipo de datos.
Una posibilidad era que estábamos usando la versión interna de JAXB en Java 6, por lo que decidió utilizar la propiedad Sistema -Djava.endorsed.dirs y poner los tres frascos (jaxb-api-2.2.4 .jar, jaxb-impl-2.2.4.jar y jaxb-xjc-2.2.4.jar) en esa ruta, pero todavía no funciona.
Creemos que el problema podría ser que estamos utilizando una versión diferente de JAXB en el tiempo de ejecución de OSGi y en el proceso de compilación, por lo que el código generado no es compatible. Pero tal vez estamos equivocados y hay otro problema.
¿Tiene alguna idea?
Gracias de antemano.
(Edit: más detalles sobre esto)
creamos el JAXBContext de esta manera:
ClassLoader classLoader = new JAXBServiceClassLoader(getParentClassLoader(),
Collections.unmodifiableMap(objectFactories));
context = JAXBContext.newInstance(contextPath.toString(), classLoader);
donde contextPath es una cadena que contiene todas nuestras factorías de objetos separados por ':', y la JAXBServiceClassLoader es:
private static final class JAXBServiceClassLoader extends ClassLoader
{
@NotNull
private final Map<String, Object> objectFactories;
private JAXBServiceClassLoader(@NotNull ClassLoader parent, @NotNull Map<String, Object> objectFactories)
{
super(parent);
this.objectFactories = objectFactories;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException
{
Class<?> ret;
try
{
ret = super.loadClass(name);
}
catch (ClassNotFoundException e)
{
Object objectFactory = objectFactories.get(name);
if (objectFactory != null)
{
ret = objectFactory.getClass();
}
else
{
throw new ClassNotFoundException(name + " class not found");
}
}
return ret;
}
}
(Editar: después del post de Aaron)
He estado depurando todas las partes internas de JAXBContextImpl y el hecho es que JAXBContextImpl está tratando de obtener la información de tipo de nuestras clases de ObjectFactory, lo cual es incorrecto. De hecho, en com.sun.xml.internal.bind.v2.model.impl.ModelBuilder: 314, la llamada getClassAnnotation() devuelve null pero cuando veo la instancia puedo ver la anotación XmlRegistry.
El caso es que, en ese punto XmlRegistry.class.getClassLoader() devuelve un valor nulo, pero si run() C (Clase) .getAnnotations() [0] .annotationType(). GetClassLoader() devuelve el classLoader del paquete de OSGi "lib.jaxb" que contiene mis jar de JAXB, que es correcto.
Por lo tanto, supongo que estamos cargando al mismo tiempo dos versiones diferentes de XmlRegistry, una del JDK y la otra de JAXB 2.2.4 jar. La pregunta es: ¿por qué?
Y, aún más, en lugar de cargar todas las clases com.sun.xml.internal. * (Como JAXBContextImpl), no debería cargar y ejecutar com.sun.xml.bind.v2.runtime.JAXBContextImpl desde Jars JAXB? Durante el proceso de depuración puedo ver que está haciendo algunas cosas con la reflexión, pero no entiendo por qué está haciendo eso.
Uso de Java SE 6 Recomendaría utilizar el último parche de su JAXB impl que sea compatible con JAXB 2.1 a menos que exista una característica particular de JAXB 2.2 que esté tratando de usar. –
Perdón por no haberlo mencionado. La razón para actualizar a JAXB 2.2.4 es que estamos actualizando nuestra versión JAX-WS a 2.2.5 y depende de esa versión de JAXB (http://jax-ws.java.net/2.2.5/docs/ ReleaseNotes.html). De lo contrario, podríamos usar JAXB 2.1. – Denian
Parece que su JAXB impl está tratando erróneamente a 'ObjectFactory' como una clase de dominio. Esto probablemente se debe a que la anotación '@ XmlRegistry' no se reconoce debido a la diferencia' ClassLoader' entre las clases de dominio y la implementación de JAX-WS. ¿Estás creando el 'JAXBContext' directamente o la implementación de JAX-WS está haciendo esto? –