Два класса имеют одинаковое имя типа XML " objectFactory"

мы используем JAXB 2.1 в течение длительного времени в нашей системе. У нас есть платформа, которая построена с Ant и генерирует кучу пакетов, которые развертываются во время выполнения OSGi. Мы используем Java SE 6.

мы используем JAXB во время процесса сборки для генерации типов данных из разных схем. Эти классы упаковываются в пакеты и используются во время выполнения для сериализации/десериализации содержимого. Кроме того, мы используем JAXB в нашей платформе во время выполнения для генерации типов данных из других схем пользователем (это своего рода платформа MDA).

в среде выполнения OSGi у нас есть пакет, который имеет банки JAXB и экспортирует необходимые пакеты. Мы создаем экземпляр JAXBContext с контекстным путем всех созданных фабрик объектов, поэтому мы можем Маршалл / unmarshall все наши типы данных.

это работает до сих пор, но прямо сейчас мы пытаемся обновить до последней стабильной версии 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, поэтому мы решили использовать системное свойство -Джава.одобренный.Дирс!--11--> и поставить три баночки (jaxb-api-2.2.4.jar, jaxb-impl-2.2.4.jar и jaxb-xjc-2.2.4.Джар) в этом пути, но все равно не работает.

мы думаем, что проблема может быть в том, что мы используем другую версию 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;
    }
  }

(Edit: после Аарона post)

Я отлаживал все внутренние компоненты JAXBContextImpl, и дело в том, что JAXBContextImpl пытается получить информацию о типе из наших классов ObjectFactory, что неправильно. На самом деле, в com.солнце.XML.внутренний.связывать.П2.модель.impl.ModelBuilder: 314, вызов getClassAnnotation () возвращает null, но когда я вижу экземпляр, я вижу аннотацию XmlRegistry.

дело в том, что в этот момент XmlRegistry.класс.getClassLoader () возвращает null, но если I выполнить ((класс) c).getAnnotations()[0].annotationType().getClassLoader () возвращает загрузчик классов пакета OSGi "lib.jaxb", который содержит мои банки JAXB, что правильно.

Итак, я думаю, что мы загружаем одновременно две разные версии XmlRegistry, одну из JDK, а другую из JAXB 2.2.4 jars. Вопрос в том, почему?

и, более того, вместо загрузки всех этих com.солнце.XML.внутренний.* классы (например, JAXBContextImpl) не должны загружаться и выполнения com.солнце.XML.связывать.П2.во время выполнения.JAXBContextImpl из JAXB банок? В процессе отладки я вижу, что он делает некоторые вещи с отражением, но я не понимаю, почему это делает.

4 ответов


  1. убедитесь, что есть только один @XmlRegistry аннотация в пути к классам (Поиск XmlRegistry.class файл, а не использование). Может быть, подобрали не ту аннотацию.

  2. если это не работает, создайте свой собственный загрузчик классов, который видит только одну фабрику. В этом нет необходимости, но кто знает.

  3. попробуйте установить точку останова в JAXBContextImpl.java: 436, чтобы увидеть, какие типы он обрабатывает и почему.


мы, наконец, нашли решение для этого.

из документации JAXB (обнаружение реализации JAXB):

http://jaxb.java.net/nonav/2.2.4-1/docs/api/javax/xml/bind/JAXBContext.html

мы попытались добавить ресурс в META-INF / services / javax.XML.связывать.JAXBContext чтобы использовать com.солнце.XML.связывать.П2.ContextFactory вместо внутренней фабрики Sun. Что не сработало, вероятно, потому, что мы используем пакет OSGi.

в любом случае, поскольку мы используем наш собственный загрузчик классов, мы переопределяем метод getResourceAsStream (), который вызывается из ContextFinder: 343:

@Override
public InputStream getResourceAsStream(String name)
{
  if (name!=null && name.equals("META-INF/services/javax.xml.bind.JAXBContext"))
  {
    return new ByteArrayInputStream("com.sun.xml.bind.v2.ContextFactory".getBytes());
  }
  return super.getResourceAsStream(name);
}

Это не самое красивое решение, но оно работает на нас. И этот загрузчик классов используется только тогда, когда мы создаем JAXBContext, это должно быть хорошо.


у меня была та же проблема, но другая причина. Даже если это не может исправить проблемы авторов, я публикую этот ответ для всех, читая этот пост позже и имея ту же проблему, что и я.

я использовал эту конфигурацию компилятора-плагина, которая исключила package-info.Java файлы из проекта. После удаления исключается все работало как шарм! Кажется, что JAXB включает в себя некоторые важные определения в этих файлах!

сломанный Config:

<plugin>
    <artifactId>maven-compiler-plugin</artifactId>
        <version>3.0</version>
        <configuration>
            <source>1.6</source>
            <target>1.6</target>
            <encoding>UTF-8</encoding>
        <excludes>
            <exclude>**/package-info.java</exclude>
        </excludes>
        <showDeprecation>true</showDeprecation>
        <showWarnings>true</showWarnings>
        <fork>false</fork>
    </configuration>
</plugin>

Рабочий Конфиг:

 <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.0</version>
        <configuration>
            <source>1.6</source>
            <target>1.6</target>
            <encoding>UTF-8</encoding>
            <showDeprecation>true</showDeprecation>
            <showWarnings>true</showWarnings>
            <fork>false</fork>
        </configuration>
    </plugin>

у меня была аналогичная проблема при попытке развернуть веб-службу soap на основе spring. Я добавил пакет в contextPaths на org.springframework.oxm.jaxb.Jaxb2Marshaller весна фасоли. Проблема заключалась в том, что тот же класс был в других пакетах, включенных в тот же contextPaths. Я изменил сценарий сборки Ant, чтобы исключить эти другие классы из пакета, который я добавлял, что решило проблему.