http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/package.html ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/package.html b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/package.html new file mode 100755 index 0000000..a498e78 --- /dev/null +++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/package.html @@ -0,0 +1,3600 @@ +<!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>REST Servlet API</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 for defining REST resources as servlets. +</p> + +<a name='TOC'></a><h5 class='toc'>Table of Contents</h5> +<ol class='toc'> + <li><p><a class='doclink' href='#Intro'>Introduction</a></p> + <li><p><a class='doclink' href='#HelloWorldResource'>Hello World Example</a></p> + <li><p><a class='doclink' href='#ClassHierarchy'>Class Hierarchy</a></p> + <li><p><a class='doclink' href='#RestServlets'>REST Servlets</a></p> + <ol> + <li><p><a class='doclink' href='#RestServlets.MethodSignature'>REST Java Method Signature</a></p> + <ol> + <li><p><a class='doclink' href='#RestServlets.MethodSignature.Path'>Path</a></p> + <li><p><a class='doclink' href='#RestServlets.MethodSignature.Matchers'>Matchers</a></p> + </ol> + <li><p><a class='doclink' href='#RestServlets.RequestContent'>Request Content</a></p> + <ol> + <li><p><a class='doclink' href='#RestServlets.RequestContent.FormPosts'>Form Posts</a></p> + <li><p><a class='doclink' href='#RestServlets.RequestContent'>Multipart Form Posts</a></p> + </ol> + <li><p><a class='doclink' href='#RestServlets.ResponseContent'>Response Content</a></p> + <li><p><a class='doclink' href='#RestServlets.OptionsPages'>OPTIONS Pages</a></p> + <li><p><a class='doclink' href='#RestServlets.Serializers'>Serializers</a></p> + <li><p><a class='doclink' href='#RestServlets.Parsers'>Parsers</a></p> + <li><p><a class='doclink' href='#RestServlets.Properties'>Properties</a></p> + <li><p><a class='doclink' href='#RestServlets.Transforms'>Transforms</a></p> + <li><p><a class='doclink' href='#RestServlets.Guards'>Guards</a></p> + <li><p><a class='doclink' href='#RestServlets.Converters'>Converters</a></p> + <li><p><a class='doclink' href='#RestServlets.Children'>Child Resources</a></p> + <li><p><a class='doclink' href='#RestServlets.Labels'>Localized Messages</a></p> + <li><p><a class='doclink' href='#RestServlets.Encoders'>Encoders</a></p> + <li><p><a class='doclink' href='#RestServlets.SvlVars'>SVL Vars</a></p> + <li><p><a class='doclink' href='#RestServlets.StaticFiles'>Static Files</a></p> + <li><p><a class='doclink' href='#RestServlets.Listeners'>Listener Methods</a></p> + <li><p><a class='doclink' href='#RestServlets.Stylesheet'>Stylesheet</a></p> + <li><p><a class='doclink' href='#RestServlets.Headers'>Default Headers</a></p> + <li><p><a class='doclink' href='#RestServlets.Errors'>Handling Errors / Logging</a></p> + <li><p><a class='doclink' href='#RestServlets.ConfigFile'>Configuration Files</a></p> + <li><p><a class='doclink' href='#RestServlets.Inheritence'>Annotation Inheritence</a></p> + <li><p><a class='doclink' href='#RestServlets.HttpStatusCodes'>HTTP Status Codes</a></p> + <li><p><a class='doclink' href='#RestServlets.OverloadedHttpMethods'>Overloaded HTTP Methods</a></p> + <li><p><a class='doclink' href='#RestServlets.BuildInParams'>Built-In Parameters</a></p> + <li><p><a class='doclink' href='#RestServlets.CustomSerializersParsers'>Defining your own serializers/parsers</a></p> + <li><p><a class='doclink' href='#RestServlets.ResponseHandlers'>Response Handlers</a></p> + <li><p><a class='doclink' href='#RestServlets.OtherNotes'>Other Notes</a></p> + </ol> + <li><p><a class='doclink' href='#Osgi'>Using with OSGi</a></p> + <li><p><a class='doclink' href='#PojosConvertableFromString'>POJOs Convertable From Strings</a></p> + <li><p><a class='doclink' href='#AddressBookResource'>Address Book Resource</a></p> +</ol> + +<!-- ======================================================================================================== --> +<a name="Intro"></a> +<h2 class='topic' onclick='toggle(this)'>1 - Introduction</h2> +<div class='topic'> + <p> + The <l>juneau-server.jar</l> library allows you to quickly wrap POJOs and expose them as full-fledged REST resources served up in a servlet container using a bare-minimum amount of code. + The primary goal for Juneau was to make it as easy as possible to implement easy-to-read and self-documenting REST resources using very little code. + </p> + <p> + One of the biggest advantages of the Juneau REST framework over similar architectures is that it hides the serialization layer from the developer. + The developer can work entirely with POJOs and let the Juneau framework handle all the serialization and parsing work. + The developer need never know what the <l>Accept</l> or <l>Content-Type</l> or <l>Accept-Encoding</l> (etc...) header values are because those details are all handled by the framework. + </p> + <p> + The API builds upon the existing JEE Servlet API. + The root class, {@link org.apache.juneau.server.RestServlet} is nothing but a specialized {@link javax.servlet.http.HttpServlet}, and the + {@link org.apache.juneau.server.RestRequest} and {@link org.apache.juneau.server.RestResponse} classes are nothing more than specialized {@link javax.servlet.http.HttpServletRequest} and + {@link javax.servlet.http.HttpServletResponse} objects. + This allows maximum flexibility for the developer since you can let Juneau handle operations such as serialization, or you can revert + to the existing servlet APIs to do low-level processing of requests yourself. + It also means you need nothing more than a Servlet container such as Jetty to use the REST framework. + </p> + <h6 class='topic'>Features</h6> + <ul class='spaced-list'> + <li>Serializes POJOs to JSON, XML, HTML, URL-Encoding, UON, RDF/XML, N-Triple, Turtle, N3, SOAP, or Java-serialized-object based on + value of <l>Accept</l> header. <br> + No user code is required to handle these types. + <br> + <ul> + <li>Extensible design that provides ability to override existing content type handlers, or add the ability to handle other kinds of content types. + </ul> + <br> + <li>Parses content of POST/PUT request bodies to POJOs. + <br><br> + <li>Automatic built-in ability to serialize POJO metadata to JSON+SCHEMA, XML+SCHEMA, or HTML+SCHEMA based on <l>Accept</l> header. + <br><br> + <li>Automatic negotiation of output Writer based on HTTP headers. + <br> + <ul> + <li>Automatic handling of <l>Accept-Charset</l> header for all character sets supported by the JVM. + <li>Automatic handling of <l>Accept-Encoding</l> header with registered encoders. + </ul> + <br> + <li>Automatic error handling. + <br> + <ul> + <li>Automatic 401 errors (Unauthorized) on failed guards. + <li>Automatic 404 errors (Not Found) on unmatched path patterns. + <li>Automatic 405 errors (Method Not Implemented) on unimplemented methods. + <li>Automatic 406 errors (Not Acceptable) when no matching serializer was found to handle the <l>Accept</l> header. + <li>Automatic 412 errors (Precondition Failed) when all matchers failed to match. + <li>Automatic 415 errors (Unsupported Media Type) when no matching parser was found was found to handle the <l>Content-Type</l> header. + <li>Automatic 500 errors on uncaught exceptions. + </ul> + <br> + <li>Self-documenting REST interfaces. + <br> + <li>Various useful debugging features that make debugging using a browser extremely simple... + <br> + <ul> + <li>Ability to pass HTTP header values as URL GET parameters (e.g. <l>&Accept=text/xml</l>). + <li>Ability to pass HTTP content on PUT/POST requests as a URL GET parameter (e.g. <l>&content={foo:"bar"}</l>). + <li>Ability to simulate non-GET requests using a <l>&method</l> GET parameter (e.g. <l>&method=POST</l>). + <li>Ability to force <ss>"text/plain"</ss> on response using GET parameter <l>&plainText=true</l>. + </ul> + <br> + <li>Ability to implement overloaded HTTP methods through the use of the <l>&method</l> attribute (e.g. <l>&method=FOO</l>). + <br><br> + <li>Ability to match URL patterns (e.g. <l>/foo/{fooId}/bar/{barId}</l>) against URLs (e.g. <l>/foo/123/bar/456/bing</l>). + <br><br> + <li>Ability to associate guards at the resource or method levels through annotations.<br> + Typically useful for security, but can be used for a variety of purposes. + <br><br> + <li>Ability to associate converters at the resource or method levels through annotations.<br> + Typically useful for performing conversions on input and output, such as for supporting older input and output formats. + </ul> + <p> + Many of the examples in this document are pulled directly from the <l>microservice-samples-project.zip</l> project. + </p> +</div> + +<!-- ======================================================================================================== --> +<a name="HelloWorldResource"></a> +<h2 class='topic' onclick='toggle(this)'>2 - Hello World Example</h2> +<div class='topic'> + <p> + A REST resource is an implementation of {@link org.apache.juneau.server.RestServlet}, which itself is simply an extension of {@link javax.servlet.http.HttpServlet}. + </p> + <p> + In this example, we define a resource called <l>HelloWorldResource</l>. + This example is located in the <l>microservice-samples-project.zip</l> project. + It's assumed the reader is familiar with defining servlets in web applications. + </p> + <p> + Like any servlet, we could define our resource in the <l>web.xml</l> file of the web application like so... + </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>HelloWorldResource<xt></servlet-name></xt> + <xt><servlet-class></xt>com.ibm.sample.HelloWorldResource<xt></servlet-class></xt> + <xt></servlet></xt> + <xt><servlet-mapping></xt> + <xt><servlet-name></xt>HelloWorldResource<xt></servlet-name></xt> + <xt><url-pattern></xt>/*<xt></url-pattern></xt> + <xt></servlet-mapping></xt> + <xt></web-app></xt> + </p> + <p> + Our servlet code is shown below: + </p> + <p class='bcode'> + <jd>/** + * Sample REST resource that prints out a simple "Hello world!" message. + */</jd> + <ja>@RestResource</ja>( + messages=<js>"nls/HelloWorldResource"</js>, + properties={ + <ja>@Property</ja>(name=<jsf>HTMLDOC_links</jsf>, value=<js>"{up:'$R{requestParentURI}',options:'?method=OPTIONS'}"</js>) + } + ) + <jk>public class</jk> HelloWorldResource <jk>extends</jk> Resource { + + <jd>/** GET request handler */</jd> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/*"</js>) + <jk>public</jk> String sayHello() { + <jk>return</jk> <js>"Hello world!"</js>; + } + } + </p> + <p> + The <l>messages</l> annotation points to a properties file on the classpath whose contents are shown below: + </p> + <p class='bcode'> + <cc>#-------------------------------------------------------------------------------- + # HelloWorldResource labels + #--------------------------------------------------------------------------------</cc> + <ck>label</ck> = <cv>Hello World sample resource</cv> + <ck>description</ck> = <cv>Simplest possible resource</cv> + <ck>sayHello</ck> = <cv>Responds with "Hello world!"</cv> + </p> + <p> + It doesn't much simpler than that. + In this case, we're simply returning a string that will be converted to any of the supported languages (e.g. JSON, XML, HTML, ...). + However, we could have returned any POJO consisting of beans, maps, collections, etc... + </p> + <p> + The {@link org.apache.juneau.server.RestServletDefault} class that we're using here is a subclass of {@link org.apache.juneau.server.RestServlet} that provides default support for a variety of content types. + Implementers can choose to use this class, or create their own subclass of {@link org.apache.juneau.server.RestServlet} with their own specialized serializers and parsers. + </p> + <p> + If you were to start up this servlet and view it with a browser, you would see this: + </p> + <img class='bordered' src="doc-files/HelloWorldResource1.png"> + <p> + The Juneau REST interface is designed to make it easy to interact with resources using nothing but a browser. + Therefore, several built-in features are provided for making it easy to do so. + Specifically, we'll be using these available URL parameters... + </p> + <ul class='normal'> + <li><l>&plainText=true</l> - If specified, then the <l>Content-Type</l> on the response is always <l>"text/plain"</l> regardless of the data format. + <br><br> + <li><l>&Accept=X</l> - Specify the content type of the response. + In a browser, <l>"text/html"</l> is the default content type, but this parameter can be used to override the content type on the response.<br> + Note: The behavior is identical to setting the <l>Accept</l> header on the request. + In fact, Juneau allows ANY HTTP request headers to be specified as URL parameters for debugging purposes. + </ul> + <p> + Using the <l>plainText</l> parameter, we can view the HTML as plain text... + </p> + <img class='bordered' src="doc-files/HelloWorldResource2.png"> + <p> + You'll notice that the HTML view has a simple stylesheet associated with it to improve the look of the interface. + It is possible to specify your own stylesheet, but the default styles will usually suffice for most purposes. + </p> + <p> + When accessed through a browser, the content type will default to HTML (based on the value of the <l>Accept</l> HTTP header). + </p> + <p> + Let's use the <l>&Accept</l> URL paramter to override the <l>Accept</l> HTTP header to view this servlet in other formats... + </p> + <p> + In the case of <l>JSON</l>, we're serialize a single string, so it gets rendered as a JSON fragment.... + </p> + <img class='bordered' src="doc-files/HelloWorldResource3.png"> + <p> + ...or as <l>XML</l>... + </p> + <img class='bordered' src="doc-files/HelloWorldResource4.png"> + <p> + ...or any of the other supported languages. + </p> + <p> + If you click the OPTIONS link on the page, you'll see the results from an <l>HTTP OPTIONS</l> request: + </p> + <img class='bordered' src="doc-files/HelloWorldResourceOptions.png"> + <p> + The OPTIONS page is generated automatically by introspection of the class itself combined with + labels in the messages properties file. + It's composed of a POJO that gets serialized just like any other POJO. + Therefore, the POJO can be searialized to any of the supported languages, like JSON. + </p> + <img class='bordered' src="doc-files/HelloWorldResourceOptionsJson.png"> +</div> + +<!-- ======================================================================================================== --> +<a name="ClassHierarchy"></a> +<h2 class='topic' onclick='toggle(this)'>3 - Class Hierarchy</h2> +<div class='topic'> + <p> + The class hierarchy for the REST servlet class is shown below: + </p> + <ul class='javahierarchy'> + <li class='a'>{@link javax.servlet.http.HttpServlet javax.servlet.http.HttpServlet} + <ul> + <li class='a'>{@link org.apache.juneau.server.RestServlet org.apache.juneau.server.RestServlet} + <br>Contains all the main logic. + <ul> + <li class='a'>{@link org.apache.juneau.server.RestServletDefault org.apache.juneau.server.RestServletDefault} + <br>Provides a default set of serializers, parsers, options page, stylesheet, and other common settings. + <br><b>Developers will typically subclass this when creating REST resources in JEE environments.</b> + <ul> + <li class='a'>{@link org.apache.juneau.microservice.Resource org.apache.juneau.microservice.Resource} + <br>Subclass intented to be used in REST microservices. + <br><b>Developers will typically subclass this when creating microservices.</b> + <li class='a'>{@link org.apache.juneau.server.RestServletGroupDefault org.apache.juneau.server.RestServletGroupDefault} + <br>A default implementation for "router" pages. + <ul> + <li class='a'>{@link org.apache.juneau.microservice.ResourceGroup org.apache.juneau.microservice.ResourceGroup} + <br>Subclass intented to be used in REST microservices. + </ul> + <li class='c'>{@link org.apache.juneau.server.remoteable.RemoteableServlet org.apache.juneau.server.remoteable.RemoteableServlet} + <br>REST servlet for implementing remoteable proxy interfaces. + </ul> + <li class='a'>{@link org.apache.juneau.server.jena.RestServletJenaDefault org.apache.juneau.server.jena.RestServletJenaDefault} + <br>Same as {@link org.apache.juneau.server.RestServletDefault}, but adds RDF support. + <ul> + <li class='a'>{@link org.apache.juneau.microservice.ResourceJena org.apache.juneau.microservice.ResourceJena} + <br>Subclass intented to be used in REST microservices. + <li class='a'>{@link org.apache.juneau.server.jena.RestServletJenaGroupDefault org.apache.juneau.server.jena.RestServletJenaGroupDefault} + <br>Same as {@link org.apache.juneau.server.RestServletGroupDefault}, but adds RDF support. + </ul> + <li class='a'><code>com.ibm.team.repository.service.JazzRestResource</code> + <br>Parent class in Jazz Foundation for REST-based services. + <ul> + <li class='a'><code>com.ibm.team.repository.service.JazzDefaultRestResource</code> + <br>Provides a default set of serializers, parsers, options page, stylesheet, and other common settings. + </ul> + </ul> + </ul> + </ul> + <p> + The servlets with RDF support require Jena on the classpath. + All other serializers and parsers do not have any external library dependencies. + For this reason, we have separate servlets for supporting RDF so that you don't need Jena if you don't need to support RDF. + </p> + <p> + The {@link org.apache.juneau.server.RestRequest} and {@link org.apache.juneau.server.RestResponse} classes described later also extend from their servlet equivalents: + </p> + <ul class='javahierarchy'> + <li class='i'>{@link javax.servlet.http.HttpServletRequest javax.servlet.http.HttpServletRequest} + <ul> + <li class='c'>{@link org.apache.juneau.server.RestRequest org.apache.juneau.server.RestRequest} - Augmented with specialized REST methods. + </ul> + <li class='i'>{@link javax.servlet.http.HttpServletResponse javax.servlet.http.HttpServletResponse} + <ul> + <li class='c'>{@link org.apache.juneau.server.RestResponse org.apache.juneau.server.RestResponse} - Augmented with specialized REST methods. + </ul> + </ul> +</div> + + <!-- ======================================================================================================== --> +<a name="RestResources"></a> +<h2 class='topic' onclick='toggle(this)'>4 - REST Servlets</h2> + <div class='topic'> + <p> + Since REST servlets are subclasses of <l>HttpServlet</l>, they can be deployed in a J2EE + container like any other servlet, typically inside a <l>web.xml</l> file. + The REST servlet framework does not depend on any classloader scanning or external setup + other than registering the servlet with the J2EE container. + </p> + <p> + REST servlets can also be deployed by declaring them as children of other REST servlets (described later). + </p> + <p> + A REST servlet consists of an instance of {@link org.apache.juneau.server.RestServlet} + annotated with {@link org.apache.juneau.server.annotation.RestResource @RestResource} containing + public Java methods annotated with {@link org.apache.juneau.server.annotation.RestMethod @RestMethod}. + </p> + <p> + Developers will typically subclass directly from {@link org.apache.juneau.server.RestServletDefault} + since it provides a default set of serializers and parsers for a variety of + <l>Accept</l> and <l>Content-Type</l> types. + </p> + <h6 class='figure'>Valid Accept headers for RestServletDefault</h6> + <table class='styled'> + <tr> + <th>Accept</th> + <th>Content-Type</th> + <th>Serializer</th> + </tr> + <tr> + <td class='code'>application/json<br>text/json</td> + <td class='code'>application/json</td> + <td>{@link org.apache.juneau.json.JsonSerializer}</td> + </tr> + <tr> + <td class='code'>application/json+simple<br>text/json+simple</td> + <td class='code'>application/json</td> + <td>{@link org.apache.juneau.json.JsonSerializer.Simple}</td> + </tr> + <td class='code'>application/json+schema<br>text/json+schema</td> + <td class='code'>application/json</td> + <td>{@link org.apache.juneau.json.JsonSchemaSerializer}</td> + </tr> + <tr> + <td class='code'>text/xml</td> + <td class='code'>text/xml</td> + <td>{@link org.apache.juneau.xml.XmlDocSerializer}</td> + </tr> + <tr> + <td class='code'>text/xml+schema</td> + <td class='code'>text/xml</td> + <td>{@link org.apache.juneau.xml.XmlSchemaDocSerializer}</td> + </tr> + <tr> + <td class='code'>text/html</td> + <td class='code'>text/html</td> + <td>{@link org.apache.juneau.html.HtmlDocSerializer}</td> + </tr> + <tr> + <td class='code'>text/html+stripped</td> + <td class='code'>text/html</td> + <td>{@link org.apache.juneau.html.HtmlStrippedDocSerializer}</td> + </tr> + <tr> + <td class='code'>text/uon</td> + <td class='code'>text/uon</td> + <td>{@link org.apache.juneau.urlencoding.UonSerializer}</td> + </tr> + <tr> + <td class='code'>text/uon-simple</td> + <td class='code'>text/uon</td> + <td>{@link org.apache.juneau.urlencoding.UonSerializer.Simple}</td> + </tr> + <tr> + <td class='code'>application/x-www-form-urlencoded</td> + <td class='code'>application/x-www-form-urlencoded</td> + <td>{@link org.apache.juneau.urlencoding.UrlEncodingSerializer}</td> + </tr> + <tr> + <td class='code'>application/x-www-form-urlencoded-simple</td> + <td class='code'>application/x-www-form-urlencoded</td> + <td>{@link org.apache.juneau.urlencoding.UrlEncodingSerializer.Simple}</td> + </tr> + <tr> + <td class='code'>text/xml+soap</td> + <td class='code'>text/xml</td> + <td>{@link org.apache.juneau.soap.SoapXmlSerializer}</td> + </tr> + <tr> + <td class='code'>text/plain</td> + <td class='code'>text/plain</td> + <td>{@link org.apache.juneau.plaintext.PlainTextSerializer}</td> + </tr> + <tr> + <td class='code'>application/x-java-serialized-object</td> + <td class='code'>application/x-java-serialized-object</td> + <td>{@link org.apache.juneau.jso.JavaSerializedObjectSerializer}</td> + </tr> + </table> + <h6 class='figure'>Valid Content-Type headers for RestServletDefault</h6> + <table class='styled'> + <tr> + <th>Content-Type</th> + <th>Parser</th> + </tr> + <tr> + <td class='code'>application/json<br>text/json</td> + <td>{@link org.apache.juneau.json.JsonParser}</td> + </tr> + <tr> + <td class='code'>text/xml<br>application/xml</td> + <td>{@link org.apache.juneau.xml.XmlParser}</td> + </tr> + <tr> + <td class='code'>text/html<br>text/html+stripped</td> + <td>{@link org.apache.juneau.html.HtmlParser}</td> + </tr> + <tr> + <td class='code'>text/uon</td> + <td>{@link org.apache.juneau.urlencoding.UonParser}</td> + </tr> + <tr> + <td class='code'>application/x-www-form-urlencoded</td> + <td>{@link org.apache.juneau.urlencoding.UrlEncodingParser}</td> + </tr> + <tr> + <td class='code'>text/plain</td> + <td>{@link org.apache.juneau.plaintext.PlainTextParser}</td> + </tr> + </table> + <p> + {@link org.apache.juneau.server.RestServletDefault} also provides a default OPTIONS page by implementing + a {@link org.apache.juneau.server.RestServletDefault#getOptions(RestRequest)} method that returns a POJO consisting + of beans describing the class. + This is what produces the output for the OPTIONS page on the Hello World sample above. + </p> + + <h6 class='topic'>Additional Information</h6> + <ul class='javahierarchy'> + <li class='a'>{@link org.apache.juneau.server.RestServletDefault} + <li class='a'>{@link org.apache.juneau.server.jena.RestServletJenaDefault} + </ul> + + <!-- ======================================================================================================== --> + <a name="RestResources.MethodSignature"></a> + <h3 class='topic' onclick='toggle(this)'>4.1 - REST Java Method Signature</h3> + <div class='topic'> + <p> + REST Java methods are identified on REST servlets using the {@link org.apache.juneau.server.annotation.RestMethod @RestMethod} annotation. + The annotation allows the framework to identify the available REST methods through reflection. + </p> + <p class='bcode'> + <jd>/** GET request handler */</jd> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/"</js>) + <jk>public</jk> String sayHello() { + <jk>return</jk> <js>"Hello world!"</js>; + } + </p> + <h6 class='topic'>Method Name</h6> + <p> + There are no restrictions on the name of the Java method. However, if you plan on making use of the + {@link org.apache.juneau.server.annotation.RestResource#messages() @RestResource.messages()} + annotation (described later), the method names must be unique to make it possible to identify unique keys for labels in the resource bundle. + Therefore, you should not define two identically-named <l>doFoo(...)</l> methods that differ only by parameters. + If you're not using messages for NLS support, then name them whatever you want! + </p> + <h6 class='topic'>Method Return Type</h6> + <p> + The return type can be any serializable POJO as defined in <a class='doclink' href='../../../../overview-summary.html#Core.PojoCategories'>POJO Categories</a>. + It can also be <jk>void</jk> if the method is not sending any output (e.g. a request redirect) or + is setting the output using the {@link org.apache.juneau.server.RestResponse#setOutput(Object)} method. + Calling the {@link org.apache.juneau.server.RestResponse#setOutput(Object)} method is functionally equivalent to returning a value. + </p> + <p class='bcode'> + <jc>// Equivalent method 1</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>) + <jk>public void</jk> doGet(RestResponse res) { + res.setOutput(<js>"Hello World!"</js>); + } + + <jc>// Equivalent method 2</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>) + <jk>public</jk> String doGet() { + <jk>return</jk> <js>"Hello World!"</js>; + } + </p> + <p> + The return type can also be any of the following special object types: + </p> + <ul class='javahierarchy'> + <li class='c'>{@link java.io.InputStream} + <br>The contents are simply piped to the output stream returned by {@link org.apache.juneau.server.RestResponse#getNegotiatedOutputStream()}. + <br>Note that you should call {@link org.apache.juneau.server.RestResponse#setContentType(String)} to set the <l>Content-Type</l> header if you use this object type. + <li class='c'>{@link java.io.Reader} + <br>The contents are simply piped to the output stream returned by {@link org.apache.juneau.server.RestResponse#getNegotiatedWriter()}. + <br>Note that you should call {@link org.apache.juneau.server.RestResponse#setContentType(String)} to set the <l>Content-Type</l> header if you use this object type. + <li class='c'>{@link org.apache.juneau.server.Redirect} + <br>Represents an HTTP redirect response. + <li class='i'>{@link org.apache.juneau.Streamable} + <br>Interface that identifies that an object can be serialized directly to an output stream. + <li class='i'>{@link org.apache.juneau.Writable} + <br>Interface that identifies that an object can be serialized directly to a writer. + <li class='c'>{@link org.apache.juneau.utils.ZipFileList} + <br>Special interface for sending zip files as responses. + </ul> + <p> + Additional "special types" can be defined through the {@link org.apache.juneau.server.ResponseHandler} interface (described later). + </p> + <h6 class='topic'>Method Parameters</h6> + <p> + The method can contain any of the following parameters in any order: + </p> + <ul class='spaced-list'> + <li>Parameter of type {@link org.apache.juneau.server.RestRequest} + <li>Parameter of type {@link javax.servlet.http.HttpServletRequest} + <li>Parameter of type {@link org.apache.juneau.server.RestResponse} + <li>Parameter of type {@link javax.servlet.http.HttpServletResponse} + <li>Parameters annotated with {@link org.apache.juneau.server.annotation.Attr @Attr} + <br>These match variables in matched URL path patterns. + <li>Parameters annotated with with {@link org.apache.juneau.server.annotation.Param @Param} + <br>These denote query parameter values. + <li>Parameters annotated with {@link org.apache.juneau.server.annotation.HasParam @HasParam} + <br>Similar to <ja>@Param</ja>, but resolves to a simple boolean <jk>true/false</jk> denoting whether the query parameter exists. + <li>Parameters annotated with {@link org.apache.juneau.server.annotation.QParam @QParam} + <br>Same as <ja>@Param</ja>, but only looks for actual query parameters, not form post query parameters. + <br>Using this prevents the HTTP body from being processed as a URL-Encoded form post. + <li>Parameters annotated with {@link org.apache.juneau.server.annotation.HasQParam @HasQParam} + <br>Similar to <ja>@QParam</ja>, but resolves to a simple boolean <jk>true/false</jk> denoting whether the query parameter exists. + <li>Parameters annotated with {@link org.apache.juneau.server.annotation.Header @Header} + <br>These denote header values. + <li>Parameter annotated with {@link org.apache.juneau.server.annotation.Method @Method} + <br>This denotes the HTTP method name. + <li>Parameter annotated with {@link org.apache.juneau.server.annotation.PathRemainder @PathRemainder} + <br>This denotes the path remainder value after path pattern match. + <li>Parameter annotated with {@link org.apache.juneau.server.annotation.Content @Content} + <br>This denotes the HTTP content parsed as a POJO. + <br>The type can be any parsable POJO type as defined in <a class='doclink' href='../../../../overview-summary.html#Core.PojoCategories'>POJO Categories</a> + <li>Parameter annotated with {@link org.apache.juneau.server.annotation.Messages @Messages} + <br>This gives you access to the resource bundle for the servlet localized to the language on the request. + <li>Parameter annotated with {@link org.apache.juneau.server.annotation.Properties @Properties} + <br>This gives you access to the serializer/parser/servlet properties so they can be read or altered on the request. + </ul> + <p class='bcode'> + <jc>// Example GET request using annotated attributes</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/example1/{a1}/{a2}/{a3}/*"</js>) + <jk>public</jk> String doGetExample1( + RestRequest req, + RestResponse res, + <ja>@Method</ja> String method, + <ja>@Attr</ja> String a1, + <ja>@Attr</ja> <jk>int</jk> a2, + <ja>@Attr</ja> UUID a3, + <ja>@Param</ja>(<js>"p1"</js>) <jk>int</jk> p1, + <ja>@Param</ja>(<js>"p2"</js>) String p2, + <ja>@Param</ja>(<js>"p3"</js>) UUID p3, + <ja>@HasParam</ja>(<js>"p3"</js>) boolean hasP3, + <ja>@PathRemainder</ja> String remainder, + <ja>@Header</ja>(<js>"Accept-Language"</js>) String lang, + <ja>@Header</ja>(<js>"Accept"</js>) String accept, + <ja>@Header</ja>(<js>"DNT"</js>) <jk>int</jk> doNotTrack, + <ja>@Properties</ja> ObjectMap properties, + <ja>@Messages</ja> ResourceBundle nls + ) { + <jc>// Do something with all of those</jc> + } + </p> + <p> + All the annotated parameters (with the exception of <l>@Content</l>) can be any POJO type convertable from a <l>String</l>. + (See <a class='doclink' href='#PojosConvertableFromString'>POJOs Convertable From String</a>) + </p> + <p> + For example, headers can be accessed as Strings or UUIDs... + </p> + <p class='bcode'> + <jc>// Example GET with access to HTTP headers</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/*"</js>) + <jk>public</jk> String doGet(<ja>@Header</ja>(<js>"Accept-Language"</js>) String lang, <ja>@Header</ja>(<js>"ETag"</js>) UUID eTag) <jk>throws</jk> Exception { + ... + } + </p> + <p> + All annotations have programmatic equivalents on the {@link org.apache.juneau.server.RestRequest} class: + </p> + <ul class='javahierarchy'> + <li class='m'>{@link org.apache.juneau.server.RestRequest#getAttribute(String,Class)} + <li class='m'>{@link org.apache.juneau.server.RestRequest#getParameter(String,Class)} + <li class='m'>{@link org.apache.juneau.server.RestRequest#hasParameter(String)} + <li class='m'>{@link org.apache.juneau.server.RestRequest#getQueryParameter(String,Class)} + <li class='m'>{@link org.apache.juneau.server.RestRequest#hasQueryParameter(String)} + <li class='m'>{@link org.apache.juneau.server.RestRequest#getInput(Class)} + <li class='m'>{@link org.apache.juneau.server.RestRequest#getHeader(String,Class)} + <li class='m'>{@link org.apache.juneau.server.RestRequest#getMethod()} + <li class='m'>{@link org.apache.juneau.server.RestRequest#getPathRemainder()} + <li class='m'>{@link org.apache.juneau.server.RestRequest#getMessage(String,Object[])} + <li class='m'>{@link org.apache.juneau.server.RestRequest#getProperties()} + </ul> + + <!-- ======================================================================================================== --> + <a name="RestResources.MethodSignature.Path"></a> + <h4 class='topic' onclick='toggle(this)'>4.1.1 - Path</h4> + <div class='topic'> + <p> + The {@link org.apache.juneau.server.annotation.RestMethod#path() @RestMethod.path()} annotation + allows you to define URL path patterns to match against. + These patterns can contain variables of the form <l>"{xxx}"</l> that can be passed in directly to the + Java methods as extra parameters. + </p> + <p> + In the following example, 3 separate GET request handlers are defined with different path patterns. + Note how the variables are passed in as additional arguments on the method, and how those arguments are automatically + converted to the specified class type... + </p> + <p class='bcode'> + <jc>// Default method</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/*"</js>) + <jk>public void</jk> doGetDefault() { + ... + } + + <jc>// Method with path pattern</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/xxx"</js>) + <jk>public void</jk> doGetNoArgs(...) { + ... + } + + <jc>// Method with path pattern with arguments</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/xxx/{foo}/{bar}/{baz}/{bing}"</js>) + <jk>public void</jk> doGetWithArgs(<ja>@Attr</ja> String foo, <ja>@Attr</ja> <jk>int</jk> bar, <ja>@Attr</ja> MyEnum baz, <ja>@Attr</ja> UUID bing) { + ... + } + </p> + <p> + By default, path patterns are matched using a best-match heuristic. + When overlaps occur, URLs are matched from most-specific to most-general order: + </p> + <p class='bcode'> + <jc>// Try first </jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foo/bar"</js>) + <jk>public void</jk> method1() { + ... + } + + <jc>// Try second</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foo/{bar}"</js>) + <jk>public void</jk> method2(...) { + ... + } + + <jc>// Try third</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foo/*"</js>) + <jk>public void</jk> method3(...) { + ... + } + + <jc>// Try last</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/*"</js>) + <jk>public void</jk> method4(...) { + ... + } + </p> + <p> + The match heuristic behavior can be overridden by the {@link org.apache.juneau.server.annotation.RestMethod#priority() @RestMethod.priority()} annotation property. + However, in practice this is almost never needed. + </p> + <p> + Paths that end with <js>"/*"</js> will do a prefix match on the incoming URL. + Any remainder after the match can be accessed through {@link org.apache.juneau.server.RestRequest#getPathRemainder()} + or parameters with the {@link org.apache.juneau.server.annotation.PathRemainder @PathRemainder} annotation. + On the other hand, paths that don't end with <js>"/*"</js> (e.g. <js>"/"</js> or <js>"/foo"</js>) will require + an exact URL match, and if any remainder exists, a 404 (not found) error will be thrown. + </p> + <p> + The following example shows the distinction. + </p> + <p class='bcode'> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/*"</js>) + <jk>public void</jk> doGet(<ja>@PathRemainder</ja> String remainder) { + <jc>// URL path pattern can have remainder accessible through req.getRemainder().</jc> + } + + <ja>@RestMethod</ja>(name=<js>"PUT"</js>, path=<js>"/"</js>) + <jk>public void</jk> doPut() { + <jc>// URL path pattern must match exactly and will cause a 404 error if a remainder exists.</jc> + } + </p> + <p> + Annotations are provided for easy access to URL parameters with automatic conversion to any parsable object type. + For example, the following example can process the URL <l>"/urlWithParams?foo=foo&bar=[1,2,3]&baz=067e6162-3b6f-4ae2-a171-2470b63dff00"</l>... + </p> + <p class='bcode'> + <jc>// Example GET request with access to query parameters</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/urlWithParams"</js>) + <jk>public</jk> String doGetWithParams(<ja>@Param</ja>(<js>"foo"</js>) String foo, <ja>@Param</ja>(<js>"bar"</js>) <jk>int</jk> bar, <ja>@Param</ja>(<js>"baz"</js>) UUID baz) <jk>throws</jk> Exception { + <jk>return</jk> <js>"GET /urlWithParams?foo="</js>+foo+<js>"&bar="</js>+bar+<js>"&baz="</js>+baz); + } + </p> + </div> + + <!-- ======================================================================================================== --> + <a name="RestResources.MethodSignature.Matchers"></a> + <h4 class='topic' onclick='toggle(this)'>4.1.2 - Matchers</h4> + <div class='topic'> + <p> + {@link org.apache.juneau.server.RestMatcher RestMatchers} are used to allow multiple Java methods to be tied to the same HTTP method and path, but + differentiated by some request attribute such as a specific header value. + <p class='bcode'> + <jc>// GET method that gets invoked for administrators</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/*"</js>, matchers=IsAdminMatcher.<jk>class</jk>) + <jk>public</jk> Object doGetForAdmin() { + ... + } + + <jc>// GET method that gets invoked for everyone else</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/*"</js>) + <jk>public</jk> Object doGetForEveryoneElse() { + ... + } + </p> + <p> + The interface for matchers is simple: + </p> + <p class='bcode'> + <jk>public class</jk> IsAdminMatcher <jk>extends</jk> RestMatcher { + <ja>@Override</ja> + <jk>public boolean</jk> matches(RestRequest req) { + <jk>return</jk> req.isUserInRole(<js>"ADMINS_GROUP"</js>); + } + } + </p> + <h6 class='topic'>Other Notes</h6> + <ul class='spaced-list'> + <li>If no methods are found with a matching matcher, a <l>412 Precondition Failed</l> status is returned. + <li>If multiple matchers are specified on the same method, ONLY ONE matcher needs to match for the method to be invoked. + <li>Note that you CANNOT define identical paths on different methods UNLESS you use matchers. + <br>That includes paths that are only different in variable names (e.g. <l>"/foo/{bar}"</l> and <l>"/foo/{baz}"</l>). + <br>If you try to do so, a <l>ServletException</l> will be thrown on startup. + <li>Methods with matchers take precedence over methods without. + <br>Otherwise, methods are attempted in the order they appear in the class. + </ul> + </div> + </div> + + <!-- ======================================================================================================== --> + <a name="RestResources.RequestContent"></a> + <h3 class='topic' onclick='toggle(this)'>4.2 - Request Content</h3> + <div class='topic'> + <p> + Annotations are provided for easy access to HTTP body content as any parsable POJO type + (See <a class='doclink' href='../../../../overview-summary.html#Core.PojoCategories'>POJO Categories</a>). + In the example below, we're POSTing beans. + </p> + <p class='bcode'> + <jc>// Example POST of a bean</jc> + <ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/"</js>) + <jk>public void</jk> doPost(<ja>@Content</ja> Person person) <jk>throws</jk> Exception { + <jc>// Do something with person.</jc> + } + </p> + <p> + The HTTP body of a request can be retrieved as a parsed POJO using either the + {@link org.apache.juneau.server.RestRequest#getInput(Class)} method, or a parameter + annotated with {@link org.apache.juneau.server.annotation.Content @Content}. + </p> + <p class='bcode'> + <jc>// Equivalent method 1</jc> + <ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/example1"</js>) + <jk>public void</jk> doPost1(<ja>@Content</ja> Person p) { + <jc>// Do something with p.</jc> + } + + <jc>// Equivalent method 2</jc> + <ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/example2"</js>) + <jk>public void</jk> doPost2(RestRequest req) { + Person p = req.getInput(Person.<jk>class</jk>); + <jc>// Do something with p.</jc> + } + </p> + <p> + The Juneau framework will automatically determine the appropriate <l>Parser</l> to use based on the + <l>Content-Type</l> HTTP header. So the body content could be JSON or XML or any other supported parsing types. + </p> + + <!-- ======================================================================================================== --> + <a name="RestResources.RequestContent.FormPosts"></a> + <h4 class='topic' onclick='toggle(this)'>4.2.1 - Form Posts</h4> + <div class='topic'> + <p> + URL-Encoded form posts require their own topic since they can be handled in multiple ways. + </p> + <p> + The best way to handle a form post is by using an input bean. + The samples include a <l>UrlEncodedFormResource</l> class that takes in URL-Encoded + form post of the form <l>"aString=foo&aNumber=123&aDate=2001-07-04T15:30:45Z"</l>. + The code is shown here: + </p> + <p class='bcode'> + <ja>@RestResource</ja>( + path=<js>"/urlEncodedForm"</js> + ) + <jk>public class</jk> UrlEncodedFormResource <jk>extends</jk> Resource { + + <jd>/** POST request handler */</jd> + <ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/"</js>) + <jk>public</jk> Object doPost(<ja>@Content</ja> FormInputBean input) <jk>throws</jk> Exception { + <jc>// Just mirror back the request</jc> + <jk>return</jk> input; + } + + <jk>public static class</jk> FormInputBean { + <jk>public</jk> String <jf>aString</jf>; + <jk>public int</jk> <jf>aNumber</jf>; + <ja>@BeanProperty</ja>(transform=CalendarTransform.<jsf>ISO8601DT</jsf>.<jk>class</jk>) + <jk>public</jk> Calendar <jf>aDate</jf>; + } + } + </p> + <p> + Another possibility is to access the form parameters individually: + </p> + <p class='bcode'> + <jd>/** POST request handler */</jd> + <ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/"</js>) + <jk>public</jk> Object doPost(<ja>@Param</ja>(<js>"aString"</js>) String aString, <ja>@Param</ja>(<js>"aNumber"</js>) <jk>int</jk> aNumber, <ja>@Param</ja>(<js>"aDate"</js>) Calendar aDate) <jk>throws</jk> Exception { + ... + } + </p> + <p> + The advantage to the form input bean is that it can handle any of the parsable types (e.g. JSON, XML...) + in addition to URL-Encoding. The latter approach only supports URL-Encoding. + </p> + <p class='severe'> + If you're using form input beans, DO NOT use the <l>@Param</l> attribute + or {@link org.apache.juneau.server.RestRequest#getParameter(String)} method since this will + cause the underlying JEE servlet to parse the HTTP body as a form post. + Your input bean will end up being null since there won't be any content left + after the servlet has parsed the body of the request. + This applies to WHENEVER you use <l>@Content</l> or {@link org.apache.juneau.server.RestRequest#getInput(Class)}. + </p> + </div> + + <!-- ======================================================================================================== --> + <a name="RestResources.RequestContent"></a> + <h4 class='topic' onclick='toggle(this)'>4.2.2 - Multipart Form Posts</h4> + <div class='topic'> + <p> + The Juneau framework does not natively support multipart form posts. + However, it can be used in conjunction wih the Apache Commons File Upload library to do so. + </p> + <p> + The samples include a <l>TempDirResource</l> class that uses the File Upload library + to allow files to be uploaded as multipart form posts. + </p> + <p class='bcode'> + <ja>@RestResource</ja>( + path=<js>"/tempDir"</js> + ) + <jk>public class</jk> TempDirResource <jk>extends</jk> DirectoryResource { + + <jd>/** + * [POST /upload] - Upload a file as a multipart form post. + * Shows how to use the Apache Commons ServletFileUpload class for handling multi-part form posts. + */</jd> + <ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/upload"</js>, matchers=TempDirResource.MultipartFormDataMatcher.<jk>class</jk>) + <jk>public</jk> Redirect uploadFile(RestRequest req) <jk>throws</jk> Exception { + ServletFileUpload upload = <jk>new</jk> ServletFileUpload(); + FileItemIterator iter = upload.getItemIterator(req); + <jk>while</jk> (iter.hasNext()) { + FileItemStream item = iter.next(); + <jk>if</jk> (item.getFieldName().equals(<js>"contents"</js>)) { + File f = <jk>new</jk> File(getRootDir(), item.getName()); + IOPipe.<jsm>create</jsm>(item.openStream(), <jk>new</jk> FileOutputStream(f)).closeOut().run(); + } + } + <jk>return new</jk> Redirect(); <jc>// Redirect to the servlet root.</jc> + } + + <jd>/** Causes a 404 if POST isn't multipart/form-data */</jd> + <jk>public static class</jk> MultipartFormDataMatcher <jk>extends</jk> RestMatcher { + <ja>@Override</ja> <jc>/* RestMatcher */</jc> + <jk>public boolean</jk> matches(RestRequest req) { + String contentType = req.getContentType(); + <jk>return</jk> contentType != <jk>null</jk> && contentType.startsWith(<js>"multipart/form-data"</js>); + } + } + </p> + </div> + </div> + + <!-- ======================================================================================================== --> + <a name="RestResources.ResponseContent"></a> + <h3 class='topic' onclick='toggle(this)'>4.3 - Response Content</h3> + <div class='topic'> + <p> + REST Java methods can generate output in any of the following ways: + </p> + <ul class='spaced-list'> + <li>By returning a serializable POJO, or any of the following: + <br>{@link java.io.Reader}, {@link java.io.InputStream}, {@link org.apache.juneau.Streamable}, {@link org.apache.juneau.Writable} + <li>By calling {@link org.apache.juneau.server.RestResponse#setOutput(Object)} with any of the types above. + <li>By accessing the {@link java.io.Writer} directly by calling {@link org.apache.juneau.server.RestResponse#getNegotiatedWriter()} and writing the output + yourself. + </ul> + <p class='bcode'> + <jc>// Equivalent method 1</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/example1/{personId}"</js>) + <jk>public</jk> Person doGet1(<ja>@Attr</ja> UUID personId) { + Person p = getPersonById(personId); + <jk>return</jk> p; + } + + <jc>// Equivalent method 2</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/example2/{personId}"</js>) + <jk>public void</jk> doGet2(RestResponse res, <ja>@Attr</ja> UUID personId) { + Person p = getPersonById(personId); + res.setOutput(p); + } + + <jc>// (Sorta) Equivalent method 3</jc> + <jc>// (Ignores any converters or method-level properties)</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/example3/{personId}"</js>) + <jk>public void</jk> doGet3(RestRequest req, RestResponse res, <ja>@Attr</ja> UUID personId) { + Person p = getPersonById(personId); + String accept = req.getHeader(<js>"Accept"</js>, <js>"text/json"</js>); + WriterSerializer s = res.getSerializerGroup().getWriterSerializer(accept); + res.setContentType(s.getResponseContentType()); + s.serialize(p, res.getNegotiatedWriter()); + } + </p> + </div> + + <!-- ======================================================================================================== --> + <a name="RestResources.OptionsPages"></a> + <h3 class='topic' onclick='toggle(this)'>4.4 - OPTIONS Pages</h3> + <div class='topic'> + <p> + One of the most useful features of Juneau is that it can produce OPTIONS pages for self-documenting designs (i.e. REST interfaces that document themselves). + </p> + <h6 class='figure'>OPTIONS page for HelloWorld sample resource</h6> + <img class='bordered' src='doc-files/OptionsPage.png'> + <p> + To facilitate this, the {@link org.apache.juneau.server.labels.ResourceOptions} class is provided that + inspects a <l>RestServlet</l> and its methods, and returns a serializable POJO data structure + that describes the options for that resource and pulling localized strings from the resource + bundle associated with the servlet. + </p> + <p> + {@link org.apache.juneau.server.RestServletDefault} provides a default OPTIONS page by implementing + a {@link org.apache.juneau.server.RestServletDefault#getOptions(RestRequest)} method that returns a POJO consisting + of beans describing the class. + </p> + <p class='bcode'> + <jd>/** + * [OPTIONS /*] - Show resource options. + * + * <ja>@param</ja> req The HTTP request. + * <ja>@return</ja> A bean containing the contents for the OPTIONS page. + */</jd> + <ja>@RestMethod</ja>(name=<js>"OPTIONS"</js>, path=<js>"/*"</js>, + properties={ + <ja>@Property</ja>(name=<jsf>HTMLDOC_links</jsf>, value=<js>"{back:'$R{servletURI}'}"</js>), + <ja>@Property</ja>(name=<jsf>HTMLDOC_description</jsf>, value=<js>"Resource options"</js>) + }, + description=<js>"Resource options"</js> + ) + <jk>public</jk> ResourceOptions getOptions(RestRequest req) { + <jk>return new</jk> ResourceOptions(<jk>this</jk>, req); + } + </p> + <p> + The <l>AddressBookResource</l> class in the samples shows an example of augmenting the existing + {@link org.apache.juneau.server.labels.ResourceOptions} bean with some additional information. + </p> + <p class='bcode'> + <jd>/** OPTIONS request handler */</jd> + <ja>@Override</ja> <jc>/* RestServletJenaDefault */</jc> + <ja>@RestMethod</ja>(name=<js>"OPTIONS"</js>, path=<js>"/*"</js>) + <jk>public</jk> ResourceOptions getOptions(RestRequest req) { + <jk>return new</jk> Options(req); + } + + <jd>/** + * Output POJO for OPTIONS requests. + * Note that we're extending the existing ResourceOptions class. + */</jd> + <jk>public class</jk> Options <jk>extends</jk> ResourceOptions { + <jk>public</jk> ParamDescription[] queryableParameters; + <jk>public</jk> String[] otherNotes; + + <jk>public</jk> Options(RestRequest req) { + <jk>super</jk>(AddressBookResource.<jk>this</jk>, req); + Locale locale = req.getLocale(); + queryableParameters = getQueryableParamDescriptions(locale); + otherNotes = getMessage(locale, <js>"otherNotes"</js>).split(<js>"\\.\\s*"</js>); + } + } + </p> + <p> + Refer to <a class='doclink' href='#AddressBookResource'>Address Book Resource</a> for a complete example. + </p> + <h6 class='topic'>Label and Description</h6> + <p> + The label and description can be defined in two ways. + </p> + <p> + If you don't care about internationalization, then the easiest way is to use annotations on the servlet. + </p> + <p class='bcode'> + <ja>@RestResource</ja>( + path=<js>"/example"</js>, + label=<js>"Example Resource"</js>, + description=<js>"This shows how to use labels and descriptions."</js> + ) + <jk>public class</jk> ExampleResource <jk>extends</jk> RestServletDefault { + </p> + <p> + The second approach which supports internationalization is to use the + {@link org.apache.juneau.server.annotation.RestResource#messages() @RestResource.messages()} + annotation to point to a resource bundle, and then use predefined properties + that identify the label and description. + </p> + <p class='bcode'> + <ja>@RestResource</ja>( + messages=<js>"nls/Messages"</js> + ) + <jk>public class</jk> ExampleResource <jk>extends</jk> RestServletDefault { + </p> + <p> + The label and description are specified as special properties in the resource bundle: + </p> + <p class='bcode'> + <cc>#-------------------------------------------------------------------------------- + # Contents of Messages.properties + #--------------------------------------------------------------------------------</cc> + <ck>label</ck> = <cv>Example Resource</cv> + <ck>description</ck> = <cv>This shows how to use labels and descriptions.</cv> + </p> + <p> + Message keys can optionally be prefixed by the short class name if the resource bundle is shared by multiple servlets: + </p> + <p class='bcode'> + <cc>#-------------------------------------------------------------------------------- + # Contents of Messages.properties + #--------------------------------------------------------------------------------</cc> + <ck>ExampleResource.label</ck> = <cv>Example Resource</cv> + <ck>ExampleResource.description</ck> = <cv>This shows how to use labels and descriptions.</cv> + </p> + <p> + When both annotations and properties are used, annotations take precedence. + </p> + <p> + The localized label and description are also available through the following methods: + </p> + <ul class='javahierarchy'> + <li class='m'>{@link org.apache.juneau.server.RestRequest#getServletLabel()} + <li class='m'>{@link org.apache.juneau.server.RestRequest#getServletDescription()} + </ul> + <p> + They are also made available as the request string variables <js>"$R{servletLabel}"</js> and <js>"$R{servletDescription}"</js>. + These variable facilitate the localized label and descriptions on the HTML pages when using {@link org.apache.juneau.server.RestServletDefault}: + </p> + <p class='bcode'> + <ja>@RestResource</ja>( + properties={ + <jc>// Provide a default title on HTML pages.</jc> + <ja>@Property</ja>(name=<jsf>HTMLDOC_title</jsf>, value=<js>"$R{servletLabel}"</js>), + <jc>// Provide a default description on HTML pages.</jc> + <ja>@Property</ja>(name=<jsf>HTMLDOC_description</jsf>, value=<js>"$R{servletDescription}"</js>) + } + ) + <jk>public abstract class</jk> RestServletDefault <jk>extends</jk> RestServlet { + </p> + <p> + The label and description annotations support string variables. + So in theory, you could also provide localized messages using <js>"$L"</js> variables pointing to your own resource bundle properties: + </p> + <p class='bcode'> + <ja>@RestResource</ja>( + path=<js>"/example"</js>, + messages=<js>"nls/Messages"</js> + label=<js>"$L{my.resource.label}"</js>, + description=<js>"$L{my.resource.description}"</js> + ) + <jk>public class</jk> ExampleResource <jk>extends</jk> RestServletDefault { + </p> + <p> + Another option is to override the {@link org.apache.juneau.server.RestServlet#getLabel(RestRequest)} + and {@link org.apache.juneau.server.RestServlet#getDescription(RestRequest)} methods. + </p> + <h6 class='topic'>Method Description, Input, and Responses</h6> + <p> + The <l>methods</l> field in the OPTIONS page is mostly populated through reflection. + However, the description, input, and responses field can be specified through either + annotations or resource properties. + </p> + <p> + For example, the <l>AddressBookResource</l> has a <l>getPerson()</l> method + that gets rendered in the OPTIONS page like so... + </p> + <img class='bordered' src='doc-files/Options2.png'> + <p> + This method is described through the {@link org.apache.juneau.server.annotation.RestMethod#description() @RestMethod.description()}, + {@link org.apache.juneau.server.annotation.RestMethod#input() @RestMethod.input()}, + and {@link org.apache.juneau.server.annotation.RestMethod#responses() @RestMethod.responses()} annotations. + </p> + <p class='bcode'> + <ja>@RestMethod</ja>( + name=<js>"GET"</js>, + path=<js>"/people/{id}/*"</js>, + converters={Traversable.<jk>class</jk>,Queryable.<jk>class</jk>,Introspectable.<jk>class</jk>}, + description=<js>"Get a person by id in the address book"</js>, + input={ + <ja>@Var</ja>(category=VarCategory.<jsf>ATTR</jsf>, name=<js>"id"</js>, description=<js>"Person UUID"</js>) + }, + responses={ + <ja>@Response</ja>( + value=200, + output={ + <ja>@Var</ja>(category=VarCategory.<jsf>CONTENT</jsf>, description=<js>"Person bean"</js>) + } + ), + <ja>@Response</ja>(value=404, description=<js>"Person with specified id not found"</js>) + } + ) + <jk>public</jk> Person getPerson(<ja>@Attr</ja> <jk>int</jk> id) throws Exception { + <jk>return</jk> findPerson(id); + } + </p> + <p> + These labels can also be localized by instead specifying them in the servlet properties file: + </p> + <p class='bcode'> + <ja>@RestMethod</ja>( + name=<js>"GET"</js>, + path=<js>"/people/{id}/*"</js>, + converters={Traversable.<jk>class</jk>,Queryable.<jk>class</jk>,Introspectable.<jk>class</jk>} + <jc>// Don't specify annotations for labels...they'll be detected in resource bundle.</jc> + ) + <jk>public</jk> Person getPerson(<ja>@Attr</ja> <jk>int</jk> id) throws Exception { + <jk>return</jk> findPerson(id); + } + </p> + <p class='bcode'> + <cc>#-------------------------------------------------------------------------------- + # Contents of AddressBookResource.properties + #--------------------------------------------------------------------------------</cc> + <ck>getPerson</ck> = <cv>Get a person by id in the address book</cv> + <ck>getPerson.req.attr.id</ck> = <cv>Person UUID</cv> + <ck>getPerson.res.200</ck> = <cv>Person found</cv> + <ck>getPerson.res.404</ck> = <cv>Person with specified id not found</cv> + </p> + <p> + The following table shows the predefined resource bundle message property names: + </p> + <table class='styled'> + <tr> + <th>Property</th> + <th>Description</th> + <th>Equivalent Annotation</th> + <th>Equivalent Method</th> + </tr> + <tr> + <td><ck>label</ck></td> + <td>Servlet label</td> + <td>{@link org.apache.juneau.server.annotation.RestResource#label() @RestResource.label()}</td> + <td>{@link org.apache.juneau.server.RestServlet#getLabel(RestRequest)}</td> + </tr> + <tr> + <td><ck>description</ck></td> + <td>Servlet description</td> + <td>{@link org.apache.juneau.server.annotation.RestResource#description() @RestResource.description()}</td> + <td>{@link org.apache.juneau.server.RestServlet#getDescription(RestRequest)}</td> + </tr> + <tr> + <td><ck>[javaMethodName]</ck></td> + <td>Java method description</td> + <td>{@link org.apache.juneau.server.annotation.RestMethod#description() @RestMethod.description()}</td> + <td>{@link org.apache.juneau.server.RestServlet#getMethodDescriptions(RestRequest)}</td> + </tr> + <tr> + <td><ck>[javaMethodName].req.content</ck></td> + <td> + A description of the HTTP request content. + </td> + <td>{@link org.apache.juneau.server.annotation.RestMethod#input() @RestMethod.input()}</td> + <td>{@link org.apache.juneau.server.RestServlet#getMethodDescriptions(RestRequest)}</td> + </tr> + <tr> + <td><ck>[javaMethodName].req.[category].[name]</ck></td> + <td> + A request input variable. + <br>Categories: <l>ATTR, PARAM, HEADER</l> + </td> + <td>{@link org.apache.juneau.server.annotation.RestMethod#input() @RestMethod.input()}</td> + <td>{@link org.apache.juneau.server.RestServlet#getMethodDescriptions(RestRequest)}</td> + </tr> + <tr> + <td><ck>[javaMethodName].res.[code]</ck></td> + <td> + A possible HTTP response code and description. + </td> + <td>{@link org.apache.juneau.server.annotation.RestMethod#responses() @RestMethod.responses()}</td> + <td>{@link org.apache.juneau.server.RestServlet#getMethodDescriptions(RestRequest)}</td> + </tr> + <tr> + <td><ck>[javaMethodName].res.[code].content</ck></td> + <td> + A description of response content for the specified HTTP response. + </td> + <td>{@link org.apache.juneau.server.annotation.RestMethod#responses() @RestMethod.responses()}</td> + <td>{@link org.apache.juneau.server.RestServlet#getMethodDescriptions(RestRequest)}</td> + </tr> + <tr> + <td><ck>[javaMethodName].res.[code].[category].[name]</ck></td> + <td> + A response output variable. + <br>Categories: <l>ATTR, PARAM, HEADER</l> + </td> + <td>{@link org.apache.juneau.server.annotation.RestMethod#responses() @RestMethod.responses()}</td> + <td>{@link org.apache.juneau.server.RestServlet#getMethodDescriptions(RestRequest)}</td> + </tr> + </table> + <h6 class='topic'>Additional Information</h6> + <ul class='javahierarchy'> + <li class='n'>{@link org.apache.juneau.server.annotation.RestMethod#description() @RestMethod.description()} + <li class='n'>{@link org.apache.juneau.server.annotation.RestMethod#input() @RestMethod.input()} + <li class='n'>{@link org.apache.juneau.server.annotation.RestMethod#responses() @RestMethod.responses()} + <li class='n'>{@link org.apache.juneau.server.annotation.RestMethod#rc() @RestMethod.rc()} + <li class='m'>{@link org.apache.juneau.server.RestRequest#getServletLabel()} + <li class='m'>{@link org.apache.juneau.server.RestRequest#getServletDescription()} + <li class='m'>{@link org.apache.juneau.server.RestRequest#getMethodDescription()} + <li class='m'>{@link org.apache.juneau.server.RestRequest#getMethodDescriptions()} + </ul> + </div> + + <!-- ======================================================================================================== --> + <a name="RestResources.Serializers"></a> + <h3 class='topic' onclick='toggle(this)'>4.5 - Serializers</h3> + <div class='topic'> + <p> + REST servlets use the {@link org.apache.juneau.serializer.Serializer} API for defining serializers for serializing response POJOs. + </p> + <p> + The servlet will pick which serializer to use by matching the request <l>Accept</l> header with the + media types defined through the {@link org.apache.juneau.serializer.Serializer#getMediaTypes()} method + (which itself usually comes from the {@link org.apache.juneau.annotation.Produces @Produces} annotation). + </p> + <p> + Serializers can be associated with REST servlets in the following ways: + </p> + <ul class='javahierarchy'> + <li class='n'>{@link org.apache.juneau.server.annotation.RestResource#serializers() @RestResource.serializers()} - Annotation on servlet class. + <li class='n'>{@link org.apache.juneau.server.annotation.RestMethod#serializers() @RestMethod.serializers()} - Annotation on individual servlet methods. + <li class='m'>{@link org.apache.juneau.server.RestServlet#createSerializers(ObjectMap,Class[])} - Override method to set the serializers programmatically. + </ul> + <p> + The following are equivalent ways of defining serializers used by a servlet... + </p> + <p class='bcode'> + <jc>// Example #1 - Serializers defined on servlet through annotation</jc> + <ja>@RestResource</ja>( + serializers={JsonSerializer.<jk>class</jk>, XmlSerializer.<jk>class</jk>} + ) + <jk>public</jk> MyRestServlet <jk>extends</jk> RestServlet { + ... + } + + <jc>// Example #2 - Serializers defined on method through annotation</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/*"</js> + serializers={JsonSerializer.<jk>class</jk>, XmlSerializer.<jk>class</jk>} + ) + <jk>public</jk> Object doGet() { + ... + } + + <jc>// Example #3 - Serializers defined on servlet by overriding the createSerializers(ObjectMap,Class[]) method</jc> + <ja>@Override</ja> + <jk>public</jk> SerializerGroup createSerializers(ObjectMap,Class[]) { + + SerializerGroup g = <jk>new</jk> SerializerGroup() + .append(JsonSerializer.<jk>class</jk>, XmlSerializer.<jk>class</jk>); + + <jk>return</jk> g; + } + </p> + <p class='info'> + When debugging the output from REST servlets, it's almost always easier to bypass the REST servlet and try to serialize + the POJOs using the serializers directly using the {@link org.apache.juneau.serializer.WriterSerializer#toString(Object)} method. + </p> + <h6 class='topic'>Additional Information</h6> + <ul class='javahierarchy'> + <li class='n'>{@link org.apache.juneau.server.annotation.RestMethod#serializersInherit() @RestMethod.serializersInherit()} + <br>Controls how serializers are inherited from the servlet class. + </ul> + </div> + + <!-- ======================================================================================================== --> + <a name="RestResources.Parsers"></a> + <h3 class='topic' onclick='toggle(this)'>4.6 - Parsers</h3> + <div class='topic'> + <p> + REST servlets use the {@link org.apache.juneau.parser.Parser} API for defining parsers for parsing request body content and converting them into POJOs. + </p> + <p> + The servlet will pick which parser to use by matching the request <l>Content-Type</l> header with the + media types defined through the {@link org.apache.juneau.parser.Parser#getMediaTypes()} method (which itself + usually comes from the {@link org.apache.juneau.annotation.Consumes @Consumes} annotation). + </p> + <p> + Parsers can be associated with REST servlets in the following ways: + </p> + <ul class='javahierarchy'> + <li class='n'>{@link org.apache.juneau.server.annotation.RestResource#parsers() @RestResource.parsers()} - Annotation on servlet class. + <li class='n'>{@link org.apache.juneau.server.annotation.RestMethod#parsers() @RestMethod.parsers()} - Annotation on individual servlet methods. + <li class='m'>{@link org.apache.juneau.server.RestServlet#createParsers(ObjectMap,Class[])} - Override method to set the parsers programmatically. + </ul> + <p> + The following are equivalent ways of defining parsers used by a servlet... + </p> + <p class='bcode'> + <jc>// Example #1 - Parsers defined on servlet through annotation</jc> + <ja>@RestResource</ja>( + parsers={JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>} + ) + <jk>public</jk> MyRestServlet <jk>extends</jk> RestServlet { + ... + } + + <jc>// Example #2 - Parsers defined on method through annotation</jc> + <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/*"</js> + parsers={JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>} + ) + <jk>public void</jk> doPut(<ja>@Content</ja> Foo input) { + ... + } + + <jc>// Example #3 - Parsers defined on servlet by overriding the getParserGroup method</jc> + <ja>@Override</ja> + <jk>public</jk> ParserGroup getParserGroup() { + + ParserGroup g = <jk>new</jk> ParserGroup() + .append(JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>); + + <jk>return</jk> g; + } + </p> + <h6 class='topic'>Additional Information</h6> + <ul class='javahierarchy'> + <li class='n'>{@link org.apache.juneau.server.annotation.RestMethod#parsersInherit() @RestMethod.parsersInherit()} + <br>Controls how parsers are inherited from the servlet class. + </ul> + </div> + + <!-- ======================================================================================================== --> + <a name="RestResources.Properties"></a> + <h3 class='topic' onclick='toggle(this)'>4.7 - Properties</h3> + <div class='topic'> + <p> + The Juneau serializers and parsers are highly-configurable through properties. + (See <a class='doclink' href='../../../../overview-summary.html#Core.ConfigurableProperties'>Configurable Properties</a>) + </p> + <p> + There are several ways of defining properties in the REST API. + The most common way is going to be through the {@link org.apache.juneau.server.annotation.RestResource#properties() @RestResource.properties()} + and {@link org.apache.juneau.server.annotation.RestMethod#properties() @RestMethod.properties()} annotations. + </p> + <p> + The {@link org.apache.juneau.server.annotation.RestResource#properties() @RestResource.properties()} annotation + can be used as a convenient way to set various serializer and parser + properties to all serializers and parsers registered with the servlet. + </p> + <p class='bcode'> + <jk>import static</jk> org.apache.juneau.SerializerContext.*; + <jk>import static</jk> org.apache.juneau.xml.XmlSerializerContext.*; + <jk>import static</jk> org.apache.juneau.server.serializers.HtmlSerializerContext.*; + + <jc>// Servlet with properties applied</jc> + <ja>@RestResource</ja>( + properties={ + <jc>// Nulls should not be serialized</jc> + <ja>@Property</ja>(name=<jsf>TRIM_NULLS</jsf>, value=<js>"true"</js>), + + <jc>// Empty lists should not be serialized</jc> + <ja>@Property</ja>(name=<jsf>SERIALIZER_trimEmptyLists</jsf>, value=<js>"true"</js>), + + <jc>// Specify the default namespaces for the XML serializer</jc> + <ja>@Property</ja>(name=<jsf>XML_defaultNamespaceUriS</jsf>, + value=<js>"{jp06:'http://jazz.net/xmlns/prod/jazz/process/0.6/',jp:'http://jazz.net/xmlns/prod/jazz/process/1.0/'}"</js>), + + <jc>// Specify a default title for the HtmlSerializer serializer</jc> + <ja>@Property</ja>(name=<jsf>HTMLDOC_title</jsf>, value=<js>"My resource"</js>) + } + ) + <jk>public</jk> MyRestServlet <jk>extends</jk> RestServlet { + ... + } + </p> + <p> + The {@link org.apache.juneau.server.annotation.RestMethod#properties() @RestMethod.properties()} annotation + can be used to define method-level properties that can alter the behavior of serializers and parsers at the method level only. + </p> + <p class='bcode'> + <jc>// GET method with method-level properties</jc> + <ja>@RestMethod</ja>( + name=<js>"GET"</js>, path=<js>"/*"</js>, + properties={ + <jc>// Nulls should not be serialized</jc> + <ja>@Property</ja>(name=<jsf>TRIM_NULLS</jsf>, value=<js>"true"</js>), + + <jc>// Empty lists should not be serialized</jc> + <ja>@Property</ja>(name=<jsf>SERIALIZER_trimEmptyLists</jsf>, value=<js>"true"</js>), + + <jc>// Specify the default namespaces for the XML serializer</jc> + <ja>@Property</ja>(name=<jsf>XML_defaultNamespaceUriS</jsf>, + value=<js>"{jp06:'http://jazz.net/xmlns/prod/jazz/process/0.6/',jp:'http://jazz.net/xmlns/prod/jazz/process/1.0/'}"</js>), + + <jc>// Specify a default title for the HtmlSerializer serializer</jc> + <ja>@Property</ja>(name=<jsf>HTMLDOC_title</jsf>, value=<js>"My resource"</js>) + } + <jk>public</jk> Object doGet() { + ... + } + </p> + <p> + In particular, the {@link org.apache.juneau.server.RestServletContext} class has a variety of properties + for controlling the behavior of the {@link org.apache.juneau.server.RestServlet} class itself. + </p> + <p> + There are also ways to provide properties programmatically. + </p> + <ul class='spaced-list'> + <li>By overriding the {@link org.apache.juneau.server.RestServlet#createProperties()} method. + <li>By overriding the {@link org.apache.juneau.server.RestServlet#createSerializers(ObjectMap,Class[])} and + {@link org.apache.juneau.server.RestServlet#createParsers(ObjectMap,Class[])} methods and setting properties on the + serializers and parsers directly. + + </ul> + <h6 class='topic'>Additional Information</h6> + <ul class='javahierarchy'> + <li class='c'>{@link org.apache.juneau.server.RestServletContext} + <br>Properties associated with the {@link org.apache.juneau.server.RestServlet} class. + <li class='n'>{@link org.apache.juneau.server.annotation.RestMethod#serializersInherit @RestMethod.serializersInherit()} + <br>Controls how serializers inherit properties from the servlet class. + <li class='n'>{@link org.apache.juneau.server.annotation.RestMethod#parsersInherit @RestMethod.parsersInheritInherit()} + <br>Controls how parsers inherit properties from the servlet class. + </ul> + </div> + + <!-- ======================================================================================================== --> + <a name="RestResources.Transforms"></a> + <h3 class='topic' onclick='toggle(this)'>4.8 - Transforms</h3> + <div class='topic'> + <p> + The Juneau serializers and parsers can be configured on how to handle POJOs through the use of Transforms. + (See <a class='doclink' href='../../../../overview-summary.html#Core.Transforms'>Transforms</a>) + </p> + <p> + The {@link org.apache.juneau.server.annotation.RestResource#transforms() @RestResource.transforms()} annotation + can be used as a convenient way to add POJO transforms to the serializers and parsers + registered with the servlet. + </p> + <p class='bcode'> + <jc>// Servlet with transforms applied</jc> + <ja>@RestResource</ja>( + transforms={ + <jc>// Calendars should be serialized/parsed as ISO8601 date-time strings</jc> + CalendarTransform.<jsf>DEFAULT_ISO8601DT</jsf>.<jk>class</jk>, + + <jc>// Byte arrays should be serialized/parsed as BASE64-encoded strings</jc> + ByteArrayBase64Transform.<jk>class</jk>, + + <jc>// Subclasses of MyInterface will be treated as MyInterface objects.</jc> + <jc>// Bean properties not defined on that interface will be ignored.</jc> + MyInterface.<jk>class</jk> + } + ) + <jk>public</jk> MyRestServlet <jk>extends</jk> RestServlet { + ... + } + </p> + <p> + {@link org.apache.juneau.server.annotation.RestMethod#transforms() @RestMethod.transforms()} + is the equivalent annotation for individual Java methods. + </p> + <p> + Transforms can also be defined programmatically through the following: + </p> + <ul class='spaced-list'> + <li>By overriding the {@link org.apache.juneau.server.RestServlet#createTransforms()} method. + <li>By overriding the {@link org.apache.juneau.server.RestServlet#createSerializers(ObjectMap,Class[])} and + {@link org.apache.juneau.server.RestServlet#createParsers(ObjectMap,Class[])} methods and setting transforms on the + serializers and parsers directly. + + </ul> + <h6 class='topic'>Additional Information</h6> + <ul class='javahierarchy'> + <li class='n'>{@link org.apache.juneau.server.annotation.RestMethod#serializersInherit @RestMethod.serializersInherit()} + <br>Controls how serializers inherit transforms from the servlet class. + <li class='n'>{@link org.apache.juneau.server.annotation.RestMethod#parsersInherit @RestMethod.parsersInherit()} + <br>Controls how parsers inherit transforms from the servlet class. + </ul> + </div> + + <!-- ======================================================================================================== --> + <a name="RestResources.Guards"></a> + <h3 class='topic' onclick='toggle(this)'>4.9 - Guards</h3> + <div class='topic'> + <p> + Guards are classes that control access to REST servlets and methods. + </p> + <p> + The {@link org.apache.juneau.server.annotation.RestResource#guards @RestResource.guards()} annotation + can be used to associate one or more class-level {@link org.apache.juneau.server.RestGuard RestGuards} with a servlet. + </p> + <p class='bcode'> + <jc>// Servlet with class-level guard applied</jc> + <ja>@RestResource</ja>(guards=BillyGuard.<jk>class</jk>) + <jk>public</jk> MyRestServlet <jk>extends</jk> RestServlet { + + <jc>// Delete method that only Billy is allowed to call.</jc> + <jk>public</jk> doDelete(RestRequest req, RestResponse res) <jk>throws</jk> Exception {...} + } + + <jc>// Define a guard that only lets Billy make a request</jc> + <jk>public</jk> BillyGuard <jk>extends</jk> RestGuard { + + <ja>@Override</ja> + <jk>public boolean</jk> isRequestAllowed(RestRequest req) { + return req.getUserPrincipal().getName().equals(<js>"Billy"</js>); + } + } + </p> + <p> + A common use for guards is to only allow admin access to certain Java methods... + </p> + <p class='bcode'> + <jc>// DELETE method</jc> + <ja>@RestMethod</ja>(name=<js>"DELETE"</js>, guards={AdminGuard.<jk>class</jk>}) + <jk>public void</jk> doDelete(RestRequest req, RestResponse res) <jk>throws</jk> Exception { + ... + </p> + <p class='bcode'> + <jk>public class</jk> AdminGuard <jk>extends</jk> RestGuard { + <ja>@Override</ja> + <jk>public boolean</jk> isRequestAllowed(RestRequest req) { + <jk>return</jk> req.getUserPrincipal().isUserInRole(<js>"ADMIN"</js>); + } + } + </p> + <p> + A guard failure results in an <l>HTTP 401 Unauthorized</l> response. + However, this can be configured by overriding the {@link org.apache.juneau.server.RestGuard#guard(RestRequest,RestResponse)} + and processing the response yourself. + </p> + <p> + When guards are associated at the class-level, it's equivalent to associating guards on all Java methods on the servlet. + </p> + <p> + Class-level guards can also be created programmatically by overriding the {@link org.apache.juneau.server.RestServlet#createGuards(ObjectMap)} method. + </p> + <h6 class='topic'>Additional Information</h6> + <ul class='javahierarchy'> + <li class='a'>{@link org.apache.juneau.server.RestGuard} + </ul> + </div> + + <!-- ======================================================================================================== --> + <a name="RestResources.Converters"></a> + <h3 class='topic' onclick='toggle(this)'>4.10 - Converters</h3> + <div class='topic'> + <p> + Converters can be thought of as a "post-processor" for POJOs before they get passed to the serializers. + </p> + <p> + The {@link org.apache.juneau.server.annotation.RestResource#converters @RestResource.converters()} annotation + can be used as a convenient way to add {@link org.apache.juneau.server.RestConverter RestConverters} to + all Java REST methods on a servlet. + </p> + <p class='bcode'> + <jc>// Associate the Traversable converter to all Java REST methods in this servlet</jc> + <ja>@RestResource</ja>(converters=Traversable.<jk>class</jk>) + <jk>public</jk> MyRestServlet <jk>extends</jk> RestServlet { + ... + } + </p> + <p> + The {@link org.apache.juneau.server.annotation.RestMethod#converters() @RestMethod.converters()} annotation + can be used to associate converters on individual methods. + </p> + <p class='bcode'> + <jc>// GET person request handler.</jc> + <jc>// Traversable conversion enabled to allow nodes in returned POJO tree to be addressed.</jc> + <jc>// Queryable conversion enabled to allow returned POJO to be searched/viewed/sorted.</jc> + <ja>@RestMethod</ja>( + name=<js>"GET"</js>, path=<js>"/people/{id}/*"</js>, + converters={Traversable.<jk>class</jk>,Queryable.<jk>class</jk>} + ) + <jk>public</jk> Person getPerson(<ja>@Attr</ja> <jk>int</jk> id) { + <jk>return</jk> findPerson(id); + } + </p> + <p> + The following converter is used to provide support for addressing child nodes in a POJO tree with + URL path remainders. + <br>In this code, the 3rd parameter is the object that was returned by the Java method (or set through <l>request.setObject(o);</l>). + <br>The converter uses the {@link org.apache.juneau.utils.PojoRest} wrapper class to address nodes in the tree. + </p> + <p class='bcode'> + <jd>/** + * Converter for enablement of PojoRest support on response objects returned by a @RestMethod method. + * When enabled, objects in a POJO tree returned by the REST method can be addressed through additional URL path information. + */</jd> + <jk>public class</jk> Traversable <jk>implements</jk> RestConverter { + + <ja>@Override</ja> + <jk>public</jk> Object convert(RestServlet resource, RestRequest req, Object o) { + if (o == <jk>null</jk>) + <jk>return null</jk>; + + BeanContext beanContext = resource.getBeanContext(); + + <jk>if</jk> (req.getRemainder() != <jk>null</jk>) { + PojoRest p = <jk>new</jk> PojoRest(o, beanContext); + <jk>try</jk> { + o = p.get(req.getRemainder()); + } <jk>catch</jk> (PojoRestException e) { + <jk>throw new</jk> RestException(e.getStatus(), e.getMessage(), e); + } + } + + <jk>return</jk> o; + } + } + </p> + <p> + Juneau defines the following converters out-of-the-box: + </p> + <ul class='javahierarchy'> + <li class='i'>{@link org.apache.juneau.server.RestConverter} + <ul> + <li class='c'>{@link org.apache.juneau.server.converters.Queryable} + <br>Provides query parameters that can be used to transform the response (i.e. search/view/sort the POJO response before being serialized). + <li class='c'>{@link org.apache.juneau.server.converters.Traversable} + <br>Allows nodes in the POJO response tree to be individually accessed through additional path info on the request. + <li class='c'>{@link org.apache.juneau.server.converters.Introspectable} + <br>Allows method calls to be made on the response POJO, and for the result of that method call to be serialized as the response. + </ul> + </ul> + <p> + Class-level converters can be created programmatically by overriding the {@link org.apache.juneau.server.RestServlet#createConverters(ObjectMap)} method. + </p> + <p> + Note that from the example above, you can specify more than one converter. + When multiple converters are used, they're executed in the order they're specified in the annotation + (e.g. first the results will be traversed, then the resulting node will be searched/sorted). + + </p> + <h6 class='topic'>Additional Information</h6> + <ul class='javahierarchy'> + <li class='i'>{@link org.apache.juneau.server.RestConverter} + </ul> + </div> + + <!-- ======================================================================================================== --> + <a name="RestResources.Children"></a> + <h3 class='topic' onclick='toggle(this)'>4.11 - Child Resources</h3> + <div class='topic'> + <p> + Child Resources are REST servlets that are linked to parent servlets through the + {@link org.apache.juneau.server.annotation.RestResource#children() @RestResource.children()} annnotation. + </p> + <p class='bcode'> + <jd>/** Parent Resource */</jd> + <ja>@RestResource</ja>( + path=<js>"/parent"</js>, + children={Foo.<jk>class</jk>} + ) + <jk>public</jk> MyResource <jk>extends</jk> RestServlet { + ... + </p> + <p class='bcode'> + <jd>/** Child Resource */</jd> + <ja>@RestResource</ja>( + path=<js>"/foo"</js> // Path relative to parent resource. + ) + <jk>public</jk> FooResource <jk>extends</jk> RestServlet { + ... + </p> + <p> + A HUGE advantage of using child resources is that they do not need to be declared in the JEE <l>web.xml</l> file. + Initialization of and access to the child resources occurs through the parent resource. + Children can be nested arbitrary deep to create complex REST interfaces with a single top-level REST servlet. + </p> + <p> + The path of the child resource gets appended to the path of the parent resource. + So in the example above, the child resource is accessed through the URL <l>/parent/foo</l>. + </p> + <p> + The {@link org.apache.juneau.server.RestServletGroupDefault} class provides a default "router" page for + child resources when a parent resource is nothing more than a grouping of child resources. + </p> + <p> + The <l>RootResources</l> class in the Samples project is an example of a router page: + </p> + <p class='bcode'> + <jd>/** + * Sample REST resource showing how to implement a "router" resource page. + */</jd> + <ja>@RestResource</ja>( + path=<js>"/"</js>, + messages=<js>"nls/RootResources"</js>, + properties={ + <ja>@Property</ja>(name=HTMLDOC_links, value=<js>"{options:'$R{servletURI}?method=OPTIONS',source:'$R{servletURI}/source?classes=(org.apache.juneau.server.samples.RootResources)'}"</js>) + }, + children={ + HelloWorldResource.<jk>class</jk>, + MethodExampleResource.<jk>class</jk>, + RequestEchoResource.<jk>class</jk>, + TempDirResource.<jk>class</jk>, + AddressBookResource.<jk>class</jk>, + SampleRemoteableServlet.<jk>class</jk>, + PhotosResource.<jk>class</jk>, + AtomFeedResource.<jk>class</jk>, + JsonSchemaResource.<jk>class</jk>, + SqlQueryResource.<jk>class</jk>, + TumblrParserResource.<jk>class</jk>, + CodeFormatterResource.<jk>class</jk>, + UrlEncodedFormResource.<jk>class</jk>, + SourceResource.<jk>class</jk>, + ConfigResource.<jk>class</jk>, + LogsResource.<jk>class</jk>, + DockerRegistryResource.<jk>class</jk>, + ShutdownResource.<jk>class</jk> + } + ) + <jk>public class</jk> RootResources <jk>extends</jk> ResourceGroup { + <jk>private static final long</jk> <jsf>serialVersionUID</jsf> = 1L; + } + </p> + <p> + When you bring up this resource in a browser, you see the following: + </p> + <img class='bordered' src="doc-files/Samples_RootResources.png"/> + <p> + The <l>RestServletGroupDef
<TRUNCATED>