Два класса имеют одинаковое имя типа XML "objectFactory" - PullRequest
7 голосов
/ 09 сентября 2011

Мы долгое время использовали 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. банки? В процессе отладки я вижу, что он делает что-то с отражением, но я не понимаю, почему это делает.

Ответы [ 4 ]

3 голосов
/ 20 сентября 2011

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

Из документации JAXB ( Обнаружение реализации JAXB * секция 1004 *):

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

Мы попытались добавить ресурс в META-INF / services / javax.xml.bind.JAXBContext , чтобы обеспечить использование com.sun.xml.bind.v2.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, все должно быть в порядке.

2 голосов
/ 09 сентября 2011
  1. Убедитесь, что в вашем пути к классам есть только одна аннотация @XmlRegistry (поиск по XmlRegistry.class файлу, а не по использованию).Возможно, выбрана неправильная аннотация.

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

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

0 голосов
/ 06 сентября 2013

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

0 голосов
/ 21 декабря 2012

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

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

Broken 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>
...