Мы долгое время использовали 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 и поставить три банки ( jaxb- api-2.2.4.jar, jaxb-impl-2.2.4.jar и jaxb-xjc-2.2.4.jar ) на этом пути, но все еще не работает.
Мы думаем, что проблема может заключаться в том, что мы используем другую версию JAXB во время выполнения OSGi и в процессе сборки, поэтому сгенерированный код не совместим. Но, возможно, мы ошибаемся, и есть другая проблема.
У вас есть идеи?
Заранее спасибо.
(Изменить: подробнее об этом)
Мы создаем 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 () возвращает ноль, но если я запускаю ((Class) c) .getAnnotations () [0] .annotationType (). GetClassLoader (), он возвращает classLoader пакета OSGi "lib.jaxb", который содержит мои файлы JAXB, и это правильно.
Итак, я полагаю, что мы загружаем одновременно две разные версии XmlRegistry, одну из JDK и другую из JAXB 2.2.4 jar. Вопрос: почему?
И, более того, вместо загрузки всех этих классов com.sun.xml.internal. * (Например, JAXBContextImpl) не следует загружать и выполнять com.sun.xml.bind.v2.runtime.JAXBContextImpl из JAXB. банки? В процессе отладки я вижу, что он делает что-то с отражением, но я не понимаю, почему это делает.