Почему JAXB не может найти мой jaxb.index при запуске внутри Apache Felix?

StackOverflow https://stackoverflow.com/questions/1043109

  •  20-08-2019
  •  | 
  •  

Вопрос

Это прямо там, в пакете, который он должен индексировать.Тем не менее, когда я звоню

JAXBContext jc = JAXBContext.newInstance("my.package.name");

Я получаю исключение JAXBException, в котором говорится, что

"my.package.name" не содержит ObjectFactory.class или jaxb.index

хотя в нем есть и то, и другое.

Что действительно работает, но не совсем то, чего я хочу, это

JAXBContext jc = JAXBContext.newInstance(my.package.name.SomeClass.class);

Этот вопрос от разных других людей появляется во многих списках рассылки и форумах, но, похоже, не получает ответов.

Я запускаю это на OpenJDK 6, поэтому я получил исходные пакеты и подключил свой отладчик к библиотеке.Он начинает с поиска jaxb.properties, затем ищет системные свойства и, не найдя ни того, ни другого, пытается создать контекст по умолчанию, используя com.sun.internal.xml.bind.v2.ContextFactory.Там генерируется исключение (внутри ContextFactor.createContext(String ClassLoader, Map)), но я не вижу, что происходит, потому что источника здесь нет.

ETA:

Судя по исходному коду ContentFactory, я нашел здесь, вероятно, это тот фрагмент кода, который не работает должным образом:

/**
 * Look for jaxb.index file in the specified package and load it's contents
 *
 * @param pkg package name to search in
 * @param classLoader ClassLoader to search in
 * @return a List of Class objects to load, null if there weren't any
 * @throws IOException if there is an error reading the index file
 * @throws JAXBException if there are any errors in the index file
 */
private static List<Class> loadIndexedClasses(String pkg, ClassLoader classLoader) throws IOException, JAXBException {
    final String resource = pkg.replace('.', '/') + "/jaxb.index";
    final InputStream resourceAsStream = classLoader.getResourceAsStream(resource);

    if (resourceAsStream == null) {
        return null;
    }

От моего Предыдущая страница Откройте для себя вики, Я предполагаю, что это связано с механизмами загрузки классов контейнера OSGi, в котором это выполняется.К сожалению, здесь я все еще немного не в своей тарелке.

Это было полезно?

Решение

Хорошо, это потребовало немалых усилий, но ответ не такой уж удивительный и даже не такой сложный:

JAXB не может найти jaxb.index, потому что по умолчанию, newInstance(String) использует загрузчик классов текущего потока (возвращаемый Thread.getContextClassLoader()).Это не работает внутри Felix, потому что пакеты OSGi и потоки фреймворка имеют отдельные загрузчики классов.

Решение состоит в том, чтобы откуда-то достать подходящий загрузчик классов и использовать newInstance(String, ClassLoader).Я получил подходящий загрузчик классов из одного из классов в пакете, который содержит jaxb.index, разумным выбором по соображениям гибкости , вероятно, является ObjectFactory:

ClassLoader cl = my.package.name.ObjectFactory.class.getClassLoader();
JAXBContext jc = JAXBContext.newInstance("my.package.name", cl);

Может быть, вы могли бы также получить доступ к загрузчику классов, который Bundle экземпляр используется, но я не мог понять как, и приведенное выше решение кажется мне безопасным.

Другие советы

Я столкнулся с аналогичной проблемой с проектом, над которым я работаю.После прочтения http://jaxb.java.net/faq/index.html#classloader Я понял, что JAXBContext не может найти пакет, содержащий jaxb.index.

Я постараюсь сделать это как можно более ясным.

У нас есть

Bundle A
   -- com.a
      A.java
        aMethod()
        {
            B.bMethod("com.c.C");
        }
MANIFEST.MF
Import-Package: com.b, com.c         

Bundle B
   -- com.b
      B.java
        bmethod(String className)
        {
            Class clazz = Class.forName(className);
        }

Export-Package: com.b

Bundle C
   -- com.c
      C.java
        c()
        {
            System.out.println("hello i am C");
        }

Export-Package: com.c

Относиться к ДЖАКСБ. класс B - это JAXBContext, а bMethod - это newInstance()

Если вы знакомы с ограничениями пакетов OSGi, то теперь вам должно быть предельно ясно, что Комплект B не импортирует пакет com.c т.е. класс C является не виден Для класс В следовательно, он не может создать экземпляр C.

Решением было бы передать Загрузчик классов к методу BM.Этот загрузчик классов должен исходить из пакет, который импортирует com.c.В этом случае мы можем пройти A.class.getClassLoader() с тех пор как пакет A импортирует com.c

Надеюсь, это было полезно.

Для решения той же проблемы я решил ее, вручную поместив пакет в импорт.

Если вы используете maven в своем проекте, то просто используйте эту библиотеку:

<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-osgi</artifactId>
    <version>2.2.7</version>
</dependency>

Он создан для сервера Glasfish, но также работает с Tomcat (проверено).С помощью этой библиотеки вы можете легко использовать JAXB с пакетами OSGI.

Правка 2:

Однажды у меня была похожая странная проблема с загрузкой класса в моем приложении.Если я запускал его как обычное приложение, все было в порядке, но когда я вызывал его как службу Windows, начинался сбой с ClassNotFoundExceptions.Анализ показал, что потоки каким-то образом имеют свои загрузчики классов равными null.Я решил проблему, установив SystemClassLoader в потоках:

// ...
thread.setContextClassLoader(ClassLoader.getSystemClassLoader());
thread.start();
// ...

Однако не знаю, допускает ли ваш контейнер такого рода изменения.

Я только что столкнулся с этой проблемой.Для меня решением было использовать JRE от IBM вместо Oracle.Похоже, что в этом реализация JAXB более удобна для OSGI.

Я успешно решил эту проблему, добавив пакет моих сгенерированных классов, содержащий ObjectFactory к тому <Private-Package> часть моего определения пакета, плюс org.jvnet.jaxb2_commons.*

Может быть другой сценарий, который может привести к этой проблеме.

Когда вы устанавливаете и запускаете пакет, который экспортирует пакет, содержащий jaxb.index или objectFactory.java

Затем, пожалуйста, убедитесь, что пакеты, импортирующие классы, остановлены или указывают на правильное имя пакета.

Также проверьте инструкции экспорта и импорта в pom.xml

Столкнулся с аналогичной проблемой в контейнере servicemix (karaf) osgi

Для меня проблема заключалась в том, что модульный тест, который не был связан с модулем, который я разработал, не имел в нем зависимости pom.xml от моего модуля.UT все еще распознал мой модуль из-за извлечения списка пакетов из общего файла конфигурации.

При запуске UT он не скомпилировал новый модуль, поэтому он не сгенерировал ObjectFactory.java поэтому я получил ошибку, хотя, когда я скомпилировал модуль, я смог увидеть ObjectFactory.java

добавлена следующая зависимость:

<dependency>
    <groupId>com.myCompany</groupId>
    <artifactId>my-module-name</artifactId>
    <version>${project.version}</version>
    <scope>test</scope>
</dependency>

Моим Решением было:

Контекст JAXBContext = JAXBContext.newInstance (новый класс[]{"my.package.name "});

или

Контекст JAXBContext = JAXBContext.newInstance (новый класс[]{class.getName()});

или

полное решение:

public static <T> T deserializeFile(Class<T> _class, String _xml) {

        try {

            JAXBContext context = JAXBContext.newInstance(new Class[]{_class});
            Unmarshaller um = context.createUnmarshaller();

            File file = new File(_xml);
            Object obj = um.unmarshal(file);

            return _class.cast(obj);

        } catch (JAXBException exc) {
            return null;
        }
    }

Работает на 100%

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top