Dealing with Sun JDK related NoClassDefFoundError under Jboss

On a recent server upgrade from Tomcat to Jboss 7 we kept facing issues related to code that made use of sun jdk classes.

Few of Exceptions were:
java.lang.NoClassDefFoundError: com/sun/net/ssl/internal/ssl/Provider
java.lang.NoClassDefFoundError: sun/net/www/protocol/http/Handler

JBoss was not kind enough to allow such references which tomcat or prior Jboss servers were happy to serve!

The solution:

JBoss has a module “sun.jdk” which is used to load the jdk classes. For some reason not all classes are referenced.

In order to allow for the sun or com related jdk packages which are not getting loaded we need to register them under the “sun.jdk” module.

So, first step is to register the various sun/jdk packages that your application is going to depend upon.

This is done by adding few entries into the module.xml found here:

Eg: jboss-as-7.1.1.Final/modules/sun/jdk/main/module.xml

The complete module.xml for reference:

<module xmlns="urn:jboss:module:1.1" name="sun.jdk">
    <resources>
        <!-- currently jboss modules has not way of importing services from
        classes.jar so we duplicate them here -->
        <resource-root path="service-loader-resources"/>
    </resources>
    <dependencies>
        <system export="true">
            <paths>
                <path name="com/sun/script/javascript"/>
                <path name="com/sun/jndi/dns"/>
                <path name="com/sun/jndi/ldap"/>
                <path name="com/sun/jndi/url"/>
                <path name="com/sun/jndi/url/dns"/>
                <path name="com/sun/security/auth"/>
                <path name="com/sun/security/auth/login"/>
                <path name="com/sun/security/auth/module"/>
                <path name="sun/misc"/>
                <path name="sun/io"/>
                <path name="sun/nio"/>
                <path name="sun/nio/ch"/>
                <path name="sun/security"/>
                <path name="sun/security/krb5"/>
                <path name="sun/util"/>
                <path name="sun/util/calendar"/>
                <path name="sun/util/locale"/>
                <path name="sun/security/provider"/>
		<!-- Registered additional packages below which are not enabled by default -->
		<path name="sun/net/www/protocol/https"/>
		<path name="sun/net/www/protocol/http"/>
		<path name="com/sun/net/ssl/internal/ssl"/>
		<!-- Additional package additions ends here -->

                <path name="META-INF/services"/>
            </paths>
            <exports>
                <include-set>
                    <path name="META-INF/services"/>
                </include-set>
            </exports>
        </system>
    </dependencies>
</module>

Note: In this example I have added the below three packages only:

<path name="sun/net/www/protocol/https"/>
<path name="sun/net/www/protocol/http"/>
<path name="com/sun/net/ssl/internal/ssl"/>

Ok, do not rush off to start the server yet, there is one more part remaining to get rid off that nasty NoClassDefFoundError.
Now, we need to reference the “sun.jdk” module.
There are two options we have now:

Approach 1
Reference the module (“sun.jdk”) from your web application by creating a jboss-deployment-structure.xml under your applications WEB-INF/ folder.
Sample:

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.1">
    <deployment>
        <dependencies>
                <module name="sun.jdk"/>
        </dependencies>
    </deployment>
</jboss-deployment-structure>

Approach 2
Reference the module (“sun.jdk”) globally which makes it available to any application deployed on the server. With this you can ignore the custom jboss-deployment-structure.xml (No longer required to be put in each of your web applications).
For this you have to edit the standalone.xml and register the module globally.
Find the tag:

<subsystem xmlns="urn:jboss:domain:ee:1.0"/>

Then change it with this:

<subsystem xmlns="urn:jboss:domain:ee:1.0">
   <global-modules>
      <module name="sun.jdk" slot="main" /> 
   </global-modules> 
</subsystem>

With either of the above two approaches done, you can go ahead and start up your server.
You should no longer see the NoClassDefFoundError for the packages that you have registered.

References that helped me arrive at this solution:
http://www.mastertheboss.com/jboss-server/jboss-as-7/how-to-install-a-module-on-jboss-as-7
https://developer.jboss.org/thread/171932?tstart=0

Advertisements
Post a comment or leave a trackback: Trackback URL.

Comments

  • James Livingston  On December 15, 2014 at 6:19 am

    I would suggest creating a new module with the system dependencies you want, and depending on that, rather than modifying the existing one, to prevent conflicts with future changes. If you are using jboss-deployment-structure.xml, you can add the system dependencies directly there too.

    One of the reasons for hiding them, is that they are implementation details of the specific JDK, and may change or be removed in future, so it’s best not to depend on them unless you deliberately want to do so. I beleive the SSL internal classes have broken API compatibility in the past, for example. I think the ones which are exported out of the box and done so because either they are so widely used that it’s not practical to hide them, or they are needed in every classloader to make other common code work.

  • Well  On July 11, 2015 at 9:50 am

    Thank you this is perfect. Helped me a lot. Kudos!!!!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: