Hi,
I am exploring the possibilities of Jersey and JAX-RS. I want to produce an
XML-representation of my domain-objects. The XML-should contain a
"<xsl-stylesheet..." header.
As suggested at
http://blogs.sun.com/enterprisetechtips/entry/configuring_json_for_restful_web,
I created a custom resolver as follows:
package be.kvvcr.thesauri.rest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ws.rs.Produces;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
import be.kvvcr.thesauri.Attribute;
import be.kvvcr.thesauri.DescLabel;
import be.kvvcr.thesauri.Descriptor;
import be.kvvcr.thesauri.Domain;
import be.kvvcr.thesauri.Label;
import be.kvvcr.thesauri.MicroThesaurus;
import be.kvvcr.thesauri.MultiLingualConcept;
import be.kvvcr.thesauri.NonDescLabel;
import be.kvvcr.thesauri.Perm;
import be.kvvcr.thesauri.ScopeNote;
@Produces({"text/xml"})
@Provider
public class JAXBXSLResolver implements ContextResolver<JAXBContext> {
private JAXBContext context;
private Class[] types = {MultiLingualConcept.class, Descriptor.class,
Label.class, Attribute.class, DescLabel.class, MicroThesaurus.class,
Domain.class, ScopeNote.class, Perm.class, NonDescLabel.class };
public JAXBXSLResolver() throws Exception {
Map<String, Object> props = new HashMap<String, Object>();
System.out.println("instantiating the JAXBXSLResolver");
this.context = MyJAXBContext.newInstance(types,props);
}
@Override
public JAXBContext getContext(Class<?> objectType) {
JAXBContext returnCtxt = null;
List<Class> typesList = Arrays.asList(types);
System.out.println("testing whether " + objectType + " is
supported...");
if(typesList.contains(objectType)){
System.out.println("yes it is...");
returnCtxt = this.context;
}
System.err.println("nope it isn't...");
return returnCtxt;
}
}
And this custom JAXBResolver makes use of the context defined in
MyJAXBContext:
package be.kvvcr.thesauri.rest;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.Validator;
public final class MyJAXBContext extends JAXBContext{
private final JAXBContext context;
public MyJAXBContext(Class[] classes) throws JAXBException{
Map<String, Object> props = new HashMap<String, Object>();
props.put("com.sun.xml.bind.xmlHeaders", "<?xml-stylesheet
type='text/xsl' href='foobar.xsl' ?>");
this.context = JAXBContext.newInstance(classes,props);
}
public JAXBContext getContext(){
return this.context;
}
@Override
public Marshaller createMarshaller() throws JAXBException {
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty("com.sun.xml.bind.xmlHeaders",
"<?xml-stylesheet type='text/xsl' href='foobar.xsl' ?>");
return marshaller;
}
@Override
public Unmarshaller createUnmarshaller() throws JAXBException {
Unmarshaller unmarshaller = context.createUnmarshaller();
return unmarshaller;
}
@Override
public Validator createValidator() throws JAXBException {
return null;
}
}
Now, when I startup my appserver (Tomcat 6.0), I see encouraging messages in
the console:
24-jun-2009 16:06:58 com.sun.jersey.api.core.ClasspathResourceConfig init
INFO: Provider classes found:
class be.kvvcr.thesauri.rest.JAXBXSLResolver
24-jun-2009 16:06:58
com.sun.jersey.server.impl.application.WebApplicationImpl initiate
INFO: Initiating Jersey application, version 'Jersey: 1.1.0-ea 04/30/2009
04:46 PM'
instantiating the JAXBXSLResolver
However, I notice that my custom Provider is not used when invoking my
resources... It is the default resolver which is used (as far as a default
resolver exists). If I change the value of the @Produces annotation for my
custom Resolver from "text/xml" into, say, "browser/xml", I get an
errormessage (upon requesting a resource):
24-jun-2009 16:43:33 com.sun.jersey.spi.container.ContainerResponse write
SEVERE: A message body writer for Java type, class
be.kvvcr.thesauri.Descriptor, and MIME media type, browser/xml, was not
found
24-jun-2009 16:43:33
com.sun.jersey.server.impl.application.WebApplicationImpl onException
SEVERE: Internal server error
javax.ws.rs.WebApplicationException
at
com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:241)
at
com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:693)
at
com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:616)
at
com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:607)
at
com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:309)
at
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:425)
at
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:590)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:263)
at
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:584)
at
org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Unknown Source)
I have been looking around with my (eclipse-) debugger in the source code.
I noticed that the "browser/xml" mime-type which I provided in the
annotation of my resolver, could not be found when requesting my
resource... Please note that my Resource-class contains the annotation
@Produces({"text/xml", "browser/xml"}). I guess something went wrong during
the registration of the resolver/provider. But I have no clue what.
Moreover, the api changed slightly during the upgrade to 1.1. Perhaps I
mixed something up?
As a consequence, I'm a bit stuck. I guess I miss something... Should I
explicitly define a new MessageBodyWriter? Should I register something?
I've found a few hints via Google, but none were for Jersey.
regards,
Bruno.