Why can't JAXB find my jaxb.index when working inside Apache Felix?

It is there, in the package, that it should be indexed. However, when I call

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

I get a JAXBException saying that

"my.package.name" does not contain ObjectFactory.class or jaxb.index

although it contains both.

What works, but not exactly what I want

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

This question from other people appears on some mailing lists and forums, but doesn't seem to get any answers.

I run this on OpenJDK 6, so I got the source packages and stepped back from my debugger in the library. It starts by searching for jaxb.properties, then searches for system properties and does not find them, it tries to create a default context using com.sun.internal.xml.bind.v2.ContextFactory. An Exception is ContextFactor.createContext(String ClassLoader, Map) (inside ContextFactor.createContext(String ClassLoader, Map) ), but I do not see what happens because there is no source.

Eta

Judging by the source code of ContentFactory, I found here , this is probably the part of the code that is not working properly:

 /** * Look for jaxb.index file in the specified package and load it 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 assume that this is due to mechanisms for loading classes from the OSGi container in which it works. Unfortunately, I'm still a little out of my depth.

+50
java jaxb osgi apache-felix
Jun 25 '09 at 10:21
source share
10 answers

OK, it took quite a bit of a breakthrough, but the answer is not so surprising and not even so complicated:

JAXB cannot find jaxb.index because by default newInstance(String) uses the current thread class loader (which is returned by Thread.getContextClassLoader() ). This does not work inside Felix because OSGi packages and frame streams 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 containing jaxb.index , a reasonable choice for flexibility reasons is probably ObjectFactory :

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

You may also be able to get a class loader that uses an instance of the Bundle , but I couldnโ€™t figure out how, and the solution above seems safe to me.

+57
Jun 25 '09 at 13:08
source share

I ran into a similar problem with the project I'm working on. After reading http://jaxb.java.net/faq/index.html#classloader, I realized that JAXBContext cannot find the package containing jaxb.index.

I will try to make it as clear as possible.

We have

 Bundle A -- com.a A.java aMethod() { B.bMethod("com.cC"); } 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 

Treat JAXB . class B is JAXBContext and bMethod is newInstance ()

If you are familiar with the limitations of the OSGi package, then it should be very clear that Bundle B does not import the com.c package, that is, class C is not displayed until class B , so it cannot create an instance of C.

The solution is to pass ClassLoader to bMethod. This ClassLoader should consist of a package that imports com.c. In this case, we can pass A.class.getClassLoader () since package A imports com.c

Hope this was helpful.

+6
Sep 30 '11 at 17:41
source share

For the same issue, I resolved it by manually placing the package in the import.

+4
Jan 21 '13 at 4:22
source share

If you use maven in your project, just use this library:

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

It was created for the Glasfish server, but it also works with Tomcat (verified). With this library, you can easily use JAXB with OSGI packages.

+1
Sep 05 '13 at 9:15
source share

Edit 2:

I had the same strange problem of loading classes in my application. If I started it as a regular application, everything was fine, but when I called it as a Windows service, it started to fail with ClassNotFoundExceptions. The analysis showed that threads have their class loaders somehow. I solved the problem by installing SystemClassLoader in streams:

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

I donโ€™t know if your container allows such a change.

0
Jun 25 '09 at 10:35
source share

I just ran into this problem. For me, the solution was to use the IBM JRE instead of Oracle. It seems that the JAXB implementation is more convenient for OSGI in this.

0
Mar 04 2018-12-12T00:
source share

I successfully resolved this by adding a package of my generated classes containing an ObjectFactory to the <Private-Package> my package definition, plus org.jvnet.jaxb2_commons.*

0
Jan 10 '14 at 11:02
source share

Another scenario may arise that may give this problem.

When you install and run a package that exports a package that contains jaxb.index or objectFactory.java

Then make sure that packages importing classes are stopped or point to the correct package name.

Also check the export and import instructions in the pom.xml file

Faced with a similar problem in the osgi servicemix (karaf) container

0
Feb 28 '14 at 6:09
source share

For me, the problem was that the unit test, which was not connected to the module I developed, had nothing to do with pom.xml in my module. UT still recognized my module due to the selection of the list of packages from the general configuration file.

When starting UT, he did not compile a new module so that it would not generate ObjectFactory.java, so I received an error, although when compiling the module I could see ObjectFactory.java

The following dependency is added:

 <dependency> <groupId>com.myCompany</groupId> <artifactId>my-module-name</artifactId> <version>${project.version}</version> <scope>test</scope> </dependency> 
0
Sep 15 '16 at 8:56
source share

My solution was:

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

OR

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

OR

complete 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%

-one
Jan 30 '14 at 20:24
source share



All Articles