Why can't JAXB find my jaxb.index when running

2019-01-30 08:13发布

It's right there, in the package that it should be indexing. Still, when I call

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

I get a JAXBException saying that

"my.package.name" doesnt contain ObjectFactory.class or jaxb.index

although it does contain both.

What does work, but isn't quite what I want, is

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

This question from various other people appears on quite some mailing lists and forums but seemingly doesn't get answers.

I'm running this on OpenJDK 6, so I got the source packages and stepped my debugger into the library. It starts by looking for jaxb.properties, then looks for system properties and failing to find either, it tries to create the default context using com.sun.internal.xml.bind.v2.ContextFactory. In there, the Exception gets thrown (inside ContextFactor.createContext(String ClassLoader, Map)), but I can't see what's going on because the source isn't here.

ETA:

Judging from the source code for ContentFactory, I found here, this is probably the piece of code that fails to work as intended:

/**
 * 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;
    }

From my previous experience, I'm guessing that this has to do with the class loading mechanisms of the OSGi container that this is running in. Unfortunately, I am still a little out of my depth here.

10条回答
劫难
2楼-- · 2019-01-30 08:24

For the same problem, I resolved it by manually putting the package into the import.

查看更多
贼婆χ
3楼-- · 2019-01-30 08:26

My Solution was:

JAXBContext context = JAXBContext.newInstance(new Class[]{"my.package.name"});

OR

JAXBContext context = JAXBContext.newInstance(new Class[]{class.getName()});

OR

a full solution:

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;
        }
    }

Works 100%

查看更多
再贱就再见
4楼-- · 2019-01-30 08:29

There may be another scenario which can give this problem.

When you install and start a bundle which export the package that contains the jaxb.index or objectFactory.java

Then please make sure that the bundles importing the classes are stopped or pointing to the correct package name.

Also check the export and import statements in the pom.xml

Faced similar issue in servicemix(karaf) osgi container

查看更多
狗以群分
5楼-- · 2019-01-30 08:39

I've just run into this issue. For me, the solution was to use IBM's JRE instead of Oracle's. Seems like the JAXB implementation is more OSGI-friendly in that one.

查看更多
萌系小妹纸
6楼-- · 2019-01-30 08:39

For me the problem was that a unit test which was not related to the module that I have developed did not had a dependency in it pom.xml to my module. The UT still recognized my module due to fetching the packages list from shared configuration file.

When running the UT it didn't compile the new module so it didn't generate the ObjectFactory.java therefore I received the error even though when I compiled the module I was able to see the ObjectFactory.java

added the following dependency:

<dependency>
    <groupId>com.myCompany</groupId>
    <artifactId>my-module-name</artifactId>
    <version>${project.version}</version>
    <scope>test</scope>
</dependency>
查看更多
Lonely孤独者°
7楼-- · 2019-01-30 08:40

OK, this took quite some digging, but the answer is not that surprising and not even that complicated:

JAXB can't find jaxb.index, because by default, newInstance(String) uses the current thread's class loader (as returned by Thread.getContextClassLoader()). This doesn't work inside Felix, because the OSGi bundles and the framework's threads have separate class loaders.

The solution is to get a suitable class loader from somewhere and use newInstance(String, ClassLoader). I got a suitable class loader from one of the classes in the package that contains jaxb.index, a sensible choice for flexibility reasons probably is ObjectFactory:

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

Maybe you could also get at the class loader that the Bundle instance is using, but I couldn't figure out how, and the above solution seems safe to me.

查看更多
登录 后发表回答