Defines an API and default provides for using Juneau serializers and parsers as JAX-RS providers.
The Juneau framework contains the org.apache.juneau.server.jaxrs
package for performing simple
integration of Juneau serializers and parsers in JAX-RS compliant environments.
It should be noted that although some of the functionality of the Juneau Server API is provided through the JAX-RS
integration components, it is not nearly as flexible as using the {@link org.apache.juneau.server.RestServlet} class directly.
What you can do with the Juneau JAX-RS provider classes:
- Use existing Juneau serializers and parsers for converting streams to POJOs and vis-versa.
- Use annotations to specify filters and properties using the {@link org.apache.juneau.server.annotation.RestMethod}
and {@link org.apache.juneau.server.jaxrs.JuneauProvider} annotations.
What you can't do with the Juneau JAX-RS provider classes:
- Specify or override serializers/parsers at the Java class and method levels.
JAX-RS does not provide the capability to use different providers for the same media types
at the class or method levels.
- Specify or override filters and properties at the Java class level.
- Default stylesheets for the {@link org.apache.juneau.html.HtmlDocSerializer} class.
It will produce HTML, but it won't contain any styles applied.
However, it's possible to specify your own stylesheet using the {@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_cssUrl} property.
- The ability to specify HTTP method, headers, and content using GET parameters.
These make debugging REST interfaces using only a browser possible.
- Class or method level encoding.
- Class or method level guards.
- Class or method level converters.
Juneau JAX-RS Provider API
The Juneau JAX-RS provider API consists of the following classes:
- {@link org.apache.juneau.server.jaxrs.BaseProvider} - The base provider class that implements the JAX-RS
MessageBodyReader
and MessageBodyWriter
interfaces.
- {@link org.apache.juneau.server.jaxrs.JuneauProvider} - Annotation that is applied to subclasses of
BaseProvider
to specify the serializers/parsers associated with a provider, and optionally filters and properties to
apply to those serializers and parsers.
- {@link org.apache.juneau.server.jaxrs.DefaultProvider} - A default provider that provides the same level
of media type support as the {@link org.apache.juneau.server.RestServletDefault} class.
For the most part, when using these components, you'll either use the existing DefaultProvider
or
JuneauProvider
providers, or define your own by subclassing BaseProvider
.
Example:
The juneau_sample.war
project contains a sample HelloWorldResource
class that
shows how to use the JAX-RS provider. It uses Wink as the JAX-RS implementation.
Wink is configured by registering the following servlet in the web.xml
file of the web app:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.3">
<servlet>
<servlet-name>WinkService</servlet-name>
<servlet-class>org.apache.wink.server.internal.servlet.RestServlet</servlet-class>
<init-param>
<param-name>applicationConfigLocation</param-name>
<param-value>/WEB-INF/wink.cfg</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>WinkService</servlet-name>
<url-pattern>/wink/*</url-pattern>
</servlet-mapping>
</web-app>
The wink.cfg
file lists our default provider and our sample resource:
org.apache.juneau.server.jaxrs.DefaultProvider
com.foo.sample.jaxrs.HelloWorldResource
Interestingly, the DefaultProvider
itself is a subclass of BaseProvider
with no code at all. It consists of annotations only:
@Provider
@Produces(
"application/json,text/json,"+ // JsonSerializer
"application/json+schema,text/json+schema,"+ // JsonSchemaSerializer
"text/xml,"+ // XmlDocSerializer
"text/xml+schema,"+ // XmlDocSerializer
"text/html,"+ // HtmlDocSerializer
"application/x-www-form-urlencoded,"+ // UrlEncodingSerializer
"text/xml+soap,"+ // SoapXmlSerializer
"text/xml+rdf,"+ // RdfXmlDocSerializer
"application/x-java-serialized-object" // JavaSerializedObjectSerializer
)
@Consumes(
"application/json,text/json,"+ // JsonParser
"text/xml,"+ // XmlParser
"text/html,"+ // HtmlParser
"application/x-www-form-urlencoded" // UrlEncodingParser
)
@JuneauProvider(
serializers={
JsonSerializer.class,
JsonSchemaSerializer.class,
XmlDocSerializer.class,
XmlSchemaDocSerializer.class,
HtmlDocSerializer.class,
UrlEncodingSerializer.class,
SoapXmlSerializer.class,
RdfXmlDocSerializer.class,
JavaSerializedObjectSerializer.class
},
parsers={
JsonParser.class,
XmlParser.class,
HtmlParser.class,
UrlEncodingParser.class
}
)
public final class DefaultProvider extends BaseProvider {}
Similarly, if you're defining your own JAX-RS provider, you can do so using annotations only.
Our sample resource is shown below.
In this example, we've specified a @RestMethod
annotation on the
getter to show how properties can be overridden on the serializers/parsers at the method level.
This annotation is optional.
@Path("/helloworld")
public class HelloWorldResource {
// Our bean message class
public static class Message {
// No-arg bean constructor (needed for parsers)
public Message() {}
public Message(String text, String author) {
this.text = text;
this.author = author;
}
public String text;
public String author;
}
private static Message message = new Message("Hello world", "John Smith");
@GET
@Produces("*/*")
@RestMethod( /* Override some properties */
properties={
@Property(name=SerializerContext.SERIALIZER_useIndentation, value="true"),
@Property(name=JsonSerializerContext.LAX_MODE, value="true")
}
)
public Message getMessage() {
return message;
}
@PUT
@Produces("*/*")
@Consumes("*/*")
public Message replaceMessage(Message message) {
HelloWorldResource.message = message;
return message;
}
}
When we start up the servlet, we can interact with the resource using cURL.
In these examples, note that the SERIALIZER_useIndentation and LAX_MODE settings
cause the output to be readable instead of condensed.
C:\>curl.exe -H "Accept: text/json" -X GET http://localhost:9080/sample/wink/helloworld
{
text:"Hello world",
author:"John Smith"
}
C:\>curl.exe -H "Accept: text/html" -X GET http://localhost:9080/sample/wink/helloworld
<html>
<head>
</head>
<body>
<table type="object">
<tr>
<th>
<string>key</string>
</th>
<th>
<string>value</string>
</th>
</tr>
<tr>
<td>
<string>text</string>
</td>
<td>
<string>Hello world</string>
</td>
</tr>
<tr>
<td>
<string>author</string>
</td>
<td>
<string>John Smith</string>
</td>
</tr>
</table>
</body>
</html>
C:\>curl.exe -H "Accept: text/xml" -X GET http://localhost:9080/sample/wink/helloworld
<?xml version="1.0" encoding="UTF-8"?>
<object>
<text>Hello world</text>
<author>John Smith</author>
</object>
C:\>curl.exe -H "Accept: application/x-www-form-urlencoded" -X GET http://localhost:9080/sample/wink/helloworld
text='Hello+world'&author='John+Smith'
C:\>curl.exe -H "Accept: text/xml+schema" -X GET http://localhost:9080/sample/wink/helloworld
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xs:element name="object" nillable="true">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="text" type="xs:string" nillable="true" minOccurs="0"/>
<xs:element name="author" type="xs:string" nillable="true" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="null"/>
</xs:schema>
C:\>curl.exe -H "Accept: application/x-java-serialized-object" -X GET http://localhost:9080/sample/wink/helloworld
detailMessaget ↕Ljava/lang/String;[ ption(Vx τå▬5☻ xr ↔java.io.ObjectStreamExceptiond├Σkì9√▀☻ xr ‼java.io.IOExcept
stackTracet ▲[Ljava/lang/StackTraceElement;xpq t /org.apache.juneau.samples.jaxrs.HelloWorldResource$Messageur ▲[Ljava.lang.Sta
lineNumberL ♫declaringClassq ~ ♠LfileNameq ~ ♠L
methodNameq ~ ♠xp ♦át →java.io.ObjectOutputStreamt ↨ObjectOutputStream.javat ♀writeObject0sq ~ ♀ ☺[t →java.io.Obje
3org.apache.juneau.serializer.OutputStreamSerializert ←OutputStreamSerializer.javat serializesq ~ ♀ ^t &com.ib
&t /org.apache.wink.server.handlers.AbstractHandlert ¶AbstractHandler.javat ♫handleResponsesq ~ ♀ →t 5org.apache.
sq ~ ♀ Ct 5org.apache.wink.server.handlers.AbstractHandlersChaint →AbstractHandlersChain.javat doChainsq ~ ♀ 't
♠handlesq ~ ♀ ▬t 5org.apache.wink.server.handlers.ResponseHandlersChaint →ResponseHandlersChain.javat ♠handlesq ~
♫handleResponsesq ~ ♀ →t 5org.apache.wink.server.handlers.ResponseHandlersChaint →ResponseHandlersChain.javat ♠ha
tHandlersChain.javat doChainsq ~ ♀ Zt -org.apache.wink.server.internal.log.Responsest ♫Responses.javat ♫handleResp
eHandlersChain.javat ♠handlesq ~ ♀ Ct 5org.apache.wink.server.handlers.AbstractHandlersChaint →AbstractHandlersCha
handleRequestsq ~ ♀ |t 3org.apache.wink.server.internal.servlet.RestServlett ►RestServlet.javat servicesq ~ ♀ ☻£t
handleRequestsq ~ ♀ ├t -com.ibm.ws.webcontainer.channel.WCChannelLinkt ↕WCChannelLink.javat ♣readysq ~ ♀ ☺─t 4com
►handleNewRequestsq ~ ♀ ☺1t 4com.ibm.ws.http.channel.inbound.impl.HttpInboundLinkt ¶HttpInboundLink.javat ♫process
nnectionInitialReadCallback.javat ¶sendToDiscriminatorssq ~ ♀ qt <com.ibm.ws.tcp.channel.impl.NewConnectionInitial
┘t $com.ibm.io.async.AbstractAsyncFuturet ↑AbstractAsyncFuture.javat ♫invokeCallbacksq ~ ♀ ít #com.ibm.io.async.
t ↕ResultHandler.javatcompletesq ~ ♀ ♥t ▲com.ibm.io.async.ResultHandlert ↕ResultHandler.javat ▬runEventProcessingLo
on: java.io.NotSerializableException: org.apache.juneau.samples.jaxrs.HelloWorldResource$Message
The following shows the PUT method being invoked.
In this case, we're passing in the new bean as a JSON object.
Also notice how the response is in standard condensed JSON since we did not override any properties on the REST method.
C:\>curl.exe -H "Content-Type: text/json" -H "Accept: text/json" -d "{text:'Hello again',author:'Jane Doe'}"
-X PUT http://localhost:9080/sample/wink/helloworld
{"text":"Hello again","author":"Jane Doe"}