glassfish
  1. glassfish
  2. GLASSFISH-11748

JAXB does not work in vanilla OSGi bundle context

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Critical Critical
    • Resolution: Fixed
    • Affects Version/s: V3
    • Fix Version/s: 3.1
    • Component/s: web_services
    • Labels:
      None
    • Environment:

      Operating System: All
      Platform: All

    • Issuezilla Id:
      11,748

      Description

      I am deploying a vanilla OSGi bundle in GlassFish. This has nothing to do with
      any Java EE programming model. It tries to obtain a JAXBContext to do some XML
      unmarshalling, but gets NPE as the stack below shows:

      java.lang.NullPointerException
      at javax.xml.bind.ContextFinder.handleClassCastException(ContextFinder.java:95)
      at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:204)
      at javax.xml.bind.ContextFinder.find(ContextFinder.java:375)
      at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:618)
      at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:565)
      at sahoo.metainfservicetest.Activator.start(Activator.java:9)
      at
      org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:640)
      at org.apache.felix.framework.Felix.activateBundle(Felix.java:1700)
      at org.apache.felix.framework.Felix.startBundle(Felix.java:1622)
      at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:915)
      at org.apache.felix.shell.impl.StartCommandImpl.execute(StartCommandImpl.java:114)
      at
      org.apache.felix.shell.impl.Activator$ShellServiceImpl.executeCommand(Activator.java:286)
      at org.apache.felix.shell.remote.Shell.run(Shell.java:109)
      at java.lang.Thread.run(Thread.java:619)

      To reproduce, use the attached test case. Run it like this:
      mvn package
      cp target/metainfservicetest-1.0-SNAPSHOT.jar domain1/autodeploy/bundles/
      See server.log

        Activity

        Hide
        egarcia_sms added a comment -

        I'm the user Sahoo was referring to.

        As almost all our products depends on this (parsing XML using JAXB, as we have lot of classes) it will be
        nice to know the status of the bug, because I'm now experiencing side issues related to this one (not being
        able to load a class inside a WAR using JAXB)

        Thank you in advance.

        �ngel Eduardo

        Show
        egarcia_sms added a comment - I'm the user Sahoo was referring to. As almost all our products depends on this (parsing XML using JAXB, as we have lot of classes) it will be nice to know the status of the bug, because I'm now experiencing side issues related to this one (not being able to load a class inside a WAR using JAXB) Thank you in advance. �ngel Eduardo
        Hide
        Martin Grebac added a comment -

        The OSGi based loading of JAXB Context depending on Sahoo's utility classes has been integrated to GF so
        marking this as fixed.

        Show
        Martin Grebac added a comment - The OSGi based loading of JAXB Context depending on Sahoo's utility classes has been integrated to GF so marking this as fixed.
        Hide
        aaronjwhiteside added a comment -

        I am still seeing this error with Glassfish 3.1.2 and an OSGi bundle..

        The bundle is Apache Camel, and the corresponding code is, it seems that GlassFish fails to find the ContextFactory if a ClassLoader is supplied. This same code works under other OSGi containers Servicemix and JBoss 7..

                    // must use classloader from CamelContext to have JAXB working
                    jaxbContext = JAXBContext.newInstance(Constants.JAXB_CONTEXT_PACKAGES, CamelContext.class.getClassLoader());
        

        Stacktrace below...

        [#|2013-01-10T16:51:01.480-0500|INFO|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=224;_ThreadName=Thread-2;|ERROR [EclipseGeminiBlueprintExtenderThread-42] com.mm.gateway.messaging.routing.RouteDeployer - An error occurred while trying to load the routing file: /tmp/routes/hello.xml
        javax.xml.bind.JAXBException: Provider com.sun.xml.internal.bind.v2.ContextFactory not found
        	at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:148) ~[jaxb-api-osgi.jar:na]
        	at javax.xml.bind.ContextFinder.find(ContextFinder.java:361) ~[jaxb-api-osgi.jar:na]
        	at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:446) ~[jaxb-api-osgi.jar:na]
        	at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:409) ~[jaxb-api-osgi.jar:na]
        	at com.mm.gateway.messaging.routing.RouteLoader.load(RouteLoader.java:61) ~[routing-engine-1.0-SNAPSHOT.jar:1.0-SNAPSHOT]
        	at com.mm.gateway.messaging.routing.RouteDeployer.loadRoutes(RouteDeployer.java:266) [routing-engine-1.0-SNAPSHOT.jar:1.0-SNAPSHOT]
        	at com.mm.gateway.messaging.routing.RouteDeployer.loadExistingRoutes(RouteDeployer.java:106) [routing-engine-1.0-SNAPSHOT.jar:1.0-SNAPSHOT]
        	at com.mm.gateway.messaging.routing.RouteDeployer.start(RouteDeployer.java:79) [routing-engine-1.0-SNAPSHOT.jar:1.0-SNAPSHOT]
        	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_09]
        	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_09]
        	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_09]
        	at java.lang.reflect.Method.invoke(Method.java:601) ~[na:1.7.0_09]
        	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1612) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE]
        	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1553) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE]
        	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1483) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE]
        	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE]
        	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE]
        	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE]
        	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE]
        	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE]
        	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE]
        	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:607) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE]
        	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) [org.springframework.context-3.2.0.RELEASE.jar:3.2.0.RELEASE]
        	at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.access$1600(AbstractDelegatedExecutionApplicationContext.java:60) [gemini-blueprint-core-1.0.2.RELEASE.jar:1.0.2.RELEASE]
        	at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext$4.run(AbstractDelegatedExecutionApplicationContext.java:325) [gemini-blueprint-core-1.0.2.RELEASE.jar:1.0.2.RELEASE]
        	at org.eclipse.gemini.blueprint.util.internal.PrivilegedUtils.executeWithCustomTCCL(PrivilegedUtils.java:85) [gemini-blueprint-core-1.0.2.RELEASE.jar:1.0.2.RELEASE]
        	at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.completeRefresh(AbstractDelegatedExecutionApplicationContext.java:290) [gemini-blueprint-core-1.0.2.RELEASE.jar:1.0.2.RELEASE]
        	at org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor$CompleteRefreshTask.run(DependencyWaiterApplicationContextExecutor.java:137) [gemini-blueprint-extender-1.0.2.RELEASE.jar:1.0.2.RELEASE]
        	at java.lang.Thread.run(Thread.java:722) [na:1.7.0_09]
        Caused by: java.lang.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory not found by org.apache.camel.camel-core [286]
        	at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1460) ~[na:na]
        	at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72) ~[na:na]
        	at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843) ~[na:na]
        	at java.lang.ClassLoader.loadClass(ClassLoader.java:356) ~[na:1.7.0_09]
        	at javax.xml.bind.ContextFinder.safeLoadClass(ContextFinder.java:573) ~[jaxb-api-osgi.jar:na]
        	at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:145) ~[jaxb-api-osgi.jar:na]
        	... 28 common frames omitted
        |#]
        
        Show
        aaronjwhiteside added a comment - I am still seeing this error with Glassfish 3.1.2 and an OSGi bundle.. The bundle is Apache Camel, and the corresponding code is, it seems that GlassFish fails to find the ContextFactory if a ClassLoader is supplied. This same code works under other OSGi containers Servicemix and JBoss 7.. // must use classloader from CamelContext to have JAXB working jaxbContext = JAXBContext.newInstance(Constants.JAXB_CONTEXT_PACKAGES, CamelContext.class.getClassLoader()); Stacktrace below... [#|2013-01-10T16:51:01.480-0500|INFO|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=224;_ThreadName= Thread -2;|ERROR [EclipseGeminiBlueprintExtenderThread-42] com.mm.gateway.messaging.routing.RouteDeployer - An error occurred while trying to load the routing file: /tmp/routes/hello.xml javax.xml.bind.JAXBException: Provider com.sun.xml.internal.bind.v2.ContextFactory not found at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:148) ~[jaxb-api-osgi.jar:na] at javax.xml.bind.ContextFinder.find(ContextFinder.java:361) ~[jaxb-api-osgi.jar:na] at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:446) ~[jaxb-api-osgi.jar:na] at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:409) ~[jaxb-api-osgi.jar:na] at com.mm.gateway.messaging.routing.RouteLoader.load(RouteLoader.java:61) ~[routing-engine-1.0-SNAPSHOT.jar:1.0-SNAPSHOT] at com.mm.gateway.messaging.routing.RouteDeployer.loadRoutes(RouteDeployer.java:266) [routing-engine-1.0-SNAPSHOT.jar:1.0-SNAPSHOT] at com.mm.gateway.messaging.routing.RouteDeployer.loadExistingRoutes(RouteDeployer.java:106) [routing-engine-1.0-SNAPSHOT.jar:1.0-SNAPSHOT] at com.mm.gateway.messaging.routing.RouteDeployer.start(RouteDeployer.java:79) [routing-engine-1.0-SNAPSHOT.jar:1.0-SNAPSHOT] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_09] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_09] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_09] at java.lang.reflect.Method.invoke(Method.java:601) ~[na:1.7.0_09] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1612) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1553) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1483) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:607) [org.springframework.beans-3.2.0.RELEASE.jar:3.2.0.RELEASE] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) [org.springframework.context-3.2.0.RELEASE.jar:3.2.0.RELEASE] at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.access$1600(AbstractDelegatedExecutionApplicationContext.java:60) [gemini-blueprint-core-1.0.2.RELEASE.jar:1.0.2.RELEASE] at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext$4.run(AbstractDelegatedExecutionApplicationContext.java:325) [gemini-blueprint-core-1.0.2.RELEASE.jar:1.0.2.RELEASE] at org.eclipse.gemini.blueprint.util.internal.PrivilegedUtils.executeWithCustomTCCL(PrivilegedUtils.java:85) [gemini-blueprint-core-1.0.2.RELEASE.jar:1.0.2.RELEASE] at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.completeRefresh(AbstractDelegatedExecutionApplicationContext.java:290) [gemini-blueprint-core-1.0.2.RELEASE.jar:1.0.2.RELEASE] at org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor$CompleteRefreshTask.run(DependencyWaiterApplicationContextExecutor.java:137) [gemini-blueprint-extender-1.0.2.RELEASE.jar:1.0.2.RELEASE] at java.lang. Thread .run( Thread .java:722) [na:1.7.0_09] Caused by: java.lang.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory not found by org.apache.camel.camel-core [286] at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1460) ~[na:na] at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72) ~[na:na] at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843) ~[na:na] at java.lang. ClassLoader .loadClass( ClassLoader .java:356) ~[na:1.7.0_09] at javax.xml.bind.ContextFinder.safeLoadClass(ContextFinder.java:573) ~[jaxb-api-osgi.jar:na] at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:145) ~[jaxb-api-osgi.jar:na] ... 28 common frames omitted |#]
        Hide
        aaronjwhiteside added a comment -

        So after more digging it turns out that it will load correctly when using the current threads context ClassLoader but not the actual bundle's class loader (where the classes are actually located).

        The bundle ClassLoader should be able to find the ContextFactory too.

        Show
        aaronjwhiteside added a comment - So after more digging it turns out that it will load correctly when using the current threads context ClassLoader but not the actual bundle's class loader (where the classes are actually located). The bundle ClassLoader should be able to find the ContextFactory too.
        Hide
        Sanjeeb Sahoo added a comment - - edited

        There are three things I would like to highlight:
        1. It seems you are passing your bundle class loader to JAXBContext.newInstance.
        In such a case JAXB seems to be searching available service provider using that class loader only.
        Since your bundle does not have a dependency on a JAXB implementation bundle,
        JAXB API is not able to locate a provider.

        I am assuming you are not trying to locate a specific JAXB provider. Any provider is good for for you.
        In that case, why do you pass a classloader argument? If you leave it unspecified, I am sure
        JAXB can locate the default provider. So, I think you should change your code to leave it unspecified.

        2. Coming to the issue of JAXB not being able to locate the default behavior.
        I am hesitant to call it a bug, but I definitely call it a poor implementation.
        I can't call it a bug because the javadocs for JAXBContext [1] only recommends the API to locate the default provider.
        The wordings from javadocs [1] is produced below verbatim:

        "Finally, if all the steps above fail, then the rest of the look up is unspecified.
        That said, the recommended behavior is to simply look for some hard-coded platform default JAXB implementation.
        This phase of the look up is so that JavaSE can have its own JAXB implementation as the last resort."

        It does not mandate as you can see from the above wording. By no means, I am defending their behavior.

        3. Finally coming to the issue of why JAXBContext.newInstance succeeds when you pass it a classloader that's
        same as Thread's context classloader. Without knowing what's set as Thread's context classloader, it is difficult
        to say why it works. There is one thing I would like to highlight is the following code in FactoryFinder:

        if (getContextClassLoader() == classLoader) {
        Class factory = lookupUsingOSGiServiceLoader("javax.xml.bind.JAXBContext");
        if (factory != null)

        { logger.fine("OSGi environment detected"); return newInstance(contextPath, factory, classLoader, properties); }

        }

        I definitely don't endorse the "if (getContextClassLoader() == classLoader)" check here.
        This may explain why you code behaved differently when you passed TCL as the argument.
        I am not the author of this class and my experience says that it will take a long time
        to get this fixed. So, the simple thing to do would be to do what I asked you to do in #1.

        Thanks,
        Sahoo

        [1] http://docs.oracle.com/javaee/6/api/javax/xml/bind/JAXBContext.html

        Show
        Sanjeeb Sahoo added a comment - - edited There are three things I would like to highlight: 1. It seems you are passing your bundle class loader to JAXBContext.newInstance. In such a case JAXB seems to be searching available service provider using that class loader only. Since your bundle does not have a dependency on a JAXB implementation bundle, JAXB API is not able to locate a provider. I am assuming you are not trying to locate a specific JAXB provider. Any provider is good for for you. In that case, why do you pass a classloader argument? If you leave it unspecified, I am sure JAXB can locate the default provider. So, I think you should change your code to leave it unspecified. 2. Coming to the issue of JAXB not being able to locate the default behavior. I am hesitant to call it a bug, but I definitely call it a poor implementation. I can't call it a bug because the javadocs for JAXBContext [1] only recommends the API to locate the default provider. The wordings from javadocs [1] is produced below verbatim: "Finally, if all the steps above fail, then the rest of the look up is unspecified. That said, the recommended behavior is to simply look for some hard-coded platform default JAXB implementation. This phase of the look up is so that JavaSE can have its own JAXB implementation as the last resort." It does not mandate as you can see from the above wording. By no means, I am defending their behavior. 3. Finally coming to the issue of why JAXBContext.newInstance succeeds when you pass it a classloader that's same as Thread's context classloader. Without knowing what's set as Thread's context classloader, it is difficult to say why it works. There is one thing I would like to highlight is the following code in FactoryFinder: if (getContextClassLoader() == classLoader) { Class factory = lookupUsingOSGiServiceLoader("javax.xml.bind.JAXBContext"); if (factory != null) { logger.fine("OSGi environment detected"); return newInstance(contextPath, factory, classLoader, properties); } } I definitely don't endorse the "if (getContextClassLoader() == classLoader)" check here. This may explain why you code behaved differently when you passed TCL as the argument. I am not the author of this class and my experience says that it will take a long time to get this fixed. So, the simple thing to do would be to do what I asked you to do in #1. Thanks, Sahoo [1] http://docs.oracle.com/javaee/6/api/javax/xml/bind/JAXBContext.html

          People

          • Assignee:
            Martin Grebac
            Reporter:
            Sanjeeb Sahoo
          • Votes:
            2 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: