users@jersey.java.net

Re: SV: [Jersey] Jersey client accessing Jesery REST server message writer issue

From: Paul Sandoz <Paul.Sandoz_at_oracle.com>
Date: Tue, 10 Aug 2010 12:45:26 +0200

On Aug 10, 2010, at 12:22 PM, Jimi Hullegård wrote:

> Hi Paul and Kevin,
>
> I must say that I have more or less the same problems as you Kevin.
> And I definately suspect a classloader issue, since that was the
> problem when I tried to marshall and unmarshall JAXB objects before.
> It turned out that since my code is used in a Jira plugin the
> special classloader situation caused Jersey/JAXB to use the wrong
> classloader. It tried to use the one from
> Thread.currentThread().getContextClassLoader(), but that returned
> the Webapp classloader while all relevant code (including jaxb and
> jersey classes) were in the plugin classloader.
>
> I got around that problem by providing my own
> ContextResolver<JAXBContext> that created a JAXBContext with the
> correct classloader.
>
> So, I really suspect that somehow, somewere, Jersey is trying to use
> the context class loader from the thread, and end up with the wrong
> one.


By default Jersey creates a JAXBContext using:

   JAXBCOntext.newInstance(type)

   http://download.oracle.com/javase/6/docs/api/javax/xml/bind/JAXBContext.html#newInstance%28java.lang.Class...%29

     protected JAXBContext getStoredJAXBContext(Class type) throws
JAXBException {
         synchronized (jaxbContexts) {
             JAXBContext c = jaxbContexts.get(type);
             if (c == null) {
                 c = JAXBContext.newInstance(type);
                 jaxbContexts.put(type, c);
             }
             return c;
         }
     }

There is no class loader to specify as the type (the type of the JAXB
bean to parse or serialize) is already loaded. You only need to
specify the class loader when creating a JAXBContext and declaring a
location for the context path.

By default Jersey only has the type to go on. I suspect in your case
the type was not sufficient and you definitely need to tell Jersey
what the JAXBContext should be, and that is what ContextResolver is
for (which can also declare the Marshaller or Unmarshaller too).

Hth,
Paul.




> But I can't for the love of me figure out how to change this
> behaivor, or change what classloader is returned by
> Thread.currentThread().getContextClassLoader(). I guess there is
> some code that runs long before my code is running, because I tried
> specifically setting the threads context class loader in the
> constructor of my plugin class, but that didn't help at all.
>
> Maybe you have any input on this, Paul? Is there a solution similar
> to the ContextResolver<JAXBContext> that I can try, so I can
> specifically tell jersey/jaxb to use a specific classloader? Without
> having to write my own message body writer... If I use my own
> contextresolver and marshall the object into a string, then I can
> post it using jersey just fine, but I would like not having to
> marshall it myself.

> And Kevin, sorry if you think that I hijacked your thread. Maybe
> some of these links can help you, even though they don't work for me:
>
> http://jersey.576304.n2.nabble.com/com-sun-jersey-api-client-ClientHandlerException-A-message-body-reader-for-Java-type-td4122001.html
>
> http://markmail.org/thread/btvlaxkpxf2hluou#query:+page:1+mid:upvg2l24l47ywvlh+state:results
>
> http://jersey.576304.n2.nabble.com/Jersey-client-problem-with-mvn-assembly-td4129445.html
>
> Regards
> /Jimi
>
> Från: Paul Sandoz [Paul.Sandoz_at_oracle.com]
> Skickat: den 10 augusti 2010 11:40
> Till: users_at_jersey.dev.java.net
> Ämne: Re: [Jersey] Jersey client accessing Jesery REST server
> message writer issue
>
> Hi Kevin,
>
> It looks like there might be a class loading issue. It indicates
> that the Client instance cannot see the JAXB libs and therefore the
> JAXB message body writers for the client are not being utilized. Can
> you access JAXB directly from the application code in server 1 e.g.
> new JAXBContext(Transaction.class);
>
> When you say simple calls did you try a simple GET request such as:
>
> String s = webResource....get(String.class);
>
> if that works it certainly indicates an issue with JAXB rather than
> a fundamental issue with META-INF/services.
>
> Anything else in the logs on initialization? If you set JDK logging
> to CONFIG or above you may got some more clues.
>
> Since Jersey is distributed with GF you might want to be careful if
> you are also distributing a different version of Jersey in the WEB-
> INF/lib, also GF ships with JAXB so you may not require it to be in
> the WEB-INF/lib unless you need a specific version.
>
> Paul.
>
> On Aug 10, 2010, at 3:41 AM, Kevin Duffey wrote:
>
> Hey all,
>
> I am working on a project that uses two servers to communicate back
> and forth. The one server makes a REST call to the 2nd server. Both
> are my own code, both use Jersey and so forth. They both use the
> same .xsd and compiled JAXB classes. From server 1 I can reach
> server 2 no problem on simple calls. It's when I use the Jersey
> client code to pass a JAXB object to server 2 that I get the problem.
>
> Client client = Client.create();
> WebResource webResource =
> client.resource(getServerURL()).path("resources/transaction");
> Transaction response = webResource.header("Authorization",
> auth).accept("application/vnd.mycompany..transactions
> +xml").type("application/vnd.mycompany.transactions
> +xml").post(Transaction.class, t);
>
> Maybe I am doing this wrong? But when I execute this code I get the
>
> com.sun.jersey.api.client.ClientHandlerException: A message body
> writer for Java type...
>
> exception. I did some searching and see where Paul has replied to
> make sure all the JAXB libraries are in the class path. I definitely
> have all these in the WEB-INF/lib folder of my .war app that I
> deploy on both servers.
>
> So I am stumped as of now why this is telling me to have a message
> body writer. The Transaction class is a class generated from
> the .xsd.. and in fact on the server 1, I can make a REST call to it
> with xml in the format of the Transaction JAXB class, and it works.
> So I am not sure why it is telling me I need a separate writer.. it
> should have been part of the JAXB generated shouldn't it?
>
> I am using Jersey client 1.1.5 and GlassFish v3.
>
> Thanks in advance.
>
>
>
>