Topic
  • 11 replies
  • Latest Post - ‏2012-10-19T09:34:44Z by JoeChacko
SystemAdmin
SystemAdmin
590 Posts

Pinned topic REST Service working on WAS 8.5 LP - NOT on 8.5.next Alpha

‏2012-10-17T18:06:31Z |
Hello,

I am porting a very simple (Hello World complexity) REST service from WLP 8.5 to WLP 8.5.next alpha and it fails to serve request.
See FFDC log file attached below
I am also copying/pasting source code

How does it come that it can not find JSON's Jackson classes ?

Any workaround ? or a bug ?

Seb
------Start of DE processing------ = 10/17/12 20:06:59:356 CEST
Exception = java.lang.NoClassDefFoundError
Source = com.ibm.ws.webcontainer.osgi.VirtualHost
probeid = startWebApp
Stack Dump = java.lang.NoClassDefFoundError: org/codehaus/jackson/JsonGenerationException
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at com.ibm.ws.webcontainer.osgi.webapp.WebApp.addClassToHandlesTypesStartupSet(WebApp.java:1076)
at com.ibm.ws.webcontainer.osgi.webapp.WebApp.scanForHandlesTypesClasses(WebApp.java:1013)
at com.ibm.ws.webcontainer.webapp.WebApp.initializeServletContainerInitializers(WebApp.java:2075)
at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:743)
at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:5760)
at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApp(DynamicVirtualHost.java:443)
at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.createRunnableHandler(DynamicVirtualHost.java:249)
at com.ibm.ws.http.internal.VirtualHostImpl.discriminate(VirtualHostImpl.java:181)
at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink.ready(HttpDispatcherLink.java:167)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:448)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.handleNewRequest(HttpInboundLink.java:382)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.processRequest(HttpInboundLink.java:282)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.ready(HttpInboundLink.java:253)
at com.ibm.ws.tcpchannel.internal.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:174)
at com.ibm.ws.tcpchannel.internal.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:83)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager.requestComplete(WorkQueueManager.java:502)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager.attemptIO(WorkQueueManager.java:550)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager.workerRun(WorkQueueManager.java:899)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager$Worker.run(WorkQueueManager.java:981)
at com.ibm.ws.threading.internal.Worker.executeWork(Worker.java:449)
at com.ibm.ws.threading.internal.Worker.run(Worker.java:431)
at java.lang.Thread.run(Thread.java:680)
Caused by: java.lang.ClassNotFoundException: org.codehaus.jackson.JsonGenerationException
at com.ibm.ws.classloading.internal.AppClassLoader.findClassCommonLibraryClassLoaders(AppClassLoader.java:351)
at com.ibm.ws.classloading.internal.AppClassLoader.findClass(AppClassLoader.java:217)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at com.ibm.ws.classloading.internal.AppClassLoader.loadClass(AppClassLoader.java:327)
... 24 more
package test;

import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.PathParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;

import java.util.*;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
//defined in web.xml instead
//@javax.ws.rs.ApplicationPath("resources")
@Path("/test")
public class TestREST extends javax.ws.rs.core.Application {

@Context
private UriInfo context;

@GET
@Produces(MediaType.APPLICATION_JSON)
public String get() {
ObjectMapper mapper = new ObjectMapper();
Map<String, String> map = new HashMap<String, String>();
map.put("now", new java.util.Date().toString());

String result = null;
try {

// write JSON to a String
result = mapper.writeValueAsString(map);

} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (java.io.IOException e) {
e.printStackTrace();
}

return result;
}

@POST
@Consumes("application/xml")
//curl -i -X POST -d "<xml>test</xml>" --header 'Content-Type:application/xml' "http://localhost:9080/TestREST/resources/test"
public Response put(String content) {
System.out.println(content);

//returns HTTP 200 OK when everything is OK
return Response.ok().build();
}
}
  • SystemAdmin
    SystemAdmin
    590 Posts

    Re: REST Service working on WAS 8.5 LP - NOT on 8.5.next Alpha

    ‏2012-10-17T18:08:03Z  
    I failed to mention the same code is working OK on WLP 8.5
  • SystemAdmin
    SystemAdmin
    590 Posts

    Re: REST Service working on WAS 8.5 LP - NOT on 8.5.next Alpha

    ‏2012-10-17T18:33:28Z  
    I failed to mention the same code is working OK on WLP 8.5
    Hi Sebastien,

    It appears that your app is using this class: org.codehaus.jackson.JsonGenerationException The jackson packages are classified as 'third-party API' by Liberty... this means that they are not available on the application classloader by default and you need to explicitly configure the application to allow visibility. This is done to protect against inadvertent use of third party packages that we do not control and thus cannot guarantee backward compatibility of (see http://www14.software.ibm.com/webapp/wsbroker/redirect?version=phil&product=was-base-dist&topic=rwlp_profile_externals). To configuer your application to see third party API packages, use something like this in the server.xml:

    <application name="Scholar" type="ear" location="scholar.ear">
    <classloader apiTypeVisibility="spec, ibm-api, third-party" />
    </application>

    There's more detail on how to do this in the infocenter at this link: http://www14.software.ibm.com/webapp/wsbroker/redirect?version=phil&product=was-nd-dist&topic=twlp_classloader_3p_apis

    As to why the application worked on a previous driver - I suspect there was a bug in the class visibility logic that has now been fixed. The design principle here is to hide the app server 'internals' so they don't interfere/clash with the contents of applications. Let me know if this doesn't work (also if your app is not using that class directly, I'd be interested to know).

    Thanks, Alex Mulholland.
  • SystemAdmin
    SystemAdmin
    590 Posts

    Re: REST Service working on WAS 8.5 LP - NOT on 8.5.next Alpha

    ‏2012-10-17T19:29:59Z  
    Hi Sebastien,

    It appears that your app is using this class: org.codehaus.jackson.JsonGenerationException The jackson packages are classified as 'third-party API' by Liberty... this means that they are not available on the application classloader by default and you need to explicitly configure the application to allow visibility. This is done to protect against inadvertent use of third party packages that we do not control and thus cannot guarantee backward compatibility of (see http://www14.software.ibm.com/webapp/wsbroker/redirect?version=phil&product=was-base-dist&topic=rwlp_profile_externals). To configuer your application to see third party API packages, use something like this in the server.xml:

    <application name="Scholar" type="ear" location="scholar.ear">
    <classloader apiTypeVisibility="spec, ibm-api, third-party" />
    </application>

    There's more detail on how to do this in the infocenter at this link: http://www14.software.ibm.com/webapp/wsbroker/redirect?version=phil&product=was-nd-dist&topic=twlp_classloader_3p_apis

    As to why the application worked on a previous driver - I suspect there was a bug in the class visibility logic that has now been fixed. The design principle here is to hide the app server 'internals' so they don't interfere/clash with the contents of applications. Let me know if this doesn't work (also if your app is not using that class directly, I'd be interested to know).

    Thanks, Alex Mulholland.
    Hello Alex,

    Thanks for your explanation - it makes sense :-)

    However ... I still have the same issue

    I added
    <application id="TestREST" location="TestREST.war" name="TestREST" type="war">
    <classloader apiTypeVisibility="spec, ibm-api, third-party"/>
    </application>

    Restarted

    and I still receive
    Caused by: java.lang.ClassNotFoundException: org.codehaus.jackson.JsonGenerationException
    at com.ibm.ws.classloading.internal.AppClassLoader.findClassCommonLibraryClassLoaders(AppClassLoader.java:351)
    at com.ibm.ws.classloading.internal.AppClassLoader.findClass(AppClassLoader.java:217)
  • SystemAdmin
    SystemAdmin
    590 Posts

    Re: REST Service working on WAS 8.5 LP - NOT on 8.5.next Alpha

    ‏2012-10-17T20:55:01Z  
    Hello Alex,

    Thanks for your explanation - it makes sense :-)

    However ... I still have the same issue

    I added
    <application id="TestREST" location="TestREST.war" name="TestREST" type="war">
    <classloader apiTypeVisibility="spec, ibm-api, third-party"/>
    </application>

    Restarted

    and I still receive
    Caused by: java.lang.ClassNotFoundException: org.codehaus.jackson.JsonGenerationException
    at com.ibm.ws.classloading.internal.AppClassLoader.findClassCommonLibraryClassLoaders(AppClassLoader.java:351)
    at com.ibm.ws.classloading.internal.AppClassLoader.findClass(AppClassLoader.java:217)
    Hi Sebastien,

    I added a simple use (construction) of JsonGenerationException into my very simple app, confirmed the ClassNotFoundException with the original configuration (no classloader element) and then changed it to this:

    <application type="war" id="basicapp" name="basicapp" location="${server.config.dir}/apps/basicapp.war">
    <classloader apiTypeVisibility="spec, ibm-api, third-party" />
    </application>

    and the application worked.

    Please can you check a couple of things for me:
    1) what is the absolute location of your app? If it's in the dropins directory then the configuration won't be applied, it needs to be in the apps directory
    2) is your application referencing/importing that exception class directly? If not, do you know what your app is doing to require that class?

    Thanks, Alex.
  • SystemAdmin
    SystemAdmin
    590 Posts

    Re: REST Service working on WAS 8.5 LP - NOT on 8.5.next Alpha

    ‏2012-10-18T06:57:18Z  
    Hi Sebastien,

    I added a simple use (construction) of JsonGenerationException into my very simple app, confirmed the ClassNotFoundException with the original configuration (no classloader element) and then changed it to this:

    <application type="war" id="basicapp" name="basicapp" location="${server.config.dir}/apps/basicapp.war">
    <classloader apiTypeVisibility="spec, ibm-api, third-party" />
    </application>

    and the application worked.

    Please can you check a couple of things for me:
    1) what is the absolute location of your app? If it's in the dropins directory then the configuration won't be applied, it needs to be in the apps directory
    2) is your application referencing/importing that exception class directly? If not, do you know what your app is doing to require that class?

    Thanks, Alex.
    Hello,

    After a full night of sleep for my machine and myself (and a reboot - just for the machine) - still the same issue.

    I was deploying from Eclipse and, reading your post - I thought this might be the source of my problem.
    But I just tried all three deployment options : 1/ From Eclipse, 2/ in dropins and 3/in Apps

    All three deployments caused the same ClassNotFound.

    I am sending you by email the project and server.xml to have a look :-)

    I probably missed something very basic and stupid.

    I tested on JDK 6 and JDK 7 on Mac OS X
    I am importing the JSON classes directly from my PoJo and reference them in my code.
    As you will see, this is a very simple example - Hello World kind of complexity

    Seb
  • SystemAdmin
    SystemAdmin
    590 Posts

    Re: REST Service working on WAS 8.5 LP - NOT on 8.5.next Alpha

    ‏2012-10-18T10:46:34Z  
    Hello,

    After a full night of sleep for my machine and myself (and a reboot - just for the machine) - still the same issue.

    I was deploying from Eclipse and, reading your post - I thought this might be the source of my problem.
    But I just tried all three deployment options : 1/ From Eclipse, 2/ in dropins and 3/in Apps

    All three deployments caused the same ClassNotFound.

    I am sending you by email the project and server.xml to have a look :-)

    I probably missed something very basic and stupid.

    I tested on JDK 6 and JDK 7 on Mac OS X
    I am importing the JSON classes directly from my PoJo and reference them in my code.
    As you will see, this is a very simple example - Hello World kind of complexity

    Seb
    Surprisingly, even when including jackson-core.jar and jackson-binding.jar in WEB-INF/lib, I still receive the NoClassDefFound exception.
  • SystemAdmin
    SystemAdmin
    590 Posts

    Re: REST Service working on WAS 8.5 LP - NOT on 8.5.next Alpha

    ‏2012-10-18T10:54:47Z  
    Hi Sebastien,

    I added a simple use (construction) of JsonGenerationException into my very simple app, confirmed the ClassNotFoundException with the original configuration (no classloader element) and then changed it to this:

    <application type="war" id="basicapp" name="basicapp" location="${server.config.dir}/apps/basicapp.war">
    <classloader apiTypeVisibility="spec, ibm-api, third-party" />
    </application>

    and the application worked.

    Please can you check a couple of things for me:
    1) what is the absolute location of your app? If it's in the dropins directory then the configuration won't be applied, it needs to be in the apps directory
    2) is your application referencing/importing that exception class directly? If not, do you know what your app is doing to require that class?

    Thanks, Alex.
    OK - my fault - I included Jackson 2.1 which uses a different package name. When including Jackson 1.9 it works as expect from Eclipse and from /apps
    with no <classloader> element defined

    Seb
  • SystemAdmin
    SystemAdmin
    590 Posts

    Re: REST Service working on WAS 8.5 LP - NOT on 8.5.next Alpha

    ‏2012-10-19T01:15:06Z  
    OK - my fault - I included Jackson 2.1 which uses a different package name. When including Jackson 1.9 it works as expect from Eclipse and from /apps
    with no <classloader> element defined

    Seb
    Hi Sebastien,

    Thanks for the app - I recreated your problem and believe I have identified the bug. The application's classloader configuration is being cached so that, once the application has been started in the server, the apiVisibilityType is not updated until the server undergoes a clean start. In your scenario, the application was initially started with the default apiVisibilityType of 'spec, ibm-api, user', and (because of the bug) this will not change without clean start of the server. As a workaround, there are two ways you can force the server to perform a clean start:
    a) in the eclipse tools, right-click on the server and select 'Clean Server on Next Start' (don't use the 'Clean...' option in this scenario)
    b) on the command line, add the --clean option to the 'server run' or 'server start' command

    I will log the bug as the correct behaviour is for the updated configuration to take immediate effect.

    Thanks, Alex.
  • SystemAdmin
    SystemAdmin
    590 Posts

    Re: REST Service working on WAS 8.5 LP - NOT on 8.5.next Alpha

    ‏2012-10-19T07:28:30Z  
    Hi Sebastien,

    Thanks for the app - I recreated your problem and believe I have identified the bug. The application's classloader configuration is being cached so that, once the application has been started in the server, the apiVisibilityType is not updated until the server undergoes a clean start. In your scenario, the application was initially started with the default apiVisibilityType of 'spec, ibm-api, user', and (because of the bug) this will not change without clean start of the server. As a workaround, there are two ways you can force the server to perform a clean start:
    a) in the eclipse tools, right-click on the server and select 'Clean Server on Next Start' (don't use the 'Clean...' option in this scenario)
    b) on the command line, add the --clean option to the 'server run' or 'server start' command

    I will log the bug as the correct behaviour is for the updated configuration to take immediate effect.

    Thanks, Alex.
    Hello Alex,

    I do confirm it works as described. Thanks for having investigated this issue.
    Can you elaborate a little bit on what "--clean" does ?

    Thanks

    Seb
  • SystemAdmin
    SystemAdmin
    590 Posts

    Re: REST Service working on WAS 8.5 LP - NOT on 8.5.next Alpha

    ‏2012-10-19T07:28:53Z  
    Thanks Alex - the workaround proposed is indeed solving the issue.
  • JoeChacko
    JoeChacko
    15 Posts

    Re: REST Service working on WAS 8.5 LP - NOT on 8.5.next Alpha

    ‏2012-10-19T09:34:44Z  
    Hello Alex,

    I do confirm it works as described. Thanks for having investigated this issue.
    Can you elaborate a little bit on what "--clean" does ?

    Thanks

    Seb
    The --clean option removes the cached information from the previous server start, i.e. the results of processing the config. This improves server start time for any unchanged config, but should still read in any changes since the previous server start.

    As Alex said, there is a bug that means the new class loader configuration is not taking precedence over the cached one. The --clean option works around this bug by removing the cache and forcing the server to use the new config. You do not need to issue --clean on every server start, but it can help when config changes are not being processed as you expect.

    Thanks, Seb for finding this bug, and thanks to Alex for diagnosing it.
    --
    Joe
    WebSphere Application Server Liberty Profile Developer