4.18.2012

OSGi Classpaths and Jersey

OSGi is cool, but it adds a ton of classpath constraints. I'll put up a complete OSGi page about some of the headaches I've run into and the basic setup I use at a later date, but today I want to share how to get rid of a ClassNotFoundException when trying to deploy Jersey.

If you're not familiar with Jersey it's an implementation from Sun/Oracle of the JAX-RS spec. Basically an annotation system in java for deploying rest based web services.

Anyway, this post isn't about that, it's about this:

java.lang.ClassNotFoundException: com.sun.jersey.spi.container.servlet.ServletContainer
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:513)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:429)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:417)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:107)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:424)
...
at org.eclipse.jetty.osgi.boot.OSGiAppProvider.addContext(OSGiAppProvider.java:232)
at org.eclipse.jetty.osgi.boot.OSGiAppProvider.addContext(OSGiAppProvider.java:214)
...
at org.osgi.util.tracker.BundleTracker$Tracked.customizerAdding(BundleTracker.java:439)
at org.osgi.util.tracker.AbstractTracked.trackAdding(AbstractTracked.java:261)
at org.osgi.util.tracker.AbstractTracked.trackInitial(AbstractTracked.java:184)
at org.osgi.util.tracker.BundleTracker.open(BundleTracker.java:159)
at org.eclipse.jetty.osgi.boot.JettyBootstrapActivator.start(JettyBootstrapActivator.java:118)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl$1.run(BundleContextImpl.java:711)
at java.security.AccessController.doPrivileged(Native Method)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:702)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:683)
at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:381)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:299)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:291)


I'd been beating my head into the wall all morning when the problem/solution struck me. I'd doubled checked that I had these bundles installed and started (maven dependencies):

        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-core</artifactId>
            <version>1.12</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>1.12</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-servlet</artifactId>
            <version>1.12</version>
        </dependency>

They were right there in the OSGi runtime: "Active". So what was up? The answer lies in how I was referencing the Jersey context in my web.xml:

      <servlet>
        <servlet-name>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.my.Application</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

It turns out this is the only reference to the ServletContainer anywhere in my "code", in the web.xml. I use the maven-bundle-plugin for generating the bundles. The Bnd tool at the core of that plugin automatically collects all the Import-Packages from what's being imported in your Java code.

The classpath in OSGi is partly derived from your Import-Package statement, and since nowhere in my code was I explicitly referencing the ServletContainer, that class was never made available on the classpath.

Solution, changed the configuration of the maven-bundle-plugin to add the package to the Import-Package statement:

<Import-Package>com.sun.jersey.spi.container.servlet,*</Import-Package>

And then Jersey was deployed, and the world was calm.

2 comments:

Anonymous said...

Sega Genesis - The snk21.com
SEGA Genesis - The snk21.com is the ultimate 예스카지노 retro gaming source. We have brought you complete access to the hottest titles 카지노사이트 in the industry today.

Jack Will said...

OSGi Classpaths and Jersey explain how modular Java systems manage dependencies and REST services efficiently. The topic highlights flexibility and structure in development. In a different context, Online essay writing services can support learners by simplifying complex tasks and improving understanding through clear guidance and helpful resources for better learning