Мы давно используем JAXB 2.1 в нашей системе. У нас есть платформа, созданная с помощью Ant и генерирующая набор пакетов, которые развертываются в среде выполнения OSGi. Мы используем Java SE 6.
Мы используем JAXB в процессе сборки для генерации типов данных из разных схем. Эти классы упакованы в пакеты и используются во время выполнения для сериализации / десериализации контента. Кроме того, мы используем JAXB на нашей платформе во время выполнения для генерации типов данных из других схем, предоставленных пользователем (это своего рода платформа MDA).
В среде выполнения OSGi у нас есть пакет, который содержит jar-файлы JAXB и экспортирует необходимые пакеты. Мы создаем экземпляр JAXBContext с контекстным путем всех сгенерированных фабрик объектов, чтобы мы могли маршалировать / демаршалировать все наши типы данных.
Пока это работает, но сейчас мы пытаемся обновить до последней стабильной версии JAXB (2.2.4) , и у нас возникают проблемы при попытке создать контекст во время выполнения. Мы получаем следующее исключение:
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
Ошибка Два класса имеют одинаковое имя типа XML. «ObjectFactory» печатается для каждой из фабрик объектов, созданных в процессе сборки.
Мы видели несколько сообщений в SO с той же ошибкой, но применительно к сгенерированным типам, а не к фабрике объектов.Мы думаем, что JAXB может идентифицировать класс ObjectFactory не как фабрику объектов, а как тип данных.
Одна из возможностей заключалась в том, что мы использовали внутреннюю версию JAXB в Java 6, поэтому мы решили использовать свойство системы -Djava.endorsed.dirs и поместить три jar-файла ( jaxb- api-2.2.4.jar, jaxb-impl-2.2.4.jar и jaxb-xjc-2.2.4.jar ) по этому пути, но по-прежнему не работает.
Мы думаем, что проблема может заключаться в том, что мы используем другую версию JAXB в среде выполнения OSGi и в процессе сборки, поэтому сгенерированный код несовместим. Но, возможно, мы ошибаемся и возникает другая проблема.
У вас есть идеи?
Заранее спасибо.
(Edit: подробнее об этом)
Мы создаем JAXBContext следующим образом:
ClassLoader classLoader = new JAXBServiceClassLoader(getParentClassLoader(),
Collections.unmodifiableMap(objectFactories));
context = JAXBContext.newInstance(contextPath.toString(), classLoader);
где contextPath - это строка, содержащая все наши фабрики объектов, разделенные ':', а JAXBServiceClassLoader:
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;
}
}
(Правка: после сообщения Аарона)
Я отлаживал все внутренние компоненты JAXBContextImpl, и дело в том, что JAXBContextImpl пытается получить информацию о типе из наших классов ObjectFactory, что неверно. Фактически, в com.sun.xml.internal.bind.v2.model.impl.ModelBuilder: 314 вызов getClassAnnotation () возвращает значение null, но когда я вижу экземпляр, я вижу аннотацию XmlRegistry.
Дело в том, что в этот момент XmlRegistry.class.getClassLoader () возвращает null, но если я запускаю ((Class) c) .getAnnotations () [0] .annotationType (). GetClassLoader (), он возвращает classLoader пакета OSGi "lib.jaxb", который содержит мои jar-файлы JAXB, и это правильно.
Итак, я предполагаю, что мы загружаем одновременно две разные версии XmlRegistry, одну из JDK, а другую из jar-файлов JAXB 2.2.4. Возникает вопрос: почему?
И даже более того, вместо загрузки всех этих классов com.sun.xml.internal. * (Например, JAXBContextImpl) не следует загружать и выполнять com.sun.xml.bind.v2 .runtime.JAXBContextImpl из jar-файлов JAXB? Во время процесса отладки я вижу, что он что-то делает с отражением, но я не понимаю, почему это происходит.