<!DOCTYPE HTML> | |
<!-- | |
/*************************************************************************************************************************** | |
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations under the License. | |
* | |
***************************************************************************************************************************/ | |
--> | |
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | |
<style type="text/css"> | |
/* For viewing in Page Designer */ | |
@IMPORT url("../../../../../javadoc.css"); | |
/* For viewing in REST interface */ | |
@IMPORT url("../htdocs/javadoc.css"); | |
body { | |
margin: 20px; | |
} | |
</style> | |
<script> | |
/* Replace all @code and @link tags. */ | |
window.onload = function() { | |
document.body.innerHTML = document.body.innerHTML.replace(/\{\@code ([^\}]+)\}/g, '<code>$1</code>'); | |
document.body.innerHTML = document.body.innerHTML.replace(/\{\@link (([^\}]+)\.)?([^\.\}]+)\}/g, '<code>$3</code>'); | |
} | |
</script> | |
</head> | |
<body> | |
<p>JAX-RS / Wink integration components</p> | |
<script> | |
function toggle(x) { | |
var div = x.nextSibling; | |
while (div != null && div.nodeType != 1) | |
div = div.nextSibling; | |
if (div != null) { | |
var d = div.style.display; | |
if (d == 'block' || d == '') { | |
div.style.display = 'none'; | |
x.className += " closed"; | |
} else { | |
div.style.display = 'block'; | |
x.className = x.className.replace(/(?:^|\s)closed(?!\S)/g , '' ); | |
} | |
} | |
} | |
</script> | |
<p> | |
Defines an API and default provides for using Juneau serializers and parsers as JAX-RS providers. | |
</p> | |
<a id='TOC'></a><h5 class='toc'>Table of Contents</h5> | |
<ol class='toc'> | |
<li><p><a class='doclink' href='#BaseProvider'>Juneau JAX-RS Provider</a></p> | |
</ol> | |
<!-- ======================================================================================================== --> | |
<a id="BaseProvider"></a> | |
<h2 class='topic' onclick='toggle(this)'>1 - Juneau JAX-RS Provider</h2> | |
<div class='topic'> | |
<p> | |
The Juneau framework contains the <code>org.apache.juneau.rest.jaxrs</code> package for performing simple | |
integration of Juneau serializers and parsers in JAX-RS compliant environments. | |
</p> | |
<p> | |
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.rest.RestServlet} class directly. | |
</p> | |
<p> | |
What you can do with the Juneau JAX-RS provider classes: | |
</p> | |
<ul class='spaced-list'> | |
<li>Use existing Juneau serializers and parsers for converting streams to POJOs and vis-versa. | |
<li>Use annotations to specify filters and properties using the {@link org.apache.juneau.rest.annotation.RestMethod} | |
and {@link org.apache.juneau.rest.jaxrs.JuneauProvider} annotations. | |
</ul> | |
<p> | |
What you can't do with the Juneau JAX-RS provider classes: | |
</p> | |
<ul class='spaced-list'> | |
<li>Specify or override serializers/parsers at the Java class and method levels. | |
<br>JAX-RS does not provide the capability to use different providers for the same media types | |
at the class or method levels. | |
<li>Specify or override filters and properties at the Java class level. | |
<li>Default stylesheets for the {@link org.apache.juneau.html.HtmlDocSerializer} class. | |
<br>It will produce HTML, but it won't contain any styles applied. | |
<br>However, it's possible to specify your own stylesheet using the {@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_cssUrl} property. | |
<li>The ability to specify HTTP method, headers, and content using GET parameters. | |
<br>These make debugging REST interfaces using only a browser possible. | |
<li>Class or method level encoding. | |
<li>Class or method level guards. | |
<li>Class or method level converters. | |
</ul> | |
<h6 class='topic'>Juneau JAX-RS Provider API</h6> | |
<p> | |
The Juneau JAX-RS provider API consists of the following classes: | |
</p> | |
<ul class='spaced-list'> | |
<li>{@link org.apache.juneau.rest.jaxrs.BaseProvider} - The base provider class that implements the JAX-RS | |
<code>MessageBodyReader</code> and <code>MessageBodyWriter</code> interfaces. | |
<li>{@link org.apache.juneau.rest.jaxrs.JuneauProvider} - Annotation that is applied to subclasses of <code>BaseProvider</code> | |
to specify the serializers/parsers associated with a provider, and optionally filters and properties to | |
apply to those serializers and parsers. | |
<li>{@link org.apache.juneau.rest.jaxrs.DefaultProvider} - A default provider that provides the same level | |
of media type support as the {@link org.apache.juneau.rest.RestServletDefault} class. | |
</ul> | |
<p> | |
For the most part, when using these components, you'll either use the existing <code>DefaultProvider</code> or | |
<code>JuneauProvider</code> providers, or define your own by subclassing <code>BaseProvider</code>. | |
<h6 class='topic'>Example:</h6> | |
<p> | |
The <code>juneau_sample.war</code> project contains a sample <code>HelloWorldResource</code> class that | |
shows how to use the JAX-RS provider. It uses Wink as the JAX-RS implementation. | |
</p> | |
<p> | |
Wink is configured by registering the following servlet in the <code>web.xml</code> file of the web app: | |
</p> | |
<p class='bcode'> | |
<xt><?xml</xt> <xa>version</xa>=<xs>"1.0"</xs> <xa>encoding</xa>=<xs>"UTF-8"</xs><xt>?></xt> | |
<xt><web-app</xt> <xa>version</xa>=<xs>"2.3"</xs><xt>></xt> | |
<xt><servlet></xt> | |
<xt><servlet-name></xt>WinkService<xt></servlet-name></xt> | |
<xt><servlet-class></xt>org.apache.wink.server.internal.servlet.RestServlet<xt></servlet-class></xt> | |
<xt><init-param></xt> | |
<xt><param-name></xt>applicationConfigLocation<xt></param-name></xt> | |
<xt><param-value></xt>/WEB-INF/wink.cfg<xt></param-value></xt> | |
<xt></init-param></xt> | |
<xt></servlet></xt> | |
<xt><servlet-mapping></xt> | |
<xt><servlet-name></xt>WinkService<xt></servlet-name></xt> | |
<xt><url-pattern></xt>/wink/*<xt></url-pattern></xt> | |
<xt></servlet-mapping></xt> | |
<xt></web-app></xt> | |
</p> | |
<p> | |
The <code>wink.cfg</code> file lists our default provider and our sample resource: | |
</p> | |
<p class='bcode'> | |
org.apache.juneau.rest.jaxrs.DefaultProvider | |
com.foo.sample.jaxrs.HelloWorldResource | |
</p> | |
<p> | |
Interestingly, the <code>DefaultProvider</code> itself is a subclass of <code>BaseProvider</code> | |
with no code at all. It consists of annotations only: | |
</p> | |
<p class='bcode'> | |
<ja>@Provider</ja> | |
<ja>@Produces</ja>( | |
<js>"application/json,text/json,"</js>+ <jc>// JsonSerializer</jc> | |
<js>"application/json+schema,text/json+schema,"</js>+ <jc>// JsonSchemaSerializer</jc> | |
<js>"text/xml,"</js>+ <jc>// XmlDocSerializer</jc> | |
<js>"text/xml+schema,"</js>+ <jc>// XmlDocSerializer</jc> | |
<js>"text/html,"</js>+ <jc>// HtmlDocSerializer</jc> | |
<js>"application/x-www-form-urlencoded,"</js>+ <jc>// UrlEncodingSerializer</jc> | |
<js>"text/xml+soap,"</js>+ <jc>// SoapXmlSerializer</jc> | |
<js>"text/xml+rdf,"</js>+ <jc>// RdfXmlDocSerializer</jc> | |
<js>"application/x-java-serialized-object"</js> <jc>// JavaSerializedObjectSerializer</jc> | |
) | |
<ja>@Consumes</ja>( | |
<js>"application/json,text/json,"</js>+ <jc>// JsonParser</jc> | |
<js>"text/xml,"</js>+ <jc>// XmlParser</jc> | |
<js>"text/html,"</js>+ <jc>// HtmlParser</jc> | |
<js>"application/x-www-form-urlencoded"</js> <jc>// UrlEncodingParser</jc> | |
) | |
<ja>@JuneauProvider</ja>( | |
serializers={ | |
JsonSerializer.<jk>class</jk>, | |
JsonSchemaSerializer.<jk>class</jk>, | |
XmlDocSerializer.<jk>class</jk>, | |
XmlSchemaDocSerializer.<jk>class</jk>, | |
HtmlDocSerializer.<jk>class</jk>, | |
UrlEncodingSerializer.<jk>class</jk>, | |
SoapXmlSerializer.<jk>class</jk>, | |
RdfXmlDocSerializer.<jk>class</jk>, | |
JavaSerializedObjectSerializer.<jk>class</jk> | |
}, | |
parsers={ | |
JsonParser.<jk>class</jk>, | |
XmlParser.<jk>class</jk>, | |
HtmlParser.<jk>class</jk>, | |
UrlEncodingParser.<jk>class</jk> | |
} | |
) | |
<jk>public final class</jk> DefaultProvider <jk>extends</jk> BaseProvider {} | |
</p> | |
<p> | |
Similarly, if you're defining your own JAX-RS provider, you can do so using annotations only. | |
</p> | |
<p> | |
<p> | |
Our sample resource is shown below. | |
In this example, we've specified a <code><ja>@RestMethod</ja></code> annotation on the | |
getter to show how properties can be overridden on the serializers/parsers at the method level. | |
This annotation is optional. | |
</p> | |
<p class='bcode'> | |
<ja>@Path</ja>(<js>"/helloworld"</js>) | |
<jk>public class</jk> HelloWorldResource { | |
<jc>// Our bean message class</jc> | |
<jk>public static class</jk> Message { | |
<jc>// No-arg bean constructor (needed for parsers)</jc> | |
<jk>public</jk> Message() {} | |
<jk>public</jk> Message(String text, String author) { | |
<jk>this</jk>.text = text; | |
<jk>this</jk>.author = author; | |
} | |
<jk>public</jk> String text; | |
<jk>public</jk> String author; | |
} | |
<jk>private static</jk> Message message = <jk>new</jk> Message(<js>"Hello world"</js>, <js>"John Smith"</js>); | |
<ja>@GET</ja> | |
<ja>@Produces</ja>(<js>"*/*"</js>) | |
<ja>@RestMethod</ja>( <jc>/* Override some properties */</jc> | |
properties={ | |
<ja>@Property</ja>(name=SerializerContext.<jsf>SERIALIZER_useWhitespace</jsf>, value=<js>"true"</js>), | |
<ja>@Property</ja>(name=JsonSerializerContext.<jsf>LAX_MODE</jsf>, value=<js>"true"</js>) | |
} | |
) | |
<jk>public</jk> Message getMessage() { | |
<jk>return</jk> message; | |
} | |
<ja>@PUT</ja> | |
<ja>@Produces</ja>(<js>"*/*"</js>) | |
<ja>@Consumes</ja>(<js>"*/*"</js>) | |
<jk>public</jk> Message replaceMessage(Message message) { | |
HelloWorldResource.message = message; | |
<jk>return</jk> message; | |
} | |
} | |
</p> | |
<p> | |
When we start up the servlet, we can interact with the resource using cURL. | |
In these examples, note that the <jsf>SERIALIZER_useWhitespace</jsf> and <jsf>LAX_MODE</jsf> settings | |
cause the output to be readable instead of condensed. | |
</p> | |
<p class='bcode'> | |
C:\>curl.exe -H "Accept: text/json" -X GET http://localhost:9080/sample/wink/helloworld | |
<ja>{ | |
text:"Hello world", | |
author:"John Smith" | |
}</ja> | |
</p> | |
<p class='bcode'> | |
C:\>curl.exe -H "Accept: text/html" -X GET http://localhost:9080/sample/wink/helloworld | |
<ja><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></ja> | |
</p> | |
<p class='bcode'> | |
C:\>curl.exe -H "Accept: text/xml" -X GET http://localhost:9080/sample/wink/helloworld | |
<ja><?xml version="1.0" encoding="UTF-8"?> | |
<object> | |
<text>Hello world</text> | |
<author>John Smith</author> | |
</object></ja> | |
</p> | |
<p class='bcode'> | |
C:\>curl.exe -H "Accept: application/x-www-form-urlencoded" -X GET http://localhost:9080/sample/wink/helloworld | |
<ja>text='Hello+world'&author='John+Smith'</ja> | |
</p> | |
<p class='bcode'> | |
C:\>curl.exe -H "Accept: text/xml+schema" -X GET http://localhost:9080/sample/wink/helloworld | |
<ja><?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></ja> | |
</p> | |
<p class='bcode'> | |
C:\>curl.exe -H "Accept: application/x-java-serialized-object" -X GET http://localhost:9080/sample/wink/helloworld | |
<ja>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</ja> | |
</p> | |
<p> | |
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. | |
</p> | |
<p class='bcode'> | |
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 | |
<ja>{"text":"Hello again","author":"Jane Doe"}</ja> | |
</p> | |
</div> | |
</body> | |
</html> |