Fixing the Class Not Found Exception when running a CXF JAX-RS service

If you are trying to deploy a CXF JAX-RS service inside an OSGI container, you can be haunted by the exception given below. But, surprisingly, the fix could be pretty simple 2 step process.

Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: com.sun.ws.rs.ext.RuntimeDelegateImpl
	at javax.ws.rs.ext.RuntimeDelegate.findDelegate(RuntimeDelegate.java:122)
	at javax.ws.rs.ext.RuntimeDelegate.getInstance(RuntimeDelegate.java:91)
	at javax.ws.rs.core.MediaType.<clinit>(MediaType.java:44)
	... 56 more
Caused by: java.lang.ClassNotFoundException: com.sun.ws.rs.ext.RuntimeDelegateImpl
	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:247)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:169)
	at javax.ws.rs.ext.FactoryFinder.newInstance(FactoryFinder.java:62)
	at javax.ws.rs.ext.FactoryFinder.find(FactoryFinder.java:155)
	at javax.ws.rs.ext.RuntimeDelegate.findDelegate(RuntimeDelegate.java:105)
	... 58 more

First, make sure you follow the steps to register your servlet through the osgi HTTP service as pointed out in the minimal osgi sample.

Then, the reason most probably would be a non-OSGIfied jsr 311 implementation present. Replace this jar with an OSGI compatible implementation located at org.apache.servicemix.specs.jsr311-api-1.1.1-1.9.0.jar.

That should (hopefully) solve your problem.

Handling Exceptions with Axis2 Web Services (Code-First Approach)

If you are writing a web service using Java and deploying it in Axis2, you need to follow the steps below to propagate the exception properly to the client side.

Let’s say you have an exception you want to throw with a respective error message. Your method would look something like;

 public String foo throws MyException {
    if (true) {
       throw new MyException("This is my exception");
    }
 }

If you codegen your axis2 client stub you will see that the exception will be thrown when using the client. But if you catch that exception and print out the message, you will notice that the message is lost.

try {
   String s = client.foo();
} catch (MyExceptionException e) { // the codegen exception thrown
   System.out.println("The error that occurred is : " +  e.getMessage());
}

This will output something like;

The error that occurred is : MyException

To preserve the exception message, we need to include it as an attribute just like we would do in a bean class. Here’s an example of the MyException class;

public class MyException extends Exception {
    private String message;

    public MyException(String s, Throwable throwable) {
        super(s, throwable);
        this.message = s;
    }

    public MyException(String s) {
        super(s);
        this.message = s;
    }

    @Override
    public String getMessage() {
        return this.message;
    }

}

This can of course be extended to send any number of arbitrary attributes with the exception, given that they are web service friendly.

Now, you need to codegen your client and modify the client code as follows:

try {
   String s = client.foo();
} catch (MyExceptionException e) {
   System.out.println("The error that occurred is : " +  e.getFaultMessage().getMyException().getMessage());
}

When you run the code, the output will be as follows:

The error that occurred is : This is my exception