blob: 43c3b15a1c8dbcab471689c574ea81e50d732744 [file] [log] [blame]
<!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>&lt;?xml</xt> <xa>version</xa>=<xs>"1.0"</xs> <xa>encoding</xa>=<xs>"UTF-8"</xs><xt>?&gt;</xt>
<xt>&lt;web-app</xt> <xa>version</xa>=<xs>"2.3"</xs><xt>&gt;</xt>
<xt>&lt;servlet&gt;</xt>
<xt>&lt;servlet-name&gt;</xt>WinkService<xt>&lt;/servlet-name&gt;</xt>
<xt>&lt;servlet-class&gt;</xt>org.apache.wink.server.internal.servlet.RestServlet<xt>&lt;/servlet-class&gt;</xt>
<xt>&lt;init-param&gt;</xt>
<xt>&lt;param-name&gt;</xt>applicationConfigLocation<xt>&lt;/param-name&gt;</xt>
<xt>&lt;param-value&gt;</xt>/WEB-INF/wink.cfg<xt>&lt;/param-value&gt;</xt>
<xt>&lt;/init-param&gt;</xt>
<xt>&lt;/servlet&gt;</xt>
<xt>&lt;servlet-mapping&gt;</xt>
<xt>&lt;servlet-name&gt;</xt>WinkService<xt>&lt;/servlet-name&gt;</xt>
<xt>&lt;url-pattern&gt;</xt>/wink/*<xt>&lt;/url-pattern&gt;</xt>
<xt>&lt;/servlet-mapping&gt;</xt>
<xt>&lt;/web-app&gt;</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>&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;table type="object"&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;string&gt;key&lt;/string&gt;
&lt;/th&gt;
&lt;th&gt;
&lt;string&gt;value&lt;/string&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;string&gt;text&lt;/string&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;string&gt;Hello world&lt;/string&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;string&gt;author&lt;/string&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;string&gt;John Smith&lt;/string&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/body&gt;
&lt;/html&gt;</ja>
</p>
<p class='bcode'>
C:\&gt;curl.exe -H "Accept: text/xml" -X GET http://localhost:9080/sample/wink/helloworld
<ja>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;object&gt;
&lt;text&gt;Hello world&lt;/text&gt;
&lt;author&gt;John Smith&lt;/author&gt;
&lt;/object&gt;</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'&amp;author='John+Smith'</ja>
</p>
<p class='bcode'>
C:\&gt;curl.exe -H "Accept: text/xml+schema" -X GET http://localhost:9080/sample/wink/helloworld
<ja>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;
&lt;xs:element name="object" nillable="true"&gt;
&lt;xs:complexType&gt;
&lt;xs:sequence minOccurs="0" maxOccurs="unbounded"&gt;
&lt;xs:element name="text" type="xs:string" nillable="true" minOccurs="0"/&gt;
&lt;xs:element name="author" type="xs:string" nillable="true" minOccurs="0"/&gt;
&lt;/xs:sequence&gt;
&lt;/xs:complexType&gt;
&lt;/xs:element&gt;
&lt;xs:element name="null"/&gt;
&lt;/xs:schema&gt;</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 &amp;com.ib
&amp;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 &lt;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>