blob: ddb4486b8265941a25945f4f2a2a439b83464554 [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 file system and page designer */
@IMPORT url("../../../../juneau-core/java/src/main/javadoc/javadoc.css");
@IMPORT url("../../../../juneau-core/java/src/main/javadoc/resources/juneau-doc.css");
@IMPORT url("../../../../juneau-core/java/src/main/javadoc/resources/juneau-code.css");
body {
margin: 20px;
}
.spaced-list li { padding:5px; }
.footer .spaced-list ul { margin:0 }
</style>
<script type="text/javascript">
/* 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>Apache Juneau Overview</p>
<script type="text/javascript">
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>
<ul class='spaced-list'>
<li>A toolkit for marshalling POJOs to a wide variety of content types using a common framework.
<li>A REST server API for creating self-documenting REST interfaces using POJOs.
<li>A REST client API for interacting with REST interfaces using POJOs.
<li>A remote proxy API built on top of REST.
<li>A sophisticated INI config file API.
<li>A REST microservice API that combines all the features above for creating lightweight standalone REST interfaces that start up in milliseconds.
</ul>
<a id='TOC'></a><h5 class='toc'>Table of Contents</h5>
<ol class='toc'>
<li><p><a class='doclink' href='#Intro'>Juneau - What is it?</a></p>
<li><p><a class='doclink' href='#Core'>Juneau Core (org.apache.juneau)</a></p>
<ol>
<li><p><a class='doclink' href='#Core.Serializers'>Serializers</a></p>
<li><p><a class='doclink' href='#Core.Parsers'>Parsers</a></p>
<li><p><a class='doclink' href='#Core.SerializerAndParserGroups'>SerializerGroups and ParserGroups</a></p>
<li><p><a class='doclink' href='#Core.ObjectMap'>ObjectMap and ObjectList</a></p>
<li><p><a class='doclink' href='#Core.ConfigurableProperties'>Configurable Properties</a></p>
<li><p><a class='doclink' href='#Core.Transforms'>Transforms</a></p>
<ol>
<li><p><a class='doclink' href='#Core.PojoSwaps'>PojoSwaps</a></p>
<li><p><a class='doclink' href='#Core.SwapMethods'>Swap methods</a></p>
<li><p><a class='doclink' href='#Core.BeanFilters'>BeanFilters and @Bean annotations</a></p>
</ol>
<li><p><a class='doclink' href='#Core.BeanDictionaries'>Bean Name and Dictionaries</a></p>
<ol>
<li><p><a class='doclink' href='#Core.BeanSubTypes'>Bean Subtypes</a></p>
</ol>
<li><p><a class='doclink' href='#Core.VirtualBeans'>Virtual Beans</a></p>
<li><p><a class='doclink' href='#Core.PojoCategories'>POJO Categories</a></p>
<li><p><a class='doclink' href='#Core.SimpleVarLanguage'>Simple Variable Language</a></p>
<li><p><a class='doclink' href='#Core.ConfigFile'>Configuration Files</a></p>
<li><p><a class='doclink' href='#Core.SupportedLanguages'>Supported Languages</a></p>
<li><p><a class='doclink' href='#Core.JacksonComparison'>Comparison with Jackson</a></p>
</ol>
<li><p><a class='doclink' href='#DTOs'>Juneau Data Transfer Objects (org.apache.juneau.dto)</a></p>
<ol>
<li><p><a class='doclink' href='#DTOs.HTML5'>HTML5</a></p>
<li><p><a class='doclink' href='#DTOs.Atom'>Atom</a></p>
<li><p><a class='doclink' href='#DTOs.Swagger'>Swagger</a></p>
<li><p><a class='doclink' href='#DTOs.JsonSchema'>JSON-Schema</a></p>
</ol>
<li><p><a class='doclink' href='#Server'>Juneau Server (org.apache.juneau.rest)</a></p>
<li><p><a class='doclink' href='#Client'>Juneau Client (org.apache.juneau.rest.client)</a></p>
<li><p><a class='doclink' href='#Remoteable'>Remoteable services (org.apache.juneau.rest.remoteable)</a></p>
<ol>
<li><p><a class='doclink' href='#Remoteable.3rdParty'>Interface proxies against 3rd-party REST interfaces</a></p>
</ol>
<li><p><a class='doclink' href='#Microservices'>Juneau Microservices (org.apache.juneau.microservice)</a></p>
<li><p><a class='doclink' href='#Samples'>Samples</a></p>
<ol>
<li><p><a class='doclink' href='#Samples.Installing'>Installing in Eclipse</a></p>
<li><p><a class='doclink' href='#Samples.Running'>Running in Eclipse</a></p>
<li><p><a class='doclink' href='#Samples.Building'>Building and Running from Command-Line</a></p>
<li><p><a class='doclink' href='#Samples.RestResource'>MANIFEST.MF</a></p>
<li><p><a class='doclink' href='#Samples.RootResources'>RootResources</a></p>
<li><p><a class='doclink' href='#Samples.HelloWorldResource'>HelloWorldResource</a></p>
<li><p><a class='doclink' href='#Samples.MethodExampleResource'>MethodExampleResource</a></p>
<li><p><a class='doclink' href='#Samples.UrlEncodedFormResource'>UrlEncodedFormResource</a></p>
<li><p><a class='doclink' href='#Samples.RequestEchoResource'>RequestEchoResource</a></p>
<li><p><a class='doclink' href='#Samples.AddressBookResource'>AddressBookResource</a></p>
<ol>
<li><p><a class='doclink' href='#Samples.AddressBookResource.Classes'>Classes</a></p>
<li><p><a class='doclink' href='#Samples.AddressBookResource.Demo'>Demo</a></p>
<li><p><a class='doclink' href='#Samples.AddressBookResource.Traversable'>Traversable</a></p>
<li><p><a class='doclink' href='#Samples.AddressBookResource.Queryable'>Queryable</a></p>
<li><p><a class='doclink' href='#Samples.AddressBookResource.Introspectable'>Introspectable</a></p>
<li><p><a class='doclink' href='#Samples.AddressBookResource.RestClient'>ClientTest</a></p>
<li><p><a class='doclink' href='#Samples.AddressBookResource.Browser'>Browser Tips</a></p>
</ol>
<li><p><a class='doclink' href='#Samples.SampleRemoteableServlet'>SampleRemoteableServlet</a></p>
<li><p><a class='doclink' href='#Samples.TempDirResource'>TempDirResource</a></p>
<li><p><a class='doclink' href='#Samples.AtomFeedResource'>AtomFeedResource</a></p>
<li><p><a class='doclink' href='#Samples.DockerRegistryResource'>DockerRegistryResource</a></p>
<li><p><a class='doclink' href='#Samples.TumblrParserResource'>TumblrParserResource</a></p>
<li><p><a class='doclink' href='#Samples.PhotosResource'>PhotosResource</a></p>
<li><p><a class='doclink' href='#Samples.JsonSchemaResource'>JsonSchemaResource</a></p>
<li><p><a class='doclink' href='#Samples.SqlQueryResource'>SqlQueryResource</a></p>
<li><p><a class='doclink' href='#Samples.ConfigResource'>ConfigResource</a></p>
<li><p><a class='doclink' href='#Samples.LogsResource'>LogsResource</a></p>
</ol>
<li><p><a class='doclink' href='#Cookbook'>Cookbook Examples</a></p>
<ol>
<li><p><a class='doclink' href='#Cookbook.Core'>Core API</a></p>
<li><p><a class='doclink' href='#Cookbook.Server'>Server API</a></p>
<ol>
<li><p><a class='doclink' href='#Cookbook.Server.applyDoubletransform'>Apply a transform that changes the format of doubles</a></p>
<li><p><a class='doclink' href='#Cookbook.Server.applyTransformsSubset'>Apply transforms to a subset of serializers or parsers</a></p>
</ol>
<li><p><a class='doclink' href='#Cookbook.Client'>Client API</a></p>
<ol>
</ol>
<li><p><a class='doclink' href='#Cookbook.Microservice'>Microservice API</a></p>
<ol>
</ol>
</ol>
<li><p><a class='doclink' href='#BestPractices'>Best Practices</a></p>
<li><p><a class='doclink' href='#ImportantLinks'>Important Documentation Links</a></p>
<li><p><a class='doclink' href='#ReleaseNotes'>Release Notes</a></p>
</ol>
<!-- ======================================================================================================== -->
<a id="Intro"></a>
<h2 class='topic' onclick='toggle(this)'>1 - Juneau - What is it?</h2>
<div class='topic'>
<p>
Juneau started off as a popular internal IBM toolkit called Juno.
Originally used for serializing POJOs to and from JSON, it later expanded in scope to include a variety of content types, and then later REST servlet, client, and microservice APIs.
It's use grew to more than 50 projects and was one of the most popular community source projects within IBM.
</p>
<p>
In 2016, the code was donated to the Apache Foundation under the project <l>Apache Juneau</l>.
</p>
<h5 class='toc'>Features</h5>
<ol class='toc'>
<li>
<p>Extensive and extensible support for a large variety of POJOs, including structured data (beans) and unstructured data (<code>Maps</code> and <code>Collections</code>).</p>
<li>
<p>Serialization support:</p>
<ul>
<li>JSON (including variants)
<li>XML
<li>HTML
<li>URL-Encoding
<li>UON (URL-Encoded Object Notation)
<li>MessagePack
<li>RDF/XML
<li>RDF/XML-Abbrev
<li>N-Triple
<li>Turtle
<li>N3
<li>SOAP/XML
</ul>
<li>
<p>Parsing support:</p>
<ul>
<li>JSON (including lax syntax, comments, concatenated strings)
<li>XML
<li>HTML
<li>URL-Encoding
<li>UON (URL-Encoded Object Notation)
<li>MessagePack
<li>RDF/XML
<li>RDF/XML-Abbrev
<li>N-Triple
<li>Turtle
<li>N3
</ul>
<li>
<p>Data Transfer Objects:</p>
<ul>
<li>HTML5
<li>ATOM
<li>Swagger
<li>Cognos
<li>JSON-Schema
</ul>
<p>DTOs can be used with any serializers and parsers (e.g. ATOM as JSON).
<li>
<p>Serialization of POJO meta-models (e.g. the POJO class structure itself) to:</p>
<ul>
<li>JSON-Schema
<li>XML-Schema
<li>HTML-Schema
</ul>
<li>
<p>
Serializers/parsers require only Java 6+.
(RDF support requires Jena 2.7.1+)
</p>
<li>
<p>
REST APIs require only Java 6+ and JEE 1.3+.
(JAX/RS integration component requires JAX/RS provider)
</p>
</ol>
<h5 class='topic'>Components</h5>
<p>
Juneau ships as a single Java library called <l>juneau.jar</l>.
</p>
<p>
Juneau requires Java 6+. The majority of the code has no other dependencies except for the following packages:
</p>
<ul class='doctree'>
<li class='jp'> <a class='doclink' href='org/apache/juneau/jena/package-summary.html#TOC'>org.apache.juneau.jena</a> - RDF support. Requires Apache Jena 2.7.1+.
<li class='jp'> <a class='doclink' href='org/apache/juneau/rest/package-summary.html#TOC'>org.apache.juneau.rest</a> - REST servlet support. Requires JEE 1.3+.
<li class='jp'> <a class='doclink' href='org/apache/juneau/rest/client/package-summary.html#TOC'>org.apache.juneau.rest.client</a> - REST client support. Requires Apache HttpClient 4.5+.
</ul>
<p>
OSGi bundles are also provided that break down Juneau into the following components:
</p>
<ul class='spaced-list'>
<li><l>org.apache.juneau.core.jar</l> - Serializers, parsers, INI file support.<br>
<li><l>org.apache.juneau.rest.jar</l> - REST servlet support.<br>
<li><l>org.apache.juneau.rest.client.jar</l> - REST client support.<br>
<li><l>org.apache.juneau.microservice.jar</l> - Microservice support.<br>
</ul>
<p>
The following zip files are also provided:
</p>
<ul class='spaced-list'>
<li><l>microservice-project.zip</l> - Contains a template Eclipse project for quickly creating REST resources as executable jars.
<li><l>microservice-samples-project.zip</l> - Contains sample code demonstrating various aspects of Juneau.<br>
These are discussed in detail in the <a class='doclink' href="#Samples">Samples</a> section.
</ul>
<ul class='doctree'>
<li class='info'>
Many of the examples below use beans with public field properties instead of standard getters/setters.
This is to simplify the examples.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Core"></a>
<h2 class='topic' onclick='toggle(this)'>2 - Juneau Core (org.apache.juneau)</h2>
<div class='topic'>
<p>
The core packages of Juneau contains serializers and parsers for converting POJOs to and from a wide variety of content types.
It uses a common API for defining serializers and parsers.
</p>
<p>
One of the goals of Juneau was to make serialization as simple as possible.
In a single line of code, you should be able to serialize and parse most POJOs.
Despite this simplicity, Juneau provides lots of extensibility and configuration properties for tailoring how POJOs are serialized and parsed.
</p>
<!-- ======================================================================================================== -->
<a id="Core.Serializers"></a>
<h3 class='topic' onclick='toggle(this)'>2.1 - Serializers</h3>
<div class='topic'>
<p>
The built-in serializers in Juneau are fast, efficient, and highly configurable.
They work by serializing POJOs directly to streams instead of using intermediate Document Object Model objects.
</p>
<p>
In most cases, you can serialize objects in one line of code by using one of the default serializers:
</p>
<p class='bcode'>
<jc>// A simple bean</jc>
<jk>public class</jk> Person {
<jk>public</jk> String <jf>name</jf> = <js>"John Smith"</js>;
<jk>public int</jk> <jf>age</jf> = 21;
}
<jc>// Serialize to JSON, XML, or HTML</jc>
Person p = <jk>new</jk> Person();
<jc>// Produces:
// "{name:'John Smith',age:21}"</jc>
String json = JsonSerializer.<jsf>DEFAULT</jsf>.serialize(p);
<jc>// Produces:
// &lt;object&gt;
// &lt;name&gt;John Smith&lt;/name&gt;
// &lt;age&gt;21&lt;/age&gt;
// &lt;/object&gt;</jc>
String xml = XmlSerializer.<jsf>DEFAULT</jsf>.serialize(p);
<jc>// Produces:
// &lt;table&gt;
// &lt;tr&gt;&lt;th&gt;key&lt;/th&gt;&lt;th&gt;value&lt;/th&gt;&lt;/tr&gt;
// &lt;tr&gt;&lt;td&gt;name&lt;/td&gt;&lt;td&gt;John Smith&lt;/td&gt;&lt;/tr&gt;
// &lt;tr&gt;&lt;td&gt;age&lt;/td&gt;&lt;td&gt;21&lt;/td&gt;&lt;/tr&gt;
// &lt;/table&gt;</jc>
String html = HtmlSerializer.<jsf>DEFAULT</jsf>.serialize(p);
<jc>// Produces:
// "(name='John Smith',age=21)"</jc>
String uon = UonSerializer.<jsf>DEFAULT</jsf>.serialize(p);
<jc>// Produces:
// "name='John+Smith'&amp;age=21"</jc>
String urlencoding = UrlEncodingSerializer.<jsf>DEFAULT</jsf>.serialize(p);
<jc>// Produces:
// 82 A4 6E 61 6D 65 AA 4A 6F 68 6E 20 53 6D 69 74 68 A3 61 67 65 15 </jc>
<jk>byte</jk>[] b = MsgPackSerializer.<jsf>DEFAULT</jsf>.serialize(p);
</p>
<p>
In addition to the default serializers, customized serializers can be created using various built-in options:
</p>
<p class='bcode'>
<jc>// Use one of the default serializers to serialize a POJO</jc>
String json = JsonSerializer.<jsf>DEFAULT</jsf>.serialize(someObject);
<jc>// Create a custom serializer for lax syntax using single quote characters</jc>
JsonSerializer serializer = <jk>new</jk> JsonSerializerBuilder().simple().sq().build();
<jc>// Clone an existing serializer and modify it to use single-quotes</jc>
JsonSerializer serializer = JsonSerializer.<jsf>DEFAULT</jsf>.builder().sq().build();
<jc>// Serialize a POJO to JSON</jc>
String json = serializer.serialize(someObject);
</p>
<p>
Default serialization support is provided for Java primitives, <code>Maps</code>, <code>Collections</code>, beans, and arrays. <br>
Extensible support for other data types such as <code>Calendars</code>, <code>Dates</code>, <code>Iterators</code> is available through the use of POJO swaps (described later).
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/serializer/package-summary.html#TOC'>org.apache.juneau.serializer</a> - Serializer API Javadoc
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Core.Parsers"></a>
<h3 class='topic' onclick='toggle(this)'>2.2 - Parsers</h3>
<div class='topic'>
<p>
Parsers work by parsing input directly into POJOs instead of having to create intermediate Document Object Models.
This allows them to parse input with minimal object creation.
</p>
<p>
Like the serializers, you can often parse objects in one line of code by using one of the default parsers:
</p>
<p class='bcode'>
<jc>// Use one of the predefined parsers.</jc>
Parser parser = JsonParser.<jsf>DEFAULT</jsf>;
<jc>// Parse a JSON object as a bean.</jc>
String json = <js>"{name:'John Smith',age:21}"</js>;
Person p = parser.parse(json, Person.<jk>class</jk>);
<jc>// Or parse it into a generic Map.</jc>
Map m1 = parser.parse(json, Map.<jk>class</jk>);
<jc>// Parse a JSON string.</jc>
json = <js>"'foobar'"</js>;
String s2 = parser.parse(json, String.<jk>class</jk>);
<jc>// Parse a JSON number as a Long or Float.</jc>
json = <js>"123"</js>;
Long l3 = parser.parse(json, Long.<jk>class</jk>);
Float f3 = parser.parse(json, Float.<jk>class</jk>);
<jc>// Parse a JSON object as a HashMap&lt;String,Person&gt;.</jc>
json = <js>"{a:{name:'John Smith',age:21},b:{name:'Joe Smith',age:42}}"</js>;
Map&lt;String,Person&gt; m4 = parser.parse(json, HashMap.<jk>class</jk>, String.<jk>class</jk>, Person.<jk>class</jk>)
<jc>// Parse a JSON object as a HashMap&lt;String,LinkedList&lt;Person&gt;&gt;.</jc>
json = <js>"{a:[{name:'John Smith',age:21},{name:'Joe Smith',age:42}]}"</js>;
Map&lt;String,List&lt;Person&gt;&gt; m5 = parser.parse(json, HashMap.<jk>class</jk>, String.<jk>class</jk>, LinkedList.<jk>class</jk>, Person.<jk>class</jk>)
<jc>// Parse a JSON array of integers as a Collection of Integers or int[] array.</jc>
json = <js>"[1,2,3]"</js>;
List&lt;Integer&gt; l6 = parser.parse(json, LinkedList.<jk>class</jk>, Integer.<jk>class</jk>);
<jk>int</jk>[] i7 = parser.parse(json, <jk>int</jk>[].<jk>class</jk>);
</p>
<p>
The parsers can also be used to populating existing bean and collection objects:
</p>
<p class='bcode'>
<jc>// Use one of the predefined parsers.</jc>
Parser parser = JsonParser.<jsf>DEFAULT</jsf>;
<jc>// Populate the properties on an existing bean from a JSON object.</jc>
String json = <js>"{name:'John Smith',age:21}"</js>;
Person p = <jk>new</jk> Person();
parser.parseIntoBean(json, p);
<jc>// Populate an existing list from a JSON array of numbers.</jc>
json = <js>"[1,2,3]"</js>;
List&lt;Integer&gt; l2 = <jk>new</jk> LinkedList&lt;Integer&gt;();
parser.parseIntoCollection(json, l2, Integer.<jk>class</jk>);
<jc>// Populate an existing map from a JSON object containing beans.</jc>
json = <js>"{a:{name:'John Smith',age:21},b:{name:'Joe Smith',age:42}}"</js>;
Map&lt;String,Person&gt; m3 = <jk>new</jk> TreeMap&lt;String,Person&gt;();
parser.parseIntoMap(json, m3, String.<jk>class</jk>, Person.<jk>class</jk>);
</p>
<ul class='doctree'>
<li class='info'>
In the example above, we're parsing "lax" JSON (single quotes, unquoted attributes).
The JSON parser can handle any valid JSON syntax (such as quoted or unquoted attributes, single or double quotes).<br>
It can also handle JSON fragements and embedded Javascript comments.
Many of the JSON examples provided will use lax syntax which is easier to read since we don't have to deal with escapes.
</ul>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/parser/package-summary.html#TOC'>org.apache.juneau.parser</a> - Parser API Javadoc
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Core.SerializerAndParserGroups"></a>
<h3 class='topic' onclick='toggle(this)'>2.3 - SerializerGroups and ParserGroups</h3>
<div class='topic'>
<p>
Above the serializers and parsers are the {@link org.apache.juneau.serializer.SerializerGroup} and {@link org.apache.juneau.parser.ParserGroup} classes.
These classes allow serializers and parsers to be retrieved by W3C-compliant HTTP <code>Accept</code> and <code>Content-Type</code> values...
</p>
<p class='bcode'>
<jc>// Construct a new serializer group with configuration parameters that get applied to all serializers.</jc>
SerializerGroup sg = <jk>new</jk> SerializerGroupBuilder()
.append(JsonSerializer.<jk>class</jk>, UrlEncodingSerializer.<jk>class</jk>);
.ws <jc>// or .useWhitespace(true)</jc>
.pojoSwaps(CalendarSwap.ISO8601DT.<jk>class</jk>)
.build();
<jc>// Find the appropriate serializer by Accept type and serialize our POJO to the specified writer.</jc>
sg.getSerializer(<js>"text/invalid, text/json;q=0.8, text/*;q:0.6, *\/*;q=0.0"</js>)
.serialize(myPersonObject, myWriter);
<jc>// Construct a new parser group with configuration parameters that get applied to all parsers.</jc>
ParserGroup pg = <jk>new</jk> ParserGroupBuilder()
.append(JsonSerializer.<jk>class</jk>, UrlEncodingSerializer.<jk>class</jk>);
.pojoSwaps(CalendarSwap.ISO8601DT.<jk>class</jk>)
.build();
Person p = pg.getParser(<js>"text/json"</js>).parse(myReader, Person.<jk>class</jk>);
</p>
<p>
The REST servlet API builds upon the <code>SerializerGroup</code> and <code>ParserGroup</code> classes
to provide annotated REST servlets that automatically negotiate the HTTP media types and allow the developer
to work with requests and responses as POJOs.
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.serializer.SerializerGroup}
<li class='jc'>{@link org.apache.juneau.parser.ParserGroup}
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Core.ObjectMap"></a>
<h3 class='topic' onclick='toggle(this)'>2.4 - ObjectMap and ObjectList</h3>
<div class='topic'>
<p>
The {@link org.apache.juneau.ObjectMap} and {@link org.apache.juneau.ObjectList} classes are generic Java representations of JSON objects and arrays.
These classes can be used to create "unstructured" models for serialization (as opposed to "structured" models consisting of beans).
If you want to quickly generate JSON/XML/HTML from generic maps/collections, or parse JSON/XML/HTML into generic maps/collections, these classes work well.
</p>
<p>
These classes extend directly from the following JCF classes:
</p>
<ul class='doctree'>
<li class='jc'> {@link java.util.LinkedHashMap java.util.LinkedHashMap}
<ul>
<li class='jc'> {@link org.apache.juneau.ObjectMap org.apache.juneau.ObjectMap}
</ul>
<li class='jc'> {@link java.util.LinkedList java.util.LinkedList}
<ul>
<li class='jc'> {@link org.apache.juneau.ObjectMap org.apache.juneau.ObjectList}
</ul>
</ul>
<p>
The <l>ObjectMap</l> and <l>ObjectList</l> classes are very similar to the <l>JSONObject</l> and <l>JSONArray</l>
classes found in other libraries. However, the names were chosen
because the concepts of <l>Maps</l> and <l>Lists</l> are already familiar to
Java programmers, and these classes can be used with any of the serializers or parsers.
</p>
<p>
These object can be serialized in one of two ways:
</p>
<ol class='spaced-list'>
<li>Using the provided {@link org.apache.juneau.ObjectMap#serializeTo(java.io.Writer)} or {@link org.apache.juneau.ObjectList#serializeTo(java.io.Writer)} methods.
<li>Passing them to one of the {@link org.apache.juneau.serializer.Serializer} serialize methods.
</ol>
<p>
Any valid JSON can be parsed into an unstructured model consisting of generic {@link org.apache.juneau.ObjectMap} and {@link org.apache.juneau.ObjectList} objects.
</p>
<p class='bcode'>
<jc>// Parse an arbitrary JSON document into an unstructered data model
// consisting of ObjectMaps, ObjectLists, and java primitive objects.</jc>
Parser parser = JsonParser.<jsf>DEFAULT</jsf>;
String json = <js>"{a:{name:'John Smith',age:21},b:{name:'Joe Smith',age:42}}"</js>;
ObjectMap m = parser.parse(json, ObjectMap.<jk>class</jk>);
<jc>// Use ObjectMap API to extract data from the unstructured model.</jc>
<jk>int</jk> johnSmithAge = m.getObjectMap(<js>"a"</js>).getInt(<js>"age"</js>);
<jc>// Convert it back into JSON.</jc>
json = JsonSerializer.<jsf>DEFAULT</jsf>.serialize(m);
<jc>// Or convert it to XML.</jc>
String xml = XmlSerializer.<jsf>DEFAULT</jsf>.serialize(m);
</p>
<ul class='doctree'>
<li class='info'>
As a general rule, if you do not specify a target type during parsing, or if the target type cannot be determined
through reflection, the parsers automatically generate <l>ObjectMaps</l> and <l>ObjectLists</l>.
</ul>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.ObjectMap}
<li class='jc'>{@link org.apache.juneau.ObjectList}
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Core.ConfigurableProperties"></a>
<h3 class='topic' onclick='toggle(this)'>2.5 - Configurable Properties</h3>
<div class='topic'>
<p>
Serializers and parsers have a wide variety of configurable properties.<br>
For example, the following code shows how to configure a JSON serializer:
</p>
<p class='bcode'>
JsonSerializer s = <jk>new</jk> JsonSerializerBuilder().simple().ws().sq().build();
</p>
<p>
However, each of the serializers and parsers already contain reusable instances with common configurations.<br>
For example, JSON has the following predefined reusable serializers and parsers:
</p>
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.json.JsonSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.json.JsonSerializer#DEFAULT DEFAULT}
<li class='jf'>{@link org.apache.juneau.json.JsonSerializer#DEFAULT_LAX DEFAULT_LAX}
<li class='jf'>{@link org.apache.juneau.json.JsonSerializer#DEFAULT_READABLE DEFAULT_READABLE}
<li class='jf'>{@link org.apache.juneau.json.JsonSerializer#DEFAULT_LAX_READABLE DEFAULT_LAX_READABLE}
</ul>
<li class='jc'>{@link org.apache.juneau.json.JsonParser}
<ul>
<li class='jf'>{@link org.apache.juneau.json.JsonParser#DEFAULT DEFAULT}
<li class='jf'>{@link org.apache.juneau.json.JsonParser#DEFAULT_STRICT DEFAULT_STRICT}
</ul>
</ul>
<p>
These can be used directly, as follows:
</p>
<p class='bcode'>
<jc>// Serialize a POJO to LAX JSON.</jc>
String json = JsonSerializer.<jsf>DEFAULT_LAX</jsf>.serialize(myPojo);
</p>
<p>
Serializers and parsers can be locked to prevent further modification to the properties.
They can also be cloned to copy the configuration of other serializers and parsers.
</p>
<p class='bcode'>
<jc>// Clone and customize an existing serializer.</jc>
JsonSerializer s = JsonSerializer.<jsf>DEFAULT_LAX</jsf>
.builder()
.quoteChar(<js>'"'</js>)
.build();
<jc>// Lock it so that the configuration cannot be changed.</jc>
s.lock();
</p>
<h6 class='topic'>Additional Information</h6>
<p>
The following is a list of all configurable properties across all serializers and parsers.
</p>
<ul class='doctree'>
<li class='jc'><a class='doclink' href='org/apache/juneau/BeanContext.html#ConfigProperties'>BeanContext</a> - Properties associated with handling beans on serializers and parsers.
<ul>
<li class='jc'><a class='doclink' href='org/apache/juneau/serializer/SerializerContext.html#ConfigProperties'>SerializerContext</a> - Configurable properties common to all serializers.
<ul>
<li class='jc'><a class='doclink' href='org/apache/juneau/html/HtmlSerializerContext.html#ConfigProperties'>HtmlSerializerContext</a> - Configurable properties on the HTML serializer.
<ul>
<li class='jc'><a class='doclink' href='org/apache/juneau/html/HtmlDocSerializerContext.html#ConfigProperties'>HtmlDocSerializerContext</a> - Configurable properties on the HTML document serializer.
</ul>
<li class='jic'><a class='doclink' href='org/apache/juneau/jena/RdfCommonContext.html#ConfigProperties'>RdfCommonContext</a> - Configurable properties common to the RDF serializers and parsers.
<ul>
<li class='jc'><a class='doclink' href='org/apache/juneau/jena/RdfSerializerContext.html#ConfigProperties'>RdfSerializerContext</a> - Configurable properties on the RDF serializers.
</ul>
<li class='jc'><a class='doclink' href='org/apache/juneau/json/JsonSerializerContext.html#ConfigProperties'>JsonSerializerContext</a> - Configurable properties on the JSON serializer.
<li class='jc'><a class='doclink' href='org/apache/juneau/msgpack/MsgPackSerializerContext.html#ConfigProperties'>MsgPackSerializerContext</a> - Configurable properties on the MessagePack serializer.
<li class='jc'><a class='doclink' href='org/apache/juneau/soap/SoapXmlSerializerContext.html#ConfigProperties'>SoapXmlSerializerContext</a> - Configurable properties on the SOAP/XML serializer.
<li class='jc'><a class='doclink' href='org/apache/juneau/urlencoding/UonSerializerContext.html#ConfigProperties'>UonSerializerContext</a> - Configurable properties on the URL-Encoding and UON serializers.
<li class='jc'><a class='doclink' href='org/apache/juneau/xml/XmlSerializerContext.html#ConfigProperties'>XmlSerializerContext</a> - Configurable properties on the XML serializer.
</ul>
<li class='jc'><a class='doclink' href='org/apache/juneau/parser/ParserContext.html#ConfigProperties'>ParserContext</a> - Configurable properties common to all parsers.
<ul>
<li class='jc'><a class='doclink' href='org/apache/juneau/html/HtmlParserContext.html#ConfigProperties'>HtmlParserContext</a> - Configurable properties on the HTML parser.
<li class='jic'><a class='doclink' href='org/apache/juneau/jena/RdfCommonContext.html#ConfigProperties'>RdfCommonContext</a> - Configurable properties common to the RDF serializers and parsers.
<ul>
<li class='jc'><a class='doclink' href='org/apache/juneau/jena/RdfParserContext.html#ConfigProperties'>RdfParserContext</a> - Configurable properties on the RDF parsers.
</ul>
<li class='jc'><a class='doclink' href='org/apache/juneau/json/JsonParserContext.html#ConfigProperties'>JsonParserContext</a> - Configurable properties on the JSON parser.
<li class='jc'><a class='doclink' href='org/apache/juneau/msgpack/MsgPackParserContext.html#ConfigProperties'>MsgPackParserContext</a> - Configurable properties on the MessagePack parser.
<li class='jc'><a class='doclink' href='org/apache/juneau/urlencoding/UonParserContext.html#ConfigProperties'>UonParserContext</a> - Configurable properties on the URL-Encoding and UON parsers.
<li class='jc'><a class='doclink' href='org/apache/juneau/xml/XmlParserContext.html#ConfigProperties'>XmlParserContext</a> - Configurable properties on the XML parser.
</ul>
</ul>
<li class='jc'><a class='doclink' href='org/apache/juneau/server/RestContext.html#ConfigProperties'>RestContext</a> - Configurable properties on the REST servlet.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Core.Transforms"></a>
<h3 class='topic' onclick='toggle(this)'>2.6 - Transforms</h3>
<div class='topic'>
<p>
By default, the Juneau framework can serialize and parse a wide variety of POJOs out-of-the-box.
However, two special classes are provided tailor how certain Java objects are handled by the framework.
These classes are:
</p>
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.transform.PojoSwap} - Tailor how specific non-bean classes are handled by the framework.
<li class='jc'>{@link org.apache.juneau.transform.BeanFilter} - Tailor how specific bean classes are handled by the framework.
</ul>
<p>
Annotations are also provided that allow you to use transformations directly on class definitions:
</p>
<ul class='doctree'>
<li class='ja'>{@link org.apache.juneau.annotation.Pojo @Pojo} - Used to tailor how non-bean POJOs get interpreted by the framework.
<li class='ja'>{@link org.apache.juneau.annotation.Bean @Bean} - Used to tailor how beans get interpreted by the framework.
<li class='ja'>{@link org.apache.juneau.annotation.BeanConstructor @BeanConstructor} - Maps constructor arguments to property names on beans with read-only properties.
<li class='ja'>{@link org.apache.juneau.annotation.BeanIgnore @BeanIgnore} - Ignore classes, fields, and methods from being interpreted as bean or bean components.
<li class='ja'>{@link org.apache.juneau.annotation.BeanProperty @BeanProperty} - Used to tailor how bean properties get interpreted by the framework.
<li class='ja'>{@link org.apache.juneau.annotation.NameProperty @NameProperty} - Identifies a setter as a method for setting the name of a POJO as it's known by its parent object.
<li class='ja'>{@link org.apache.juneau.annotation.ParentProperty @ParentProperty} - Identifies a setter as a method for adding a parent reference to a child object.
<li class='ja'>{@link org.apache.juneau.annotation.URI @URI} - Used to identify a class or bean property as a URI.
</ul>
<!-- ======================================================================================================== -->
<a id="Core.PojoSwaps"></a>
<h4 class='topic' onclick='toggle(this)'>2.6.1 - PojoSwaps</h4>
<div class='topic'>
<p>
{@link org.apache.juneau.transform.PojoSwap PojoSwaps} are a critical component of Juneau.
They allow the serializers and parsers to handle Java objects that wouldn't normally be serializable.
</p>
<p>
Swaps are very easy to understand.
Simply put, they can be thought of as 'object swappers' that swap in serializable objects for non-serializable ones during serialization, and vis-versa during parsing.
</p>
<p>
Some examples of non-serializable POJOs are <code>File</code>, <code>Reader</code>, <code>Iterable</code>, etc...
These are classes that aren't beans and cannot be represented as simple maps, collections, or primitives.
</p>
<p>
In the following example, we introduce a <code>PojoSwap</code> that will swap in ISO8601 strings for <code>Date</code> objects:
</p>
<p class='bcode'>
<jc>// Sample swap for converting Dates to ISO8601 strings.</jc>
<jk>public class</jk> MyDateSwap <jk>extends</jk> PojoSwap&lt;Date,String&gt; {
<jc>// ISO8601 formatter.</jc>
<jk>private</jk> DateFormat <jf>format</jf> = <jk>new</jk> SimpleDateFormat(<js>"yyyy-MM-dd'T'HH:mm:ssZ"</js>);
<jd>/** Converts a Date object to an ISO8601 string. */</jd>
<ja>@Override</ja>
<jk>public</jk> String swap(BeanSession session, Date o) {
<jk>return</jk> <jf>format</jf>.format(o);
}
<jd>/** Converts an ISO8601 string to a Date object. */</jd>
<ja>@Override</ja>
<jk>public</jk> Date unswap(BeanSession session, String o, ClassMeta hint) <jk>throws</jk> ParseException {
<jk>try</jk> {
<jk>return</jk> <jf>format</jf>.parse(o);
} <jk>catch</jk> (java.text.ParseException e) {
<jk>throw new</jk> ParseException(e);
}
}
}
</p>
<p>
The swap can then be associated with serializers and parsers like so:
</p>
<p class='bcode'>
<jc>// Sample bean with a Date field.</jc>
<jk>public class</jk> MyBean {
<jk>public</jk> Date <jf>date</jf> = <jk>new</jk> Date(112, 2, 3, 4, 5, 6);
}
<jc>// Create a new JSON serializer, associate our date swap with it, and serialize a sample bean.</jc>
Serializer serializer = <jk>new</jk> JsonSerializerBuilder().pojoSwaps(MyDateSwap.<jk>class</jk>).build();
String json = serializer.serialize(<jk>new</jk> MyBean()); <jc>// == "{date:'2012-03-03T04:05:06-0500'}"</jc>
<jc>// Create a JSON parser, associate our date swap with it, and reconstruct our bean (including the date).</jc>
ReaderParser parser = <jk>new</jk> JsonParserBuilder().pojoSwaps(MyDateSwap.<jk>class</jk>).build();
MyBean bean = parser.parse(json, MyBean.<jk>class</jk>);
<jk>int</jk> day = bean.<jf>date</jf>.getDay(); <jc>// == 3</jc>
</p>
<p>
Several <code>PojoSwaps</code> are already provided for common Java objects:
</p>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/transforms/package-summary.html#TOC'>org.apache.juneau.transforms</a>
<ul>
<li class='jc'>{@link org.apache.juneau.transforms.ByteArrayBase64Swap}
<li class='jac'>{@link org.apache.juneau.transforms.CalendarSwap}
<li class='jac'>{@link org.apache.juneau.transforms.DateSwap}
<li class='jc'>{@link org.apache.juneau.transforms.EnumerationSwap}
<li class='jc'>{@link org.apache.juneau.transforms.IteratorSwap}
<li class='jc'>{@link org.apache.juneau.transforms.ReaderSwap}
<li class='jc'>{@link org.apache.juneau.transforms.XMLGregorianCalendarSwap}
</ul>
</ul>
<p>
In particular, the {@link org.apache.juneau.transforms.CalendarSwap} and {@link org.apache.juneau.transforms.DateSwap} tramsforms
provide a large number of customized swaps to ISO, RFC, or localized strings.
</p>
<ul class='doctree'>
<li class='info'>
The 'swapped' class type must be a serializable type.<br>
See the definition for Category 4 objects in <a class='doclink' href='#Core.PojoCategories'>POJO Categories</a>.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Core.SwapMethods"></a>
<h4 class='topic' onclick='toggle(this)'>2.6.2 - Swap methods</h4>
<div class='topic'>
<p>
Various methods can be defined on a class directly to affect how it gets serialized.
This can often be simpler than using <code>PojoSwaps</code>.
</p>
<p>
Objects serialized as <code>Strings</code> can be parsed back into their original objects by implementing
one of the following methods on the class:
</p>
<ul>
<li><code><jk>public static</jk> T fromString(String)</code> method.<br>
Any of the following method names also work:
<ul>
<li><code>valueOf(String)</code>
<li><code>parse(String)</code>
<li><code>parseString(String)</code>
<li><code>forName(String)</code>
<li><code>forString(String)</code>
</ul>
<li><code><jk>public</jk> T(String)</code> constructor.
</ul>
<p>
Note that these methods cover conversion from several built-in Java types, meaning the parsers can automatically construct these objects from strings:
</p>
<ul>
<li><code>fromString(String)</code> - {@link java.util.UUID}
<li><code>valueOf(String)</code> - {@link java.lang.Boolean}, {@link java.lang.Byte}, {@link java.lang.Double}, {@link java.lang.Float},
{@link java.lang.Integer}, {@link java.lang.Long}, {@link java.lang.Short}, {@link java.sql.Date}, {@link java.sql.Time}, {@link java.sql.Timestamp}
<li><code>parse(String)</code> - {@link java.text.DateFormat}, {@link java.text.MessageFormat}, {@link java.text.NumberFormat}, {@link java.util.Date}, {@link java.util.logging.Level}
<li><code>parseString(String)</code> - {@link javax.xml.bind.DatatypeConverter}
<li><code>forName(String)</code> - {@link java.lang.Class}
</ul>
<p>
If you want to force a bean-like class to be serialized as a string, you can use the {@link org.apache.juneau.annotation.BeanIgnore @BeanIgnore}
annotation on the class to force it to be serialized to a string using the <code>toString()</code> method.
</p>
<p>
Serializing to other intermediate objects can be accomplished by defining a swap method directly on the class:
</p>
<ul>
<li><code><jk>public</jk> X swap(BeanSession)</code> method, where <code>X</code> is any serializable object.
</ul>
<p>
The <code>BeanSession</code> parameter allows you access to various information about the current serialization session.
For example, you could provide customized results based on the media type being produced ({@link org.apache.juneau.BeanSession#getMediaType()}).
</p>
<p>
The following example shows how an HTML5 form template object can be created that gets serialized as a populated HTML5 {@link org.apache.juneau.dto.html5.Form} bean.
</p>
<p class='bcode'>
<jk>import static</jk> org.apache.juneau.dto.html5.HtmlBuilder.*;
<jd>/**
* A simple HTML form template whose serialized form is an HTML5 Form object.
*/</jd>
<jk>public class</jk> FormTemplate {
<jk>private</jk> String <jf>action</jf>;
<jk>private int</jk> <jf>value1</jf>;
<jk>private boolean</jk> <jf>value2</jf>;
<jc>// Some constructor that initializes our fields. </jc>
<jk>public</jk> FormTemplate(String action, <jk>int</jk> value1, <jk>boolean</jk> value2) {
<jk>this</jk>.<jf>action</jf> = action;
<jk>this</jk>.<jf>value1</jf> = value1;
<jk>this</jk>.<jf>value2</jf> = value2;
}
<jc>// Special swap method that converts this template to a serializable bean</jc>
<jk>public</jk> Form swap(BeanSession session) {
<jk>return</jk> <jsm>form</jsm>(<jf>action</jf>,
<jsm>input</jsm>(<js>"text"</js>).name(<js>"v1"</js>).value(<jf>value1</jf>),
<jsm>input</jsm>(<js>"text"</js>).name(<js>"v2"</js>).value(<jf>value2</jf>)
);
}
}
</p>
<p>
Swapped objects can be converted back into their original form by the parsers by specifying one of the following methods:
</p>
<ul>
<li><code><jk>public static</jk> T unswap(BeanSession, X)</code> method where <code>X</code> is the swap class type.
<li><code><jk>public</jk> T(X)</code> constructor where <code>X</code> is the swap class type.
</ul>
<p>
The following shows how our form template class can be modified to allow the parsers to reconstruct our original object:
</p>
<p class='bcode'>
<jk>import static</jk> org.apache.juneau.dto.html5.HtmlBuilder.*;
<jd>/**
* A simple HTML form template whose serialized form is an HTML5 Form object.
* This time with parsing support.
*/</jd>
<ja>@Bean</ja>(beanDictionary=HtmlBeanDictionary.<jk>class</jk>)
<jk>public class</jk> FormTemplate {
<jk>private</jk> String <jf>action</jf>;
<jk>private int</jk> <jf>value1</jf>;
<jk>private boolean</jk> <jf>value2</jf>;
<jc>// Our 'unswap' constructor</jc>
<jk>public</jk> FormTemplate(Form f) {
<jk>this</jk>.<jf>action</jf> = f.getAttr(<js>"action"</js>);
<jk>this</jk>.<jf>value1</jf> = f.getChild(Input.<jk>class</jk>, 0).getAttr(<jk>int</jk>.<jk>class</jk>, <js>"value"</js>);
<jk>this</jk>.<jf>value2</jf> = f.getChild(Input.<jk>class</jk>, 1).getAttr(<jk>boolean</jk>.<jk>class</jk>, <js>"value"</js>);
}
<jk>public</jk> FormTemplate(String action, <jk>int</jk> value1, <jk>boolean</jk> value2) {
<jk>this</jk>.<jf>action</jf> = action;
<jk>this</jk>.<jf>value1</jf> = value1;
<jk>this</jk>.<jf>value2</jf> = value2;
}
<jk>public</jk> Form swap(BeanSession session) {
<jk>return</jk> <jsm>form</jsm>(<jf>action</jf>,
<jsm>input</jsm>(<js>"text"</js>).name(<js>"v1"</js>).value(<jf>value1</jf>),
<jsm>input</jsm>(<js>"text"</js>).name(<js>"v2"</js>).value(<jf>value2</jf>)
);
}
}
</div>
<!-- ======================================================================================================== -->
<a id="Core.BeanFilters"></a>
<h4 class='topic' onclick='toggle(this)'>2.6.3 - BeanFilters and @Bean annotations</h4>
<div class='topic'>
<p>
{@link org.apache.juneau.transform.BeanFilter BeanFilters} are used to control aspects of how beans are handled during serialization and parsing.
They allow you to control various aspects of beans, such as...
</p>
<ul>
<li>Which properties to include or exclude.
<li>Property order.
<li>Property naming conventions.
<li>Overriding reading and writing of properties.
</ul>
<p>
In practice, however, it's simpler to use the {@link org.apache.juneau.annotation.Bean @Bean} and {@link org.apache.juneau.annotation.BeanProperty @BeanProperty}
annotations on your bean classes.
The annotations are functionally equivalent to the bean filter class.
</p>
<p class='bcode'>
<jc>// Address class with only street/city/state properties (in that order).</jc>
<jc>// All other properties are ignored.</jc>
<ja>@Bean</ja>(properties=<js>"street,city,state"</js>)
<jk>public class</jk> Address {
...
</p>
<p>
Bean filters are defined through {@link org.apache.juneau.transform.BeanFilterBuilder BeanFilterBuilders}.
The programmatic equivalent to the the annotation above would be:
</p>
<p class='bcode'>
<jk>public class</jk> MyAddressBeanFilter <jk>extends</jk> BeanFilterBuilder {
<jc>// Must provide a no-arg constructor!</jc>
<jk>public</jk> MyAddressBeanFilter() {
<jk>super</jk>(Address.<jk>class</jk>); <jc>// The bean class that this filter applies to.</jc>
setIncludeProperties(<js>"street,city,state"</js>); <jc>// The properties we want exposed.</jc>
}
}
</p>
<p>
Bean filters are added to serializers and parsers using the <code>*BeanFilters(Class...)</code> methods.
For example:
</p>
<p class='bcode'>
<jc>// Create a new JSON serializer and associate a bean filter with it.</jc>
Serializer serializer = <jk>new</jk> JsonSerializerBuilder().beanFilters(MyAddressBeanFilter.<jk>class</jk>).build();
</p>
<p>
Note that if you use the annotation, you do NOT need to set anything on the serializers/parsers.
The annotations will be detected and bean filters will automatically be created for them.
</p>
<p>
The <code>addBeanFilter(Class...)</code> method also allows you to pass in interfaces.
Any class that's not a subclass of {@link org.apache.juneau.transform.BeanFilterBuilder} get interpreted
as bean interface classes.
These cause bean implementations of those interfaces to only expose the properties defined on the interface.
</p>
<p class='bcode'>
<jc>// An interface with the 3 properties we want serialized.</jc>
<jk>public interface</jk> AddressInterface {
<jk>public</jk> String getStreet();
<jk>public</jk> String getCity();
<jk>public</jk> String getState();
}
<jc>// Our bean implementation.</jc>
<jk>public class</jk> Address <jk>implements</jk> AddressInterface {
...
}
<jc>// Create a new JSON serializer that only exposes street,city,state on Address bean.</jc>
Serializer serializer = <jk>new</jk> JsonSerializerBuilder().beanFilters(AddressInterface.<jk>class</jk>).build();
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/transform/package-summary.html#TOC'>org.apache.juneau.transform</a>
</ul>
</div>
</div>
<!-- ======================================================================================================== -->
<a id="Core.BeanDictionaries"></a>
<h3 class='topic' onclick='toggle(this)'>2.7 - Bean Names and Dictionaries</h3>
<div class='topic'>
<p>
While parsing into beans, Juneau attempts to determine the class types of bean properties through reflection on the bean property getter or setter.
Often this is insufficient if the property type is an interface or abstract class that cannot be instantiated.
This is where bean names and dictionaries come into play.
</p>
<p>
Bean names and dictionary are used for identifying class types when they cannot be inferred through reflection.
</p>
<p>
Bean classes are given names through the {@link org.apache.juneau.annotation.Bean#typeName() @Bean.typeName()} annotation.
These names are then added to the serialized output as virtual <js>"_type"</js> properties (or element names in XML).
</p>
<p>
On the parsing side, these type names are resolved to classes through the use of bean dictionaries.
</p>
<p>
For example, if a bean property is of type <code>Object</code>, then the serializer will add <js>"_type"</js> attributes so that the class can be determined during parsing.
</p>
<p class='bcode'>
<ja>@Bean</ja>(typeName=<js>"foo"</js>)
<jk>public class</jk> Foo {
<jc>// A bean property where the object types cannot be inferred since it's an Object[].</jc>
<ja>@BeanProperty</ja>(typeDictionary={Bar.<jk>class</jk>,Baz.<jk>class</jk>})
<jk>public</jk> Object[] x = <jk>new</jk> Object[]{<jk>new</jk> Bar(), <jk>new</jk> Baz()};
}
<ja>@Bean</ja>(typeName=<js>"bar"</js>)
<jk>public class</jk> Bar {}
<ja>@Bean</ja>(typeName=<js>"baz"</js>)
<jk>public class</jk> Baz {}
</p>
<p>
When serialized as JSON, <js>"_type"</js> attributes would be added when needed to infer the type during parsing:
</p>
<p class='bcode'>
{
x: [
{_type:<js>'bar'</js>},
{_type:<js>'baz'</js>}
]
}
</p>
<p>
Type names can be represented slightly differently in different languages.
For example, the dictionary name is used as element names when serialized to XML.
This allows the <code>typeName</code> annotation to be used as a shortcut for defining element names for beans.
</p>
<p>
When serialized as XML, the bean is rendered as:
</p>
<p class='bcode'>
<xt>&lt;foo&gt;</xt>
<xt>&lt;x&gt;</xt>
<xt>&lt;bar/&gt;</xt>
<xt>&lt;baz/&gt;</xt>
<xt>&lt;/x&gt;</xt>
<xt>&lt;/foo&gt;</xt>
</p>
<p>
Bean dictionaries are defined at two levels:
</p>
<ul>
<li>On individual bean properties through the {@link org.apache.juneau.annotation.BeanProperty#beanDictionary() @BeanProperty.beanDictionary()} annotation.
<li>Globally for a parser using the {@link org.apache.juneau.parser.ParserBuilder#beanDictionary(Class...)} method.
</ul>
<ul class='doctree'>
<li class='info'>
Type names do not need to be universally unique.
However, they must be unique within a dictionary.
<li class='info'>
The following reserved words cannot be used as type names: <code>object, array, number, boolean, null</code>.
<li class='info'>
Serialized type names are DISABLED by default.
They must be enabled on the serializer using the {@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_addBeanTypeProperties} configuration property.
<li class='info'>
The <js>"_type"</js> property name can be overridden using the {@link org.apache.juneau.BeanContext#BEAN_beanTypePropertyName} configuration property.
</ul>
<!-- ======================================================================================================== -->
<a id="Core.BeanSubTypes"></a>
<h4 class='topic' onclick='toggle(this)'>2.7.1 - Bean Subtypes</h4>
<div class='topic'>
<p>
In addition to the bean type name support described above, simplified support is provided
for bean subtypes.
</p>
<p>
Bean subtypes are similar in concept to bean type names, except for the following differences:
</p>
<ul>
<li>You specify the list of possible subclasses through an annotation on a parent bean class.
<li>You do not need to register the subtype classes on the bean dictionary of the parser.
</ul>
<p>
In the following example, the abstract class has two subclasses:
</p>
<p class='bcode'>
<jc>// Abstract superclass</jc>
<ja>@Bean</ja>(
beanDictionary={A1.<jk>class</jk>, A2.<jk>class</jk>}
)
<jk>public abstract class</jk> A {
<jk>public</jk> String <jf>f0</jf> = <js>"f0"</js>;
}
<jc>// Subclass 1</jc>
<ja>@Bean</ja>(typeName=<js>"A1"</js>)
<jk>public class</jk> A1 <jk>extends</jk> A {
<jk>public</jk> String <jf>f1</jf>;
}
<jc>// Subclass 2</jc>
<ja>@Bean</ja>(typeName=<js>"A2"</js>)
<jk>public class</jk> A2 <jk>extends</jk> A {
<jk>public</jk> String <jf>f2</jf>;
}
</p>
<p>
When serialized, the subtype is serialized as a virtual <js>"_type"</js> property:
</p>
<p class='bcode'>
JsonSerializer s = JsonSerializer.<jsf>DEFAULT_LAX</jsf>;
A1 a1 = <jk>new</jk> A1();
a1.<jf>f1</jf> = <js>"f1"</js>;
String r = s.serialize(a1);
<jsm>assertEquals</jsm>(<js>"{_type:'A1',f1:'f1',f0:'f0'}"</js>, r);
</p>
<p>
The following shows what happens when parsing back into the original object.
</p>
<p class='bcode'>
JsonParser p = JsonParser.<jsf>DEFAULT</jsf>;
A a = p.parse(r, A.<jk>class</jk>);
<jsm>assertTrue</jsm>(a <jk>instanceof</jk> A1);
</p>
</div>
</div>
<!-- ======================================================================================================== -->
<a id="Core.VirtualBeans"></a>
<h3 class='topic' onclick='toggle(this)'>2.8 - Virtual Beans</h3>
<div class='topic'>
<p>
The {@link org.apache.juneau.BeanContext#BEAN_useInterfaceProxies} setting (enabled by default) allows
the Juneau parsers to parse content into virtual beans (bean interfaces without implementation classes).
</p>
<p>
For example, the following code creates an instance of the specified unimplemented interface:
</p>
<p class='bcode'>
<jc>// Our unimplemented interface</jc>
<jk>public interface</jk> Address {
String getStreet();
<jk>void</jk> setStreet(String x);
String getCity();
<jk>void</jk> setCity(String x);
StateEnum getState();
<jk>void</jk> setState(StateEnum x);
<jk>int</jk> getZip();
<jk>void</jk> setZip(<jk>int</jk> zip);
}
<jc>// Our code</jc>
Address address = JsonParser.<jsf>DEFAULT</jsf>.parse(
<js>"{street:'123 Main St', city:'Anywhere', state:'PR', zip:12345}"</js>,
Address.<jk>class</jk>
);
<jk>int</jk> zip = address.getZip();
address.setState(StateEnum.<jsf>NY</jsf>);
</p>
<p>
Getter and setter values can be any parsable values, even other virtual beans.
</p>
<p>
Under-the-covers, a virtual bean is simply a proxy interface on top of an existing <code>BeanMap</code>
instance. From a programmatic point-of-view, they're indistinguishable from real beans, and can be
manipulated and serialized like any other bean.
</p>
<p>
Virtual beans can also be created programmatically using the <code>BeanContext</code> class:
</p>
<p class='bcode'>
Address address = BeanContext.<jsf>DEFAULT</jsf>.createSession().newBean(Address.<jk>class</jk>);
</p>
</div>
<!-- ======================================================================================================== -->
<a id="Core.PojoCategories"></a>
<h3 class='topic' onclick='toggle(this)'>2.9 - POJO Categories</h3>
<div class='topic'>
<p>
The following chart shows POJOs categorized into groups and whether they can be serialized or parsed:
</p>
<table class='styled' style='border-collapse: collapse;'>
<tr><th>Group</th><th>Description</th><th>Examples</th><th>Can<br>serialize?</th><th>Can<br>parse?</th></tr>
<tr class='dark bb' style='background-color:lightyellow;'>
<td style='text-align:center'>1</td>
<td><b>Java primitive objects</b></td>
<td>
<ul class='normal'>
<li>{@code String}
<li>{@code Integer}
<li>{@code Float}
<li>{@code Boolean}
</ul>
</td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
</tr>
<tr class='dark bb' style='background-color:lightyellow'>
<td style='text-align:center'>2</td>
<td><b>Java Collections Framework objects and Java arrays</b></td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr class='light bb'>
<td style='text-align:center'>2a</td>
<td>
<b>With standard keys/values</b><br>
Map keys are group [1, 4a, 5a] objects.<br>
Map, Collection, and array values are group [1, 2, 3ac, 4a, 5a] objects.
</td>
<td>
<ul class='normal'>
<li><code>HashSet&lt;String,Integer&gt;</code>
<li><code>TreeMap&lt;Integer,Bean&gt;</code>
<li><code>List&lt;<jk>int</jk>[][]&gt;</code>
<li><code>Bean[]</code>
</ul>
</td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
</tr>
<tr class='light bb'>
<td style='text-align:center'>2b</td>
<td>
<b>With non-standard keys/values</b><br>
Map keys are group [2, 3, 4b, 5b, 6] objects.<br>
Map, Collection, and array values are group [3b, 4b, 5b, 6] objects.
</td>
<td>
<ul class='normal'>
<li><code>HashSet&lt;Bean,Integer&gt;</code>
<li><code>TreeMap&lt;Integer,Reader&gt;</code>
</ul>
</td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
<td style='background-color:salmon;text-align:center'><b>no</b></td>
</tr>
<tr class='dark bb' style='background-color:lightyellow'>
<td style='text-align:center'>3</td>
<td><b>Java Beans</b></td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr class='light bb'>
<td style='text-align:center'>3a</td>
<td>
<b>With standard properties</b><br>
These are beans that have no-arg constructors and one or more properties defined by public getter and setter methods or public fields.<br>
Property values are group [1, 2, 3ac, 4a, 5a] objects.
</td>
<td>&nbsp;</td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
</tr>
<tr class='light bb'>
<td style='text-align:center'>3b</td>
<td>
<b>With non-standard properties or not true beans</b><br>
These include true beans that have no-arg constructors and one or more properties defined by getter and setter methods or properties,
but property types include group [3b, 4b, 5b, 6] objects.<br>
This also includes classes that look like beans but aren't true beans.
For example, classes that have getters but not setters, or classes without no-arg constructors.
</td>
<td>&nbsp;</td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
<td style='background-color:salmon;text-align:center'><b>no</b></td>
</tr>
<tr class='light bb'>
<td style='text-align:center'>3c</td>
<td>
<b>Virtual beans</b><br>
These are unimplemented bean interfaces with properties of type [1, 2, 3ac, 4a, 5a] objects.<br>
Parsers will automatically create interface proxies on top of BeanMap instances.
</td>
<td>&nbsp;</td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
</tr>
<tr class='dark bb' style='background-color:lightyellow'>
<td style='text-align:center'>4</td>
<td>
<b>Swapped objects</b><br>
These are objects that are not directly serializable, but have {@link org.apache.juneau.transform.PojoSwap PojoSwaps} associated with them.
The purpose of a POJO swap is to convert an object to another object that is easier to serialize and parse.
For example, the {@link org.apache.juneau.transforms.DateSwap.ISO8601DT} class can be used to serialize {@link java.util.Date} objects
to ISO8601 strings, and parse them back into {@link java.util.Date} objects.
</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr class='light bb'>
<td style='text-align:center'>4a</td>
<td>
<b>2-way swapped to group [1, 2a, 3ac] objects</b><br>
For example, a swap that converts a {@code Date} to a {@code String}.
</td>
<td>
<ul class='normal'>
<li><code>java.util.Date</code>
<li><code>java.util.GregorianCalendar</code>
</ul>
</td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
</tr>
<tr class='light bb'>
<td style='text-align:center'>4b</td>
<td>
<b>1-way swapped to group [1, 2, 3] objects</b><br>
For example, a swap that converts an {@code Iterator} to a {@code List}.
This would be one way, since you cannot reconstruct an {@code Iterator}.
</td>
<td>
<ul class='normal'>
<li><code>java.util.Iterator</code>
</ul>
</td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
<td style='background-color:salmon;text-align:center'><b>no</b></td>
</tr>
<tr class='dark bb' style='background-color:lightyellow'>
<td style='text-align:center'>5</td>
<td>
<b>Non-serializable objects with standard methods for converting to a serializable form</b><br>
</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr class='light bb' style='background-color:lightyellow'>
<td style='text-align:center'>5a</td>
<td>
Classes with a method that converts it to a serializable form:
<ul>
<li><code><jk>public</jk> X swap(BeanSession);</code> where <code>X</code> is in groups [1, 2a, 3ac].
<li><code><jk>public</jk> String toString();</code> where the string is any meaningful data.
</ul>
And a method that converts it back into the original object:
<ul>
<li><code><jk>public static</jk> T fromString(String);</code>
<li><code><jk>public static</jk> T valueOf(String);</code>
<li><code><jk>public static</jk> T parse(String);</code>
<li><code><jk>public static</jk> T parseString(String);</code>
<li><code><jk>public static</jk> T forName(String);</code>
<li><code><jk>public static</jk> T forString(String);</code>
<li><code><jk>public</jk> T(X);</code> where <code>X</code> is in groups [1, 2a, 3ac].
<li><code><jk>public static</jk> T unswap(BeanSession,X);</code> where <code>X</code> is in groups [1, 2a, 3ac].
</ul>
</td>
<td>
<ul class='normal'>
<li><code>java.lang.Class</code>
<li><code>java.sql.Time</code>
<li><code>java.sql.Timestamp</code>
<li><code>java.text.MessageFormat</code>
<li><code>java.text.NumberFormat</code>
<li><code>java.util.Date</code>
<li><code>java.util.UUID</code>
<li><code>java.util.logging.Level</code>
<li><code>javax.xml.bind.DatatypeConverter</code>
</ul>
</td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
</tr>
<tr class='light bb' style='background-color:lightyellow'>
<td style='text-align:center'>5b</td>
<td>
Classes that only have a method to convert to a serializable form:
<ul>
<li><code><jk>public</jk> X swap(BeanSession);</code> where <code>X</code> is in groups [1, 2, 3].
<li><code><jk>public</jk> String toString();</code> where the string is any meaningful data.
</ul>
</td>
<td>&nbsp;</td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
<td style='background-color:salmon;text-align:center'><b>no</b></td>
</tr>
<tr class='dark' style='background-color:lightyellow'>
<td style='text-align:center'>6</td>
<td>
<b>All other objects</b><br>
Anything that doesn't fall into one of the groups above are simply converted to {@code Strings} using the {@code toString()} method.
</td>
<td>&nbsp;</td>
<td style='background-color:lightgreen;text-align:center'><b>yes</b></td>
<td style='background-color:salmon;text-align:center'><b>no</b></td>
</tr>
</table>
<ul class='doctree'>
<li class='info'>
Serializers are designed to work on tree-shaped POJO models.
These are models where there are no referential loops (e.g. leaves with references to nodes, or nodes in one branch referencing nodes in another branch).
There is a serializer setting {@code detectRecursions} to look for and handle these kinds of loops (by setting these references to <jk>null</jk>),
but it is not enabled by default since it introduces a moderate performance penalty.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Core.SVL"></a>
<h4 class='topic' onclick='toggle(this)'>2.10 - Simple Variable Language</h4>
<div class='topic'>
<p>
The <a class='doclink' href='org/apache/juneau/svl/package-summary.html#TOC'>org.apache.juneau.svl</a> package defines an API for a language called "Simple Variable Language".
In a nutshell, Simple Variable Language (or SVL) is text that contains variables of the form <js>"$varName{varKey}"</js>.
</p>
<p>
Variables can be recursively nested within the varKey (e.g. <js>"$FOO{$BAR{xxx},$BAZ{xxx}}"</js>).
Variables can also return values that themselves contain more variables.
</p>
<p class='bcode'>
<jc>// Use the default variable resolver to resolve a string that contains $S (system property) variables</jc>
String myProperty = VarResolver.<jsf>DEFAULT</jsf>.resolve(<js>"The Java home directory is $S{java.home}"</js>);
</p>
<p>
The following shows how variables can be arbitrarily nested...
</p>
<p class='bcode'>
<jc>// Look up a property in the following order:
// 1) MYPROPERTY environment variable.
// 2) 'my.property' system property if environment variable not found.
// 3) 'not found' string if system property not found.</jc>
String myproperty = VarResolver.<jsf>DEFAULT</jsf>.resolve(<js>"$E{MYPROPERTY,$S{my.property,not found}}"</js>);
</p>
<p>
SVL is a large topic on it's own.
It is used extensively in the ConfigFile, REST and Microservice APIs.
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/svl/package-summary.html#TOC'>org.apache.juneau.svl</a> - Simple Variable Language Javadocs.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Core.ConfigFile"></a>
<h3 class='topic' onclick='toggle(this)'>2.11 - Configuration Files</h3>
<div class='topic'>
<p>
The <a class='doclink' href='org/apache/juneau/ini/package-summary.html#TOC'>org.apache.juneau.ini</a> package contains a powerful API for creating and using INI-style config files.
</p>
<p>
An example of an INI file:
</p>
<p class='bcode'>
<cc># Default section</cc>
<ck>key1</ck> = <cv>1</cv>
<ck>key2</ck> = <cv>true</cv>
<ck>key3</ck> = <cv>[1,2,3]</cv>
<ck>key4</ck> = <cv>http://foo</cv>
<cc># Section 1</cc>
<cs>[Section1]</cs>
<ck>key1</ck> = <cv>2</cv>
<ck>key2</ck> = <cv>false</cv>
<ck>key3</ck> = <cv>[4,5,6]</cv>
<ck>key4</ck> = <cv>http://bar</cv>
</p>
<p>
This class can be used to easily access contents of the file:
</p>
<p class='bcode'>
<jk>int</jk> key1;
<jk>boolean</jk> key2;
<jk>int</jk>[] key3;
URL key4;
<jc>// Load our config file</jc>
ConfigFile f = <jk>new</jk> ConfigFileBuilder().build(<js>"MyConfig.cfg"</js>);
<jc>// Read values from default section</jc>
key1 = f.getInt(<js>"key1"</js>);
key2 = f.getBoolean(<js>"key2"</js>);
key3 = f.getObject(<jk>int</jk>[].<jk>class</jk>, <js>"key3"</js>);
key4 = f.getObject(URL.<jk>class</jk>, <js>"key4"</js>);
<jc>// Read values from section #1</jc>
key1 = f.getInt(<js>"Section1/key1"</js>);
key2 = f.getBoolean(<js>"Section1/key2"</js>);
key3 = f.getObject(<jk>int</jk>[].<jk>class</jk>, <js>"Section1/key3"</js>);
key4 = f.getObject(URL.<jk>class</jk>, <js>"Section1/key4"</js>);
</p>
<p>
The interface also allows a config file to be easily constructed programmatically:
</p>
<p class='bcode'>
<jc>// Construct the sample INI file programmatically</jc>
ConfigFile cf = <jk>new</jk> ConfigFileBuilder().build(<js>"MyConfig.cfg"</js>)
.addLines(<jk>null</jk>,
<js>"# Default section"</js>,
<js>"key1 = 1"</js>,
<js>"key2 = true"</js>,
<js>"key3 = [1,2,3]"</js>,
<js>"key4 = http://foo"</js>,
<js>""</js>)
.addHeaderComments(<js>"Section1"</js>,
<js>"# Section 1"</js>)
.addLines(<js>"Section1"</js>,
<js>"key1 = 2"</js>,
<js>"key2 = false"</js>,
<js>"key3 = [4,5,6]"</js>,
<js>"key4 = http://bar"</js>)
.save();
</p>
<p>
The following is equivalent, except that it uses {@link org.apache.juneau.ini.ConfigFile#put(String, Object)} to set values:
</p>
<p class='bcode'>
<jc>// Construct the sample INI file programmatically</jc>
ConfigFile cf = <jk>new</jk> ConfigFileBuilder().build(<js>"MyConfig.cfg"</js>)
.addLines(<jk>null</jk>,
<js>"# Default section"</js>)
.addHeaderComments(<js>"section1"</js>,
<js>"# Section 1"</js>);
cf.put(<js>"key1"</js>, 1);
cf.put(<js>"key2"</js>, <jk>true</jk>);
cf.put(<js>"key3"</js>, <jk>new int</jk>[]{1,2,3});
cf.put(<js>"key4"</js>, <jk>new</jk> URL(<js>"http://foo"</js>));
cf.put(<js>"Section1/key1"</js>, 2);
cf.put(<js>"Section1/key2"</js>, <jk>false</jk>);
cf.put(<js>"Section1/key3"</js>, <jk>new int</jk>[]{4,5,6});
cf.put(<js>"Section1/key4"</js>, <jk>new</jk> URL(<js>"http://bar"</js>));
cf.save();
</p>
<p>
Values are LAX JSON (i.e. unquoted attributes, single quotes) except for top-level strings which are left unquoted.
Any parsable object types are supported as values (e.g. arrays, collections, beans, swappable objects, enums, etc...).
</p>
<p>
The config file looks deceptively simple, the config file API is a very powerful feature with many capabilities, including:
</p>
<ul class='spaced-list'>
<li>The ability to use variables to reference environment variables, system properties, other config file entries, and a host of other types.
<li>APIs for updating, modifying, and saving configuration files without losing comments or formatting.
<li>Extensive listener APIs.
</ul>
<h6 class='topic'>Example:</h6>
<p class='bcode'>
<cc>#--------------------------</cc>
<cc># My section</cc>
<cc>#--------------------------</cc>
<cs>[MySection]</cs>
<cc># An integer</cc>
<ck>anInt</ck> = <cv>1</cv>
<cc># A boolean</cc>
<ck>aBoolean</ck> = <cv>true</cv>
<cc># An int array</cc>
<ck>anIntArray</ck> = <cv>[1,2,3]</cv>
<cc># A POJO that can be converted from a String</cc>
<ck>aURL</ck> = <cv>http://foo </cv>
<cc># A POJO that can be converted from JSON</cc>
<ck>aBean</ck> = <cv>{foo:'bar',baz:123}</cv>
<cc># A system property</cc>
<ck>locale</ck> = <cv>$S{java.locale, en_US}</cv>
<cc># An environment variable</cc>
<ck>path</ck> = <cv>$E{PATH, unknown}</cv>
<cc># A manifest file entry</cc>
<ck>mainClass</ck> = <cv>$MF{Main-Class}</cv>
<cc># Another value in this config file</cc>
<ck>sameAsAnInt</ck> = <cv>$C{MySection/anInt}</cv>
<cc># A command-line argument in the form "myarg=foo"</cc>
<ck>myArg</ck> = <cv>$ARG{myarg}</cv>
<cc># The first command-line argument</cc>
<ck>firstArg</ck> = <cv>$ARG{0}</cv>
<cc># Look for system property, or env var if that doesn't exist, or command-line arg if that doesn't exist.</cc>
<ck>nested</ck> = <cv>$S{mySystemProperty,$E{MY_ENV_VAR,$ARG{0}}}</cv>
<cc># A POJO with embedded variables</cc>
<ck>aBean2</ck> = <cv>{foo:'$ARG{0}',baz:$C{MySection/anInt}}</cv>
</p>
<p class='bcode'>
<jc>// Java code for accessing config entries above.</jc>
ConfigFile cf = Microservice.<jsm>getConfig</jsm>();
<jk>int</jk> anInt = cf.getInt(<js>"MySection/anInt"</js>);
<jk>boolean</jk> aBoolean = cf.getBoolean(<js>"MySection/aBoolean"</js>);
<jk>int</jk>[] anIntArray = cf.getObject(<jk>int</jk>[].<jk>class</jk>, <js>"MySection/anIntArray"</js>);
URL aURL = cf.getObject(URL.<jk>class</jk>, <js>"MySection/aURL"</js>);
MyBean aBean = cf.getObject(MyBean.<jk>class</jk>, <js>"MySection/aBean"</js>);
Locale locale = cf.getObject(Locale.<jk>class</jk>, <js>"MySection/locale"</js>);
String path = cf.getString(<js>"MySection/path"</js>);
String mainClass = cf.getString(<js>"MySection/mainClass"</js>);
<jk>int</jk> sameAsAnInt = cf.getInt(<js>"MySection/sameAsAnInt"</js>);
String myArg = cf.getString(<js>"MySection/myArg"</js>);
String firstArg = cf.getString(<js>"MySection/firstArg"</js>);
</p>
<p>
Config files can also be used to directly populate beans using the {@link org.apache.juneau.ini.ConfigFile#getSectionAsBean(String,Class,boolean)}:
</p>
<p class='bcode'>
<jc>// Example config file</jc>
<cs>[MyAddress]</cs>
<ck>name</ck> = <cv>John Smith</cv>
<ck>street</ck> = <cv>123 Main Street</cv>
<ck>city</ck> = <cv>Anywhere</cv>
<ck>state</ck> = <cv>NY</cv>
<ck>zip</ck> = <cv>12345</cv>
<jc>// Example bean</jc>
<jk>public class</jk> Address {
public String name, street, city;
public StateEnum state;
public int zip;
}
<jc>// Example usage</jc>
ConfigFile cf = <jk>new</jk> ConfigFileBuilder().build(<js>"MyConfig.cfg"</js>);
Address myAddress = cf.getSectionAsBean(<js>"MySection"</js>, Address.<jk>class</jk>);
</p>
<p>
Config file sections can also be accessed via interface proxies using {@link org.apache.juneau.ini.ConfigFile#getSectionAsInterface(String,Class)}:
</p>
<p class='bcode'>
<jc>// Example config file</jc>
<cs>[MySection]</cs>
<ck>string</ck> = <cv>foo</cv>
<ck>int</ck> = <cv>123</cv>
<ck>enum</ck> = <cv>ONE</cv>
<ck>bean</ck> = <cv>{foo:'bar',baz:123}</cv>
<ck>int3dArray</ck> = <cv>[[[123,null],null],null]</cv>
<ck>bean1d3dListMap</ck> = <cv>{key:[[[[{foo:'bar',baz:123}]]]]}</cv>
<jc>// Example interface</jc>
<jk>public interface</jk> MyConfigInterface {
String getString();
<jk>void</jk> setString(String x);
<jk>int</jk> getInt();
<jk>void</jk> setInt(<jk>int</jk> x);
MyEnum getEnum();
<jk>void</jk> setEnum(MyEnum x);
MyBean getBean();
<jk>void</jk> setBean(MyBean x);
<jk>int</jk>[][][] getInt3dArray();
<jk>void</jk> setInt3dArray(<jk>int</jk>[][][] x);
Map&lt;String,List&lt;MyBean[][][]&gt;&gt; getBean1d3dListMap();
<jk>void</jk> setBean1d3dListMap(Map&lt;String,List&lt;MyBean[][][]&gt;&gt; x);
}
<jc>// Example usage</jc>
ConfigFile cf = <jk>new</jk> ConfigFileBuilder().build(<js>"MyConfig.cfg"</js>);
MyConfigInterface ci = cf.getSectionAsInterface(<js>"MySection"</js>, MyConfigInterface.<jk>class</jk>);
<jk>int</jk> myInt = ci.getInt();
ci.setBean(<jk>new</jk> MyBean());
cf.save();
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/ini/package-summary.html#TOC'>org.apache.juneau.ini</a> - Config API Javadocs.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Core.SupportedLanguages"></a>
<h3 class='topic' onclick='toggle(this)'>2.12 - Supported Languages</h3>
<div class='topic'>
<p>
Extensive javadocs exist for individual language support.
Refer to these docs for language-specific information.
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/html/package-summary.html#TOC'>org.apache.juneau.html</a> - HTML support.
<li class='jp'><a class='doclink' href='org/apache/juneau/jena/package-summary.html#TOC'>org.apache.juneau.jena</a> - RDF support.
<li class='jp'><a class='doclink' href='org/apache/juneau/jso/package-summary.html#TOC'>org.apache.juneau.jso</a> - Java Serialized Object support.
<li class='jp'><a class='doclink' href='org/apache/juneau/json/package-summary.html#TOC'>org.apache.juneau.json</a> - JSON support.
<li class='jp'><a class='doclink' href='org/apache/juneau/msgpack/package-summary.html#TOC'>org.apache.juneau.msgpack</a> - MessagePack support.
<li class='jp'><a class='doclink' href='org/apache/juneau/plaintext/package-summary.html#TOC'>org.apache.juneau.plaintext</a> - Plain-text support.
<li class='jp'><a class='doclink' href='org/apache/juneau/soap/package-summary.html#TOC'>org.apache.juneau.soap</a> - SOAP support.
<li class='jp'><a class='doclink' href='org/apache/juneau/urlencoding/package-summary.html#TOC'>org.apache.juneau.urlencoding</a> - URL-Encoding and UON support.
<li class='jp'><a class='doclink' href='org/apache/juneau/xml/package-summary.html#TOC'>org.apache.juneau.xml</a> - XML support.
<li class='jp'><a class='doclink' href='org/apache/juneau/dto/atom/package-summary.html#TOC'>org.apache.juneau.dto.atom</a> - ATOM support.
<li class='jp'><a class='doclink' href='org/apache/juneau/dto/cognos/package-summary.html#TOC'>org.apache.juneau.dto.cognos</a> - Cognos support.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Core.JacksonComparison"></a>
<h3 class='topic' onclick='toggle(this)'>2.13 - Comparison with Jackson</h3>
<div class='topic'>
<p>
Juneau was developed independently from Jackson, but shares many of the same features and capabilities.
Whereas Jackson was created to work primariliy with JSON, Juneau was created to work for multiple languages.
Therefore, the terminology and annotations in Juneau are similar, but language-agnostic.
</p>
<p>
The following charts describe equivalent features between the two libraries:
</p>
<h6 class='topic'>Annotations</h6>
<table class='styled'>
<tr><th>Jackson</th><th>Juneau</th></tr>
<tr>
<td><ja>@JsonGetter</ja><br><ja>@JsonSetter</ja></td>
<td>
{@link org.apache.juneau.annotation.BeanProperty @BeanProperty}
</td>
</tr>
<tr>
<td><ja>@JsonAnyGetter</ja><br><ja>@JsonAnySetter</ja></td>
<td>
{@link org.apache.juneau.annotation.BeanProperty#name() @BeanProperty(name="*")}
</td>
</tr>
<tr>
<td><ja>@JsonIgnore</ja><br><ja>@JsonIgnoreType</ja></td>
<td>
{@link org.apache.juneau.annotation.BeanIgnore @BeanIgnore}
</td>
</tr>
<tr>
<td><code><ja>@JsonIgnoreProperties</ja>({...})</code></td>
<td>
{@link org.apache.juneau.annotation.Bean#excludeProperties @Bean(excludeProperties="...")}
</td>
</tr>
<tr>
<td><code><ja>@JsonAutoDetect</ja>(fieldVisibility=...)</code></td>
<td>
No equivalent annotation, but can be controlled via: <br>
{@link org.apache.juneau.BeanContext#BEAN_beanFieldVisibility}<br>
{@link org.apache.juneau.BeanContext#BEAN_methodVisibility}<br>
Future annotation support planned.
</td>
</tr>
<tr>
<td><ja>@JsonCreator</ja><br><ja>@JsonProperty</ja></td>
<td>
{@link org.apache.juneau.annotation.BeanConstructor @BeanConstructor}
</td>
</tr>
<tr>
<td><ja>@JacksonInject</ja></td>
<td>
No equivalent.<br>
Future support planned.
</td>
</tr>
<tr>
<td><ja>@JsonSerialize</ja><br><ja>@JsonDeserialize</ja></td>
<td>
Juneau uses swaps to convert non-serializable object to serializable forms:<br>
{@link org.apache.juneau.annotation.BeanProperty#swap() @BeanProperty(swap=...)}<br>
{@link org.apache.juneau.annotation.Pojo#swap() @Pojo(swap=...)}
</td>
</tr>
<tr>
<td><ja>@JsonInclude</ja></td>
<td>
No equivalent annotation, but can be controlled via various settings:<br>
{@link org.apache.juneau.BeanContext}<br>
{@link org.apache.juneau.serializer.SerializerContext}<br>
Future annotation support planned.
</td>
</tr>
<tr>
<td><ja>@JsonPropertyOrder</ja></td>
<td>
{@link org.apache.juneau.annotation.Bean#properties @Bean(properties="...")}<br>
{@link org.apache.juneau.annotation.Bean#sort @Bean(sort=x)}<br>
</td>
</tr>
<tr>
<td><ja>@JsonValue</ja><br><ja>@JsonRawValue</ja></td>
<td>
No equivalents.<br>
Future support unlikely since these are JSON-centric.
</td>
</tr>
</table>
</div>
</div>
<!-- ======================================================================================================== -->
<a id="DTOs"></a>
<h2 class='topic' onclick='toggle(this)'>3 - Juneau Data Transfer Objects (org.apache.juneau.dto)</h2>
<div class='topic'>
<p>
The Juneau Core library contains several predefined POJOs for generating commonly-used document types.
This section describes support for these POJOs.
</p>
<!-- ======================================================================================================== -->
<a id="DTOs.HTML5"></a>
<h3 class='topic' onclick='toggle(this)'>3.1 - HTML5</h3>
<div class='topic'>
<p>
The Juneau HTML5 DTOs are simply beans with fluent-style setters that allow you to quickly construct HTML
fragments as Java objects. These object can then be serialized to HTML using one of the existing HTML serializers,
or to other languages such as JSON using the JSON serializers.
</p>
<p>
The {@link org.apache.juneau.dto.html5.HtmlBuilder} class is a utility class with predefined static methods
that allow you to easily construct DTO instances in a minimal amount of code.
</p>
<p>
The following examples show how to create HTML tables.
</p>
<table class='styled' style='width:auto'>
<tr>
<th>Java code</th>
<th>HTML</th>
</tr>
<tr>
<td class='code'>
<jk>import static</jk> org.apache.juneau.dto.html5.HtmlBuilder.*;
Object mytable =
<jsm>table</jsm>(
<jsm>tr</jsm>(
<jsm>th</jsm>(<js>"c1"</js>),
<jsm>th</jsm>(<js>"c2"</js>)
),
<jsm>tr</jsm>(
<jsm>td</jsm>(<js>"v1"</js>),
<jsm>td</jsm>(<js>"v2"</js>)
)
);
String html = HtmlSerializer.<jsf>DEFAULT</jsf>.serialize(mytable);
</td>
<td class='code'><xt>
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;<xv>c1</xv>&lt;/th&gt;
&lt;th&gt;<xv>c2</xv>&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>v1</xv>&lt;/td&gt;
&lt;td&gt;<xv>v2</xv>&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<jk>import static</jk> org.apache.juneau.dto.html5.HtmlBuilder.*;
Object mydiv =
<jsm>div</jsm>().align(<js>"center"</js>).onmouseover(<js>"alert(\"boo!\");"</js>)
.children(
<jsm>p</jsm>(<js>"Juneau supports "</js>, <jsm>b</jsm>(<jsm>i</jsm>(<js>"mixed"</js>)), <js>" content!"</js>)
);
String html = HtmlSerializer.<jsf>DEFAULT</jsf>.serialize(mydiv);
</td>
<td class='code'><xt>
&lt;div <xa>align</xa>=<xs>'center'</xs> <xa>onmouseover</xa>=<xs>'alert("boo!");'</xs>&gt;
&lt;p&gt;<xv>Juneau supports </xv>&lt;b&gt;&lt;i&gt;<xv>mixed</xv>&lt;/i&gt;&lt;/b&gt; <xv>content!</xv>&lt;/p&gt;
&lt;/table&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<jk>import static</jk> org.apache.juneau.dto.html5.HtmlBuilder.*;
Object myform =
<jsm>form</jsm>().action(<js>"/submit"</js>).method(<js>"POST"</js>)
.children(
<js>"Position (1-10000): "</js>, <jsm>input</jsm>(<js>"number"</js>).name(<js>"pos"</js>).value(1), <jsm>br</jsm>(),
<js>"Limit (1-10000): "</js>, <jsm>input</jsm>(<js>"number"</js>).name(<js>"limit"</js>).value(100), <jsm>br</jsm>(),
<jsm>button</jsm>(<js>"submit"</js>, <js>"Submit"</js>),
<jsm>button</jsm>(<js>"reset"</js>, <js>"Reset"</js>)
);
String html = HtmlSerializer.<jsf>DEFAULT</jsf>.serialize(myform);
</td>
<td class='code'><xt>
&lt;form <xa>action</xa>=<xs>'/submit'</xs> <xa>method</xa>=<xs>'POST'</xs>&gt;
<xv>Position (1-10000):</xv> &lt;input <xa>name</xa>=<xs>'pos'</xs> <xa>type</xa>=<xs>'number'</xs> <xa>value</xa>=<xs>'1'</xs>/&gt;&lt;br/&gt;
<xv>Limit (1-10000):</xv> &lt;input <xa>name</xa>=<xs>'pos'</xs> <xa>type</xa>=<xs>'number'</xs> <xa>value</xa>=<xs>'100'</xs>/&gt;&lt;br/&gt;
&lt;button <xa>type</xa>=<xs>'submit'</xs>&gt;<xv>Submit</xv>&lt;/button&gt;
&lt;button <xa>type</xa>=<xs>'reset'</xs>&gt;<xv>Reset</xv>&lt;/button&gt;
&lt;/form&gt;
</xt></td>
</tr>
</table>
<p>
Using the HTML5 DTOs, you should be able to construct any valid HTML5 from full document bodies
to any possible fragements.
</p>
<p>
The {@link org.apache.juneau.html.HtmlParser} class can be used convert these HTML documents back
into POJOs.
</p>
<p>
Other serializers and parsers (e.g. {@link org.apache.juneau.json.JsonSerializer}) can be used to
represent these POJOs in languages other than HTML.
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/dto/html5/package-summary.html#TOC'>org.apache.juneau.dto.html5</a> - HTML5 beans.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="DTOs.Atom"></a>
<h3 class='topic' onclick='toggle(this)'>3.2 - Atom</h3>
<div class='topic'>
<p>
The Juneau ATOM feed DTOs are simply beans with fluent-style setters.<br>
The following code shows a feed being created programmatically using the {@link org.apache.juneau.dto.atom.AtomBuilder} class.
</p>
<p class='bcode'>
<jk>import static</jk> org.apache.juneau.dto.atom.AtomBuilder.*;
Feed feed =
<jsm>feed</jsm>(<js>"tag:juneau.apache.org"</js>, <js>"Juneau ATOM specification"</js>, <js>"2016-01-02T03:04:05Z"</js>)
.subtitle(<jsm>text</jsm>(<js>"html"</js>).text(<js>"Describes &lt;em&gt;stuff&lt;/em&gt; about Juneau"</js>))
.links(
<jsm>link</jsm>(<js>"alternate"</js>, <js>"text/html"</js>, <js>"http://juneau.apache.org"</js>).hreflang(<js>"en"</js>),
<jsm>link</jsm>(<js>"self"</js>, <js>"application/atom+xml"</js>, <js>"http://juneau.apache.org/feed.atom"</js>)
)
.rights(<js>"Copyright (c) 2016, Apache Foundation"</js>)
.generator(
<jsm>generator</jsm>(<js>"Juneau"</js>).uri(<js>"http://juneau.apache.org/"</js>).version(<js>"1.0"</js>)
)
.entries(
<jsm>entry</jsm>(<js>"tag:juneau.sample.com,2013:1.2345"</js>, <js>"Juneau ATOM specification snapshot"</js>, <js>"2016-01-02T03:04:05Z"</js>)
.links(
<jsm>link</jsm><js>"alternate"</js>, <js>"text/html"</js>, <js>"http://juneau.apache.org/juneau.atom"</js>),
<jsm>link</jsm>(<js>"enclosure"</js>, <js>"audio/mpeg"</js>, <js>"http://juneau.apache.org/audio/juneau_podcast.mp3"</js>).length(1337)
)
.published(<js>"2016-01-02T03:04:05Z"</js>)
.authors(
<jsm>person</jsm>(<js>"Jane Smith"</js>).uri(<js>"http://juneau.apache.org/"</js>).email(<js>"janesmith@apache.org"</js>)
)
.contributors(
<jsm>person</jsm>(<js>"John Smith"</js>)
)
.content(
<jsm>content</jsm>(<js>"xhtml"</js>)
.lang(<js>"en"</js>)
.base(<js>"http://www.apache.org/"</js>)
.text(<js>"&lt;div&gt;&lt;p&gt;&lt;i&gt;[Update: Juneau supports ATOM.]&lt;/i&gt;&lt;/p&gt;&lt;/div&gt;"</js>)
)
);
</p>
<p>
To serialize this to ATOM, use the {@link org.apache.juneau.xml.XmlSerializer} class:
</p>
<h6 class='figure'>Example with no namespaces</h6>
<p class='bcode'>
<jc>// Create a serializer with readable output, no namespaces yet.</jc>
XmlSerializer s = <jk>new</jk> XmlSerializerBuilder().sq().ws().build();
<jc>// Serialize to ATOM/XML</jc>
String atomXml = s.serialize(feed);
</p>
<h6 class='figure'>Results</h6>
<p class='bcode'>
<xt>&lt;feed&gt;</xt>
<xt>&lt;id&gt;</xt>
tag:juneau.apache.org
<xt>&lt;/id&gt;</xt>
<xt>&lt;link</xt> <xa>href</xa>=<xs>'http://juneau.apache.org/'</xs> <xa>rel</xa>=<xs>'alternate'</xs> <xa>type</xa>=<xs>'text/html'</xs> <xa>hreflang</xa>=<xs>'en'</xs>/<xt>&gt;</xt>
<xt>&lt;link</xt> <xa>href</xa>=<xs>'http://juneau.apache.org/feed.atom'</xs> <xa>rel</xa>=<xs>'self'</xs> <xa>type</xa>=<xs>'application/atom+xml'</xs>/<xt>&gt;</xt>
<xt>&lt;rights&gt;</xt>
Copyright (c) 2016, Apache Foundation
<xt>&lt;/rights&gt;</xt>
<xt>&lt;title</xt> <xa>type</xa>=<xs>'text'</xs>&gt;</xt>
Juneau ATOM specification
<xt>&lt;/title&gt;</xt>
<xt>&lt;updated&gt;</xt>2016-01-02T03:04:05Z<xt>&lt;/updated&gt;</xt>
<xt>&lt;generator</xt> <xa>uri</xa>=<xs>'http://juneau.apache.org/'</xs> <xa>version</xa>=<xs>'1.0'</xs><xt>&gt;</xt>
Juneau
<xt>&lt;/generator&gt;</xt>
<xt>&lt;subtitle</xt> <xa>type</xa>=<xs>'html'</xs><xt>&gt;</xt>
Describes &lt;em&gt;stuff&lt;/em&gt; about Juneau
<xt>&lt;/subtitle&gt;</xt>
<xt>&lt;entry&gt;</xt>
<xt>&lt;author&gt;</xt>
<xt>&lt;name&gt;</xt>Jane Smith<xt>&lt;/name&gt;</xt>
<xt>&lt;uri&gt;</xt>http://juneau.apache.org/<xt>&lt;/uri&gt;</xt>
<xt>&lt;email&gt;</xt>janesmith@apache.org<xt>&lt;/email&gt;</xt>
<xt>&lt;/author&gt;</xt>
<xt>&lt;contributor&gt;</xt>
<xt>&lt;name&gt;</xt>John Smith<xt>&lt;/name&gt;</xt>
<xt>&lt;/contributor&gt;</xt>
<xt>&lt;id&gt;</xt>
tag:juneau.apache.org
<xt>&lt;/id&gt;</xt>
<xt>&lt;link</xt> <xa>href</xa>=<xs>'http://juneau.apache.org/juneau.atom'</xs> <xa>rel</xa>=<xs>'alternate'</xs> <xa>type</xa>=<xs>'text/html'</xs>/<xt>&gt;</xt>
<xt>&lt;link</xt> <xa>href</xa>=<xs>'http://juneau.apache.org/audio/juneau_podcast.mp3'</xs> <xa>rel</xa>=<xs>'enclosure'</xs> <xa>type</xa>=<xs>'audio/mpeg'</xs> <xa>length</xa>=<xs>'12345'</xs>/<xt>&gt;</xt>
<xt>&lt;title&gt;</xt>
Juneau ATOM specification snapshot
<xt>&lt;/title&gt;</xt>
<xt>&lt;updated&gt;</xt>2016-01-02T03:04:05Z<xt>&lt;/updated&gt;</xt>
<xt>&lt;content</xt> <xa>base</xa>=<xs>'http://www.apache.org/'</xs> <xa>lang</xa>=<xs>'en'</xs> <xa>type</xa>=<xs>'xhtml'</xs><xt>&gt;</xt>
<xt>&lt;div</xt> <xa>xmlns</xa>=<xs>"http://www.w3.org/1999/xhtml"</xs><xt>&gt;&lt;p&gt;&lt;i&gt;</xt>[Update: Juneau supports ATOM.]<xt>&lt;/i&gt;&lt;/p&gt;&lt;/div&gt;</xt>
<xt>&lt;/content&gt;</xt>
<xt>&lt;published&gt;</xt>2016-01-02T03:04:05Z<xt>&lt;/published&gt;</xt>
<xt>&lt;/entry&gt;</xt>
<xt>&lt;/feed&gt;</xt>
</p>
<p>
The {@link org.apache.juneau.xml.XmlParser} class can be used convert these Atom documents back
into POJOs.
</p>
<p>
Other serializers and parsers (e.g. {@link org.apache.juneau.json.JsonSerializer}) can be used to
represent these POJOs in languages other than XML.
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/dto/atom/package-summary.html#TOC'>org.apache.juneau.dto.atom</a> - Atom DTOs.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="DTOs.Swagger"></a>
<h3 class='topic' onclick='toggle(this)'>3.3 - Swagger</h3>
<div class='topic'>
<p>
The Juneau Swagger DTOs are simply beans with fluent-style setters that allow you to quickly construct Swagger
documents as Java objects. These object can then be serialized to JSON using one of the existing JSON serializers,
or to other languages such as XML or HTML using the other serializers.
</p>
<p>
The {@link org.apache.juneau.dto.swagger.SwaggerBuilder} class is a utility class with predefined static methods
that allow you to easily construct DTO instances in a minimal amount of code.
</p>
<p>
The following is an example Swagger document from the <a href="http://petstore.swagger.io/">Swagger website</a>.
</p>
<p class='bcode'>
{
<jf>"swagger"</jf>: <js>"2.0"</js>,
<jf>"info"</jf>: {
<jf>"title"</jf>: <js>"Swagger Petstore"</js>,
<jf>"description"</jf>: <js>"This is a sample server Petstore server."</js>,
<jf>"version"</jf>: <js>"1.0.0"</js>,
<jf>"termsOfService"</jf>: <js>"http://swagger.io/terms/"</js>,
<jf>"contact"</jf>: {
<jf>"email"</jf>: <js>"apiteam@swagger.io"</js>
},
<jf>"license"</jf>: {
<jf>"name"</jf>: <js>"Apache 2.0"</js>,
<jf>"url"</jf>: <js>"http://www.apache.org/licenses/LICENSE-2.0.html"</js>
}
},
<jf>"host"</jf>: <js>"petstore.swagger.io"</js>,
<jf>"basePath"</jf>: <js>"/v2"</js>,
<jf>"tags"</jf>: [
{
<jf>"name"</jf>: <js>"pet"</js>,
<jf>"description"</jf>: <js>"Everything about your Pets"</js>,
<jf>"externalDocs"</jf>: {
<jf>"description"</jf>: <js>"Find out more"</js>,
<jf>"url"</jf>: <js>"http://swagger.io"</js>
}
}
],
<jf>"schemes"</jf>: [
<js>"http"</js>
],
<jf>"paths"</jf>: {
<jf>"/pet"</jf>: {
<jf>"post"</jf>: {
<jf>"tags"</jf>: [
<js>"pet"</js>
],
<jf>"summary"</jf>: <js>"Add a new pet to the store"</js>,
<jf>"description"</jf>: <js>""</js>,
<jf>"operationId"</jf>: <js>"addPet"</js>,
<jf>"consumes"</jf>: [
<js>"application/json"</js>,
<js>"text/xml"</js>
],
<jf>"produces"</jf>: [
<js>"application/json"</js>,
<js>"text/xml"</js>
],
<jf>"parameters"</jf>: [
{
<jf>"in"</jf>: <js>"body"</js>,
<jf>"name"</jf>: <js>"body"</js>,
<jf>"description"</jf>: <js>"Pet object that needs to be added to the store"</js>,
<jf>"required"</jf>: <jk>true</jk>
}
],
<jf>"responses"</jf>: {
<jf>"405"</jf>: {
<jf>"description"</jf>: <js>"Invalid input"</js>
}
}
}
}
},
}
</p>
<p>
This document can be generated by the following Java code:
</p>
<p class='bcode'>
<jk>static import</jk> org.apache.juneau.dto.swagger.SwaggerBuilder.*;
Swagger swagger = <jsm>swagger</jsm>()
.swagger(<js>"2.0"</js>)
.info(
<jsm>info</jsm>(<js>"Swagger Petstore"</js>, <js>"1.0.0"</js>)
.description(<js>"This is a sample server Petstore server."</js>)
.termsOfService(<js>"http://swagger.io/terms/"</js>)
.contact(
<jsm>contact</jsm>().email(<js>"apiteam@swagger.io"</js>)
)
.license(
<jsm>license</jsm>(<js>"Apache 2.0"</js>).url(<js>"http://www.apache.org/licenses/LICENSE-2.0.html"</js>)
)
)
.host(<js>"petstore.swagger.io"</js>)
.basePath(<js>"/v2"</js>)
.tags(
<jsm>tag</jsm>(<js>"pet"</js>).description(<js>"Everything about your Pets"</js>)
.externalDocs(
<jsm>externalDocumentation</jsm>(<js>"http://swagger.io"</js>, <js>"http://swagger.io"</js>)
)
)
.schemes(<js>"http"</js>)
.path(<js>"/pet"</js>, <js>"post"</js>,
<jsm>operation</jsm>()
.tags(<js>"pet"</js>)
.summary(<js>"Add a new pet to the store"</js>)
.description(<js>""</js>)
.operationId(<js>"addPet"</js>)
.consumes(MediaType.<jsf>JSON</jsf>, MediaType.<jsf>XML</jsf>)
.produces(MediaType.<jsf>JSON</jsf>, MediaType.<jsf>XML</jsf>)
.parameters(
<jsm>parameterInfo</jsm>(<js>"body"</js>, <js>"body"</js>)
.description(<js>"Pet object that needs to be added to the store"</js>)
.required(<jk>true</jk>)
)
.response(405, <jsm>responseInfo</jsm>(<js>"Invalid input"</js>))
);
String swaggerJson = JsonSerializer.<jsf>DEFAULT_READABLE</jsf>.serialize(swagger);
</p>
<p>
Swagger docs can be parsed back into Swagger beans using the following code:
</p>
<p class='bcode'>
Swagger swagger = JsonParser.<jsf>DEFAULT</jsf>.parse(swaggerJson, Swagger.<jk>class</jk>);
</p>
</div>
<!-- ======================================================================================================== -->
<a id="DTOs.JsonSchema"></a>
<h3 class='topic' onclick='toggle(this)'>3.4 - JSON-Schema</h3>
<div class='topic'>
TODO
</div>
</div>
<!-- ======================================================================================================== -->
<a id="Server"></a>
<h2 class='topic' onclick='toggle(this)'>4 - Juneau Server (org.apache.juneau.rest)</h2>
<div class='topic'>
<p>
The Juneau REST Server API provides servlet-based REST resources on top of existing POJOs.
</p>
<p>
The API automatically detects <l>Accept</l> header of requests and converts POJOs to any of the supported languages.
The toolkit is extensible and also allows for support of user-defined content types.
</p>
<p>
Automatic built-in support is provided for negotiation of response charsets and gzip encoding.
</p>
<p>
The following is an example of a REST API used to view and set JVM system properties.
</p>
<p class='bcode'>
<ja>@RestResource</ja>(
path=<js>"/systemProperties"</js>,
<jc>// Title and description that show up on HTML rendition page.
// Also used in Swagger doc.</jc>
title=<js>"System properties resource"</js>,
description=<js>"REST interface for performing CRUD operations on system properties."</js>,
<jc>// Links on the HTML rendition page.
// "request:/..." URIs are relative to the request URI.
// "servlet:/..." URIs are relative to the servlet URI.</jc>
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{up:'request:/..',options:'servlet:/?method=OPTIONS'}"</js>
),
<jc>// Properties that get applied to all serializers and parsers.</jc>
properties={
<jc>// Use single quotes.</jc>
<ja>@Property</ja>(name=<jsf>SERIALIZER_quoteChar</jsf>, value=<js>"'"</js>)
},
<jc>// Our stylesheet for the HTML rendition.</jc>
stylesheet=<js>"styles/devops.css"</js>,
<jc>// Support GZIP encoding on Accept-Encoding header.</jc>
encoders=GzipEncoder.<jk>class</jk>,
<jc>// Swagger info.</jc>
swagger=<ja>@ResourceSwagger</ja>(
contact=<js>"{name:'John Smith',email:'john@smith.com'}"</js>,
license=<js>"{name:'Apache 2.0',url:'http://www.apache.org/licenses/LICENSE-2.0.html'}"</js>,
version=<js>"2.0"</js>,
termsOfService=<js>"You're on your own."</js>,
tags=<js>"[{name:'Java',description:'Java utility',externalDocs:{description:'Home page',url:'http://juneau.apache.org'}}]"</js>,
externalDocs=<js>"{description:'Home page',url:'http://juneau.apache.org'}"</js>
)
)
<jk>public class</jk> SystemPropertiesResource <jk>extends</jk> RestServletDefault {
<ja>@RestMethod</ja>(
name=<js>"GET"</js>, path=<js>"/"</js>,
summary=<js>"Show all system properties"</js>,
description=<js>"Returns all system properties defined in the JVM."</js>,
parameters={
<ja>@Parameter</ja>(in=<js>"query"</js>, name=<js>"sort"</js>, description=<js>"Sort results alphabetically."</js>, _default=<js>"false"</js>)
},
responses={
<ja>@Response</ja>(value=200, description=<js>"Returns a map of key/value pairs."</js>)
}
)
<jk>public</jk> Map getSystemProperties(<ja>@Query</ja>(<js>"sort"</js>) <jk>boolean</jk> sort) <jk>throws</jk> Throwable {
<jk>if</jk> (sort)
<jk>return new</jk> TreeMap(System.<jsm>getProperties</jsm>());
<jk>return</jk> System.<jsm>getProperties</jsm>();
}
<ja>@RestMethod</ja>(
name=<js>"GET"</js>, path=<js>"/{propertyName}"</js>,
summary=<js>"Get system property"</js>,
description=<js>"Returns the value of the specified system property."</js>,
parameters={
<ja>@Parameter</ja>(in=<js>"path"</js>, name=<js>"propertyName"</js>, description=<js>"The system property name."</js>)
},
responses={
<ja>@Response</ja>(value=200, description=<js>"The system property value, or null if not found."</js>)
}
)
<jk>public</jk> String getSystemProperty(<ja>@Path</ja> String propertyName) <jk>throws</jk> Throwable {
<jk>return</jk> System.<jsm>getProperty</jsm>(propertyName);
}
<ja>@RestMethod</ja>(
name=<js>"PUT"</js>, path=<js>"/{propertyName}"</js>,
summary=<js>"Replace system property"</js>,
description=<js>"Sets a new value for the specified system property."</js>,
guards=AdminGuard.<jk>class</jk>,
parameters={
<ja>@Parameter</ja>(in=<js>"path"</js>, name=<js>"propertyName"</js>, description=<js>"The system property name."</js>),
<ja>@Parameter</ja>(in=<js>"body"</js>, description=<js>"The new system property value."</js>),
},
responses={
<ja>@Response</ja>(value=302,
headers={
<ja>@Parameter</ja>(name=<js>"Location"</js>, description=<js>"The root URL of this resource."</js>)
}
),
<ja>@Response</ja>(value=403, description=<js>"User is not an admin."</js>)
}
)
<jk>public</jk> Redirect setSystemProperty(<ja>@Path</ja> String propertyName, <ja>@Body</ja> String value) {
System.<jsm>setProperty</jsm>(propertyName, value);
<jk>return new</jk> Redirect();
}
<ja>@RestMethod</ja>(
name=<js>"POST"</js>, path=<js>"/"</js>,
summary=<js>"Add an entire set of system properties"</js>,
description=<js>"Takes in a map of key/value pairs and creates a set of new system properties."</js>,
guards=AdminGuard.<jk>class</jk>,
parameters={
<ja>@Parameter</ja>(in=<js>"path"</js>, name=<js>"propertyName"</js>, description=<js>"The system property key."</js>),
<ja>@Parameter</ja>(in=<js>"body"</js>, description=<js>"The new system property values.", schema="{example:{key1:'val1',key2:123}}"</js>),
},
responses={
<ja>@Response</ja>(value=302,
headers={
<ja>@Parameter</ja>(name=<js>"Location"</js>, description=<js>"The root URL of this resource."</js>)
}
),
<ja>@Response</ja>(value=403, description=<js>"Unauthorized: User is not an admin."</js>)
}
)
<jk>public</jk> Redirect setSystemProperties(<ja>@Body</ja> java.util.Properties newProperties) {
System.<jsm>setProperties</jsm>(newProperties);
<jk>return new</jk> Redirect();
}
<ja>@RestMethod</ja>(
name=<js>"DELETE"</js>, path=<js>"/{propertyName}"</js>,
summary=<js>"Delete system property"</js>,
description=<js>"Deletes the specified system property."</js>,
guards=AdminGuard.<jk>class</jk>,
parameters={
<ja>@Parameter</ja>(in=<js>"path"</js>, name=<js>"propertyName"</js>, description=<js>"The system property name."</js>),
},
responses={
<ja>@Response</ja>(value=302,
headers={
<ja>@Parameter</ja>(name=<js>"Location"</js>, description=<js>"The root URL of this resource."</js>)
}
),
<ja>@Response</ja>(value=403, description=<js>"Unauthorized: User is not an admin"</js>)
}
)
<jk>public</jk> Redirect deleteSystemProperty(<ja>@Path</ja> String propertyName) {
System.<jsm>clearProperty</jsm>(propertyName);
<jk>return new</jk> Redirect();
}
<ja>@RestMethod</ja>(
name=<js>"OPTIONS"</js>, path=<js>"/*"</js>,
summary=<js>"Show resource options"</js>,
description=<js>"Show resource options as a Swagger doc"</js>
)
<jk>public</jk> Swagger getOptions(RestRequest req) {
<jk>return</jk> req.getSwagger();
}
}
</p>
<p>
The resource above is deployed like any other servlet, in this way:
</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>SystemPropertiesService<xt>&lt;/servlet-name&gt;</xt>
<xt>&lt;servlet-class&gt;</xt>org.apache.juneau.examples.rest.SystemPropertiesService<xt>&lt;/servlet-class&gt;</xt>
<xt>&lt;/servlet&gt;</xt>
<xt>&lt;servlet-mapping&gt;</xt>
<xt>&lt;servlet-name&gt;</xt>SystemPropertiesService<xt>&lt;/servlet-name&gt;</xt>
<xt>&lt;url-pattern&gt;</xt>/systemProperties<xt>&lt;/url-pattern&gt;</xt>
<xt>&lt;/servlet-mapping&gt;</xt>
<xt>&lt;/web-app&gt;</xt>
</p>
<p>
Pointing your browser to the resource renders the POJOs as HTML (since that's what the browser specifies in the <code>Accept</code> header).
</p>
<img class='bordered' src="doc-files/Server.SystemPropertiesResource.png">
<p>
One of the most useful aspects of using this API is the self-discovering, self-documenting OPTIONS pages.
These are constructed automatically using reflection, augmented with information pulled from annotations (as shown above), resource bundles, or Swagger JSON files:
</p>
<img class='bordered' src="doc-files/Server.Options.png">
<p>
Arbitrarily complex POJO models can be serialized using any of the supported serializers, and content can be parsed using any of the supported parsers.
</p>
<p>
The <l>juneau-examples-rest</l> project contains various REST resource examples in an easy-to-use REST microservice.
One of these is <l>AddressBookResource</l> which serializes <l>AddressBook</l> objects defined below (some code omitted):
</p>
<p class='bcode'>
<jd>/** package-info.java */</jd>
<ja>@XmlSchema</ja>(
prefix=<js>"ab"</js>,
xmlNs={
<ja>@XmlNs</ja>(prefix=<js>"ab"</js>, namespaceURI=<js>"http://www.apache.org/addressBook/"</js>),
<ja>@XmlNs</ja>(prefix=<js>"per"</js>, namespaceURI=<js>"http://www.apache.org/person/"</js>),
<ja>@XmlNs</ja>(prefix=<js>"addr"</js>, namespaceURI=<js>"http://www.apache.org/address/"</js>),
<ja>@XmlNs</ja>(prefix=<js>"mail"</js>, namespaceURI=<js>"http://www.apache.org/mail/"</js>)
}
)
<jk>package</jk> org.apache.juneau.examples.addressBook;
<jk>import</jk> org.apache.juneau.xml.annotation.*;
&nbsp;
<jd>/** Address book bean */</jd>
<ja>@Bean</ja>(typeName=<js>"addressBook"</js>)
<jk>public class</jk> AddressBook <jk>extends</jk> LinkedList&lt;Person&gt; {}
&nbsp;
<jd>/** Person bean */</jd>
<ja>@Xml</ja>(prefix=<js>"per"</js>)
<ja>@Bean</ja>(typeName=<js>"person"</js>)
<jk>public class</jk> Person {
<jc>// Bean properties</jc>
<ja>@Rdf</ja>(beanUri=<jk>true</jk>) <jk>public</jk> URI <jf>uri</jf>;
<jk>public</jk> URI <jf>addressBookUri</jf>;
<jk>public int</jk> <jf>id</jf>;
<jk>public</jk> String <jf>name</jf>;
<ja>@BeanProperty</ja>(swap=CalendarSwap.Medium.<jk>class</jk>) <jk>public</jk> Calendar <jf>birthDate</jf>;
<jk>public</jk> LinkedList&lt;Address&gt; <jf>addresses</jf>;
}
&nbsp;
<jd>/** Address bean */</jd>
<ja>@Xml</ja>(prefix=<js>"addr"</js>)
<ja>@Bean</ja>(typeName=<js>"address"</js>)
<jk>public class</jk> Address {
<jc>// Bean properties</jc>
<ja>@Rdf</ja>(beanUri=<jk>true</jk>) <jk>public</jk> URI <jf>uri</jf>;
<jk>public</jk> URI <jf>personUri</jf>;
<jk>public int</jk> <jf>id</jf>;
<ja>@Xml</ja>(prefix=<js>"mail"</js>) <jk>public</jk> String <jf>street</jf>, <jf>city</jf>, <jf>state</jf>;
<ja>@Xml</ja>(prefix=<js>"mail"</js>) <jk>public int</jk> <jf>zip</jf>;
<jk>public boolean</jk> <jf>isCurrent</jf>;
}
</p>
<p>
The framework allows you to override header values through GET parameters, so that you can specify the <l>ACCEPT</l> header to see each type.
Adding <l>&amp;plainText=true</l> forces the response <l>Content-Type</l> to be <l>text/plain.</l>
<h6 class='figure'>HTML</h6>
<img class='bordered' src="doc-files/Server.Html.png">
<p>
Also, localization can be tested by passing in an <l>Accept-Language</l> header.
<h6 class='figure'>HTML/french</h6>
<img class='bordered' src="doc-files/Server.Html.french.png">
<h6 class='figure'>JSON</h6>
<img class='bordered' src="doc-files/Server.Json.png">
<h6 class='figure'>XML</h6>
<img class='bordered' src="doc-files/Server.Xml.png">
<h6 class='figure'>Simple XML</h6>
<img class='bordered' src="doc-files/Server.SimpleXml.png">
<h6 class='figure'>URL-Encoding</h6>
<img class='bordered' src="doc-files/Server.UrlEncoding.png">
<h6 class='figure'>UON</h6>
<img class='bordered' src="doc-files/Server.Uon.png">
<h6 class='figure'>RDF/XML</h6>
<img class='bordered' src="doc-files/Server.RdfXml.png">
<h6 class='figure'>RDF/N3</h6>
<img class='bordered' src="doc-files/Server.N3.png">
<h6 class='figure'>RDF/N-Tuple</h6>
<img class='bordered' src="doc-files/Server.NTuple.png">
<h6 class='figure'>RDF/Turtle</h6>
<img class='bordered' src="doc-files/Server.Turtle.png">
<p>
The Server API is an exhaustive topic on its own.
Refer to the additional information for an in-depth examination of the API.
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/server/package-summary.html#TOC'>org.apache.juneau.rest</a> - Juneau Server API Javadocs.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Client"></a>
<h2 class='topic' onclick='toggle(this)'>5 - Juneau Client (org.apache.juneau.rest.client)</h2>
<div class='topic'>
<p>
The REST client API provides the ability to access remote REST interfaces and transparently convert the input and output to and from POJOs using any
of the provided serializers and parsers.
</p>
<p>
Built upon the Apache HttpClient libraries, it extends that API and provides specialized APIs for working with REST interfaces while
maintaining all the functionality available in the HttpClient API.
</p>
<p class='bcode'>
<jc>// Create a reusable JSON client.</jc>
RestClient client = <jk>new</jk> RestClientBuilder().build();
<jc>// The address of the root resource.</jc>
String url = <js>"http://localhost:9080/sample/addressBook"</js>;
<jc>// Do a REST GET against a remote REST interface and convert
// the response to an unstructured ObjectMap object.</jc>
ObjectMap m1 = client.doGet(url).getResponse(ObjectMap.<jk>class</jk>);
<jc>// Same as above, except parse the JSON as a bean.</jc>
AddressBook a2 = client.doGet(url).getResponse(AddressBook.<jk>class</jk>);
<jc>// Add a person to the address book.
// Use XML as the transport medium.</jc>
client = <jk>new</jk> RestClientBuilder(XmlSerializer.<jk>class</jk>, XmlSerializer.<jk>class</jk>).build();
Person p = <jk>new</jk> Person(<js>"Joe Smith"</js>, 21);
<jk>int</jk> returnCode = client.doPost(url + <js>"/entries"</js>, p).run();
</p>
<p>
The Client API is also an exhaustive topic on its own.
Refer to the additional information for an in-depth examination of the API.
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/client/package-summary.html#TOC'>org.apache.juneau.rest.client</a> - Juneau Client API Javadocs.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Remoteable"></a>
<h2 class='topic' onclick='toggle(this)'>6 - Remoteable Services (org.apache.juneau.rest.remoteable)</h2>
<div class='topic'>
<p>
Juneau provides the capability of calling methods on POJOs on a server through client-side proxy interfaces.
It offers a number of advantages over other similar remote proxy interfaces, such as being much simpler to
define and use, and allowing much more flexibility in the types of objects serialized.
</p>
<p>
The remote proxy interface API allows you to invoke server-side POJO methods on the client side using REST as the communications protocol:
</p>
<p class='bcode'>
<jc>// Create a client with basic JSON support.</jc>
RestClient client = <jk>new</jk> RestClientBuilder().rootUrl(<js>"http://localhost/remoteable"</js>).build();
<jc>// Get an interface proxy.</jc>
IAddressBook ab = client.getRemoteableProxy(IAddressBook.<jk>class</jk>);
<jc>// Invoke a method on the server side and get the returned result.</jc>
Person p = ab.createPerson(
<jk>new</jk> Person(
<js>"John Smith"</js>,
<js>"Aug 1, 1999"</js>,
<jk>new</jk> Address(<js>"My street"</js>, <js>"My city"</js>, <js>"My state"</js>, 12345, <jk>true</jk>)
)
);
</p>
<p>
Under the covers, this method call gets converted to a REST POST.
</p>
<p class='bcode'>
HTTP POST http://localhost/remoteable/org.apache.juneau.examples.rest.IAddressBook/createPerson
Accept: application/json
Content-Type: application/json
[
{
"name":"John Smith",
"birthDate":"Aug 1, 1999",
"addresses":[
{
"street":"My street",
"city":"My city",
"state":"My state",
"zip":12345,
"isCurrent":true
}
]
}
]
</p>
<p>
Note that the body of the request is an array. This array contains the serialized arguments of the method.
The object returned by the method is then serialized as the body of the response.
</p>
<p>
To define a remoteable interface, simply add the {@link org.apache.juneau.remoteable.Remoteable @Remoteable} annotation
to your interface class.
</p>
<p class='bcode'>
<ja>@Remoteable</ja>
<jk>public interface</jk> IAddressBook {...}
</p>
<p>
This annotation tells the framework that all methods defined on this interface can be executed remotely.
It can be applied to super-interfaces, super-classes, etc..., and exposes the methods at whatever level it is defined.
</p>
<p>
The {@link org.apache.juneau.remoteable.RemoteMethod @RemoteMethod} annotation can also be used on individual methods
to tailor which methods are exposed or their paths.
</p>
<p>
There are two ways to expose remoteable proxies on the server side:
</p>
<ol class='spaced-list'>
<li>Extending from <code>RemoteableServlet</code>.
<li>Using a <code><ja>@RestMethod</ja>(name=<js>"PROXY"</js>)</code> annotation on a Java method.
</ol>
<p>
The <code>RemoteableServlet</code> class is a simple specialized servlet with an abstract <code>getServiceMap()</code>
method to define the server-side POJOs:
</p>
<p class='bcode'>
<ja>@RestResource</ja>(
path=<js>"/remote"</js>
)
<jk>public class</jk> SampleRemoteableServlet <jk>extends</jk> RemoteableServlet {
<jc>// Our server-side POJO.</jc>
AddressBook <jf>addressBook</jf> = <jk>new</jk> AddressBook();
<ja>@Override</ja> <jc>/* RemoteableServlet */</jc>
<jk>protected</jk> Map&lt;Class&lt;?&gt;,Object&gt; getServiceMap() <jk>throws</jk> Exception {
Map&lt;Class&lt;?&gt;,Object&gt; m = <jk>new</jk> LinkedHashMap&lt;Class&lt;?&gt;,Object&gt;();
<jc>// In this simplified example, we expose the same POJO service under two different interfaces.
// One is IAddressBook which only exposes methods defined on that interface, and
// the other is AddressBook itself which exposes all methods defined on the class itself (dangerous!).</jc>
m.put(IAddressBook.<jk>class</jk>, <jf>addressBook</jf>);
m.put(AddressBook.<jk>class</jk>, <jf>addressBook</jf>);
<jk>return</jk> m;
}
}
</p>
<p>
The <code><ja>@RestMethod</ja>(name=<js>"PROXY"</js>)</code> approach is easier if you only have a single interface you want to expose.
You simply define a Java method whose return type is an interface, and return the implementation of that interface:
</p>
<p class='bcode'>
<jc>// Our exposed proxy object.</jc>
<ja>@RestMethod</ja>(name=<js>"PROXY"</js>, path=<js>"/addressbookproxy/*"</js>)
<jk>public</jk> IAddressBook getProxy() {
<jk>return</jk> addressBook;
}
</p>
<p>
In either case, the proxy communications layer is pure REST.
<br>Therefore, in cases where the interface classes are not available on the client side,
the same method calls can be made through pure REST calls.
<br>This can also aid significantly in debugging, since calls to the remoteable service
can be made directly from a browser with no coding involved.
</p>
<p>
The parameters and return types of the Java methods can be any of the supported serializable and parsable types in <a class='doclink' href='#Core.PojoCategories'>POJO Categories</a>.
<br>This ends up being WAY more flexible than other proxy interfaces since Juneau can handle so may POJO types out-of-the-box.
<br>Most of the time you don't even need to modify your existing Java implementation code.
</p>
<p>
The RemoteableServlet class itself shows how sophisticated REST interfaces can be built on the Juneau RestServlet API using very little code.
<br>The RemoteableServlet class itself consists of only 53 lines of code, yet is a sophisticated discoverable and self-documenting REST interface.
<br>And since the remote proxy API is built on top of REST, it can be debugged using just a browser.
</p>
<p>
The requirements for a method to be callable through a remoteable service are:
</p>
<ul class='spaced-list'>
<li>The method must be public.
<li>The parameter and return types must be <a href='#Core.PojoCategories'>serializable and parsable</a>.
Parameterized types are supported.
<li>Methods can throw <code>Throwables</code> with public no-arg or single-arg-string constructors which will be automatically
recreated on the client side.
</ul>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/server/remoteable/package-summary.html#TOC'>org.apache.juneau.rest.remoteable</a> - Juneau Remoteable API Javadocs.
</ul>
<!-- ======================================================================================================== -->
<a id="Remoteable.3rdParty"></a>
<h3 class='topic' onclick='toggle(this)'>6.1 - Interface proxies against 3rd-party REST interfaces</h3>
<div class='topic'>
<p>
Remoteable proxies can also be used to define interface proxies against 3rd-party REST interfaces.
This is an extremely powerful feature that allows you to quickly define easy-to-use interfaces against virtually any REST interface.
</p>
<p>
Similar in concept to remoteable services defined above, but in this case we simply define our interface with
special annotations that tell us how to convert input and output to HTTP headers, query paramters, form post parameters, or request/response bodies.
</p>
<p class='bcode'>
<ja>@Remoteable</ja>
<jk>public interface</jk> MyProxyInterface {
<ja>@RemoteMethod</ja>(httpMethod=<js>"POST"</js>, path=<js>"/method"</js>)
String doMethod(<ja>@Header</ja>(<js>"E-Tag"</js>) UUID etag, <ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> debug, <ja>@Body</ja> MyPojo pojo);
}
RestClient client = <jk>new</jk> RestClientBuilder().build();
MyProxyInterface p = client.getRemoteableProxy(MyProxyInterface.<jk>class</jk>, <js>"http://hostname/some/rest/interface"</js>);
String response = p.doMethod(UUID.<jsm>generate</jsm>(), <jk>true</jk>, <jk>new</jk> MyPojo());
</p>
<p>
The Java method arguements can be annotated with any of the following:
</p>
<ul class='spaced-list'>
<li>{@link org.apache.juneau.remoteable.Query @Query} - A URL query parameter.
<br>The argument can be any of the following types:
<ul>
<li>Any serializable POJO - Converted to text using {@link org.apache.juneau.urlencoding.UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
<li><code>Map&lt;String,Object&gt;</code> - Individual name-value pairs.
<br>Values are converted to text using {@link org.apache.juneau.urlencoding.UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
<li><code>String</code> - Treated as a query string.
</ul>
<li>{@link org.apache.juneau.remoteable.QueryIfNE @QueryIfNE} - Same as <ja>@Query</ja> except skips the value if it's null/empty.
<li>{@link org.apache.juneau.remoteable.FormData @FormData} - A form-data parameter.
<br>Note that this is only available if the HTTP method is <code>POST</code>.
<br>The argument can be any of the following types:
<ul>
<li>Any serializable POJO - Converted to text using {@link org.apache.juneau.urlencoding.UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
<li>{@link org.apache.juneau.rest.client.NameValuePairs} - Individual name-value pairs.
<li><code>Map&lt;String,Object&gt;</code> - Individual name-value pairs.
<br>Values are converted to text using {@link org.apache.juneau.urlencoding.UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
</ul>
<li>{@link org.apache.juneau.remoteable.FormDataIfNE @FormDataIfNE} - Same as <ja>@FormData</ja> except skips the value if it's null/empty.
<li>{@link org.apache.juneau.remoteable.Header @Header} - A request header.
<br>The argument can be any of the following types:
<ul>
<li>Any serializable POJO - Converted to text using {@link org.apache.juneau.urlencoding.UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
<li><code>Map&lt;String,Object&gt;</code> - Individual name-value pairs.
<br>Values are converted to text using {@link org.apache.juneau.urlencoding.UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
</ul>
<li>{@link org.apache.juneau.remoteable.HeaderIfNE @HeaderIfNE} - Same as <ja>@Header</ja> except skips the value if it's null/empty.
<li>{@link org.apache.juneau.remoteable.Body @Body} - The HTTP request body.
<br>The argument can be any of the following types:
<ul>
<li>Any serializable POJO - Converted to text/bytes using the {@link org.apache.juneau.serializer.Serializer} registered with the <code>RestClient</code>.
<li>{@link java.io.Reader} - Raw contents of reader will be serialized to remote resource.
<li>{@link java.io.InputStream} - Raw contents of input stream will be serialized to remote resource.
<li>{@link org.apache.http.HttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
<li>{@link org.apache.juneau.rest.client.NameValuePairs} - Converted to a URL-encoded FORM post.
</ul>
</ul>
<p>
The return type of the Java method can be any of the following:
</p>
<ul class='spaced-list'>
<li><jk>void</jk> - Don't parse any response.
<br>Note that the method will still throw a runtime exception if an error HTTP status is returned.
<li>Any parsable POJO - The body of the response will be converted to the POJO using the parser defined on the <code>RestClient</code>.
<li><code>HttpResponse</code> - Returns the raw <code>HttpResponse</code> returned by the inner <code>HttpClient</code>.
<li>{@link java.io.Reader} - Returns access to the raw reader of the response.
<br>Note that if you don't want your response parsed as a POJO, you'll want to get the response reader directly.
<li>{@link java.io.InputStream} - Returns access to the raw input stream of the response.
</ul>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/remoteable/package-summary.html#TOC'>org.apache.juneau.remoteable</a> - Juneau Remoteable API Javadocs.
</ul>
</div>
</div>
<!-- ======================================================================================================== -->
<a id="Microservices"></a>
<h2 class='topic' onclick='toggle(this)'>7 - Juneau Microservices (org.apache.juneau.microservice)</h2>
<div class='topic'>
<p>
<b>WARNING - The microservice API is still in beta. It may be replaced with an OSGi-based architecture.</b>
</p>
<p>
The <l>microservice-project.zip</l> file contains a standalone Eclipse project that can be used
to quickly create REST microservices as standalone executable jars without the need of an application server.
They start almost instantly and are started through a simple java command:
</p>
<p>
<code class='snippet'>java -jar microservice.jar</code>
</p>
<p>
When you execute this command, you can point your browser to <l>http://localhost:10000</l> to bring up the REST interface:
</p>
<img class='bordered' src="doc-files/Microservices.1.png">
<p>
Microservices combine all the functionality of the core, server, and client APIs to provide truly powerful
and easy-to-use REST interfaces with minimal overhead.
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/microservice/package-summary.html#TOC'>org.apache.juneau.microservice</a> - Juneau Microservice API Javadocs.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Samples"></a>
<h2 class='topic' onclick='toggle(this)'>8 - Samples</h2>
<div class='topic'>
<p>
The <l>microservice-samples-project.zip</l> file is a zipped eclipse project that includes everything you
need to start the Samples REST microservice in an Eclipse workspace.
</p>
<p>
This project is packaged as a Juneau Microservice project that allows REST resources to be started
using embedded Jetty.
</p>
<!-- ======================================================================================================== -->
<a id="Samples.Installing"></a>
<h3 class='topic' onclick='toggle(this)'>8.1 - Installing in Eclipse</h3>
<div class='topic'>
<p>
Follow these instructions to create the Samples project in Eclipse:
</p>
<ol class='spaced-list'>
<li>Download the latest microservice-samples-project .zip file (e.g. <l>microservice-samples-project-5.2.zip</l>).
<li>In your Eclipse workspace, go to <b>File-&gt;Import-&gt;General-&gt;Existing Projects into Workspace</b> and click <b>Next</b>.<br><br>
<img class='bordered' src="doc-files/Samples.Installing.1.png">
<li>Select the .zip file and click <b>Finish</b>.<br><br>
<img class='bordered' src="doc-files/Samples.Installing.2.png">
<li>In your workspace, you can now see the following project:<br><br>
<img class='bordered' src="doc-files/Samples.Installing.3.png">
</ol>
<p>
The important elements in this project are:
</p>
<ul class='spaced-list'>
<li><l>META-INF/MANIFEST.MF</l> - The manifest file. <br>
This defines the entry point, classpath, top-level REST resources, and location of external configuration file. <br><br>
<p class='bcode'>
<mk>Manifest-Version</mk>: <mv>1.0</mv>
<mk>Main-Class</mk>: <mv>org.apache.juneau.microservice.RestMicroservice</mv>
<mk>Rest-Resources</mk>: <mv>org.apache.juneau.examples.rest.RootResources</mv>
<mk>Main-ConfigFile</mk>: <mv>examples.cfg</mv>
<mk>Class-Path</mk>:
<mv>lib/commons-codec-1.9.jar
lib/commons-io-1.2.jar
lib/commons-logging-1.1.1.jar
lib/httpclient-4.5.jar
lib/httpcore-4.4.1.jar
lib/httpmime-4.5.jar
lib/javax.servlet-api-3.0.jar
lib/jetty-all-8.1.0.jar
lib/juneau-all-5.2.jar
lib/org.apache.commons.fileupload_1.3.1.jar
lib/derby.jar
lib/jena-core-2.7.1.jar
lib/jena-iri-0.9.2.jar
lib/log4j-1.2.16.jar
lib/slf4j-api-1.6.4.jar
lib/slf4j-log4j12-1.6.4.jar</mv>
</p>
<li><l>RestMicroservice.java</l> - The application class.
<br>This is a specialized microservice in Juneau for exposing REST servlets.
<br>Allows REST servlets to be registered in the manifest or configuration file.
<li><l>RootResources.java</l> - The top-level REST resource.
<br>This class serves as a "router" page to child resources:<br>
<li><l>examples.cfg</l> - The external configuration file.
<br>A deceptively simple yet powerful INI-style configuration file:
<br><br>
<p class='bcode'>
<cc>#================================================================================
# Basic configuration file for SaaS microservices
# Subprojects can use this as a starting point.
#================================================================================</cc>
<cc>#================================================================================
# REST settings
#================================================================================</cc>
<cs>[REST]</cs>
<cc># The HTTP port number to use.
# Default is Rest-Port setting in manifest file, or 8000.</cc>
<ck>port</ck> = <cv>10000</cv>
...
</p>
</ul>
<p>
At this point you're ready to start the microservice from your workspace.
</p>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.Running"></a>
<h3 class='topic' onclick='toggle(this)'>8.2 - Running in Eclipse</h3>
<div class='topic'>
<p>
The <l>microservice-samples-project.launch</l> file is already provided to allow you to quickly start
the Samples microservice.
</p>
<p>
Go to <b>Run-&gt;Run Configurations-&gt;Java Application-&gt;microservice-samples.project</b> and click <b>Run</b>.
</p>
<img class='bordered' src="doc-files/Samples.Running.1.png">
<p>
In your console view, you can see the following output:
</p>
<img class='bordered' src="doc-files/Samples.Running.2.png">
<p>
Now open your browser and point to <l>http://localhost:10000</l>.
You can see the following:
</p>
<img class='bordered' src="doc-files/Samples.Running.3.png">
<p>
You have now started a REST interface on port 10000.
</p>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.Building"></a>
<h3 class='topic' onclick='toggle(this)'>8.3 - Building and Running from Command-Line</h3>
<div class='topic'>
<p>
The <l>build.xml</l> file is a very basic ANT script for building the Samples microservice
into an executable jar.
</p>
<p>
To build the Samples microservice, right-click <l>build.xml</l> and select <b>Run As-&gt;Ant Build</b>.
Once complete (which takes approximately 1 second), if you refresh the project, you can see the following new directory:
</p>
<img class='bordered' src='doc-files/Samples.Building.1.png'>
<p>
If you open up a command prompt in the <l>build/microservice</l> folder, you can start your microservice as follows:
</p>
<img class='bordered' src='doc-files/Samples.Building.2.png'>
<ul class='doctree'>
<li class='warn'>If you get an error message saying <code class='snippet'>java.net.BindException: Address already in use</code>, this means that the microservice
is already running elsewhere, so it cannot bind to port 10000.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.RestResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.4 - MANIFEST.MF</h3>
<div class='topic'>
<p>
The <l>META-INF/MANIFEST.MF</l> file is used to describe the microservice.
If you open it, you'll see the following:
</p>
<p class='bcode'>
<mk>Manifest-Version</mk>: <mv>1.0</mv>
<mk>Main-Class</mk>: <mv>org.apache.juneau.microservice.RestMicroservice</mv>
<mk>Rest-Resources</mk>: <mv>org.apache.juneau.examples.rest.RootResources</mv>
<mk>Main-ConfigFile</mk>: <mv>examples.cfg</mv>
<mk>Class-Path</mk>:
<mv>lib/commons-codec-1.9.jar
lib/commons-io-1.2.jar
lib/commons-logging-1.1.1.jar
lib/httpclient-4.5.jar
lib/httpcore-4.4.1.jar
lib/httpmime-4.5.jar
lib/javax.servlet-api-3.0.jar
lib/jetty-all-8.1.0.jar
lib/juneau-all-5.2.jar
lib/org.apache.commons.fileupload_1.3.1.jar
lib/derby.jar
lib/jena-core-2.7.1.jar
lib/jena-iri-0.9.2.jar
lib/log4j-1.2.16.jar
lib/slf4j-api-1.6.4.jar
lib/slf4j-log4j12-1.6.4.jar</mv>
</p>
<h6 class='topic'>Notes</h6>
<ul class='spaced-list'>
<li>The <mk>Main-Class</mk> entry is just the standard manifest entry describing the entry point for the executable jar.
The <l>org.apache.juneau.microservice.RestMicroservice</l> class is the standard microservice class for REST microservices.
Other kinds of microservices can be created by extending the {@link org.apache.juneau.microservice.Microservice} class.
<li>The <mk>Rest-Resources</mk> entry is a comma-delimited list of REST resources.
These are classes that subclass from {@link org.apache.juneau.rest.RestServlet}.
This is a specialized entry used by <l>org.apache.juneau.microservice.RestMicroservice</l>.
In this case, you're pointing to a resource defined in our project, <l>org.apache.juneau.examples.rest.RootResources</l>, which serves
as a "grouping" page for several other REST resources.
<li>The <mk>Main-ConfigFile</mk> entry points to the location of an external configuration file for our microservice.
<li>The <mk>Class-Path</mk> entry again is just the standard manifest file entry.
However, if you need to add extra libraries to your microservice, you'll need to copy them into your <l>lib</l>
directory and add them to the classpath here.
</ul>
<ul class='doctree'>
<li class='warn'>If you modify the manifest file and get <l>NoClassDefFoundErrors</l>, ensure that the classpath entries contain trailing spaces.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.RootResources"></a>
<h3 class='topic' onclick='toggle(this)'>8.5 - RootResources</h3>
<div class='topic'>
<p>
The <l>RootResources</l> class is the main page for the REST microservice.
It serves as the jumping-off point for the other resources.
</p>
<p>
The class hierarchy for this class is:
</p>
<ul class='doctree'>
<li class='jac'>{@link org.apache.juneau.rest.RestServlet org.apache.juneau.rest.RestServlet}
<br>Contains all the REST servlet logic.
<ul>
<li class='jac'>{@link org.apache.juneau.rest.RestServletDefault org.apache.juneau.rest.RestServletDefault}
<br>Defines default serializers and parsers, and OPTIONs page logic.
<ul>
<li class='jac'>{@link org.apache.juneau.rest.RestServletGroupDefault org.apache.juneau.rest.RestServletGroupDefault}
<br>Specialized subclass for grouping other resources
<ul>
<li class='jac'>{@link org.apache.juneau.microservice.ResourceGroup org.apache.juneau.microservice.ResourceGroup}
<br>Specialized subclass when using the Microservice API.
<ul>
<li class='jc'><code>org.apache.juneau.rest.samples.RootResources</code>
</ul>
</ul>
</ul>
</ul>
</ul>
<p>
Pointing a browser to the resource shows the following:
</p>
<img class='bordered' src='doc-files/Samples.Running.3.png'>
<p>
The <l>RootResources</l> class can also be defined as a servlet in a <l>web.xml</l> file:
</p>
<p class='bcode'>
<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>RootResources<xt>&lt;/servlet-name&gt;</xt>
<xt>&lt;servlet-class&gt;</xt>org.apache.juneau.rest.samples.RootResources<xt>&lt;/servlet-class&gt;</xt>
<xt>&lt;/servlet&gt;</xt>
<xt>&lt;servlet-mapping&gt;</xt>
<xt>&lt;servlet-name&gt;</xt>RootResources<xt>&lt;/servlet-name&gt;</xt>
<xt>&lt;url-pattern&gt;</xt>/*<xt>&lt;/url-pattern&gt;</xt>
<xt>&lt;/servlet-mapping&gt;</xt>
<xt>&lt;/web-app&gt;</xt>
</p>
<p>
The <l>RootResources</l> class consists entirely of annotations:
</p>
<h6 class='figure'>RootResources.java</h6>
<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>,
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{options:'?method=OPTIONS'}"</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>
The resource bundle contains the localized strings for the resource:
</p>
<h6 class='figure'>RootResources.properties</h6>
<p class='bcode'>
<cc>#--------------------------------------------------------------------------------
# RootResources labels
#--------------------------------------------------------------------------------</cc>
<ck>title</ck> = <cv>Root resources</cv>
<ck>description</ck> = <cv>This is an example of a router resource that is used to access other resources.</cv>
</p>
<p>
The <l>title</l> and <l>description</l> keys identify the localized values
return by the {@link org.apache.juneau.rest.RestRequest#getServletTitle()} and {@link org.apache.juneau.rest.RestRequest#getServletDescription()} methods.
</p>
<p>
The <l>children</l> annotation defines the child resources of this router resource.
These are resources whose paths are relative to the parent resource.
</p>
<p>
Child resources must also be subclasses of {@link org.apache.juneau.rest.RestServlet}, and
must specify a {@link org.apache.juneau.rest.annotation.RestResource#path()} annotation to
identify the subpath of the child.
For example, the <l>HelloWorldResource</l> class is annotated as follows:
</p>
<h6 class='figure'>HelloWorldResource.java</h6>
<p class='bcode'>
<ja>@RestResource</ja>(messages=<js>"nls/HelloWorldResource"</js>, path=<js>"/helloWorld"</js>)
<jk>public class</jk> HelloWorldResource <jk>extends</jk> Resource {
</p>
<p>
It should be noted that child resources do not need to be defined this way.
They could also be defined as servlets in the same way as the root resource.
The <l>children</l> annotation approach simply makes it easier to define them without having to touch the <l>web.xml</l> file again.
Child resources can also be defined programmatically by using the {@link org.apache.juneau.rest.RestConfig#addChildResources(Class[])} method.
</p>
<p>
Note that these router pages can be arbitrarily nested deep.
You can define many levels of router pages for arbitrarily hierarchical REST interfaces.
</p>
<ul class='doctree'>
<li class='info'>
Let's step back and describe what's going on here:<br>
During servlet initialization of the <l>RootResources</l> object, the toolkit looks for the <l>@RestResource.children()</l> annotation.
If it finds it, it instantiates instances of each class and recursively performs servlet initialization on them.
It then associates the child resource with the parent by the name specified by the <l>@RestResource.path()</l> annotation on the child class.
When a request for the child URL (<l>/helloWorld</l>) is received, the <l>RootResources</l> servlet gets the request and sees that the URL remainder matches one of its child resources.
It then forwards the request to the child resource for processing.
The request passed to the child resource is the same as if the child resource had been deployed independently (e.g. path-info, resource-URI, and so forth).
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.HelloWorldResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.6 - HelloWorldResource</h3>
<div class='topic'>
<p>
The <l>HelloWorldResource</l> class is a simple resource that prints a "Hello world!" message.
</p>
<h6 class='figure'>HelloWorldResource.java</h6>
<p class='bcode'>
<jd>/**
* Sample REST resource that prints out a simple "Hello world!" message.
*/</jd>
<ja>@RestResource</ja>(
messages=<js>"nls/HelloWorldResource"</js>,
path=<js>"/helloWorld"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{up:'request:/..',options:'servlet:/?method=OPTIONS'}"</js>
)
)
<jk>public class</jk> HelloWorldResource <jk>extends</jk> Resource {
<jk>private static final long</jk> <jsf>serialVersionUID</jsf> = 1L;
<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='figure'>HelloWorldResource.properties</h6>
<p class='bcode'>
<cc>#--------------------------------------------------------------------------------
# HelloWorldResource labels
#--------------------------------------------------------------------------------</cc>
<ck>title</ck> = <cv>Hello World sample resource</cv>
<ck>description</ck> = <cv>Simplest possible resource</cv>
<ck>sayHello.summary</ck> = <cv>Responds with "Hello world!"</cv>
</p>
<p>
The class hierarchy for this class is:
</p>
<ul class='doctree'>
<li class='jac'>{@link org.apache.juneau.rest.RestServlet org.apache.juneau.rest.RestServlet}
<br>Contains all the REST servlet logic.
<ul>
<li class='jac'>{@link org.apache.juneau.rest.RestServletDefault org.apache.juneau.rest.RestServletDefault}
<br>Defines default serializers and parsers, and OPTIONs page logic.
<ul>
<li class='jac'>{@link org.apache.juneau.microservice.Resource org.apache.juneau.microservice.Resource}
<br>Specialized subclass when using the Microservice API.
<ul>
<li class='jc'><code>org.apache.juneau.rest.samples.HelloWorldResource</code>
</ul>
</ul>
</ul>
</ul>
<p>
Pointing a browser to the resource shows the following:
</p>
<img class='bordered' src='doc-files/Samples.HelloWorldResource.1.png'>
<p>
Using the special <l>&amp;Accept=text/json</l> and <l>&amp;plainText=true</l> parameters
allows us to see this page rendered as JSON:
</p>
<img class='bordered' src='doc-files/Samples.HelloWorldResource.2.png'>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.MethodExampleResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.7 - MethodExampleResource</h3>
<div class='topic'>
<p>
The <l>MethodExampleResource</l> class provides examples of the following:
</p>
<ul class='spaced-list'>
<li>Using the {@link org.apache.juneau.rest.Redirect} object to perform redirections.
<li>Using the various Java method parameter annotations to retrieve request attributes, parameters, etc.
<li>Using the annotation programmatic equivalents on the {@link org.apache.juneau.rest.RestRequest} object.
<li>Setting response POJOs by either returning them or using the {@link org.apache.juneau.rest.RestResponse#setOutput(Object)} method.
</ul>
<p>
The resource is provided to show how various HTTP entities (e.g. parameters, headers) can be accessed
as either annotated Java parameters, or through methods on the <l>RestRequest</l> object.
</p>
<h6 class='figure'>MethodExampleResource.java</h6>
<p class='bcode'>
<jd>/**
* Sample REST resource that shows how to define REST methods and OPTIONS pages
*/</jd>
<ja>@RestResource</ja>(
path=<js>"/methodExample"</js>,
messages=<js>"nls/MethodExampleResource"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{up:'request:/..',options:'servlet:/?method=OPTIONS'}"</js>
)
)
<jk>public class</jk> MethodExampleResource <jk>extends</jk> Resource {
<jk>private static final long</jk> <jsf>serialVersionUID</jsf> = 1L;
<jd>/** Example GET request that redirects to our example method */</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/"</js>)
<jk>public</jk> Redirect doExample() <jk>throws</jk> Exception {
<jk>return new</jk> Redirect(<js>"example1/xxx/123/{0}/xRemainder?q1=123&amp;q2=yyy"</js>, UUID.<jsm>randomUUID</jsm>());
}
<jd>/**
* Methodology #1 - GET request using annotated attributes.
* This approach uses annotated parameters for retrieving input.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/example1/{p1}/{p2}/{p3}/*"</js>)
<jk>public</jk> String example1(
<ja>@Method</ja> String method, <jc>// HTTP method.</jc>
<ja>@Path</ja> String p1, <jc>// Path variables.</jc>
<ja>@Path</ja> <jk>int</jk> p2,
<ja>@Path</ja> UUID p3,
<ja>@Query</ja>(<js>"q1"</js>) <jk>int</jk> q1, <jc>// Query parameters.</jc>
<ja>@Query</ja>(<js>"q2"</js>) String q2,
<ja>@Query</ja>(<js>"q3"</js>) UUID q3,
<ja>@PathRemainder</ja> String remainder, <jc>// Path remainder after pattern match.</jc>
<ja>@Header</ja>(<js>"Accept-Language"</js>) String lang, <jc>// Headers.</jc>
<ja>@Header</ja>(<js>"Accept"</js>) String accept,
<ja>@Header</ja>(<js>"DNT"</js>) <jk>int</jk> doNotTrack
) {
<jc>// Send back a simple String response</jc>
String output = String.<jsm>format</jsm>(
<js>"method=%s, p1=%s, p2=%d, p3=%s, remainder=%s, q1=%d, q2=%s, q3=%s, lang=%s, accept=%s, dnt=%d"</js>,
method, p1, p2, p3, remainder, q1, q2, q3, lang, accept, doNotTrack);
<jk>return</jk> output;
}
<jd>/**
* Methodology #2 - GET request using methods on RestRequest and RestResponse.
* This approach uses low-level request/response objects to perform the same as above.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/example2/{p1}/{p2}/{p3}/*"</js>)
<jk>public</jk> String example2(
RestRequest req, <jc>// A direct subclass of HttpServletRequest.</jc>
RestResponse res <jc>// A direct subclass of HttpServletResponse.</jc>
) {
<jc>// HTTP method.</jc>
String method = req.getMethod();
<jc>// Path variables.</jc>
RequestPathMatch path = req.getPathMatch();
String p1 = path.get(<js>"p1"</js>, String.<jk>class</jk>);
<jk>int</jk> p2 = path.get(<js>"p2"</js>, <jk>int</jk>.<jk>class</jk>);
UUID p3 = path.get(<js>"p3"</js>, UUID.<jk>class</jk>);
<jc>// Query parameters.</jc>
RequestQuery query = req.getQuery();
<jk>int</jk> q1 = query.get(<js>"q1"</js>, 0, <jk>int</jk>.<jk>class</jk>);
String q2 = query.get(<js>"q2"</js>, String.<jk>class</jk>);
UUID q3 = query.get(<js>"q3"</js>, UUID.<jk>class</jk>);
<jc>// Path remainder after pattern match.</jc>
String remainder = req.getPathMatch().getRemainder();
<jc>// Headers.</jc>
String lang = req.getHeader(<js>"Accept-Language"</js>);
String accept = req.getHeader(<js>"Accept"</js>);
<jk>int</jk> doNotTrack = req.getHeaders().get(<js>"DNT"</js>, <jk>int</jk>.<jk>class</jk>);
<jc>// Send back a simple String response</jc>
String output = String.format(
<js>"method=%s, p1=%s, p2=%d, p3=%s, remainder=%s, q1=%d, q2=%s, q3=%s, lang=%s, accept=%s, dnt=%d"</js>,
method, p1, p2, p3, remainder, q1, q2, q3, lang, accept, doNotTrack);
res.setOutput(output); <jc>// Or use getWriter().</jc>
}
<jd>/**
* Methodology #3 - GET request using special objects.
* This approach uses intermediate-level APIs.
* The framework recognizes the parameter types and knows how to resolve them.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/example3/{p1}/{p2}/{p3}/*"</js>)
<jk>public</jk> String example3(
HttpMethod method, <jc>// HTTP method.</jc>
RequestPathMatch path, <jc>// Path variables.</jc>
RequestQuery query, <jc>// Query parameters.</jc>
RequestHeaders headers, <jc>// Headers.</jc>
AcceptLanguage lang, <jc>// Specific header classes.</jc>
Accept accept
) {
<jc>// Path variables.</jc>
String p1 = path.get(<js>"p1"</js>, String.<jk>class</jk>);
<jk>int</jk> p2 = path.get(<js>"p2"</js>, <jk>int</jk>.<jk>class</jk>);
UUID p3 = path.get(<js>"p3"</js>, UUID.<jk>class</jk>);
<jc>// Query parameters.</jc>
<jk>int</jk> q1 = query.get(<js>"q1"</js>, 0, <jk>int</jk>.<jk>class</jk>);
String q2 = query.get(<js>"q2"</js>, String.<jk>class</jk>);
UUID q3 = query.get(<js>"q3"</js>, UUID.<jk>class</jk>);
<jc>// Path remainder after pattern match.</jc>
String remainder = path.getRemainder();
<jc>// Headers.</jc>
int doNotTrack = headers.get(<js>"DNT"</js>, <jk>int</jk>.<jk>class</jk>);
<jc>// Send back a simple String response</jc>
String output = String.format(
<js>"method=%s, p1=%s, p2=%d, p3=%s, remainder=%s, q1=%d, q2=%s, q3=%s, lang=%s, accept=%s, dnt=%d"</js>,
method, p1, p2, p3, remainder, q1, q2, q3, lang, accept, doNotTrack);
res.setOutput(output);
}
}
</p>
<p>
The class consists of 4 methods:
</p>
<ul class='doctree'>
<li class='jm'><l>doExample()</l>
<br>The root page.
<br>Performs a simple redirection to the <l>doGetExample1()</l> method using a {@link org.apache.juneau.rest.Redirect} object.
<li class='jm'><l>example1()</l>
<br>Shows how to use the following annotations:
<ul>
<li class='ja'>{@link org.apache.juneau.rest.annotation.Path @Path}
<li class='ja'>{@link org.apache.juneau.rest.annotation.Query @Query}
<li class='ja'>{@link org.apache.juneau.rest.annotation.Header @Header}
<li class='ja'>{@link org.apache.juneau.rest.annotation.Method @Method}
<li class='ja'>{@link org.apache.juneau.rest.annotation.PathRemainder @PathRemainder}
</ul>
Method returns a POJO to be serialized as the output.
<li class='jm'><l>example2()</l>
<br>Identical to <l>doGetExample1()</l> but shows how to use the {@link org.apache.juneau.rest.RestRequest} and {@link org.apache.juneau.rest.RestResponse} objects:
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getPathMatch()}
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getQuery()}
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getFormData()}
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getHeaders()}
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getMethod()}
<li class='jm'>{@link org.apache.juneau.rest.RequestPathMatch#getRemainder()}
</ul>
Method sets the POJO to be serialized using the {@link org.apache.juneau.rest.RestResponse#setOutput(Object)} method.
<li class='jm'><l>example3()</l>
<br>Identical to <l>doGetExample1()</l> but uses automatically resolved parameters based on class type.
<br>Juneau automatically recognizes specific class types such as common header types and automatically
resolves them to objects for you.
<br>See <a class='doclink' href='org/apache/juneau/rest/package-summary.html#RestResources.MethodSignature'>Rest Resources / Method Signature</a>
for the list of all automatically support parameter types, and {@link org.apache.juneau.rest.annotation.RestResource#paramResolvers() @RestResource.paramResolvers()}
for defining your own custom parameter type resolvers.
</ul>
<p>
There's a lot going on in this method. Notice how you're able to access URL attributes, parameters, headers, and content
as parsed POJOs. All the input parsing is already done by the toolkit. You simply work with the resulting POJOs.
</p>
<p>
As you might notice, using annotations typically results in fewer lines of code and are therefore usually preferred over the API approach, but both are equally valid.
</p>
<p>
When you visit this page through the router page, you can see the following (after the automatic redirection occurs):
</p>
<img class='bordered' src="doc-files/Samples.MethodExampleResource.1.png">
<p>
Notice how the conversion to POJOs is automatically done for us, even for non-standard POJOs such as UUID.
</p>
<h6 class='topic'>Self-documenting design through Swagger OPTIONS pages</h6>
<p>
One of the main features of Juneau is that it produces OPTIONS pages for self-documenting design (i.e. REST interfaces that document themselves).
</p>
<p>
Much of the information populated on the OPTIONS page is determined through reflection.
This basic information can be augmented with information defined through:
</p>
<ul>
<li>Annotations - An example of this was shown in the <code>SystemPropertiesResource</code> example above.<br>
Localized strings can be pulled from resource bundles using the <code>$L</code> localization variable.
<li>Resource bundle properties - Described in detail in this section.
<li>Swagger JSON files with the same name and location as the resource class (e.g. <code>MethodExampleResource.json</code>).<br>
Localized versions are defined by appending the locale to the file name (e.g. <code>MethodExampleResource_ja_JP.json</code>);
</ul>
<p>
OPTIONS pages are simply serialized {@link org.apache.juneau.dto.swagger.Swagger} DTO beans.
Localized versions of these beans are retrieved using the {@link org.apache.juneau.rest.RestRequest#getSwagger()} method.
</p>
<p>
To define an OPTIONS request handler, the {@link org.apache.juneau.rest.RestServletDefault} class defines the following Java method:
</p>
<h6 class='figure'>RestServletDefault.java</h6>
<p class='bcode'>
<jd>/** OPTIONS request handler */</jd>
<ja>@RestMethod</ja>(name=<js>"OPTIONS"</js>, path=<js>"/*"</js>)
<jk>public</jk> Swagger getOptions(RestRequest req) {
<jk>return</jk> req.getSwagger();
}
</p>
<p>
The <l>OPTIONS</l> link that you see on the HTML version of the page is created
through a property defined by the {@link org.apache.juneau.html.HtmlDocSerializer} class
and specified on the resource class annotation:
</p>
<p class='bcode'>
<ja>@RestResource</ja>(
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{options:'?method=OPTIONS'}"</js>
)
)
</p>
<p>
This simply creates a link that's the same URL as the resource URL appended with <l>"?method=OPTIONS"</l>,
which is a shorthand way that the framework provides of defining overloaded GET requests.
Links using relative or absolute URLs can be defined this way.
</p>
<p>
Metadata about the servlet class is combined with localized strings from a properties file associated
through a <code><ja>@RestResource</ja>(messages=<js>"nls/MethodExampleResources"</js>)</code> annotation.
The properties file contains localized descriptions for the resource, resource methods, and method
parameters.
</p>
<h6 class='figure'>MethodExampleResource.properties</h6>
<p class='bcode'>
<cc>#--------------------------------------------------------------------------------
# MethodExampleResource labels
#--------------------------------------------------------------------------------</cc>
<ck>title = <cv>A simple REST method example resource</cv>
<ck>doGetExample.summary</ck> = <cv>Sample GET method</cv>
<ck>doGetExample1.summary</ck> = <cv>Sample GET using annotations</cv>
<ck>doGetExample1.req.path.a1.description</ck> = <cv>Sample variable</cv>
<ck>doGetExample1.req.path.a2.description</ck> = <cv>Sample variable</cv>
<ck>doGetExample1.req.path.a3.description</ck> = <cv>Sample variable</cv>
<ck>doGetExample1.req.query.p1.description</ck> = <cv>Sample parameter</cv>
<ck>doGetExample1.req.query.p2.description</ck> = <cv>Sample parameter</cv>
<ck>doGetExample1.req.query.p3.description</ck> = <cv>Sample parameter</cv>
<ck>doGetExample1.req.header.Accept-Language.description</ck> = <cv>Sample header</cv>
<ck>doGetExample1.req.header.DNT.description</ck> = <cv>Sample header</cv>
<ck>doGetExample2.summary</ck> = <cv>Sample GET using Java APIs</cv>
<ck>doGetExample2.req.path.a1.description</ck> = <cv>Sample variable</cv>
<ck>doGetExample2.req.path.a2.description</ck> = <cv>Sample variable</cv>
<ck>doGetExample2.req.path.a3.description</ck> = <cv>Sample variable</cv>
<ck>doGetExample2.req.query.p1.description</ck> = <cv>Sample parameter</cv>
<ck>doGetExample2.req.query.p2.description</ck> = <cv>Sample parameter</cv>
<ck>doGetExample2.req.query.p3.description</ck> = <cv>Sample parameter</cv>
<ck>doGetExample2.req.header.Accept-Language.description</ck> = <cv>Sample header</cv>
<ck>doGetExample2.req.header.DNT.description</ck> = <cv>Sample header</cv>
<ck>getOptions.summary</ck> = <cv>View these options</cv>
</p>
<p>
Clicking the <l>options</l> link on the page presents you with information about how to use this resource:
</p>
<img class='bordered' src="doc-files/Samples.MethodExampleResource.2.png">
<p>
This page (like any other) can also be rendered in JSON or XML by using the <l>&amp;Accept</l> URL parameter.
</p>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.UrlEncodedFormResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.8 - UrlEncodedFormResource</h3>
<div class='topic'>
<p>
The <l>UrlEncodedFormResource</l> class provides examples of the following:
</p>
<ul class='spaced-list'>
<li>How to use form entry beans to process form POSTs.
<li>How to use the {@link org.apache.juneau.rest.RestRequest#getReaderResource(String)} method to
serve up static files with embedded string variables.
</ul>
<p>
The class is shown below:
</p>
<h6 class='figure'>UrlEncodedFormResource.java</h6>
<p class='bcode'>
<jd>/**
* Sample REST resource for loading URL-Encoded form posts into POJOs.
*/</jd>
<ja>@RestResource</ja>(
path=<js>"/urlEncodedForm"</js>,
messages=<js>"nls/UrlEncodedFormResource"</js>
)
<jk>public class</jk> UrlEncodedFormResource <jk>extends</jk> Resource {
<jk>private static final long</jk> <jsf>serialVersionUID</jsf> = 1L;
<jd>/** GET request handler */</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/"</js>)
<jk>public</jk> ReaderResource doGet(RestRequest req) <jk>throws</jk> IOException {
<jk>return</jk> req.getReaderResource(<js>"UrlEncodedForm.html"</js>, <jk>true</jk>);
}
<jd>/** POST request handler */</jd>
<ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/"</js>)
<jk>public</jk> Object doPost(<ja>@Body</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 aString;
<jk>public int</jk> aNumber;
<ja>@BeanProperty</ja>(pojoSwaps=CalendarSwap.<jsf>ISO8601DT</jsf>.<jk>class</jk>)
<jk>public</jk> Calendar aDate;
}
}
</p>
<p>
The {@link org.apache.juneau.rest.RestRequest#getReaderResource(String,boolean)} method pulls in the following
file located in the same package as the class:
</p>
<h6 class='figure'>UrlEncodedForm.html</h6>
<p class='bcode'>
<xt>&lt;html&gt;</xt>
<xt>&lt;head&gt;</xt>
<xt>&lt;meta</xt> <xa>http-equiv</xa>=<xs>"Content-Type"</xs> <xa>content</xa>=<xs>"text/html;charset=UTF-8"</xs><xt>&gt;</xt>
<xt>&lt;style</xt> <xa>type</xa>=<xs>'text/css'</xs><xt>&gt;</xt>
<xt>@import</xt> <xs>'$R{servletURI}/style.css'</xs>;
<xt>&lt;/style&gt;</xt>
<xt>&lt;script</xt> <xa>type</xa>=<xs>"text/javascript"</xs><xt>&gt;</xt>
<jc>// Load results from IFrame into this document.</jc>
<jk>function</jk> loadResults(buff) {
<jk>var</jk> doc = buff.contentDocument || buff.contentWindow.document;
<jk>var</jk> buffBody = doc.getElementById(<js>'data'</js>);
document.getElementById(<js>'results'</js>).innerHTML = buffBody.innerHTML;
}
<xt>&lt;/script&gt;</xt>
<xt>&lt;/head&gt;</xt>
<xt>&lt;body&gt;</xt>
<xt>&lt;h3</xt> <xa>class</xa>=<xs>'title'</xs><xt>&gt;</xt>$R{servletTitle}<xt>&lt;/h3&gt;</xt>
<xt>&lt;h5</xt> <xa>class</xa>=<xs>"description"</xs><xt>&gt;</xt>$R{servletDescription}<xt>&lt;/h5&gt;</xt>
<xt>&lt;div</xt> <xa>class</xa>=<xs>'data'</xs><xt>&gt;</xt>
<xt>&lt;form</xt> <xa>id</xa>=<xs>'form'</xs> <xa>action</xa>=<xs>'$R{servletURI}'</xs> <xa>method</xa>=<xs>'POST'</xs> <xa>target</xa>=<xs>'buff'</xs><xt>&gt;</xt>
<xt>&lt;table&gt;</xt>
<xt>&lt;tr&gt;</xt>
<xt>&lt;th&gt;</xt>$L{aString}<xt>&lt;/th&gt;</xt>
<xt>&lt;td&gt;</xt><xt>&lt;input</xt> <xa>name</xa>=<xs>"aString"</xs> <xa>type</xa>=<xs>"text"</xs><xt>&gt;</xt><xt>&lt;/td&gt;</xt>
<xt>&lt;/tr&gt;</xt>
<xt>&lt;tr&gt;</xt>
<xt>&lt;th&gt;</xt>$L{aNumber}<xt>&lt;/th&gt;</xt>
<xt>&lt;td&gt;</xt><xt>&lt;input</xt> <xa>name</xa>=<xs>"aNumber"</xs> <xa>type</xa>=<xs>"number"</xs><xt>&gt;</xt><xt>&lt;/td&gt;</xt>
<xt>&lt;/tr&gt;</xt>
<xt>&lt;tr&gt;</xt>
<xt>&lt;th&gt;</xt>$L{aDate}<xt>&lt;/th&gt;</xt>
<xt>&lt;td&gt;</xt><xt>&lt;input</xt> <xa>name</xa>=<xs>"aDate"</xs> <xa>type</xa>=<xs>"datetime"</xs><xt>&gt;</xt> (ISO8601, e.g. "<xt>&lt;code&gt;</xt>2001-07-04T15:30:45Z<xt>&lt;/code&gt;</xt>")<xt>&lt;/td&gt;</xt>
<xt>&lt;/tr&gt;</xt>
<xt>&lt;tr&gt;</xt>
<xt>&lt;td</xt> <xa>colspan</xa>=<xs>'2'</xs> <xa>align</xa>=<xs>'right'</xs><xt>&gt;</xt><xt>&lt;button</xt> <xa>type</xa>=<xs>"submit"</xs><xt>&gt;</xt>$L{submit}<xt>&lt;/button&gt;</xt><xt>&lt;/td&gt;</xt>
<xt>&lt;/tr&gt;</xt>
<xt>&lt;/table&gt;</xt>
<xt>&lt;/form&gt;</xt>
<xt>&lt;br&gt;</xt>
<xt>&lt;div</xt> <xa>id</xa>=<xs>'results'</xs><xt>&gt;</xt>
<xt>&lt;/div&gt;</xt>
<xt>&lt;/div&gt;</xt>
<xt>&lt;iframe</xt> <xa>name</xa>=<xs>'buff'</xs> <xa>style</xa>=<xs>'display:none'</xs> <xa>onload</xa>=<xs>"parent.loadResults(this)"</xs><xt>&gt;</xt><xt>&lt;/iframe&gt;</xt>
<xt>&lt;/body&gt;</xt>
<xt>&lt;/html&gt;</xt>
</p>
<p>
The <l>$L</l> variables are string variable that pull in localized values from the resource bundle:
</p>
<h6 class='figure'>UrlEncodedFormResource.properties</h6>
<p class='bcode'>
<cc>#--------------------------------------------------------------------------------
# UrlEncodedFormResource labels
#--------------------------------------------------------------------------------</cc>
<ck>title</ck> = <cv>URL-Encoded Form Post Example</cv>
<ck>description</ck> = <cv>Shows how URL-Encoded form input can be loaded into POJOs. POJO is simply echoed back.</cv>
<ck>aString</ck> = <cv>A String:</cv>
<ck>aNumber</ck> = <cv>A Number:</cv>
<ck>aDate</ck> = <cv>A Date:</cv>
<ck>submit</ck> = <cv>submit</cv>
</p>
<p>
The <l>$R</l> variables are request string variables.
In this case, <l>$R{servletTitle}</l> and <l>$R{servletDescription}</l> resolve to the values returned by
{@link org.apache.juneau.rest.RestRequest#getServletTitle()} and {@link org.apache.juneau.rest.RestRequest#getServletDescription()}.
</p>
<p>
Pointing a browser to the resource shows the following:
</p>
<img class='bordered' src='doc-files/Samples.UrlEncodedFormResource.1.png'>
<p>
Entering some values and clicking <l>submit</l> causes the form bean to be populated
and returned back as a POJO response:
</p>
<img class='bordered' src='doc-files/Samples.UrlEncodedFormResource.2.png'>
<p>
Another option is to construct the HTML form in Java using <a class='doclink' href='org/apache/juneau/dto/html5/package-summary.html#TOC'>HTML5 beans</a>.
This is arguably a better approach since it's typically cleaner with less code, and the headers/links
are already part of the page.
</p>
<p class='bcode'>
<jk>import static</jk> org.apache.juneau.dto.html5.HtmlBuilder.*;
<jd>/** GET request handler */</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/"</js>)
<jk>public</jk> Div doGet(RestRequest req) {
<jk>return</jk> div(
script(<js>"text/javascript"</js>,
<js>"\n // Load results from IFrame into this document."</js>
+<js>"\n function loadResults(buff) {"</js>
+<js>"\n var doc = buff.contentDocument || buff.contentWindow.document;"</js>
+<js>"\n var buffBody = doc.getElementById('data');"</js>
+<js>"\n document.getElementById('results').innerHTML = buffBody.innerHTML;"</js>
+<js>"\n }"</js>
),
<jsf>form</jsf>().id(<js>"form"</js>).action(req.getServletURI()).method(<js>"POST"</js>).target(<js>"buff"</js>).children(
<jsf>table</jsf>(
<jsf>tr</jsf>(
<jsf>th</jsf>(req.getMessage(<js>"aString"</js>)),
<jsf>td</jsf>(<jsf>input</jsf>().name(<js>"aString"</js>).type(<js>"text"</js>))
),
<jsf>tr</jsf>(
<jsf>th</jsf>(req.getMessage(<js>"aNumber"</js>)),
<jsf>td</jsf>(<jsf>input</jsf>().name(<js>"aNumber"</js>).type(<js>"number"</js>))
),
<jsf>tr</jsf>(
<jsf>th</jsf>(req.getMessage(<js>"aDate"</js>)),
<jsf>td</jsf>(<jsf>input</jsf>().name(<js>"aDate"</js>).type(<js>"datetime"</js>), <js>" (ISO8601, e.g. "</js>, code(<js>"2001-07-04T15:30:45Z"</js>), <js>\" )"</js>)
),
<jsf>tr</jsf>(
<jsf>td</jsf>().colspan(2).style(<js>"text-align:right"</js>).children(
<jsf>button</jsf>(<js>"submit"</js>, req.getMessage(<js>"submit"</js>))
)
)
)
),
<jsf>br</jsf>(),
<jsf>div</jsf>().id(<js>"results"</js>),
<jsf>iframe</jsf>().name(<js>"buff"</js>).style(<js>"display:none"</js>).onload(<js>"parent.loadResults(this)"</js>)
);
}
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jm'>{@link org.apache.juneau.rest.RestConfig#addVars(Class[])} - Servlet and request variables.
<li class='jm'>{@link org.apache.juneau.rest.RestCallHandler#getSessionObjects(RestRequest)} - Var resolver session objects.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.RequestEchoResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.9 - RequestEchoResource</h3>
<div class='topic'>
<p>
The <l>RequestEchoResource</l> class shows how existing complex POJOs can be serialized to a variety of content types.
The example simply takes the incoming <l>HttpServletRequest</l> object and serializes it.
</p>
<p>
It provides examples of the following:
</p>
<ul class='spaced-list'>
<li>Using the {@link org.apache.juneau.rest.annotation.RestResource#properties() @RestResource.properties()}
annotation to set serializer properties.
<li>Using the {@link org.apache.juneau.rest.annotation.RestResource#beanFilters() @RestResource.beanFilters()} and {@link org.apache.juneau.rest.annotation.RestResource#pojoSwaps() @RestResource.pojoSwaps()}
annotations to set serializer transforms.
<li>Using the {@link org.apache.juneau.rest.annotation.Properties @Properties} annotation to set serializers properties
programmatically on a request.
</ul>
<p>
The class is shown below:
</p>
<h6 class='figure'>RequestEchoResource.java</h6>
<p class='bcode'>
<jd>/**
* Sample REST resource for echoing HttpServletRequests back to the browser
*/</jd>
<ja>@RestResource</ja>(
path=<js>"/echo"</js>,
messages=<js>"nls/RequestEchoResource"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{up:'request:/..',options:'servlet:/?method=OPTIONS'}"</js>,
),
properties={
<ja>@Property</ja>(name=<jsf>SERIALIZER_maxDepth</jsf>, value=<js>"10"</js>),
<ja>@Property</ja>(name=<jsf>SERIALIZER_detectRecursions</jsf>, value=<js>"true"</js>)
},
beanFilters={
<jc>// Interpret these as their parent classes, not subclasses</jc>
HttpServletRequest.<jk>class</jk>, HttpSession.<jk>class</jk>, ServletContext.<jk>class</jk>,
},
pojoSwaps={
<jc>// Add a special POJO swap for Enumerations</jc>
EnumerationSwap.<jk>class</jk>
}
)
<jk>public class</jk> RequestEchoResource <jk>extends</jk> Resource {
<jd>/** GET request handler */</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/*"</js>, converters={Queryable.<jk>class</jk>,Traversable.<jk>class</jk>})
<jk>public</jk> HttpServletRequest doGet(RestRequest req, RestResponse res, <ja>@Properties</ja> ObjectMap properties) {
<jc>// Set the HtmlDocSerializer title programmatically.</jc>
res.setPageTitle(req.getPathInfo());
<jc>// Just echo the request back as the response.</jc>
<jk>return</jk> req;
}
}
</p>
<p>
Again, there's a lot going on here that's new that requires some explanation.
The <l>HttpServletRequest</l> object is not a tree-shaped POJO model.
Instead, it contains lots of loops that can cause stack overflow errors if you were to try
to serialize it as-is.
Also, you want to look only at the properties defined on the <l>HttpServletRequest</l> class,
not implementation-specific (i.e. WAS or Jetty) fields which can get messy.
</p>
<p>
The {@link org.apache.juneau.rest.annotation.RestResource#properties() @RestResource.properties()},
{@link org.apache.juneau.rest.annotation.RestResource#beanFilters() @RestResopurce.beanFilters()}, and
{@link org.apache.juneau.rest.annotation.RestResource#pojoSwaps() @RestResopurce.pojoSwaps()} annotations are used
to set behavior properties on the resource's underlying bean context, serializers, and parsers.
You're using them here to modify the behavior of serialization for all content types.
The annotations are functionally equivalent to using the {@link org.apache.juneau.rest.RestConfig} class, as follows:
</p>
<h6 class='figure'>Hypothetical RequestEchoResource.createSerializers() method</h6>
<p class='bcode'>
<jd>/** Override the default rest serializers to add some transforms */</jd>
<ja>@Override</ja>
<jk>public synchronize void</jk> init(RestConfig config) throws Exception {
<jc>// Add bean filters for the HttpServletRequest, HttpSession, and ServletContext objects
// so that you don't show vendor-specific properties on subclasses.
// Add Enumeration POJO swap to be able to render the contents of Enumeration properties.
// The max depth and detect recursion options prevent any possible runaway serializations.
// This shouldn't happen, but future JEE APIs may introduce deep hierarchies or loops.</jc>
config
.addBeanFilters(HttpServletRequest.<jk>class</jk>, HttpSession.<jk>class</jk>, ServletContext.<jk>class</jk>)
.addPojoSwaps(EnumerationSwap.<jk>class</jk>)
.setProperty(<jsf>SERIALIZER_maxDepth</jsf>, 10)
.setProperty(<jsf>SERIALIZER_detectRecursions</jsf>, <jk>true</jk>)
.setPageLinks(<js>"{...}"</js>);
<jc>// Don't forget to call this!</jc>
<jk>super</jk>.init(config);
}
</p>
<p>
Note how the annotations generally require fewer lines of code.
</p>
<p>
Pointing a browser to the resource shows the following:
</p>
<img class='bordered' src="doc-files/Samples.RequestEchoResource.1.png">
<p>
This gives you an idea of what kinds of POJO models can be serialized, since you are serializing a regular old <l>HttpServletRequest</l> object.
</p>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.AddressBookResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.10 - AddressBookResource</h3>
<div class='topic'>
<p>
The <l>AddressBookResource</l> class is a proof-of-concept class that shows a true RESTful API using the Juneau REST toolkit.
It provides examples of the following:
</p>
<ul class='spaced-list'>
<li>How to create RESTful interfaces using only POJOs.
<li>How to use the {@link org.apache.juneau.xml.annotation.Xml @Xml} and
{@link org.apache.juneau.xml.annotation.XmlSchema @XmlSchema} annotations to provide XML namespaces
and alter how beans are handled by the XML serializer.
<li>How to use the {@link org.apache.juneau.jena.annotation.Rdf @Rdf} and
{@link org.apache.juneau.xml.annotation.XmlSchema @RdfSchema} annotations to provide XML namespaces
and alter how beans are handled by the Jena serializers.
<li>How to use the {@link org.apache.juneau.annotation.BeanProperty @BeanProperty} annotation
to alter how bean properties are handled by the serializers.
<li>How to use the {@link org.apache.juneau.rest.annotation.RestMethod#name() RestMethod.name()} annotation
to create overloaded methods beyond the standard GET/PUT/POST/DELETE.
<li>How to augment data in the OPTIONS page.
<li>How to use the {@link org.apache.juneau.rest.client.RestClient} API to interact with the REST resource using
the same POJOs used to create the server-side API.
<li>How to interact with the REST resource using only a browser.
<li>Using the {@link org.apache.juneau.rest.converters.Traversable} converter to drill down into POJO models.
<li>Using the {@link org.apache.juneau.rest.converters.Queryable} converter to provide search/view/sort functionality against POJOs.
<li>Using the {@link org.apache.juneau.rest.converters.Introspectable} converter to invoke methods on POJOs.
<li>Using proxy interfaces.
</ul>
<p>
Pointing a browser to the resource shows the following:
</p>
<img class='bordered' src='doc-files/Samples.AddressBookResource.1.png'>
<!-- ======================================================================================================== -->
<a id="Samples.AddressBookResource.Classes"></a>
<h4 class='topic' onclick='toggle(this)'>8.10.1 - Classes</h4>
<div class='topic'>
<p>
The code is straightforward, consisting of the following classes:
</p>
<ul class='spaced-list'>
<li><l>package-info.java</l> - Used to define XML namespaces for POJOs in this package.
<li><l>IAddressBook</l> - An interface describing the address book.
<li><l>AddressBook</l> - A data structure consisting of a list of <code>Persons</code>.
<li><l>Person, Address</l> - In-memory representations of people and addresses.
<li><l>CreatePerson, CreateAddress</l> - POJOs for creating and updating people and address through the REST interface.
<li><l>AddressBookResource</l> - The REST resource class.
</ul>
<ul class='doctree'>
<li class='info'>
For the sake of brevity, bean properties are defined as public fields instead of the normal getters/setters.
Also, the examples are not the most efficient design and are not thread safe.
</ul>
<p>
The <l>package-info.java</l> file is used to define XML and RDF namespaces on beans and properties in this package.
Here you define a default XML and RDF namespaces and URL mappings for namespace shortnames used throughout this package.
It should be noted that these features are entirely optional, and there are often several ways of defining these namespaces.
</p>
<h6 class='figure'>package-info.java</h6>
<p class='bcode'>
<jc>// XML and RDF namespaces used in this package</jc>
<ja>@Xml</ja>(ns=<js>"ab"</js>,
namespaces={
<ja>@XmlNs</ja>(name=<js>"ab"</js>, uri=<js>"http://www.apache.org/addressBook/"</js>),
<ja>@XmlNs</ja>(name=<js>"per"</js>, uri=<js>"http://www.apache.org/person/"</js>),
<ja>@XmlNs</ja>(name=<js>"addr"</js>, uri=<js>"http://www.apache.org/address/"</js>),
<ja>@XmlNs</ja>(name=<js>"mail"</js>, uri=<js>"http://www.apache.org/mail/"</js>)
}
)
<ja>@Rdf</ja>(ns=<js>"ab"</js>,
namespaces={
<ja>@RdfNs</ja>(name=<js>"ab"</js>, uri=<js>"http://www.apache.org/addressBook/"</js>),
<ja>@RdfNs</ja>(name=<js>"per"</js>, uri=<js>"http://www.apache.org/person/"</js>),
<ja>@RdfNs</ja>(name=<js>"addr"</js>, uri=<js>"http://www.apache.org/address/"</js>),
<ja>@RdfNs</ja>(name=<js>"mail"</js>, uri=<js>"http://www.apache.org/mail/"</js>)
}
)
<jk>package</jk> org.apache.juneau.examples.addressBook;
<jk>import</jk> org.apache.juneau.xml.annotation.*;
</p>
<p>
Our address book uses the following interface:
</p>
<h6 class='figure'>IAddressBook.java</h6>
<p class='bcode'>
<jd>/**
* Interface used to help illustrate proxy interfaces.
* See {<ja>@link</ja> SampleRemoteableServlet}.
*/</jd>
<jk>public interface</jk> IAddressBook {
<jd>/** Return all people in the address book */</jd>
List&lt;Person&gt; getPeople();
<jd>/** Return all addresses in the address book */</jd>
List&lt;Address&gt; getAddresses();
<jd>/** Create a person in this address book */</jd>
Person createPerson(CreatePerson cp) <jk>throws</jk> Exception;
<jd>/** Find a person by id */</jd>
Person findPerson(<jk>int</jk> id);
<jd>/** Find an address by id */</jd>
Address findAddress(<jk>int</jk> id);
<jd>/** Find a person by address id */</jd>
Person findPersonWithAddress(<jk>int</jk> id);
<jd>/** Remove a person by id */</jd>
Person removePerson(<jk>int</jk> id);
}
</p>
<h6 class='topic'>Notes</h6>
<ul class='spaced-list'>
<li>You interface an interface for our address book so that you can later
use it to demonstrate the proxy interface support.
</ul>
<p>
The <l>AddressBook</l> class is our address book.
It maintains a list of <l>Person</l> objects with some additional convenience methods:
</p>
<h6 class='figure'>AddressBook.java</h6>
<p class='bcode'>
<jd>/** Address book bean */</jd>
<jk>public class</jk> AddressBook <jk>extends</jk> LinkedList&lt;Person&gt; <jk>implements</jk> IAddressBook {
<jc>// The URL of this resource</jc>
<jk>private</jk> URI <jf>uri</jf>;
<jd>/** Bean constructor - Needed for instantiating on client side */</jd>
<jk>public</jk> AddressBook () {}
<jd>/** Normal constructor - Needed for instantiating on server side */</jd>
<jk>public</jk> AddressBook (URI uri) {...}
<ja>@Override</ja> <jc>/* IAddressBook */</jc>
<jk>public</jk> List&lt;Person&gt; getPeople() {
<jk>return</jk> <jk>this</jk>;
}
<ja>@Override</ja> <jc>/* IAddressBook */</jc>
<jk>public</jk> Person createPerson(CreatePerson cp) <jk>throws</jk> Exception {
Person p = <jk>new</jk> Person(uri, cp);
add(p);
<jk>return</jk> p;
}
<ja>@Override</ja> <jc>/* IAddressBook */</jc>
<jk>public</jk> Person findPerson(<jk>int</jk> id) {
<jk>for</jk> (Person p : <jk>this</jk>)
<jk>if</jk> (p.<jf>id</jf> == id)
<jk>return</jk> p;
<jk>return null</jk>;
}
<ja>@Override</ja> <jc>/* IAddressBook */</jc>
<jk>public</jk> Address findAddress(<jk>int</jk> id) {
<jk>for</jk> (Person p : <jk>this</jk>)
<jk>for</jk> (Address a : p.<jf>addresses</jf>)
<jk>if</jk> (a.<jf>id</jf> == id)
<jk>return</jk> a;
<jk>return null</jk>;
}
<ja>@Override</ja> <jc>/* IAddressBook */</jc>
<jk>public</jk> Person findPersonWithAddress(<jk>int</jk> id) {
<jk>for</jk> (Person p : <jk>this</jk>)
<jk>for</jk> (Address a : p.<jf>addresses</jf>)
<jk>if</jk> (a.<jf>id</jf> == id)
<jk>return</jk> p;
<jk>return null</jk>;
}
<ja>@Override</ja> <jc>/* IAddressBook */</jc>
<jk>public</jk> List&lt;Address&gt; getAddresses() {
Set&lt;Address&gt; s = <jk>new</jk> LinkedHashSet&lt;Address&gt;();
<jk>for</jk> (Person p : <jk>this</jk>)
<jk>for</jk> (Address a : p.<jf>addresses</jf>)
s.add(a);
<jk>return new</jk> ArrayList&lt;Address&gt;(s);
}
<ja>@Override</ja> <jc>/* IAddressBook */</jc>
<jk>public</jk> Person removePerson(<jk>int</jk> id) {
Person p = findPerson(id);
<jk>if</jk> (p != <jk>null</jk>)
remove(p);
<jk>return</jk> p;
}
<jd>/** Utility method */</jd>
<jk>public static</jk> Calendar toCalendar(String birthDate) <jk>throws</jk> Exception {
Calendar c = <jk>new</jk> GregorianCalendar();
c.setTime(DateFormat.<jsm>getDateInstance</jsm>(DateFormat.<jsf>MEDIUM</jsf>, Locale.<jsf>US</jsf>).parse(birthDate));
<jk>return</jk> c;
}
}
</p>
<h6 class='topic'>Notes</h6>
<ul class='spaced-list'>
<li>The <code><ja>@Xml</ja>(elementName=<js>"addressBook"</js>)</code> annotation tells the toolkit that
when serialized as XML, the element name is <xt>&lt;addressBook&gt;</xt>.
Without this annotation, the element would revert to the generalized <xt>&lt;array&gt;</xt> tag.
<li>The separate constructors are implementation specific and are needed because you're going to be using this class in two ways,
since you'll be demonstrating the client code as well as the server code, and it eliminates having to define separate client-side and server-side POJOs:
<ol>
<li>The normal constructor is used to programmatically create this object in the REST servlet code.
<li>The no-arg constructor is used by the Juneau parsers to construct this object in our client side code.
</ol>
</ul>
<p>
The <l>Person</l> bean is defined as follows:
</p>
<h6 class='figure'>Person.java</h6>
<p class='bcode'>
<jd>/** Person bean */</jd>
<ja>@Xml</ja>(ns=<js>"per"</js>)
<ja>@Rdf</ja>(prefix=<js>"per"</js>)
<ja>@Bean</ja>(typeName=<js>"person"</js>)
<jk>public class</jk> Person {
<jk>private static int</jk> <jsf>nextPersonId</jsf> = 1;
<jc>// Bean properties.</jc>
<ja>@Rdf</ja>(beanUri=<jk>true</jk>) public URI <jf>uri</jf>;
<jk>public</jk> URI <jf>addressBookUri</jf>;
<jk>public</jk> String <jf>id</jf>;
<jk>public</jk> String <jf>name</jf>;
<ja>@BeanProperty</ja>(swap=CalendarSwap.Medium.<jk>class</jk>) <jk>public</jk> Calendar <jf>birthDate</jf>;
<jk>public</jk> LinkedList&lt;Address&gt; <jf>addresses</jf> = new LinkedList&lt;Address&gt;();
<jd>/** Bean constructor - Needed for instantiating on server side */</jd>
<jk>public</jk> Person() {}
<jd>/** Normal constructor - Needed for instantiating on client side */</jd>
<jk>public</jk> Person(URI addressBookUri, CreatePerson cp) <jk>throws</jk> Exception {
<jk>this</jk>.<jf>id</jf> = <jsf>nextPersonId</jsf>++;
<jk>this</jk>.<jf>addressBookUri</jf> = addressBookUri;
<jk>if</jk> (addressBookUri != <jk>null</jk>)
<jk>this</jk>.<jf>uri</jf> = addressBookUri.resolve(<js>"people/"</js> + <jf>id</jf>);
<jk>this</jk>.<jf>name</jf> = cp.<jf>name</jf>;
<jk>this</jk>.<jf>birthDate</jf> = cp.<jf>birthDate</jf>;
<jk>for</jk> (CreateAddress ca : cp.<jf>addresses</jf>)
<jk>this</jk>.<jf>addresses</jf>.add(<jk>new</jk> Address(addressBookUri, <jf>uri</jf>, ca));
}
<jd>/** Extra read-only bean property */</jd>
<jk>public int</jk> getAge() {
<jk>return new</jk> GregorianCalendar().get(Calendar.<jsf>YEAR</jsf>) - birthDate.get(Calendar.<jsf>YEAR</jsf>);
}
<jd>/** Convenience method - Add an address for this person */</jd>
<jk>public</jk> Address createAddress(CreateAddress ca) <jk>throws</jk> Exception {
Address a = <jk>new</jk> Address(<jf>addressBookUri</jf>, <jf>uri</jf>, ca);
<jf>addresses</jf>.add(a);
<jk>return</jk> a;
}
<jd>/** Extra method (for method invocation example) */</jd>
<jk>public</jk> String sayHello(String toPerson, <jk>int</jk> age) {
<jk>return</jk> <jf>name</jf> + <js>" says hello to "</js> + toPerson + <js>" who is "</js> + age + <js>" years old"</js>;
}
}
</p>
<h6 class='topic'>Notes</h6>
<ul class='spaced-list'>
<li>The <l>ns="per"</l> annotations override the default <l>"ab"</l> namespace defined on the package.
It applies to this class and all properties of this class.
<li>The <code><ja>@Rdf</ja>(beanUri=<jk>true</jk>)</code> annotation identifies the <l>uri</l> property as the resource URI for this resource.
This property has special meaning for the RDF serializer.
The RDF serializer uses this property for the value of the <l>rdf:resource</l> attribute.
<li>The <code><ja>@BeanProperty</ja>(swap=CalendarSwap.Medium.<jk>class</jk>)</code> annotation causes the date field to
be serialized in the format <l>"MM dd, yyyy"</l>.
This could have also been specified globally on the resource level through the {@link org.apache.juneau.rest.annotation.RestResource#properties} annotation.
</ul>
<p>
The <l>Address</l> bean is defined as follows:
</p>
<h6 class='figure'>Address.java</h6>
<p class='bcode'>
<jd>/**
* Address bean
*/</jd>
<ja>@Xml</ja>(prefix=<js>"addr"</js>)
<ja>@Rdf</ja>(prefix=<js>"addr"</js>)
<ja>@Bean</ja>(typeName=<js>"address"</js>)
<jk>public class</jk> Address {
<jk>private static int</jk> <jsf>nextAddressId</jsf> = 1;
<jc>// Bean properties</jc>
<ja>@Rdf</ja>(beanUri=<jk>true</jk>) <jk>public</jk> URI <jf>uri</jf>;
<jk>public</jk> URI <jf>personUri</jf>;
<jk>public int</jk> <jf>id</jf>;
<ja>@Xml</ja>(prefix=<js>"mail"</js>) <ja>@Rdf</ja>(prefix=<js>"mail"</js>) <jk>public</jk> String <jf>street</jf>, <jf>city</jf>, <jf>state</jf>;
<ja>@Xml</ja>(prefix=<js>"mail"</js>) <ja>@Rdf</ja>(prefix=<js>"mail"</js>) <jk>public int</jk> <jf>zip</jf>;
<jk>public boolean</jk> <jf>isCurrent</jf>;
<jd>/** Bean constructor - Needed for instantiating on client side */</jd>
<jk>public</jk> Address() {}
<jd>/** Normal constructor - Needed for instantiating on server side */</jd>
<jk>public</jk> Address(URI addressBookUri, URI personUri, CreateAddress ca) <jk>throws</jk> Exception {
<jk>this</jk>.<jf>id</jf> = <jsf>nextAddressId</jsf>++;
<jk>if</jk> (addressBookUri != <jk>null</jk>)
<jk>this</jk>.<jf>uri</jf> = addressBookUri.resolve(<js>"addresses/"</js> + <jf>id</jf>);
<jk>this</jk>.<jf>personUri</jf> = personUri</jf>;
<jk>this</jk>.<jf>street</jf> = ca.<jf>street</jf>;
<jk>this</jk>.<jf>city</jf> = ca.<jf>city</jf>;
<jk>this</jk>.<jf>state</jf> = ca.<jf>state</jf>;
<jk>this</jk>.<jf>zip</jf> = ca.<jf>zip</jf>;
<jk>this</jk>.<jf>isCurrent</jf> = ca.<jf>isCurrent</jf>;
}
}
</p>
<h6 class='topic'>Notes</h6>
<ul class='spaced-list'>
<li>This class shows how the namespace can be overridden at the property level through the <code><ja>@Xml</ja>(ns=<js>"mail"</js>)</code> annotation.
</ul>
<p>
The <l>CreatePerson</l> bean is used as the input data for creating a person.
</p>
<h6 class='figure'>CreatePerson.java</h6>
<p class='bcode'>
<jd>/** Bean for creating a new person */</jd>
<ja>@Xml</ja>(ns=<js>"per"</js>)
<ja>@Rdf</ja>(ns=<js>"addr"</js>)
<ja>@Bean</ja>(typeName=<js>"person"</js>)
<jk>public class</jk> CreatePerson {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>name</jf>;
<ja>@BeanProperty(</ja>swap=CalendarSwap.Medium.<jk>class</jk>) <jk>public</jk> Calendar <jf>birthDate</jf>;
<jk>public</jk> LinkedList&lt;CreateAddress&gt; <jf>addresses</jf>;
<jd>/** Bean constructor - Needed for instantiating on server side */</jd>
<jk>public</jk> CreatePerson() {}
<jd>/** Normal constructor - Needed for instantiating on client side */</jd>
<jk>public</jk> CreatePerson(String name, Calendar birthDate, CreateAddress...addresses) {...}
}
</p>
<p>
The <l>CreateAddress</l> bean is used as the input data for creating an address.
</p>
<h6 class='figure'>CreateAddress.java</h6>
<p class='bcode'>
<jd>/** Bean for creating a new address */</jd>
<ja>@Xml</ja>(ns=<js>"addr"</js>)
<ja>@Rdf</ja>(ns=<js>"addr"</js>)
<ja>@Bean</ja>(typeName=<js>"address"</js>)
<jk>public class</jk> CreateAddress {
<jc>// Bean properties</jc>
<ja>@Xml</ja>(ns=<js>"mail"</js>) <ja>@Rdf</ja>(ns=<js>"mail"</js>) <jk>public</jk> String <jf>street</jf>, <jf>city</jf>, <jf>state</jf>;
<ja>@Xml</ja>(ns=<js>"mail"</js>) <ja>@Rdf</ja>(ns=<js>"mail"</js>) <jk>public int</jk> <jf>zip</jf>;
<jk>public boolean</jk> <jf>isCurrent</jf>;
<jd>/** Bean constructor -Needed for instantiating on server side */</jd>
<jk>public</jk> CreateAddress() {}
<jd>/** Normal constructor - Needed for instantiating on client side */</jd>
<jk>public</jk> CreateAddress(String street, String city, String state, <jk>int</jk> zip, <jk>boolean</jk> isCurrent) {...}
}
</p>
<p>
The <l>AddressBookResource</l> class is our REST resource class.
</p>
<h6 class='figure'>AddressBookResource.java</h6>
<p class='bcode'>
<jd>/**
* Proof-of-concept resource that shows off the capabilities of working with POJO resources.
* Consists of an in-memory address book repository.
*/</jd>
<ja>@RestResource</ja>(
path=<js>"/addressBook"</js>,
messages=<js>"nls/AddressBookResource"</js>,
<jc>// Links on the HTML rendition page.
// "request:/..." URIs are relative to the request URI.
// "servlet:/..." URIs are relative to the servlet URI.
// "$C{...}" variables are pulled from the config file.</jc>
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{up:'request:/..', options:'servlet:/?method=OPTIONS', source:'$C{Source/gitHub}/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java'}"</js>
),
<jc>// Properties that get applied to all serializers and parsers.</jc>
properties={
<jc>// Allow INIT as a method parameter.</jc>
<ja>@Property</ja>(name=<jsf>REST_allowMethodParam</jsf>, value=<js>"*"</js>),
<jc>// Use single quotes.</jc>
<ja>@Property</ja>(name=<jsf>SERIALIZER_quoteChar</jsf>, value=<js>"'"</js>),
<jc>// Make RDF/XML readable.</jc>
<ja>@Property</ja>(name=<jsf>RDF_rdfxml_tab</jsf>, value=<js>"5"</js>),
<jc>// Make RDF parsable by adding a root node.</jc>
<ja>@Property</ja>(name=<jsf>RDF_addRootProperty</jsf>, value=<js>"true"</js>),
<jc>// Make URIs absolute so that we can easily reference them on the client side.</jc>
<ja>@Property</ja>(name=<jsf>SERIALIZER_uriResolution</jsf>, value=<js>"ABSOLUTE"</js>)
<jc>// Make the anchor text on URLs be just the path relative to the servlet.</jc>
<ja>@Property</ja>(name=<jsf>HTML_uriAnchorText</jsf>, value=<js>"SERVLET_RELATIVE"</js>)
},
<jc>// Our stylesheet for the HTML rendition.</jc>
stylesheet=<js>"styles/devops.css"</js>,
<jc>// Support GZIP encoding on Accept-Encoding header.</jc>
encoders=GzipEncoder.<jk>class</jk>,
<jc>// Swagger info.</jc>
contact=<js>"{name:'John Smith',email:'john@smith.com'}"</js>,
license=<js>"{name:'Apache 2.0',url:'http://www.apache.org/licenses/LICENSE-2.0.html'}"</js>,
version=<js>"2.0"</js>,
termsOfService=<js>"You're on your own."</js>,
tags=<js>"[{name:'Java',description:'Java utility',externalDocs:{description:'Home page',url:'http://juneau.apache.org'}}]"</js>,
externalDocs=<js>"{description:'Home page',url:'http://juneau.apache.org'}"</js>
)
<jk>public class</jk> AddressBookResource <jk>extends</jk> ResourceJena {
<jk>private static final long</jk> <jsf>serialVersionUID</jsf> = 1L;
<jc>// The in-memory address book</jc>
<jk>private</jk> AddressBook <jf>addressBook</jf>;
<ja>@Override</ja> /* Servlet */
<jk>public void</jk> init() {
<jk>try</jk> {
<jc>// Create the address book</jc>
<jf>addressBook</jf> = <jk>new</jk> AddressBook(java.net.URI.create(<js>"servlet:/"</js>));
<jc>// Add some people to our address book by default</jc>
<jf>addressBook</jf>.createPerson(
<jk>new</jk> CreatePerson(
<js>"Barack Obama"</js>,
<jsm>toCalendar</jsm>(<js>"Aug 4, 1961"</js>),
<jk>new</jk> CreateAddress(<js>"1600 Pennsylvania Ave"</js>, <js>"Washington"</js>, <js>"DC"</js>, 20500, <jk>true</jk>),
<jk>new</jk> CreateAddress(<js>"5046 S Greenwood Ave"</js>, <js>"Chicago"</js>, <js>"IL"</js>, 60615, <jk>false</jk>)
)
);
<jf>addressBook</jf>.createPerson(
<jk>new</jk> CreatePerson(
<js>"George Walker Bush"</js>,
<jsm>toCalendar</jsm>(<js>"Jul 6, 1946"</js>),
<jk>new</jk> CreateAddress(<js>"43 Prairie Chapel Rd"</js>, <js>"Crawford"</js>, <js>"TX"</js>, 76638, <jk>true</jk>),
<jk>new</jk> CreateAddress(<js>"1600 Pennsylvania Ave"</js>, <js>"Washington"</js>, <js>"DC"</js>, 20500, <jk>false</jk>)
)
);
} <jk>catch</jk> (Exception e) {
<jk>throw new</jk> RuntimeException(e);
}
}
<jd>/**
* [GET /]
* Get root page.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/"</js>,
converters=Queryable.<jk>class</jk>
)
<jk>public</jk> Link[] getRoot() <jk>throws</jk> Exception {
<jk>return new</jk> Link[] {
<jk>new</jk> Link(<js>"people"</js>, <js>"people"</js>),
<jk>new</jk> Link(<js>"addresses"</js>, <js>"addresses"</js>)
};
}
<jd>/**
* [GET /people/*]
* Get all people in the address book.
* Traversable transforming enabled to allow nodes in returned POJO tree to be addressed.
* Introspectable transforming enabled to allow public methods on the returned object to be invoked.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/people/*"</js>,
converters={Traversable.<jk>class</jk>,Queryable.<jk>class</jk>,Introspectable.<jk>class</jk>}
)
<jk>public</jk> AddressBook getAllPeople() <jk>throws</jk> Exception {
<jk>return</jk> <jf>addressBook</jf>;
}
<jd>/**
* [GET /people/{id}/*]
* Get a single person by ID.
* Traversable transforming enabled to allow nodes in returned POJO tree to be addressed.
* Introspectable transforming enabled to allow public methods on the returned object to be invoked.
*/</jd>
<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>}
)
<jk>public</jk> Person getPerson(<ja>@Path</ja> <jk>int</jk> id) <jk>throws</jk> Exception {
<jk>return</jk> findPerson(id);
}
<jd>/**
* [GET /addresses/*]
* Get all addresses in the address book.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/addresses/*"</js>,
converters={Traversable.<jk>class</jk>,Queryable.<jk>class</jk>}
)
<jk>public</jk> List&lt;Address&gt; getAllAddresses() <jk>throws</jk> Exception {
<jk>return</jk> <jf>addressBook</jf>.getAddresses();
}
<jd>/**
* [GET /addresses/{id}/*]
* Get a single address by ID.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/addresses/{id}/*"</js>,
converters={Traversable.<jk>class</jk>,Queryable.<jk>class</jk>}
)
<jk>public</jk> Address getAddress(<ja>@Path</ja> <jk>int</jk> id) <jk>throws</jk> Exception {
<jk>return</jk> findAddress(id);
}
<jd>/**
* [POST /people]
* Create a new Person bean.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/people"</js>,
guards=AdminGuard.<jk>class</jk>
)
<jk>public</jk> Redirect createPerson(<ja>@Body</ja> CreatePerson cp) <jk>throws</jk> Exception {
Person p = <jf>addressBook</jf>.createPerson(cp);
<jk>return new</jk> Redirect(<js>"people/{0}"</js>, p.id);
}
<jd>/**
* [POST /people/{id}/addresses]
* Create a new Address bean.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/people/{id}/addresses"</js>,
guards=AdminGuard.<jk>class</jk>
)
<jk>public</jk> Redirect createAddress(<ja>@Path</ja> <jk>int</jk> id, <ja>@Body</ja> CreateAddress ca) <jk>throws</jk> Exception {
Person p = findPerson(id);
Address a = p.createAddress(ca);
<jk>return new</jk> Redirect(<js>"addresses/{0}"</js>, a.id);
}
<jd>/**
* [DELETE /people/{id}]
* Delete a Person bean.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"DELETE"</js>, path=<js>"/people/{id}"</js>,
guards=AdminGuard.<jk>class</jk>,
)
<jk>public</jk> String deletePerson(<ja>@Path</ja> <jk>int</jk> id) <jk>throws</jk> Exception {
<jf>addressBook</jf>.removePerson(id);
<jk>return</jk> <js>"DELETE successful"</js>;
}
<jd>/**
* [DELETE /addresses/{id}]
* Delete an Address bean.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"DELETE"</js>, path=<js>"/addresses/{id}"</js>,
guards=AdminGuard.<jk>class</jk>
)
<jk>public</jk> String deleteAddress(<ja>@Path</ja> <jk>int</jk> addressId) <jk>throws</jk> Exception {
Person p = <jf>addressBook</jf>.findPersonWithAddress(addressId);
<jk>if</jk> (p == <jk>null</jk>)
<jk>throw new</jk> RestException(<jsf>SC_NOT_FOUND</jsf>, <js>"Person not found"</js>);
Address a = findAddress(addressId);
p.addresses.remove(a);
<jk>return</jk> <js>"DELETE successful"</js>;
}
<jd>/**
* [PUT /people/{id}/*]
* Change property on Person bean.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"PUT"</js>, path=<js>"/people/{id}/*"</js>,
guards=AdminGuard.<jk>class</jk>
)
<jk>public</jk> String updatePerson(RestRequest req, <ja>@Path</ja> <jk>int</jk> id, <ja>@PathRemainder</ja> String remainder) <jk>throws</jk> Exception {
<jk>try</jk> {
Person p = findPerson(id);
PojoRest r = <jk>new</jk> PojoRest(p);
ClassMeta&lt;?&gt; cm = r.getClassMeta(remainder);
Object in = req.getBody().asType(cm);
r.put(remainder, in);
<jk>return</jk> <js>"PUT successful"</js>;
} <jk>catch</jk> (Exception e) {
<jk>throw new</jk> RestException(<jsf>SC_BAD_REQUEST</jsf>, <js>"PUT unsuccessful"</js>).initCause(e);
}
}
<jd>/**
* [PUT /addresses/{id}/*]
* Change property on Address bean.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"PUT"</js>, path=<js>"/addresses/{id}/*"</js>,
guards=AdminGuard.<jk>class</jk>
)
<jk>public</jk> String updateAddress(RestRequest req, <ja>@Path</ja> <jk>int</jk> id, <ja>@PathRemainder</ja> String remainder) <jk>throws</jk> Exception {
<jk>try</jk> {
Address a = findAddress(id);
PojoRest r = <jk>new</jk> PojoRest(a);
ClassMeta&lt;?&gt; cm = r.getClassMeta(remainder);
Object in = req.getBody().asType(cm);
r.put(remainder, in);
<jk>return</jk> <js>"PUT successful"</js>;
} <jk>catch</jk> (Exception e) {
<jk>throw new</jk> RestException(<jsf>SC_BAD_REQUEST</jsf>, <js>"PUT unsuccessful"</js>).initCause(e);
}
}
<jd>/**
* [INIT /]
* Reinitialize this resource.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"INIT"</js>, path=<js>"/"</js>,
guards=AdminGuard.<jk>class</jk>
)
<jk>public</jk> String doInit() <jk>throws</jk> Exception {
init();
<jk>return</jk> <js>"OK"</js>;
}
<jd>/**
* [GET /cognos]
* Get data in Cognos/XML format
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/cognos"</js>)
<jk>public</jk> DataSet getCognosData() <jk>throws</jk> Exception {
<jc>// The Cognos metadata</jc>
Column[] items = {
<jk>new</jk> Column(<js>"name"</js>, <js>"xs:String"</js>, 255),
<jk>new</jk> Column(<js>"age"</js>, <js>"xs:int"</js>),
<jk>new</jk> Column(<js>"numAddresses"</js>, <js>"xs:int"</js>)
.addPojoSwap(
<jk>new</jk> PojoSwap&lt;Person,Integer&gt;() {
<ja>@Override</ja> /* PojoSwap */
<jk>public</jk> Integer swap(BeanSession session, Person p) {
<jk>return</jk> p.addresses.size();
}
}
)
};
<jk>return new</jk> DataSet(items, <jf>addressBook</jf>, <jk>this</jk>.getBeanContext());
}
<jd>/**
* [OPTIONS /*]
* View resource options
*/</jd>
<ja>@Override</ja> /* RestServletJenaDefault */
<ja>@RestMethod</ja>(name=<js>"OPTIONS"</js>, path=<js>"/*"</js>)
<jk>public</jk> Swagger getOptions(RestRequest req) {
<jk>return</jk> req.getSwagger();
}
<jd>/** Convenience method - Find a person by ID */</jd>
<jk>private</jk> Person findPerson(<jk>int</jk> id) <jk>throws</jk> RestException {
Person p = <jf>addressBook</jf>.findPerson(id);
<jk>if</jk> (p == <jk>null</jk>)
<jk>throw new</jk> RestException(<jsf>SC_NOT_FOUND</jsf>, <js>"Person not found"</js>);
<jk>return</jk> p;
}
<jd>/** Convenience method - Find an address by ID */</jd>
<jk>private</jk> Address findAddress(<jk>int</jk> id) <jk>throws</jk> RestException {
Address a = <jf>addressBook</jf>.findAddress(id);
<jk>if</jk> (a == <jk>null</jk>)
<jk>throw new</jk> RestException(<jsf>SC_NOT_FOUND</jsf>, <js>"Address not found"</js>);
<jk>return</jk> a;
}
}
</p>
<h6 class='topic'>Notes</h6>
<ul class='spaced-list'>
<li>The <l>@RestResource.messages()</l> annotation identifies <l>org/apache/juneau/samples/addressbook/nls/AddressBookResource.properties</l> as the resource bundle for localized message for this class.
<li>You are setting <l>XML_enableNamespaces</l> to <l>true</l> to enable XML namespaces.
By default, XML namespace support is disabled per {@link org.apache.juneau.xml.XmlSerializerContext#XML_enableNamespaces},
so you have to explicitly enable it on our serializers.
<li>The <l>XML_autoDetectNamespaces</l> setting is needed to get the XML serializer to add <l>xmlns</l> attributes to the root elements.
This causes the XML serializer to scan the POJO objects for namespaces in order to populate the root element.
There are other ways to do this, such as explicitely specifying the <l>XML_defaultNamespaceUris</l> setting at either the resource or method level, which might be preferred in high-performance environments.
However, <l>XML_autoDetectNamespaces</l> produces the simplest code for our example.
<li>The <l>updatePerson()</l> and <l>updateAddress()</l> methods use a guard to only allow administrators access.
For the sample code, the guard does nothing. It's up to the implementer to decide how to restrict access.
<li>The <l>updatePerson()</l> and <l>updateAddress()</l> methods use the {@link org.apache.juneau.utils.PojoRest} class
to locate and update individual nodes in a POJO tree using the path remainder on the request.
<li>The <l>doInit()</l> method shows an example of an overloaded method using the <l>@RestMethod(name="INIT")</l> annotation.
<li>The <l>getOptions()</l> method shows the default OPTIONS page augmented with some additional information.
</ul>
<p>
The OPTIONS page uses the servlet resource bundle to specify the labels so that they're globalizable.
</p>
<h6 class='figure'>AddressBookResource.properties</h6>
<p class='bcode'>
<ck>title</ck> = <cv>AddressBook sample resource</cv>
<ck>description</ck> = <cv>Proof-of-concept resource that shows off the capabilities of working with POJO resources</cv>
<ck>getRoot.summary</ck> = <cv>Get root page</cv>
<ck>getRoot.description</ck> = <cv>Jumping off page for top-level Person and Address beans.</cv>
<ck>doInit.summary</ck> = <cv>Reinitialize this resource</cv>
<ck>doInit.description</ck> = <cv>Resets the address book to the original contents.</cv>
<ck>doInit.res.200.description</ck> = <cv>Returns the string "OK"</cv>
<ck>getAllPeople.summary</ck> = <cv>Get all people in the address book</cv>
<ck>getAllPeople.res.200.description</ck> = <cv>Returns a serialized List&lt;Person&gt;</cv>
<ck>getAllPeople.res.200.examples</ck> = <cv>{'text/json':"[\n\t{\n\t\turi:'http://hostname/addressBook/person/1',\n\t\taddressBookUri:'http://localhost/addressBook',\n\t\tid:1,\n\t\tname:'John Smith',\n\t\tbirthDate:'Jan 1, 2000',\n\t\taddresses:[\n\t\t\t{\n\t\t\t\turi:'http://localhost/addressBook/addresses/1',\n\t\t\t\tpersonUri:'http://localhost/addressBook/people/1',\n\t\t\t\tid:1,\n\t\t\t\tstreet:'101 Main St',\n\t\t\t\tcity:'Anywhere',\n\t\t\t\tstate:'NY',\n\t\t\t\tzip:12345,\n\t\t\t\tisCurrent:true\n\t\t\t}\n\t\t]\n\t}\n]"}</cv>
<ck>getPerson.summary</ck> = <cv>Get a single person by ID</cv>
<ck>getPerson.req.path.id.description</ck> = <cv>Person ID</cv>
<ck>getPerson.req.path.id.type</ck> = <cv>integer</cv>
<ck>getPerson.res.200.description</ck> = <cv>Returns a serialized Person bean</cv>
<ck>getPerson.res.200.examples</ck> = <cv>{'text/json':"{\n\turi:'http://hostname/addressBook/person/1',\n\taddressBookUri:'http://localhost/addressBook',\n\tid:1,\n\tname:'John Smith',\n\tbirthDate:'Jan 1, 2000',\n\taddresses:[\n\t\t{\n\t\t\turi:'http://localhost/addressBook/addresses/1',\n\t\t\tpersonUri:'http://localhost/addressBook/people/1',\n\t\t\tid:1,\n\t\t\tstreet:'101 Main St',\n\t\t\tcity:'Anywhere',\n\t\t\tstate:'NY',\n\t\t\tzip:12345,\n\t\t\tisCurrent:true\n\t\t}\n\t]\n\}"}</cv>
<ck>getPerson.res.404.description</ck> = <cv>Person ID not found</cv>
<ck>getAllAddresses.summary</ck> = <cv>Get all addresses in the address book</cv>
<ck>getAllAddresses.res.200.description</ck> = <cv>Returns a serialized List&lt;Address&gt;</cv>
<ck>getAllAddresses.res.200.examples</ck> = <cv>{'text/json':"[\n\t{\n\t\turi:'http://localhost/addressBook/addresses/1',\n\t\tpersonUri:'http://localhost/addressBook/people/1',\n\t\tid:1,\n\t\tstreet:'101 Main St',\n\t\tcity:'Anywhere',\n\t\tstate:'NY',\n\t\tzip:12345,\n\t\tisCurrent:true\n\t}\n]"}</cv>
<ck>getAddress.summary</ck> = <cv>Get a single address by ID</cv>
<ck>getAddress.req.path.id.description</ck> = <cv>Address ID</cv>
<ck>getAddress.req.path.id.type</ck> = <cv>integer</cv>
<ck>getAddress.res.200.description</ck> = <cv>Returns a serialized Address bean</cv>
<ck>getAddress.res.200.examples</ck> = <cv>{'text/json':"{\n\turi:'http://localhost/addressBook/addresses/1',\n\tpersonUri:'http://localhost/addressBook/people/1',\n\tid:1,\n\tstreet:'101 Main St',\n\tcity:'Anywhere',\n\tstate:'NY',\n\tzip:12345,\n\tisCurrent:true\n}"}</cv>
<ck>getAddress.res.404.description</ck> = <cv>Address ID not found</cv>
<ck>createPerson.summary</ck> = <cv>Create a new Person bean </cv>
<ck>createPerson.req.body.description</ck> = <cv>Serialized CreatePerson bean</cv>
<ck>createPerson.req.body.schema</ck> = <cv>{example:"{\n\tname:'John Smith',\n\tbirthDate:'Jan 1, 2000',\n\taddresses:[\n\t\t{\n\t\t\tstreet:'101 Main St',\n\t\t\tcity:'Anywhere',\n\t\t\tstate:'NY',\n\t\t\tzip:12345,\n\t\t\tisCurrent:true\n\t\t}\n\t]\n\}"}</cv>
<ck>createPerson.res.307.header.Location.description</ck> = <cv>URL of new person</cv>
<ck>createAddress.summary</ck> = <cv>Create a new Address bean</cv>
<ck>createAddress.req.path.id.description</ck> = <cv>Person ID</cv>
<ck>createAddress.req.path.id.type</ck> = <cv>integer</cv>
<ck>createAddress.req.body.schema</ck> = <cv>{example:"{\n\tstreet:'101 Main St',\n\tcity:'Anywhere',\n\tstate:'NY',\n\tzip:12345,\n\tisCurrent:true\n}"}</cv>
<ck>createAddress.res.307.header.Location.description</ck> = <cv>URL of new address</cv>
<ck>deletePerson.summary</ck> = <cv>Delete a Person bean</cv>
<ck>deletePerson.req.path.id.description</ck> = <cv>Person ID</cv>
<ck>deletePerson.req.path.id.type</ck> = <cv>integer</cv>
<ck>deletePerson.res.200.description</ck> = <cv>Returns the string "DELETE successful"</cv>
<ck>deletePerson.res.404.description</ck> = <cv>Person ID not found</cv>
<ck>deleteAddress.summary</ck> = <cv>Delete an Address bean</cv>
<ck>deleteAddress.req.path.id.description</ck> = <cv>Address ID</cv>
<ck>deleteAddress.res.200.description</ck> = <cv>Returns the string "DELETE successful"</cv>
<ck>deleteAddress.res.404.description</ck> = <cv>Address ID not found</cv>
<ck>updatePerson.summary</ck> = <cv>Change property on Person bean</cv>
<ck>updatePerson.req.path.id.description</ck> = <cv>Person ID</cv>
<ck>updatePerson.req.path.id.type</ck> = <cv>integer</cv>
<ck>updatePerson.req.body.description</ck> = <cv>Any object matching the field</cv>
<ck>updatePerson.res.200.description</ck> = <cv>Returns the string "PUT successful"</cv>
<ck>updatePerson.res.400.description</ck> = <cv>Invalid object type used</cv>
<ck>updatePerson.res.404.description</ck> = <cv>Person ID not found</cv>
<ck>updateAddress.summary</ck> = <cv>Change property on Address bean</cv>
<ck>updateAddress.req.path.id.description</ck> = <cv>Address ID</cv>
<ck>updateAddress.req.path.id.type</ck> = <cv>integer</cv>
<ck>updateAddress.req.body.description</ck> = <cv>Any object matching the field</cv>
<ck>updateAddress.res.200.description</ck> = <cv>Returns the string "PUT successful"</cv>
<ck>updateAddress.res.400.description</ck> = <cv>Invalid object type used</cv>
<ck>updateAddress.res.404.description</ck> = <cv>Address ID not foundv
<ck>getOptions.summary</ck> = <cv>View resource options</cv>
<ck>getCognosData.summary</ck> = <cv>Get data in Cognos/XML format</cv>
<ck>getCognosData.res.200.description</ck> = <cv>Returns a serialized DataSet</cv>
<ck>otherNotes</ck> = <cv>GZip support enabled. Public methods can be invoked by using the &amp;Method URL parameter. 'text/cognos+xml' support available under root resource only</cv>
</p>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.AddressBookResource.Demo"></a>
<h4 class='topic' onclick='toggle(this)'>8.10.2 - Demo</h4>
<div class='topic'>
<p>
Pointing a browser to the resource shows the results of running the <l>getRoot()</l> method:
</p>
<img class='bordered' src="doc-files/Samples.AddressBookResource.Demo.1.png">
<p>
Clicking the <l>people</l> link shows you the result of running the <l>getAllPeople()</l> method:
</p>
<img class='bordered' src="doc-files/Samples.AddressBookResource.Demo.2.png">
<p>
Notice how the <l>URI</l> properties automatically became hyperlinks.
</p>
<p>
Also notice how the dates are formatted as readable strings.
This was from the transform you added to the <l>Calendar</l> property.
</p>
<p>
Let's see what the output looks like in other formats:
</p>
<h6 class='figure'>JSON</h6>
<img class='bordered' src="doc-files/Samples.AddressBookResource.Demo.3.png">
<h6 class='figure'>Lax JSON</h6>
<img class='bordered' src="doc-files/Samples.AddressBookResource.Demo.4.png">
<h6 class='figure'>XML</h6>
<img class='bordered' src="doc-files/Samples.AddressBookResource.Demo.5.png">
<p>
Notice how our <l>XML_enableNamespaces</l> and <l>XML_autoDetectNamespaces</l> settings result
in namespaces being used.
</p>
<p>
Also notice how the <code><ja>@BeanProperty</ja>(uri=<jk>true</jk>)</code> annotations caused the <l>uri</l> properties
to become XML attributes instead of elements.
</p>
<h6 class='figure'>RDF/XML</h6>
<img class='bordered' src="doc-files/Samples.AddressBookResource.Demo.6.png">
<p>
Notice how the <code><ja>@BeanProperty</ja>(uri=<jk>true</jk>)</code> annotations are used to identify values for
<l>rdf:about</l> values.
</p>
<p>
Also notice how <l>URI</l> properties are serialized as <l>rdf:resource</l> attributes.
</p>
<p>
Now lets look at the schema outputs that can be rendered that show information about the POJO classes themselves.
</p>
<h6 class='figure'>HTML Schema</h6>
<img class='bordered' src="doc-files/Samples.AddressBookResource.Demo.7.png">
<h6 class='figure'>JSON Schema</h6>
<img class='bordered' src="doc-files/Samples.AddressBookResource.Demo.8.png">
<h6 class='figure'>XML Schema</h6>
<img class='bordered' src="doc-files/Samples.AddressBookResource.Demo.9.png">
<p>
Now let's see what else you can do.
</p>
<p>
Clicking on the first <l>personUri</l> link executes the <l>getPerson()</l> method, which renders a serialized <l>Person</l> object:
</p>
<img class='bordered' src="doc-files/Samples.AddressBookResource.Demo.10.png">
<p>
Clicking on the OPTIONS link on the page shows you the Swagger doc generated from our annotations and resource bundle properties:
</p>
<img class='bordered' src="doc-files/Samples.AddressBookResource.Options.png">
</div>
<!-- ======================================================================================================== -->
<a id="Samples.AddressBookResource.Traversable"></a>
<h4 class='topic' onclick='toggle(this)'>8.10.3 - Traversable</h4>
<div class='topic'>
<p>
Because you added the <l>Traversable</l> converter to the <l>getPerson</l> method, you can also address child nodes in the POJO model
through path remainders:
</p>
<img class="bordered" src="doc-files/Samples.AddressBookResource.Traversable.1.png">
<br><br>
<img class="bordered" src="doc-files/Samples.AddressBookResource.Traversable.2.png">
</div>
<!-- ======================================================================================================== -->
<a id="Samples.AddressBookResource.Queryable"></a>
<h4 class='topic' onclick='toggle(this)'>8.10.4 - Queryable</h4>
<div class='topic'>
<p>
The <l>Queryable</l> converter on the <l>getAllPeople()</l> method allows us to perform search/view/sort functions against the data
structure before serialization:
</p>
<h6 class='figure'>Show only the name and addresses columns</h6>
<img class="bordered" src="doc-files/Samples.AddressBookResource.Queryable.1.png">
<h6 class='figure'>Show only names that start with 'B*'</h6>
<img class="bordered" src="doc-files/Samples.AddressBookResource.Queryable.2.png">
<h6 class='figure'>Show only entries with age greater than 60</h6>
<img class="bordered" src="doc-files/Samples.AddressBookResource.Queryable.3.png">
</div>
<!-- ======================================================================================================== -->
<a id="Samples.AddressBookResource.Introspectable"></a>
<h4 class='topic' onclick='toggle(this)'>8.10.5 - Introspectable</h4>
<div class='topic'>
<p>
The <l>Introspectable</l> converter on the <l>getPerson</l> method allows us to invoke public methods on the addressed POJO (in this case, public methods on the <l>String</l> class):
</p>
<img class="bordered" src="doc-files/Samples.AddressBookResource.Introspectable.1.png">
</div>
<!-- ======================================================================================================== -->
<a id="Samples.AddressBookResource.RestClient"></a>
<h4 class='topic' onclick='toggle(this)'>8.10.6 - ClientTest</h4>
<div class='topic'>
<p>
The <l>ClientTest</l> class is provided to demonstrate how POJOs can be serialized and parsed
through the REST interface using the <l>RestClient</l> class.
</p>
<p>
You'll notice that the class is a standalone executable that can be invoked as a plain Java process.
</p>
<h6 class='figure'>ClientTest.java</h6>
<p class='bcode'>
<jd>/**
* Sample client code for interacting with AddressBookResource
*/</jd>
<jk>public class</jk> ClientTest {
<jk>public static void</jk> main(String[] args) {
<jk>try</jk> {
System.<jsf>out</jsf>.println(<js>"Running client test..."</js>);
<jc>// Create a client to handle XML requests and responses.</jc>
RestClient client = <jk>new</jk> RestClientBuilder().build();
RestClient xmlClient = <jk>new</jk> RestClientBuilder(XmlSerializer.<jsf>DEFAULT</jsf>, XmlParser.<jsf>DEFAULT</jsf>).build();
String root = <js>"http://localhost:10000/addressBook"</js>;
<jc>// Get the current contents of the address book</jc>
AddressBook ab = client.doGet(root + <js>"/people"</js>).getResponse(AddressBook.<jk>class</jk>);
System.<jsf>out</jsf>.println(<js>"Number of entries = "</js> + ab.getPeople().size());
<jc>// Same, but use XML as the protocol both ways</jc>
ab = xmlClient.doGet(root + <js>"/people"</js>).getResponse(AddressBook.<jk>class</jk>);
System.<jsf>out</jsf>.println(<js>"Number of entries = "</js> + ab.getPeople().size());
<jc>// Delete the existing entries</jc>
<jk>for</jk> (Person p : ab.getPeople()) {
String r = client.doDelete(p.<jf>uri</jf>).getResponse(String.<jk>class</jk>);
System.<jsf>out</jsf>.println(<js>"Deleted person "</js> + p.<jf>name</jf> + <js>", response = "</js> + r);
}
<jc>// Make sure they're gone</jc>
ab = client.doGet(root + <js>"/people"</js>).getResponse(AddressBook.<jk>class</jk>);
System.<jsf>out</jsf>.println(<js>"Number of entries = "</js> + ab.getPeople().size());
<jc>// Add 1st person again</jc>
CreatePerson cp = <jk>new</jk> CreatePerson(
<js>"Barack Obama"</js>,
<jsm>toCalendar</jsm>(<js>"Aug 4, 1961"</js>),
<jk>new</jk> CreateAddress(<js>"1600 Pennsylvania Ave"</js>, <js>"Washington"</js>, <js>"DC"</js>, 20500, <jk>true</jk>),
<jk>new</jk> CreateAddress(<js>"5046 S Greenwood Ave"</js>, <js>"Chicago"</js>, <js>"IL"</js>, 60615, <jk>false</jk>)
);
Person p = client.doPost(root + <js>"/people"</js>, cp).getResponse(Person.<jk>class</jk>);
System.<jsf>out</jsf>.println(<js>"Created person "</js> + p.<jf>name</jf> + <js>", uri = "</js> + p.<jf>uri</jf>);
<jc>// Add 2nd person again, but add addresses separately</jc>
cp = <jk>new</jk> CreatePerson(
<js>"George Walker Bush"</js>,
<jsm>toCalendar</jsm>(<js>"Jul 6, 1946"</js>)
);
p = client.doPost(root + <js>"/people"</js>, cp).getResponse(Person.<jk>class</jk>);
System.<jsf>out</jsf>.println(<js>"Created person "</js> + p.<jf>name</jf> + <js>", uri = "</js> + p.<jf>uri</jf>);
<jc>// Add addresses to 2nd person</jc>
CreateAddress ca = <jk>new</jk> CreateAddress(<js>"43 Prairie Chapel Rd"</js>, <js>"Crawford"</js>, <js>"TX"</js>, 76638, <jk>true</jk>);
Address a = client.doPost(p.uri + <js>"/addresses"</js>, ca).getResponse(Address.<jk>class</jk>);
System.<jsf>out</jsf>.println(<js>"Created address "</js> + a.<jf>uri</jf>);
ca = <jk>new</jk> CreateAddress(<js>"1600 Pennsylvania Ave"</js>, <js>"Washington"</js>, <js>"DC"</js>, 20500, <jk>false</jk>);
a = client.doPost(p.uri + <js>"/addresses"</js>, ca).getResponse(Address.<jk>class</jk>);
System.<jsf>out</jsf>.println(<js>"Created address "</js> + a.<jf>uri</jf>);
<jc>// Find 1st person, and change name</jc>
Person[] pp = client.doGet(root + <js>"/people?q=(name='Barack+Obama')"</js>).getResponse(Person[].<jk>class</jk>);
String r = client.doPut(pp[0].uri + <js>"/name"</js>, <js>"Barack Hussein Obama"</js>).getResponse(String.<jk>class</jk>);
System.<jsf>out</jsf>.println(<js>"Changed name, response = "</js> + r);
p = client.doGet(pp[0].<jf>uri</jf>).getResponse(Person.<jk>class</jk>);
System.<jsf>out</jsf>.println(<js>"New name = "</js> + p.<jf>name</jf>);
} <jk>catch</jk> (Exception e) {
e.printStackTrace();
}
}
<jc>// Utility method</jc>
<jk>public static</jk> Calendar toCalendar(String birthDate) <jk>throws</jk> Exception {
Calendar c = <jk>new</jk> GregorianCalendar();
c.setTime(DateFormat.getDateInstance(DateFormat.<jsf>MEDIUM</jsf>).parse(birthDate));
<jk>return</jk> c;
}
}
</p>
<p>
The output from running this code is the following:
</p>
<p class='bcode'>
Running client test...
Number of entries = 2
Deleted person Barack Obama, response = DELETE successful
Deleted person George Walker Bush, response = DELETE successful
Number of entries = 0
Created person Barack Obama, uri = http://localhost:9081/sample/addressBook/people/3
Created person George Walker Bush, uri = http://localhost:9081/sample/addressBook/people/4
Created address http://localhost:9081/sample/addressBook/addresses/7
Created address http://localhost:9081/sample/addressBook/addresses/8
Changed name, response = PUT successful
New name = Barack Hussein Obama
</p>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.AddressBookResource.Browser"></a>
<h4 class='topic' onclick='toggle(this)'>8.10.7 - Browser Tips</h4>
<div class='topic'>
<p>
The Juneau architecture is designed to make it easy to debug REST resources using nothing more than a browser.
The same actions done programmatically in the last section can also be done using URLs.
By default, you can override the HTTP Method and Content through GET parameters, as shown below:
</p>
<p class='bcode'>
<jc>// Delete the existing entries</jc>
http://localhost:10000/addressBook/people/1?method=DELETE
http://localhost:10000/addressBook/people/2?method=DELETE
<jc>// Add 1st person again</jc>
http://localhost:10000/addressBook/people?method=POST&amp;content={name:'Barack Obama',birthDate:'Aug 4, 1961',addresses:[{street:'1600 Pennsylvania Ave',city:'Washington',state:'DC',zip:20500,isCurrent:true},{street:'5046 S Greenwood Ave',city:'Chicago',state:'IL',zip:60615,isCurrent:false}]}
<jc>// Add 2nd person again</jc>
http://localhost:10000/addressBook/people?method=POST&amp;content={name:'George Walker Bush',birthDate:'Jul 6, 1946'}
http://localhost:10000/addressBook/people/4/addresses?method=POST&amp;content={street:'43 Prairie Chapel Rd',city:'Crawford',state:'TX',zip:76638,isCurrent:true}
http://localhost:10000/addressBook/people/4/addresses?method=POST&amp;content={street:'1600 Pennsylvania Ave',city:'Washington',state:'DC',zip:20500,isCurrent:false}
<jc>// Change name of 1st person</jc>
http://localhost:10000/addressBook/people/3/name?method=PUT&amp;content="'Barack Hussein Obama'"
</p>
<p>
The ability to overload methods is enabled through the {@link org.apache.juneau.rest.RestContext#REST_allowMethodParam} property.
</p>
</div>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.SampleRemoteableServlet"></a>
<h3 class='topic' onclick='toggle(this)'>8.11 - SampleRemoteableServlet</h3>
<div class='topic'>
<p>
The <l>SampleRemoteableServlet</l> class shows examples of the following:
</p>
<ul class='spaced-list'>
<li>Extending the {@link org.apache.juneau.rest.remoteable.RemoteableServlet} class to create a proxy service.
<li>Using the {@link org.apache.juneau.rest.client.RestClient} class to create remoteable proxy interfaces.
</ul>
<p>
The <l>RemoteableServlet</l> class has a single abstract method, {@link org.apache.juneau.rest.remoteable.RemoteableServlet#getServiceMap()},
that defines interface keys and POJO values.
</p>
<p>
The <l>SampleRemoteableServlet</l> exposes the <l>AddressBook</l> bean from the previous example as a service.
</p>
<p class='bcode'>
<ja>@RestResource</ja>(
path=<js>"/remoteable"</js>,
messages=<js>"nls/SampleRemoteableServlet"</js>,
title=<js>"Remoteable Service Proxy API"</js>,
description=<js>"Sample class showing how to use remoteable proxies. The list below are exposed services that can be retrieved using RestClient.getProxyInterface(Class)."</js>,
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{up:'request:/..',options:'servlet:/?method=OPTIONS'}"</js>
),
properties={
<jc>// Allow us to use method=POST from a browser.</jc>
<ja>@Property</ja>(name=<jsf>REST_allowMethodParam</jsf>, value=<js>"*"</js>)
}
)
<jk>public class</jk> SampleRemoteableServlet <jk>extends</jk> RemoteableServlet {
AddressBook <jf>addressBook</jf> = <jk>new</jk> AddressBook();
<ja>@Override</ja> <jc>/* RemoteableServlet */</jc>
<jk>protected</jk> Map&lt;Class&lt;?&gt;,Object&gt; getServiceMap() <jk>throws</jk> Exception {
Map&lt;Class&lt;?&gt;,Object&gt; m = <jk>new</jk> LinkedHashMap&lt;Class&lt;?&gt;,Object&gt;();
<jc>// In this simplified example, you expose the same POJO service under two different interfaces.</jc>
<jc>// One is IAddressBook which only exposes methods defined on that interface, and</jc>
<jc>// the other is AddressBook itself which exposes all methods defined on the class itself.</jc>
m.put(IAddressBook.<jk>class</jk>, <jf>addressBook</jf>);
m.put(AddressBook.<jk>class</jk>, <jf>addressBook</jf>);
<jk>return</jk> m;
}
}
</p>
<p>
Pointing a browser to the resource shows the following:
</p>
<img class='bordered' src='doc-files/Samples.SampleRemoteableServlet.1.png'>
<p>
Clicking the hyperlinks on each shows you the list of methods that can be invoked on that service.
Note that the <l>IAddressBook</l> link shows that you can only invoke methods defined on that
interface, whereas the <l>AddressBook</l> link shows ALL public methods defined on that class.
Since <l>AddressBook</l> extends from <l>LinkedList</l>, you may notice familiar collections
framework methods listed.
</p>
<img class='bordered' src='doc-files/Samples.SampleRemoteableServlet.2.png'>
<br><br>
<img class='bordered' src='doc-files/Samples.SampleRemoteableServlet.3.png'>
<ul class='doctree'>
<li class='info'>
As good practice, you'll want to use interfaces to prevent all public methods from being exposed.
</ul>
<p>
Proxy interfaces are then retrieved using the {@link org.apache.juneau.rest.client.RestClient#getRemoteableProxy(Class)} method.
</p>
<p>
The client side code for invoking this method is shown below:
</p>
<p class='bcode'>
<jc>// Create a RestClient using JSON for serialization, and point to the server-side remoteable servlet.</jc>
RestClient client = <jk>new</jk> RestClientBuilder()
.rootUrl(<js>"http://localhost:10000/remoteable"</js>)
.build();
<jc>// Create a proxy interface.</jc>
IAddressBook ab = client.getRemoteableProxy(IAddressBook.<jk>class</jk>);
<jc>// Invoke a method on the server side and get the returned result.</jc>
Person p = ab.createPerson(
<jk>new</jk> CreatePerson(<js>"Test Person"</js>,
AddressBook.<jsm>toCalendar</jsm>(<js>"Aug 1, 1999"</js>),
<jk>new</jk> CreateAddress(<js>"Test street"</js>, <js>"Test city"</js>, <js>"Test state"</js>, 12345, <jk>true</jk>))
);
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/server/remoteable/package-summary.html#TOC'>org.apache.juneau.rest.remoteable</a> - Remoteable API Javadoc
<li class='jac'>{@link org.apache.juneau.rest.remoteable.RemoteableServlet}
<li class='jc'>{@link org.apache.juneau.rest.client.RestClient}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.client.RestClient#getRemoteableProxy(Class) getRemoteableProxy(Class)}
<li class='jm'>{@link org.apache.juneau.rest.client.RestClient#getRemoteableProxy(Class,Object) getRemoteableProxy(Class,Object)}
</ul>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.TempDirResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.12 - TempDirResource</h3>
<div class='topic'>
<p>
The <l>TempDirResource</l> class shows examples of the following:
</p>
<ul class='spaced-list'>
<li>Extending the {@link org.apache.juneau.microservice.resources.DirectoryResource} class.
<li>Using the Apache <l>ServletFileUpload</l> class to handle multi-part form posts.
<li>Using a system property string variable.
<li>Using {@link org.apache.juneau.rest.RestMatcher RestMatchers}.
</ul>
<p>
Pointing a browser to the resource shows the following:
</p>
<img class='bordered' src='doc-files/Samples.TempDirResource.1.png'>
<p>
Pointing a browser to the <l>upload</l> link shows a form entry page:
</p>
<img class='bordered' src='doc-files/Samples.TempDirResource.2.png'>
<h6 class='figure'>TempDirResource.java</h6>
<p class='bcode'>
<jd>/**
* Sample resource that extends DirectoryResource to open up the temp directory as a REST resource.
*/</jd>
<ja>@RestResource</ja>(
path=<js>"/tempDir"</js>,
messages=<js>"nls/TempDirResource"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{up:'request:/..', options:'servlet:/?method=OPTIONS', upload:'servlet:/upload'}"</js>
),
properties={
<ja>@Property</ja>(name=<js>"DirectoryResource.rootDir"</js>, value=<js>"$S{java.io.tmpdir}"</js>),
<ja>@Property</ja>(name=<js>"DirectoryResource.allowViews"</js>, value=<js>"true"</js>),
<ja>@Property</ja>(name=<js>"DirectoryResource.allowDeletes"</js>, value=<js>"true"</js>),
<ja>@Property</ja>(name=<js>"DirectoryResource.allowPuts"</js>, value=<js>"false"</js>)
},
stylesheet=<js>"styles/devops.css"</js>
)
<jk>public class</jk> TempDirResource <jk>extends</jk> DirectoryResource {
<jk>private static final long</jk> <jsf>serialVersionUID</jsf> = 1L;
<jd>/**
* [GET /upload] - Display the form entry page for uploading a file to the temp directory.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/upload"</js>)
<jk>public</jk> ReaderResource getUploadPage(RestRequest req) <jk>throws</jk> IOException {
<jk>return</jk> req.getReaderResource(<js>"TempDirUploadPage.html"</js>, <jk>true</jk>);
}
<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> &amp;&amp; contentType.startsWith(<js>"multipart/form-data"</js>);
}
}
}
</p>
<h6 class='figure'>TempDirResource.properties</h6>
<p class='bcode'>
<cc>#--------------------------------------------------------------------------------
# TempDirResource labels
#--------------------------------------------------------------------------------</cc>
<ck>title</ck> = <cv>Temp Directory View Service</cv>
<ck>description</ck> = <cv>View and download files in the '$S{java.io.tmpdir}' directory.</cv>
</p>
<p>
Note how a system property variable can be defined in the properties file.
</p>
<h6 class='figure'>TempDirUploadPage.html</h6>
<p class='bcode'>
<xt>&lt;html&gt;</xt>
<xt>&lt;head&gt;</xt>
<xt>&lt;meta</xt> <xa>http-equiv</xa>=<xs>"Content-Type"</xs> <xa>content</xa>=<xs>"text/html; <xa>charset</xa>=UTF-8"</xs><xt>&gt;</xt>
<xt>&lt;style</xt> <xa>type</xa>=<xs>'text/css'</xs><xt>&gt;</xt>
<xt>@import</xt> <xs>'$R{servletURI}/style.css'</xs>;
<xt>&lt;/style&gt;</xt>
<xt>&lt;/head&gt;</xt>
<xt>&lt;body&gt;</xt>
<xt>&lt;h3</xt> <xa>class</xa>=<xs>'title'</xs><xt>&gt;</xt>$R{servletTitle}<xt>&lt;/h3&gt;</xt>
<xt>&lt;h5</xt> <xa>class</xa>=<xs>"description"</xs><xt>&gt;</xt>$R{servletDescription}<xt>&lt;/h5&gt;</xt>
<xt>&lt;div</xt> <xa>class</xa>=<xs>'data'</xs><xt>&gt;</xt>
<xt>&lt;form</xt> <xa>id</xa>=<xs>'form'</xs> <xa>action</xa>=<xs>'$R{servletURI}/upload'</xs> <xa>method</xa>=<xs>'POST'</xs> <xa>target</xa>=<xs>'buff'</xs> <xa>enctype</xa>=<xs>"multipart/form-data"</xs><xt>&gt;</xt>
<xt>&lt;input</xt> <xa>name</xa>=<xs>"contents"</xs> <xa>type</xa>=<xs>"file"</xs><xt>&gt;</xt><xt>&lt;button</xt> <xa>type</xa>=<xs>"submit"</xs><xt>&gt;</xt>Submit<xt>&lt;/button&gt;</xt>
<xt>&lt;/form&gt;</xt>
<xt>&lt;/div&gt;</xt>
<xt>&lt;/body&gt;</xt>
<xt>&lt;/html&gt;</xt>
</p>
<p>
Note how the HTML file contains localized variables for the servlet label and description.
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jac'>{@link org.apache.juneau.microservice.resources.DirectoryResource}
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.AtomFeedResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.13 - AtomFeedResource</h3>
<div class='topic'>
<p>
The <l>AtomFeedResource</l> class shows examples of the following:
</p>
<ul class='spaced-list'>
<li>Using the <a class='doclink' href='org/apache/juneau/dto/atom/package-summary.html#TOC'>ATOM Feed DTO</a> API.
</ul>
<p>
Pointing a browser to the resource shows the following:
</p>
<img class='bordered' src='doc-files/Samples.AtomFeedResource.1.png'>
<p>
True ATOM feeds require using an <l>Accept:text/xml</l> header:
</p>
<img class='bordered' src='doc-files/Samples.AtomFeedResource.2.png'>
<p>
Other languages, such as JSON are also supported:
</p>
<img class='bordered' src='doc-files/Samples.AtomFeedResource.3.png'>
<h6 class='figure'>AtomFeedResource.java</h6>
<p class='bcode'>
<jd>/**
* Sample resource that shows how to generate ATOM feeds.
*/</jd>
<ja>@RestResource</ja>(
path=<js>"/atom"</js>,
messages=<js>"nls/AtomFeedResource"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{up:'request:/..',options:'servlet:/?method=OPTIONS'}"</js>
),
properties={
<ja>@Property</ja>(name=<jsf>SERIALIZER_quoteChar</jsf>, value=<js>"'"</js>),
<ja>@Property</ja>(name=<jsf>RDF_rdfxml_tab</jsf>, value=<js>"5"</js>),
<ja>@Property</ja>(name=<jsf>RDF_addRootProperty</jsf>, value=<js>"true"</js>)
},
encoders=GzipEncoder.<jk>class</jk>
)
<jk>public class</jk> AtomFeedResource <jk>extends</jk> ResourceJena {
<jk>private static final long</jk> <jsf>serialVersionUID</jsf> = 1L;
<jk>private</jk> Feed <jf>feed</jf>; <jc>// The root resource object</jc>
<ja>@Override</ja> <jc>/* Servlet */</jc>
<jk>public void</jk> init() {
<jk>try</jk> {
<jf>feed</jf> = <jk>new</jk> Feed()
.setTitle(<jk>new</jk> Text(<js>"text"</js>, <js>"Juneau ATOM specification"</js>))
.setSubTitle(<jk>new</jk> Text(<js>"html"</js>, <js>"Decribes &lt;em&gt;stuff&lt;/em&gt; about Juneau"</js>))
.setUpdated(<jsm>parseDateTime</jsm>(<js>"2016-01-02T03:04:05Z"</js>))
.setId(<jk>new</jk> Id(<js>"tag:juneau.apache.org"</js>))
.addLinks(
<jk>new</jk> Link(<js>"alternate"</js>, <js>"text/html"</js>, <js>"http://juneau.apache.org/"</js>).setHreflang(<js>"en"</js>),
<jk>new</jk> Link(<js>"self"</js>, <js>"application/atom+xml"</js>, <js>"http://juneau.apache.org/feed.atom"</js>)
)
.setRights(<jk>new</jk> Text(<js>"Copyright (c) 2016, Apache Foundation"</js>))
.setGenerator(<jk>new</jk> Generator(<js>"Juneau"</js>).setUri(<jk>new</jk> URI(<js>"http://juneau.apache.org/"</js>)).setVersion(<js>"1.0"</js>))
.addEntries(
<jk>new</jk> Entry()
.setTitle(<jk>new</jk> Text(<js>"Juneau ATOM specification snapshot"</js>))
.addLinks(
<jk>new</jk> Link(<js>"alternate"</js>, <js>"text/html"</js>, <js>"http://juneau.apache.org/juneau.atom"</js>),
<jk>new</jk> Link(<js>"enclosure"</js>, <js>"audio/mpeg"</js>, <js>"http://juneau.apache.org/audio/juneau_podcast.mp3"</js>).setLength(12345)
)
.setId(<jk>new</jk> Id(<js>"tag:juneau.apache.org"</js>))
.setUpdated(<jsm>parseDateTime</jsm>(<js>"2016-01-02T03:04:05Z"</js>))
.setPublished(<jsm>parseDateTime</jsm>(<js>"2016-01-02T03:04:05Z"</js>))
.addAuthors(<jk>new</jk> Person(<js>"James Bognar"</js>).setUri(<jk>new</jk> URI(<js>"http://juneau.apache.org/"</js>)).setEmail(<js>"james.bognar@apache.org"</js>))
.addContributors(
<jk>new</jk> Person(<js>"Barry M. Caceres"</js>)
)
.setContent(
<jk>new</jk> Content()
.setLang(<js>"en"</js>)
.setBase(<jk>new</jk> URI(<js>"http://www.apache.org/"</js>))
.setType(<js>"xhtml"</js>)
.setText(<js>"&lt;div xmlns=\"http://www.w3.org/1999/xhtml\"&gt;&lt;p&gt;&lt;i&gt;[Update: Juneau supports ATOM.]&lt;/i&gt;&lt;/p&gt;&lt;/div&gt;"</js>)
)
);
} <jk>catch</jk> (Exception e) {
<jk>throw new</jk> RuntimeException(e);
}
}
<jd>/**
* GET request handler
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/"</js>)
<jk>public</jk> Feed getFeed() <jk>throws</jk> Exception {
<jk>return</jk> <jf>feed</jf>;
}
<jd>/**
* PUT request handler.
* Replaces the feed with the specified content, and then mirrors it as the response.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"PUT"</js>, path=<js>"/"</js>)
<jk>public</jk> Feed setFeed(<ja>@org.apache.juneau.rest.annotation.Content</ja> Feed feed) <jk>throws</jk> Exception {
<jk>this</jk>.<jf>feed</jf> = feed;
<jk>return</jk> feed;
}
}
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jp'><a class='doclink' href='org/apache/juneau/dto/atom/package-summary.html#TOC'>org.apache.juneau.dto.atom</a> - ATOM Feed DTO Javadocs.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.DockerRegistryResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.14 - DockerRegistryResource</h3>
<div class='topic'>
<p>
The <l>DockerRegistryResource</l> class shows examples of the following:
</p>
<ul class='spaced-list'>
<li>Accessing a docker registry REST API as POJOs using {@link org.apache.juneau.rest.client.RestClient}.
<li>Using the {@link org.apache.juneau.rest.labels.ResourceDescription} class to implement a top-level 'router' page.
<li>Using the {@link org.apache.juneau.rest.RestContext#getConfigFile()} method to access external configuration file values.
</ul>
<p>
Pointing a browser to the resource shows the following:
</p>
<img class='bordered' src='doc-files/Samples.DockerRegistryResource.1.png'>
<p>
Clicking the <l>search</l> link provides you with the search results against the Docker registry:
</p>
<img class='bordered' src='doc-files/Samples.DockerRegistryResource.2.png'>
<h6 class='figure'>DockerRegistryResource.java</h6>
<p class='bcode'>
<jd>/**
* Sample resource that shows how to mirror query results from a Docker registry.
*/</jd>
<ja>@RestResource</ja>(
path=<js>"/docker"</js>,
title=<js>"Sample Docker resource"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{up:'request:/..',options:'servlet:/?method=OPTIONS'}"</js>
)
)
<jk>public class</jk> DockerRegistryResource <jk>extends</jk> Resource {
<jk>private static final long</jk> <jsf>serialVersionUID</jsf> = 1L;
<jc>// Get registry URL from examples.cfg file.</jc>
<jk>private</jk> String <jf>registryUrl</jf> = getConfig().getString(<js>"DockerRegistry/url"</js>);
RestClient <jf>rc</jf> = <jk>new</jk> RestClientBuilder().build();
<jd>/** [GET /] - Show child resources. */</jd>
<ja>@SuppressWarnings</ja>(<js>"nls"</js>)
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/"</js>)
<jk>public</jk> ResourceDescription[] getChildren(RestRequest req) {
<jk>return new</jk> ResourceDescription[] {
<jk>new</jk> ResourceDescription(req, <js>"search"</js>, <js>"Search Registry"</js>)
};
}
<jd>/**
* PUT request handler.
* Replaces the feed with the specified content, and then mirrors it as the response.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/search"</js>)
<jk>public</jk> QueryResults query(<ja>@Query</ja>(<js>"q"</js>) String q) <jk>throws</jk> Exception {
String url = <jf>registryUrl</jf> + <js>"/search"</js> + (q == <jk>null</jk> ? <js>""</js> : <js>"?q="</js> + q);
<jk>return</jk> <jf>rc</jf>.doGet(url).getResponse(QueryResults.<jk>class</jk>);
}
<jk>public static class</jk> QueryResults {
<jk>public int</jk> <jf>num_results</jf>;
<jk>public</jk> String <jf>query</jf>;
<jk>public</jk> List&lt;DockerImage&gt; <jf>results</jf>;
}
<jk>public static class</jk> DockerImage {
<jk>public</jk> String <jf>name</jf>, <jf>description</jf>;
}
}
</p>
<p>
The Docker registry URL is specified in the <l>examples.cfg</l> file:
</p>
<h6 class='figure'>examples.cfg</h6>
<p class='bcode'>
<cc>#================================================================================
# DockerRegistryResource properties
#================================================================================</cc>
<cs>[DockerRegistry]</cs>
<ck>url</ck> = <cv>http://clmdocker02.ratl.swg.usma.apache.org:5000/v1</cv>
</p>
<h6 class='topic'>Additional Information</h6>
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.rest.labels.ResourceDescription}
<li class='jm'>{@link org.apache.juneau.rest.RestContext#getConfigFile()}
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.TumblrParserResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.15 - TumblrParserResource</h3>
<div class='topic'>
<p>
The <l>TumblrParserResource</l> class shows examples of the following:
</p>
<ul class='spaced-list'>
<li>Using {@link org.apache.juneau.rest.client.RestClient} to retrieve information from other REST resources.
<li>Using {@link org.apache.juneau.ObjectMap} and {@link org.apache.juneau.ObjectList} to produce
generalized POJO models.
</ul>
<p>
Pointing a browser at a Tumblr blog name, such as <l>ibmblr</l> causes a REST call to be make to the Tumblr
blog and the results to be parsed:
</p>
<img class='bordered' src='doc-files/Samples.TumblrParserResource.1.png'>
<h6 class='figure'>TumblrParserResource.java</h6>
<p class='bcode'>
<ja>@RestResource</ja>(
path=<js>"/tumblrParser"</js>,
messages=<js>"nls/TumblrParserResource"</js>,
title=<js>"Tumblr parser service"</js>,
description=<js>"Specify a URL to a Tumblr blog and parse the results."</js>,
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{up:'request:/..',options:'servlet:/?method=OPTIONS'}"</js>
)
)
<jk>public class</jk> TumblrParserResource <jk>extends</jk> Resource {
<jk>private static final long</jk> <jsf>serialVersionUID</jsf> = 1L;
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/"</js>)
<jk>public</jk> String getInstructions() <jk>throws</jk> Exception {
<jk>return</jk> <js>"Append the Tumblr blog name to the URL above (e.g. /tumblrParser/mytumblrblog)"</js>;
}
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/{blogName}"</js>)
<jk>public</jk> ObjectList parseBlog(<ja>@Path</ja> String blogName) <jk>throws</jk> Exception {
ObjectList l = <jk>new</jk> ObjectList();
RestClient rc = <jk>new</jk> RestClientBuilder().build();
String site = <js>"http:<jc>//"</js> + blogName + <js>".tumblr.com/api/read/json"</js>;</jc>
ObjectMap m = rc.doGet(site).getResponse(ObjectMap.<jk>class</jk>);
<jk>int</jk> postsTotal = m.getInt(<js>"posts-total"</js>);
<jk>for</jk> (<jk>int</jk> i = 0; i &lt; postsTotal; i += 20) {
m = rc.doGet(site + <js>"?start="</js> + i + <js>"&amp;num=20&amp;transform=text"</js>).getResponse(ObjectMap.<jk>class</jk>);
ObjectList ol = m.getObjectList(<js>"posts"</js>);
<jk>for</jk> (<jk>int</jk> j = 0; j &lt; ol.size(); j++) {
ObjectMap om = ol.getObjectMap(j);
String type = om.getString(<js>"type"</js>);
Entry e = <jk>new</jk> Entry();
e.date = om.getString(<js>"date"</js>);
<jk>if</jk> (type.equals(<js>"link"</js>))
e.entry = <jk>new</jk> Link(om.getString(<js>"link-text"</js>), om.getString(<js>"link-url"</js>));
<jk>else if</jk> (type.equals(<js>"audio"</js>))
e.entry = <jk>new</jk> ObjectMap().append(<js>"type"</js>,<js>"audio"</js>).append(<js>"audio-caption"</js>, om.getString(<js>"audio-caption"</js>));
<jk>else if</jk> (type.equals(<js>"video"</js>))
e.entry = <jk>new</jk> ObjectMap().append(<js>"type"</js>,<js>"video"</js>).append(<js>"video-caption"</js>, om.getString(<js>"video-caption"</js>));
<jk>else if</jk> (type.equals(<js>"quote"</js>))
e.entry = <jk>new</jk> ObjectMap().append(<js>"type"</js>,<js>"quote"</js>).append(<js>"quote-source"</js>, om.getString(<js>"quote-source"</js>)).append(<js>"quote-text"</js>, om.getString(<js>"quote-text"</js>));
<jk>else if</jk> (type.equals(<js>"regular"</js>))
e.entry = om.getString(<js>"regular-body"</js>);
<jk>else if</jk> (type.equals(<js>"photo"</js>))
e.entry = <jk>new</jk> Img(om.getString(<js>"photo-url-250"</js>));
<jk>else</jk>
e.entry = <jk>new</jk> ObjectMap().append(<js>"type"</js>, type);
l.add(e);
}
}
<jk>return</jk> l;
}
<jk>public static class</jk> Entry {
<jk>public</jk> String <jf>date</jf>;
<jk>public</jk> Object <jf>entry</jf>;
}
}
</p>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.PhotosResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.16 - PhotosResource</h3>
<div class='topic'>
<p>
The <l>PhotosResource</l> class shows examples of the following:
</p>
<ul class='spaced-list'>
<li>How to define custom serializers and parsers at the method level.
In this case, you define a serializer and parser to handle images.
</ul>
<p>
The resource consists of a simple registry of images with integer IDs.
</p>
<img class='bordered' src='doc-files/Samples.PhotosResource.1.png'>
<p>
It is initialized with a single entry, which can be accessed through a GET request.
</p>
<img class='bordered' src='doc-files/Samples.PhotosResource.2.png'>
<h6 class='figure'>PhotosResource.java</h6>
<p class='bcode'>
<jd>/**
* Sample resource that allows images to be uploaded and retrieved.
*/</jd>
<ja>@RestResource</ja>(
path=<js>"/photos"</js>,
messages=<js>"nls/PhotosResource"</js>,
title=<js>"Photo REST service"</js>,
description=<js>"Use a tool like Poster to upload and retrieve jpeg and png images."</js>,
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{options:'?method=OPTIONS'}"</js>
)
)
<jk>public class</jk> PhotosResource <jk>extends</jk> RestServletDefault {
<jc>// Our cache of photos</jc>
<jk>private</jk> Map&lt;Integer,Photo&gt; photos = <jk>new</jk> TreeMap&lt;Integer,Photo&gt;();
<ja>@Override</ja> <jc>/* Servlet */</jc>
<jk>public void</jk> init() {
<jk>try</jk> {
<jc>// Preload an image.</jc>
InputStream is = getClass().getResourceAsStream(<js>"averycutedog.jpg"</js>);
BufferedImage image = ImageIO.<jsm>read</jsm>(is);
Photo photo = <jk>new</jk> Photo(0, image);
<jf>photos</jf>.put(photo.<jf>id</jf>, photo);
} <jk>catch</jk> (IOException e) {
<jk>throw new</jk> RuntimeException(e);
}
}
<jd>/** Bean class for storing photos */</jd>
<jk>public static class</jk> Photo {
<jk>private int</jk> <jf>id</jf>;
BufferedImage <jf>image</jf>;
Photo(int id, BufferedImage image) {
<jk>this</jk>.<jf>id</jf> = id;
<jk>this</jk>.<jf>image</jf> = image;
}
<jk>public</jk> URI getURI() <jk>throws</jk> URISyntaxException {
<jk>return new</jk> URI(<js>"photos/"</js>+<jf>id</jf>);
}
<jk>public int</jk> getID() {
<jk>return</jk> <jf>id</jf>;
}
}
<jd>/** GET request handler for list of all photos */</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/"</js>)
<jk>public</jk> Collection&lt;Photo&gt; getAllPhotos(RestRequest req, RestResponse res) <jk>throws</jk> Exception {
res.setPageTitle(<js>"Photo REST service"</js>);
res.setPageText(<js>"Use a tool like Poster to upload and retrieve jpeg and png images."</js>);
<jk>return</jk> photos.values();
}
<jd>/** GET request handler for single photo */</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/{id}"</js>, serializers=ImageSerializer.<jk>class</jk>)
<jk>public</jk> BufferedImage getPhoto(RestRequest req, <ja>@Path</ja> int id) <jk>throws</jk> Exception {
Photo p = photos.get(id);
if (p == <jk>null</jk>)
<jk>throw new</jk> RestException(<jsf>SC_NOT_FOUND</jsf>, <js>"Photo not found"</js>);
<jk>return</jk> p.image;
}
<jd>/** PUT request handler */</jd>
<ja>@RestMethod</ja>(name=<js>"PUT"</js>, path=<js>"/{id}"</js>, parsers=ImageParser.<jk>class</jk>)
<jk>public</jk> String addPhoto(RestRequest req, <ja>@Path</ja> <jk>int</jk> id, <ja>@Body</ja> BufferedImage image) <jk>throws</jk> Exception {
photos.put(id, <jk>new</jk> Photo(id, image));
<jk>return</jk> <js>"OK"</js>;
}
<jd>/** POST request handler */</jd>
<ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/"</js>, parsers=ImageParser.<jk>class</jk>)
<jk>public</jk> Photo setPhoto(RestRequest req, <ja>@Body</ja> BufferedImage image) <jk>throws</jk> Exception {
<jk>int</jk> id = photos.size();
Photo p = <jk>new</jk> Photo(id, image);
photos.put(id, p);
<jk>return</jk> p;
}
<jd>/** DELETE request handler */</jd>
<ja>@RestMethod</ja>(name=<js>"DELETE"</js>, path=<js>"/{id}"</js>)
<jk>public</jk> String deletePhoto(RestRequest req, <ja>@Path</ja> <jk>int</jk> id) <jk>throws</jk> Exception {
Photo p = photos.remove(id);
if (p == <jk>null</jk>)
<jk>throw new</jk> RestException(<jsf>SC_NOT_FOUND</jsf>, <js>"Photo not found"</js>);
<jk>return</jk> <js>"OK"</js>;
}
<jd>/** OPTIONS request handler */</jd>
<ja>@RestMethod</ja>(name=<js>"OPTIONS"</js>, path=<js>"/*"</js>)
<jk>public</jk> Swagger getOptions(RestRequest req) {
<jk>return</jk> req.getSwagger();
}
<jd>/** Serializer for converting images to byte streams */</jd>
<ja>@Produces</ja>(<js>"image/png,image/jpeg"</js>)
<jk>public static class</jk> ImageSerializer <jk>extends</jk> OutputStreamSerializer {
<ja>@Override</ja>
<jk>public void</jk> serialize(Object o, OutputStream out, SerializerSession session) <jk>throws</jk> IOException, SerializeException {
RenderedImage image = (RenderedImage)o;
String mediaType = ctx.getMediaType();
ImageIO.<jsm>write</jsm>(image, mediaType.substring(mediaType.indexOf(<js>'/'</js>)+1), out);
}
}
<jd>/** Parser for converting byte streams to images */</jd>
<ja>@Consumes</ja>(<js>"image/png,image/jpeg"</js>)
<jk>public static class</jk> ImageParser <jk>extends</jk> InputStreamParser {
<ja>@Override</ja>
<jk>public</jk> &lt;T&gt; T parse(InputStream in, ClassMeta&lt;T&gt; type, ParserSession session) <jk>throws</jk> ParseException, IOException {
BufferedImage image = ImageIO.<jsm>read</jsm>(in);
<jk>return</jk> (T)image;
}
}
}
</p>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.JsonSchemaResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.17 - JsonSchemaResource</h3>
<div class='topic'>
<p>
The <l>JsonSchemaResource</l> class shows examples of the following:
</p>
<ul class='spaced-list'>
<li>Using the <a class='doclink' href='org/apache/juneau/dto/jsonschema/package-summary.html#TOC'>JSON Schema DTO</a> API.
</ul>
<p>
The resource consists of a pre-initialized {@link org.apache.juneau.dto.jsonschema.Schema} object.
Pointing a browser to the resource shows the following:
</p>
<img class='bordered' src='doc-files/Samples.JsonSchemaResource.1.png'>
<p>
For true JSON-Schema, you need to specify the header <l>Accept: text/json</l>:
</p>
<img class='bordered' src='doc-files/Samples.JsonSchemaResource.2.png'>
<h6 class='figure'>JsonSchemaResource.java</h6>
<p class='bcode'>
<jd>/**
* Sample resource that shows how to serialize JSON-Schema documents.
*/</jd>
<ja>@RestResource</ja>(
path=<js>"/jsonSchema"</js>,
messages=<js>"nls/JsonSchemaResource"</js>,
title=<js>"Sample JSON-Schema document"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{up:'request:/..',options:'servlet:/?method=OPTIONS'}"</js>
)
)
<jk>public class</jk> JsonSchemaResource <jk>extends</jk> ResourceJena {
<jk>private static final long</jk> <jsf>serialVersionUID</jsf> = 1L;
<jk>private</jk> Schema schema; <jc>// The schema document</jc>
<ja>@Override</ja> /* Servlet */
<jk>public void</jk> init() {
<jk>try</jk> {
<jf>schema</jf> = <jk>new</jk> Schema()
.setId(<js>"http://example.com/sample-schema#"</js>)
.setSchemaVersionUri(<js>"http://json-schema.org/draft-04/schema#"</js>)
.setTitle(<js>"Example Schema"</js>)
.setType(JsonType.<jsf>OBJECT</jsf>)
.addProperties(
<jk>new</jk> SchemaProperty(<js>"firstName"</js>, JsonType.<jsf>STRING</jsf>),
<jk>new</jk> SchemaProperty(<js>"lastName"</js>, JsonType.<jsf>STRING</jsf>),
<jk>new</jk> SchemaProperty(<js>"age"</js>, JsonType.<jsf>INTEGER</jsf>)
.setDescription(<js>"Age in years"</js>)
.setMinimum(0)
)
.addRequired(<js>"firstName"</js>, <js>"lastName"</js>);
} <jk>catch</jk> (Exception e) {
<jk>throw new</jk> RuntimeException(e);
}
}
<jd>/** GET request handler */</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/"</js>)
<jk>public</jk> Schema getSchema() <jk>throws</jk> Exception {
<jk>return</jk> <jf>schema</jf>;
}
<jd>/**
* PUT request handler.
* Replaces the schema document with the specified content, and then mirrors it as the response.
*/</jd>
<ja>@RestMethod</ja>(name=<js>"PUT"</js>, path=<js>"/"</js>)
<jk>public</jk> Schema setSchema(<ja>@Body</ja> Schema schema) <jk>throws</jk> Exception {
<jk>this</jk>.<jf>schema</jf> = schema;
<jk>return</jk> schema;
}
}
</p>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.SqlQueryResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.18 - SqlQueryResource</h3>
<div class='topic'>
<p>
The <l>SqlQueryResource</l> class shows examples of the following:
</p>
<ul class='spaced-list'>
<li>Using the {@link org.apache.juneau.dto.ResultSetList} to serialize database result sets.
<li>Using {@link org.apache.juneau.rest.RestContext#getConfigFile()} to access config properties.
<li>Using form entry beans.
</ul>
<p>
The example uses embedded Derby to create a database whose name is defined in the external configuration files.
</p>
<p>
Pointing a browser to the resource shows the following:
</p>
<img class='bordered' src='doc-files/Samples.SqlQueryResource.1.png'>
<p>
Running a query results in the following output:
</p>
<img class='bordered' src='doc-files/Samples.SqlQueryResource.2.png'>
<h6 class='figure'>SqlQueryResource.java</h6>
<p class='bcode'>
<jd>/**
* Sample resource that shows how Juneau can serialize ResultSets.
*/</jd>
<ja>@RestResource</ja>(
path=<js>"/sqlQuery"</js>,
messages=<js>"nls/SqlQueryResource"</js>,
title=<js>"SQL query service"</js>,
description=<js>"Executes queries against the local derby '$C{SqlQueryResource/connectionUrl}' database"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{up:'request:/..',options:'servlet:/?method=OPTIONS'}"</js>
)
)
<jk>public class</jk> SqlQueryResource <jk>extends</jk> Resource {
<jk>private static final long</jk> <jsf>serialVersionUID</jsf> = 1L;
<jk>private</jk> ConfigFile <jf>cf</jf> = getConfig();
<jk>private</jk> String <jf>driver</jf> = cf.getString(<js>"SqlQueryResource/driver"</js>);
<jk>private</jk> String <jf>connectionUrl</jf> = cf.getString(<js>"SqlQueryResource/connectionUrl"</js>);
<jk>private boolean</jk>
<jf>allowUpdates</jf> = cf.getBoolean(<js>"SqlQueryResource/allowUpdates"</js>, <jk>false</jk>),
<jf>allowTempUpdates</jf> = cf.getBoolean(<js>"SqlQueryResource/allowTempUpdates"</js>, <jk>false</jk>),
<jf>includeRowNums</jf> = cf.getBoolean(<js>"SqlQueryResource/includeRowNums"</js>, <jk>false</jk>);
<ja>@Override</ja> <jc>/* Servlet */</jc>
<jk>public void</jk> init() {
<jk>try</jk> {
Class.<jsm>forName</jsm>(driver).newInstance();
} <jk>catch</jk> (Exception e) {
<jk>throw new</jk> RuntimeException(e);
}
}
<jd>/** GET request handler - Display the query entry page. */</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/"</js>)
<jk>public</jk> ReaderResource doGet(RestRequest req) <jk>throws</jk> IOException {
<jk>return</jk> req.getReaderResource(<js>"SqlQueryResource.html"</js>, <jk>true</jk>);
}
<jd>/** POST request handler - Execute the query. */</jd>
<ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/"</js>)
<jk>public</jk> List&lt;Object&gt; doPost(<ja>@Body</ja> PostInput in) <jk>throws</jk> Exception {
List&lt;Object&gt; results = <jk>new</jk> LinkedList&lt;Object&gt;();
<jc>// Don't try to submit empty input.</jc>
<jk>if</jk> (StringUtils.<jsm>isEmpty</jsm>(in.<jf>sql</jf>))
<jk>return</jk> results;
<jk>if</jk> (in.<jf>pos</jf> &lt; 1 || in.<jf>pos</jf> &gt; 10000)
<jk>throw new</jk> RestException(<jsf>SC_BAD_REQUEST</jsf>, <js>"Invalid value for position. Must be between 1-10000"</js>);
<jk>if</jk> (in.<jf>limit</jf> &lt; 1 || in.<jf>limit</jf> &gt; 10000)
<jk>throw new</jk> RestException(<jsf>SC_BAD_REQUEST</jsf>, <js>"Invalid value for limit. Must be between 1-10000"</js>);
<jc>// Create a connection and statement.</jc>
<jc>// If these fails, let the exception transform up as a 500 error.</jc>
Connection c = DriverManager.getConnection(<jf>connectionUrl</jf>);
c.setAutoCommit(<jk>false</jk>);
Statement st = c.createStatement();
String sql = <jk>null</jk>;
<jk>try</jk> {
<jk>for</jk> (String s : in.<jf>sql</jf>.split(<js>";"</js>)) {
sql = s.trim();
<jk>if</jk> (! sql.isEmpty()) {
Object o = <jk>null</jk>;
<jk>if</jk> (<jf>allowUpdates</jf> || (<jf>allowTempUpdates</jf> &amp;&amp; ! sql.matches(<js>"(?:i)commit.*"</js>))) {
<jk>if</jk> (st.execute(sql)) {
ResultSet rs = st.getResultSet();
o = <jk>new</jk> ResultSetList(rs, in.<jf>pos</jf>, in.<jf>limit</jf>, <jf>includeRowNums</jf>);
} <jk>else</jk> {
o = st.getUpdateCount();
}
} <jk>else</jk> {
ResultSet rs = st.executeQuery(sql);
o = <jk>new</jk> ResultSetList(rs, in.<jf>pos</jf>, in.<jf>limit</jf>, <jf>includeRowNums</jf>);
}
results.add(o);
}
}
<jk>if</jk> (<jf>allowUpdates</jf>)
c.commit();
<jk>else if</jk> (<jf>allowTempUpdates</jf>)
c.rollback();
} <jk>catch</jk> (SQLException e) {
c.rollback();
<jk>throw new</jk> RestException(<jsf>SC_BAD_REQUEST</jsf>, <js>"Invalid query: {0}"</js>, sql).initCause(e);
} <jk>finally</jk> {
c.close();
}
<jk>return</jk> results;
}
<jd>/** The parsed form post */</jd>
<jk>public static class</jk> PostInput {
<jk>public</jk> String <jf>sql</jf>;
<jk>public int</jk> <jf>pos</jf> = 1, <jf>limit</jf> = 100;
}
}
</p>
<h6 class='figure'>SqlQueryResource.html</h6>
<p class='bcode'>
<xt>&lt;html&gt;</xt>
<xt>&lt;head&gt;</xt>
<xt>&lt;style</xt> <xa>type</xa>=<xs>'text/css'</xs><xt>&gt;</xt>
<xt>@import</xt> <xs>'$R{servletURI}/style.css'</xs>;
<xt>&lt;/style&gt;</xt>
<xt>&lt;script&gt;</xt>
<jc>// Quick and dirty function to allow tabs in textarea.</jc>
<jk>function</jk> checkTab(e) {
<jk>if</jk> (e.keyCode == 9) {
<jk>var</jk> t = e.target;
<jk>var</jk> ss = t.selectionStart, se = t.selectionEnd;
t.value = t.value.slice(0,ss).concat(<js>'\t'</js>).concat(t.value.slice(ss,t.value.length));
e.preventDefault();
}
}
<jc>// Load results from IFrame into this document.</jc>
<jk>function</jk> loadResults(b) {
<jk>var</jk> doc = b.contentDocument || b.contentWindow.document;
<jk>var</jk> data = doc.getElementById(<js>'data'</js>) || doc.getElementsByTagName(<js>'body'</js>)[0];
document.getElementById(<js>'results'</js>).innerHTML = data.innerHTML;
}
<xt>&lt;/script&gt;</xt>
<xt>&lt;/head&gt;</xt>
<xt>&lt;body&gt;</xt>
<xt>&lt;h3</xt> <xa>class</xa>=<xs>'title'</xs><xt>&gt;</xt>SQL Query API<xt>&lt;/h3&gt;</xt>
<xt>&lt;div</xt> <xa>class</xa>=<xs>'data'</xs><xt>&gt;</xt>
<xt>&lt;form</xt> <xa>action</xa>=<xs>'sqlQuery'</xs> <xa>method</xa>=<xs>'POST'</xs> <xa>target</xa>=<xs>'buf'</xs><xt>&gt;</xt>
<xt>&lt;table&gt;</xt>
<xt>&lt;tr&gt;</xt>
<xt>&lt;th&gt;</xt>Position (1-10000):<xt>&lt;/th&gt;</xt>
<xt>&lt;td&gt;</xt><xt>&lt;input</xt> <xa>name</xa>=<xs>'pos'</xs> <xa>type</xa>=<xs>'number'</xs> <xa>value</xa>=<xs>'1'</xs><xt>&gt;</xt><xt>&lt;/td&gt;</xt>
<xt>&lt;th&gt;</xt>Limit (1-10000):<xt>&lt;/th&gt;</xt>
<xt>&lt;td&gt;</xt><xt>&lt;input</xt> <xa>name</xa>=<xs>'limit'</xs> <xa>type</xa>=<xs>'number'</xs> <xa>value</xa>=<xs>'100'</xs><xt>&gt;</xt><xt>&lt;/td&gt;</xt>
<xt>&lt;td&gt;</xt><xt>&lt;button</xt> <xa>type</xa>=<xs>'submit'</xs><xt>&gt;</xt>Submit<xt>&lt;/button&gt;</xt><xt>&lt;button</xt> <xa>type</xa>=<xs>'reset'</xs><xt>&gt;</xt>Reset<xt>&lt;/button&gt;</xt><xt>&lt;/td&gt;</xt>
<xt>&lt;/tr&gt;</xt>
<xt>&lt;tr&gt;</xt>
<xt>&lt;td</xt> <xa>colspan</xa>=<xs>"5"</xs><xt>&gt;</xt>
<xt>&lt;textarea</xt> <xa>name</xa>=<xs>'sql'</xs> <xa>style</xa>=<xs>'width:100%;height:200px;font-family:Courier;font-size:9pt;'</xs> <xa>onkeydown</xa>=<xs>'checkTab(event)'</xs><xt>&gt;</xt><xt>&lt;/textarea&gt;</xt>
<xt>&lt;/td&gt;</xt>
<xt>&lt;/tr&gt;</xt>
<xt>&lt;/table&gt;</xt>
<xt>&lt;/form&gt;</xt>
<xt>&lt;br&gt;</xt>
<xt>&lt;div</xt> <xa>id</xa>=<xs>'results'</xs><xt>&gt;</xt>
<xt>&lt;/div&gt;</xt>
<xt>&lt;/div&gt;</xt>
<xt>&lt;iframe</xt> <xa>name</xa>=<xs>'buf'</xs> <xa>style</xa>=<xs>'display:none'</xs> <xa>onload</xa>=<xs>"parent.loadResults(this)"</xs><xt>&gt;</xt><xt>&lt;/iframe&gt;</xt>
<xt>&lt;/body&gt;</xt>
<xt>&lt;/html&gt;</xt>
</p>
<h6 class='figure'>samples.cfg</h6>
<p class='bcode'>
<cc>#================================================================================
# SqlQueryResource properties
#================================================================================</cc>
<cs>[SqlQueryResource]</cs>
<ck>driver</ck> = <cv>org.apache.derby.jdbc.EmbeddedDriver</cv>
<ck>connectionUrl</ck> = <cv>jdbc:derby:C:/testDB;create=true</cv>
<ck>allowTempUpdates</ck> = <cv>true</cv>
<ck>includeRowNums</ck> = <cv>true</cv>
</p>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.ConfigResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.19 - ConfigResource</h3>
<div class='topic'>
<p>
The {@link org.apache.juneau.microservice.resources.ConfigResource} class is a reusable resource
defined in the <a class='doclink' href='org/apache/juneau/microservice/package-summary.html#TOC'>org.apache.juneau.microservice</a> API.
It provides a REST interface for reading and altering the microservice config file.
</p>
<p>
Pointing a browser to the resource shows the following:
</p>
<img class='bordered' src='doc-files/Samples.ConfigResource.1.png'>
<p>
An edit page is provided for altering the raw config file:
</p>
<img class='bordered' src='doc-files/Samples.ConfigResource.3.png'>
<p>
The {@link org.apache.juneau.ini.ConfigFile} class is a serializable POJO, which makes the resource
relatively straighforward to implement.
</p>
<h6 class='figure'>ConfigResource.java</h6>
<p class='bcode'>
<jd>/**
* Shows contents of the microservice configuration file.
*/</jd>
<ja>@RestResource</ja>(
path=<js>"/config"</js>,
title=<js>"Configuration"</js>,
description=<js>"Contents of configuration file."</js>,
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{up:'request:/..', options:'servlet:/?method=OPTIONS', edit:'servlet:/edit'}"</js>
)
)
<jk>public class</jk> ConfigResource <jk>extends</jk> Resource {
<jk>private static final long</jk> <jsf>serialVersionUID</jsf> = 1L;
<jd>/**
* [GET /] - Show contents of config file.
*
* <ja>@return</ja> The config file.
* <ja>@throws</ja> Exception
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/"</js>, description=<js>"Show contents of config file."</js>)
<jk>public</jk> ConfigFile getConfigContents() <jk>throws</jk> Exception {
<jk>return</jk> getConfig();
}
<jd>/**
* [GET /edit] - Show config file edit page.
*
* <ja>@param</ja> req The HTTP request.
* <ja>@return</ja> The config file as a reader resource.
* <ja>@throws</ja> Exception
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/edit"</js>, description=<js>"Show config file edit page."</js>)
<jk>public</jk> ReaderResource getConfigEditPage(RestRequest req) <jk>throws</jk> Exception {
<jc>// Note that you don't want variables in the config file to be resolved,</jc>
<jc>// so you need to escape any $ characters that you see.</jc>
req.setAttribute(<js>"contents"</js>, getConfig().toString().replaceAll(<js>"\\$"</js>, <js>"\\\\\\$"</js>));
<jk>return</jk> req.getReaderResource(<js>"ConfigEdit.html"</js>, <jk>true</jk>);
}
<jd>/**
* [GET /{section}] - Show config file section.
*
* <ja>@param</ja> section The section name.
* <ja>@return</ja> The config file section.
* <ja>@throws</ja> Exception
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/{section}"</js>,
description=<js>"Show config file section."</js>,
parameters={
<ja>@Parameter</ja>(in=<js>"path"</js>, name=<js>"section"</js>, description=<js>"Section name."</js>)
}
)
<jk>public</jk> ObjectMap getConfigSection(<ja>@Path</ja>(<js>"section"</js>) String section) <jk>throws</jk> Exception {
<jk>return</jk> getSection(section);
}
<jd>/**
* [GET /{section}/{key}] - Show config file entry.
*
* <ja>@param</ja> section The section name.
* <ja>@param</ja> key The section key.
* <ja>@return</ja> The value of the config file entry.
* <ja>@throws</ja> Exception
*/</jd>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/{section}/{key}"</js>,
description=<js>"Show config file entry."</js>,
parameters={
<ja>@Parameter</ja>(in=<js>"path"</js>, name=<js>"section"</js>, description=<js>"Section name."</js>),
<ja>@Parameter</ja>(in=<js>"path"</js>, name=<js>"key"</js>, description=<js>"Entry name."</js>)
}
)
<jk>public</jk> String getConfigEntry(<ja>@Path</ja>(<js>"section"</js>) String section, <ja>@Path</ja>(<js>"key"</js>) String key) <jk>throws</jk> Exception {
<jk>return</jk> getSection(section).getString(key);
}
<jd>/**
* [POST /] - Sets contents of config file from a FORM post.
*
* <ja>@param</ja> contents The new contents of the config file.
* <ja>@return</ja> The new config file contents.
* <ja>@throws</ja> Exception
*/</jd>
<ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/"</js>,
description=<js>"Sets contents of config file from a FORM post."</js>,
parameters={
<ja>@Parameter</ja>(in=<js>"formData"</js>, name=<js>"contents"</js>, description=<js>"New contents in INI file format."</js>)
}
)
<jk>public</jk> ConfigFile setConfigContentsFormPost(<ja>@FormData</ja>(<js>"contents"</js>) String contents) <jk>throws</jk> Exception {
<jk>return</jk> setConfigContents(<jk>new</jk> StringReader(contents));
}
<jd>/**
* [PUT /] - Sets contents of config file.
*
* <ja>@param</ja> contents The new contents of the config file.
* <ja>@return</ja> The new config file contents.
* <ja>@throws</ja> Exception
*/</jd>
<ja>@RestMethod</ja>(name=<js>"PUT"</js>, path=<js>"/"</js>,
description=<js>"Sets contents of config file."</js>,
parameters={
<ja>@Parameter</ja>(in=<js>"body"</js>, description=<js>"New contents in INI file format."</js>)
}
)
<jk>public</jk> ConfigFile setConfigContents(<ja>@Body</ja> Reader contents) <jk>throws</jk> Exception {
ConfigFile cf2 = <jk>new</jk> ConfigFileBuilder().build().load(contents);
<jk>return</jk> getConfig().merge(cf2).save();
}
<jd>/**
* [PUT /{section}] - Add or overwrite a config file section.
*
* <ja>@param</ja> section The section name.
* <ja>@param</ja> contents The new contents of the config file section.
* <ja>@return</ja> The new section.
* <ja>@throws</ja> Exception
*/</jd>
<ja>@RestMethod</ja>(name=<js>"PUT"</js>, path=<js>"/{section}"</js>,
description=<js>"Add or overwrite a config file section."</js>,
parameters={
<ja>@Parameter</ja>(in=<js>"path"</js>, name=<js>"section"</js>, description=<js>"Section name."</js>),
<ja>@Parameter</ja>(in=<js>"body"</js>, description=<js>"New contents for section as a simple map with string keys and values."</js>)
}
)
<jk>public</jk> ObjectMap setConfigSection(<ja>@Path</ja>(<js>"section"</js>) String section, <ja>@Body</ja> Map&lt;String,String&gt; contents) <jk>throws</jk> Exception {
getConfig().setSection(section, contents);
<jk>return</jk> getSection(section);
}
<jd>/**
* [PUT /{section}/{key}] - Add or overwrite a config file entry.
*
* <ja>@param</ja> section The section name.
* <ja>@param</ja> key The section key.
* <ja>@param</ja> value The new value.
* <ja>@return</ja> The new value.
* <ja>@throws</ja> Exception
*/</jd>
<ja>@RestMethod</ja>(name=<js>"PUT"</js>, path=<js>"/{section}/{key}"</js>,
description=<js>"Add or overwrite a config file entry."</js>,
parameters={
<ja>@Parameter</ja>(in=<js>"path"</js>, name=<js>"section"</js>, description=<js>"Section name."</js>),
<ja>@Parameter</ja>(in=<js>"path"</js>, name=<js>"key"</js>, description=<js>"Entry name."</js>),
<ja>@Parameter</ja>(in=<js>"body"</js>, description=<js>"New value as a string."</js>)
}
)
<jk>public</jk> String setConfigSection(<ja>@Path</ja>(<js>"section"</js>) String section, <ja>@Path</ja>(<js>"key"</js>) String key, <ja>@Body</ja> String value) <jk>throws</jk> Exception {
getConfig().put(section, key, value, <jk>false</jk>);
<jk>return</jk> getSection(section).getString(key);
}
<jk>private</jk> ObjectMap getSection(String name) {
ObjectMap m = getConfig().getSectionMap(name);
<jk>if</jk> (m == <jk>null</jk>)
<jk>throw new</jk> RestException(SC_NOT_FOUND, <js>"Section not found."</js>);
<jk>return</jk> m;
}
}
</p>
<h6 class='figure'>ConfigEdit.html</h6>
<p class='bcode'>
<xt>&lt;html&gt;</xt>
<xt>&lt;head&gt;</xt>
<xt>&lt;meta</xt> <xa>http-equiv</xa>=<xs>'Content-Type'</xs> <xa>content</xa>=<xs>'text/html; <xa>charset</xa>=UTF-8'</xs><xt>&gt;</xt>
<xt>&lt;style</xt> <xa>type</xa>=<xs>'text/css'</xs><xt>&gt;</xt>
<xt>@import</xt> <xs>'$R{servletURI}/style.css'</xs>;
<xt>&lt;/style&gt;</xt>
<xt>&lt;/head&gt;</xt>
<xt>&lt;body&gt;</xt>
<xt>&lt;h3</xt> <xa>class</xa>=<xs>'title'</xs><xt>&gt;</xt>$R{servletTitle}<xt>&lt;/h3&gt;</xt>
<xt>&lt;h5</xt> <xa>class</xa>=<xs>'description'</xs><xt>&gt;</xt>Edit config file<xt>&lt;/h5&gt;</xt>
<xt>&lt;p</xt> <xa>class</xa>=<xs>'links'</xs><xt>&gt;</xt><xt>&lt;a</xt> <xa>href</xa>=<xs>'$R{requestParentURI}'</xs><xt>&gt;</xt>up<xt>&lt;/a&gt;</xt> - <xt>&lt;a</xt> <xa>href=<xs>'$R{servletURI}?method</xa>=OPTIONS'</xs><xt>&gt;</xt>options<xt>&lt;/a&gt;</xt><xt>&lt;/p&gt;</xt>
<xt>&lt;form</xt> <xa>id</xa>=<xs>'form'</xs> <xa>action</xa>=<xs>'$R{servletURI}'</xs> <xa>method</xa>=<xs>'POST'</xs> <xa>enctype</xa>=<xs>'application/x-www-form-urlencoded'</xs><xt>&gt;</xt>
<xt>&lt;div</xt> <xa>class</xa>=<xs>'data'</xs><xt>&gt;</xt>
<xt>&lt;table&gt;</xt>
<xt>&lt;tr&gt;</xt><xt>&lt;td</xt> <xa>colspan</xa>=<xs>'2'</xs> <xa>align</xa>=<xs>'right'</xs><xt>&gt;</xt><xt>&lt;button</xt> <xa>type</xa>=<xs>'submit'</xs><xt>&gt;</xt>Submit<xt>&lt;/button&gt;</xt><xt>&lt;button</xt> <xa>type</xa>=<xs>'reset'</xs><xt>&gt;</xt>Reset<xt>&lt;/button&gt;</xt><xt>&lt;/td&gt;</xt><xt>&lt;/tr&gt;</xt>
<xt>&lt;tr&gt;</xt><xt>&lt;th</xt> <xa>colspan</xa>=<xs>'2'</xs><xt>&gt;</xt>Contents<xt>&lt;/th&gt;</xt><xt>&lt;/tr&gt;</xt>
<xt>&lt;tr&gt;</xt><xt>&lt;td</xt> <xa>colspan</xa>=<xs>'2'</xs><xt>&gt;</xt><xt>&lt;textarea</xt> <xa>name</xa>=<xs>'contents'</xs> <xa>rows</xa>=<xs>'40'</xs> <xa>cols</xa>=<xs>'120'</xs> <xa>style</xa>=<xs>'white-space: pre; word-wrap: normal; overflow-x: scroll;'</xs><xt>&gt;</xt>$SA{contents}<xt>&lt;/textarea&gt;</xt><xt>&lt;/td&gt;</xt><xt>&lt;/tr&gt;</xt>
<xt>&lt;/table&gt;</xt>
<xt>&lt;/div&gt;</xt>
<xt>&lt;/form&gt;</xt>
<xt>&lt;/body&gt;</xt>
<xt>&lt;/html&gt;</xt>
</p>
</div>
<!-- ======================================================================================================== -->
<a id="Samples.LogsResource"></a>
<h3 class='topic' onclick='toggle(this)'>8.20 - LogsResource</h3>
<div class='topic'>
<p>
The {@link org.apache.juneau.microservice.resources.LogsResource} class is a reusable resource
defined in the <a class='doclink' href='org/apache/juneau/microservice/package-summary.html#TOC'>org.apache.juneau.microservice</a> API.
It provides a REST interface for the log files generated by the microservice.
</p>
<p>
Pointing a browser to the resource shows the following:
</p>
<img class='bordered' src='doc-files/Samples.LogsResource.1.png'>
<p>
The <l>highlighted</l> links show the contents of the log file with color highlighting:
</p>
<img class='bordered' src='doc-files/Samples.LogsResource.2.png'>
<p>
The <l>parsed</l> links parse the log file and return the entries as serialized POJOs:
</p>
<img class='bordered' src='doc-files/Samples.LogsResource.3.png'>
</div>
</div>
<!-- ======================================================================================================== -->
<a id="Cookbook"></a>
<h2 class='topic' onclick='toggle(this)'>9 - Cookbook Examples</h2>
<div class='topic'>
<!-- ======================================================================================================== -->
<a id="Cookbook.Core"></a>
<h3 class='topic' onclick='toggle(this)'>9.1 - Core API</h3>
<div class='topic'>
<h6 class='topic'>TODO topics</h6>
<ol>
<li>Creating generic JSON objects
<li>Defining XML namespaces
</ol>
</div>
<!-- ======================================================================================================== -->
<a id="Cookbook.Server"></a>
<h3 class='topic' onclick='toggle(this)'>9.2 - Server API</h3>
<div class='topic'>
<!-- ======================================================================================================== -->
<a id="Cookbook.Server.applyDoubleTransform"></a>
<h3 class='topic' onclick='toggle(this)'>9.2.1 - Apply a transform that changes the format of doubles</h3>
<div class='topic'>
<p>
The {@link org.apache.juneau.rest.annotation.RestResource#pojoSwaps()} annotation can be used to add
POJO swaps to all the serializers and parsers registered with a servlet.
</p>
<p>
In this example, you define a POJO swap that converts doubles to localized-format strings using
the <l>NumberFormat</l> Java class.
</p>
<p class='bcode'>
<ja>@RestResource</ja>(
pojoSwaps={
MyRestService.DoubleSwap.<jk>class</jk>
}
)
<jk>public class</jk> MyRestService <jk>extends</jk> JazzDefaultRestResource {
<jk>private static final</jk> NumberFormat <jsf>FORMAT</jsf> = NumberFormat.<jsm>getInstance()</jsm>;
<jk>public static class</jk> DoubleSwap <jk>extends</jk> PojoSwap&lt;Double,String&gt; {
<ja>@Override</ja> <jc>/* PojoSwap */</jc>
<jk>public</jk> String swap(BeanSession session, Double o) <jk>throws</jk> SerializeException {
<jk>return</jk> <jsf>FORMAT</jsf>.format(o);
}
}
</p>
</div>
<!-- ======================================================================================================== -->
<a id="Cookbook.Server.applyTransformsSubset"></a>
<h3 class='topic' onclick='toggle(this)'>9.2.2 - Apply transforms to a subset of serializers or parsers</h3>
<div class='topic'>
<p>
The {@link org.apache.juneau.rest.RestConfig#addSerializers(Class[])} and {@link org.apache.juneau.rest.RestConfig#addParsers(Class[])}
methods are the methods that get called during servlet initialization to create the serializer and
parser groups.
These methods can be overridden to customize individual serializers and parsers in a way that can't be done using annotations.
</p>
<p>
In this example, you want to apply the swap from the previous example to change the rendered format for doubles.
However, in this case, you apply the swao to only the HTML serializer.
</p>
<p class='bcode'>
<ja>@Override</ja>
<jk>public synchronized void</jk> init(RestServletConfig config) <jk>throws</jk> Exception {
config.addSerializer(<jk>new</jk> HtmlSerializerBuilder().pojoSwaps(DoubleSwap.<jk>class</jk>).build());
super.init(config);
}
</p>
</div>
<h6 class='topic'>TODO topics</h6>
<ol>
<li>Packaging as WAR files
<li>Customizing OPTIONS pages
<li>Rendering form entry pages
<li>Using the ZipFileList response handler
<li>Implementing console-output pages in HTML
<li>Using configuration files
<li>Making a bean traversable
<li>Using the Queryable converter
<li>Sending raw output
<li>Retrieving raw input
<li>Accessing request query parameters
<li>Accessing request path variables
<li>Accessing request content
<li>Accessing request header values
<li>Accessing the path pattern remainder
<li>Creating ResourceGroup pages
<li>Using matchers to define multiple Java methods to the same path pattern
<li>Using the Remoteable API
<li>Sending a redirect request
<li>Changing the stylesheet used by the HTML serializer
<li>Using the Introspector API to invoke methods on Java objects through REST calls
<li>Customizing serializers and parsers at the method level
<li>Accessing config file values
<li>Accessing request query parameters on URL-Encoded FORM posts without triggering HTML body to be read
<li>Accessing localized messages
<li>Defining your own response handlers
<li>Guarding access to a servlet or method
<li>Handling servlet initialization errors
<li>Handling exceptions that occur during response processing
<li>Customizing logging
<li>Creating an ATOM feed
<li>Creating a REST API against a file system
<li>Creating a Docker REST API
<li>Creating a REST API for storing and retrieving images
<li>Creating a REST API for echoing requests
<li>Creating a Tumblr REST API
<li>Creating a Cloudant REST API
<li>Using onPreCall() to intercept requests before processing
<li>Using onPostCall() to intercept requests after processing
<li>Creating child resources programmatically
<li>Defining default request headers
<li>Defining default response headers
<li>Defining your own var-resolver variables
<li>Serving up static files inside the /htdocs embedded package
<li>Defining MIME types of files in the /htdocs folder using the createMimitypesFileTypeMap() method
<li>Defining the title and description of a servlet programmatically using getDescription() and getTitle().
<li>Setting properties programmatically using RestServlet.setProperty()
<li>Setting and saving config file properties
<li>Defining your own abstract subclass of RestServlet or RestServletDefault
<li>Adding GZip support
<li>Accessing environment variables in config files
</ol>
</div>
<!-- ======================================================================================================== -->
<a id="Cookbook.Client"></a>
<h3 class='topic' onclick='toggle(this)'>9.3 - Client API</h3>
<div class='topic'>
</div>
<!-- ======================================================================================================== -->
<a id="Cookbook.Microservice"></a>
<h3 class='topic' onclick='toggle(this)'>9.4 - Microservice API</h3>
<div class='topic'>
</div>
</div>
<!-- ======================================================================================================== -->
<a id="BestPractices"></a>
<h2 class='topic' onclick='toggle(this)'>10 - Best Practices</h2>
<div class='topic'>
<ol>
<li>Reuse instances of serializers and parsers whenever possible.<br>
They are designed to be thread safe, and maintain internal caches of bean metadata to increase performance.
<br><br>
<li>The {@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_detectRecursions SERIALIZER_detectRecursions} option on the {@link org.apache.juneau.serializer.Serializer} class can cause a performance penalty of around 20%.
Therefore, it's recommended that this option be used only when necessary.
<br><br>
<li>In general, JSON serialization and parsing is about 20% faster than XML. JSON is also more compact than XML.
<br><br>
<li>The {@link org.apache.juneau.parser.Parser} methods that take in {@link org.apache.juneau.ClassMeta} parameters are slightly faster than methods that
take in {@link java.lang.Class} or {@link java.lang.Object} parameters, since the latter methods involve hash lookups to resolve
to {@link org.apache.juneau.ClassMeta} parameters.
<br><br>
</ol>
</div>
<!-- ======================================================================================================== -->
<a id="ImportantLinks"></a>
<h2 class='topic' onclick='toggle(this)'>11 - Important Document Links</h2>
<div class='topic'>
<p>
All up-to-date Juneau documentation is stored in Javadocs, especially package-level Javadocs.
This index provides links to the best jumping-off points for documentation.
</p>
<a id='TOC'></a><h5 class='toc'>Links</h5>
<ul class='toc'>
<li><p><a class='doclink' href='overview-summary.html#TOC' target="classFrame">Juneau Overview</a> - This document</p>
<li><p><a class='doclink' href='org/apache/juneau/package-summary.html#TOC'>org.apache.juneau</a> - Core Architecture</p>
<ul>
<li><p><a class='doclink' href='org/apache/juneau/json/package-summary.html#TOC'>org.apache.juneau.json</a> - JSON support</p>
<li><p><a class='doclink' href='org/apache/juneau/xml/package-summary.html#TOC'>org.apache.juneau.xml</a> - XML support</p>
<li><p><a class='doclink' href='org/apache/juneau/jena/package-summary.html#TOC'>org.apache.juneau.jena</a> - RDF languages support</p>
<li><p><a class='doclink' href='org/apache/juneau/urlencoding/package-summary.html#TOC'>org.apache.juneau.urlencoding</a> - URL-Encoding support</p>
<li><p><a class='doclink' href='org/apache/juneau/dto/atom/package-summary.html#TOC'>org.apache.juneau.dto.atom</a> - ATOM support</p>
<li><p><a class='doclink' href='org/apache/juneau/dto/cognos/package-summary.html#TOC'>org.apache.juneau.dto.cognos</a> - Cognos support</p>
<li><p><a class='doclink' href='org/apache/juneau/ini/package-summary.html'>org.apache.juneau.ini</a> - Configuration File API</p>
</ul>
<li><p><a class='doclink' href='org/apache/juneau/server/package-summary.html#TOC'>org.apache.juneau.rest</a> - REST Server API</p>
<li><p><a class='doclink' href='org/apache/juneau/server/jaxrs/package-summary.html#TOC'>org.apache.juneau.rest.jaxrs</a> - JAX-RS Integration</p>
<li><p><a class='doclink' href='org/apache/juneau/client/package-summary.html#TOC'>org.apache.juneau.rest.client</a> - REST Client API</p>
<li><p><a class='doclink' href='org/apache/juneau/microservice/package-summary.html#TOC'>org.apache.juneau.microservice</a> - REST Microservice API</p>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="ReleaseNotes"></a>
<h2 class='topic' onclick='toggle(this)'>12 - Release Notes</h2>
<div class='topic'>
<h5 class='toc'>What's new in each release</h5>
<ul class='toc'>
<li><p><a class='doclink' href='#6.3.0'>6.3.0 (TBD)</a></p>
<li><p><a class='doclink' href='#6.2.0'>6.2.0 (Apr 28, 2017)</a></p>
<li><p><a class='doclink' href='#6.1.0'>6.1.0 (Feb 25, 2017)</a></p>
<li><p><a class='doclink' href='#6.0.1'>6.0.1 (Jan 3, 2017)</a></p>
<li><p><a class='doclink' href='#6.0.0'>6.0.0 (Oct 3, 2016)</a></p>
<li><p><a class='doclink' href='#5.2.0.1'>5.2.0.1 (Mar 23, 2016)</a></p>
<li><p><a class='doclink' href='#5.2.0.0'>5.2.0.0 (Dec 30, 2015)</a></p>
<li><p><a class='doclink' href='#5.1.0.20'>5.1.0.20 (Sept 5, 2015)</a></p>
<li><p><a class='doclink' href='#5.1.0.19'>5.1.0.19 (Aug 15, 2015)</a></p>
<li><p><a class='doclink' href='#5.1.0.18'>5.1.0.18 (Aug 5, 2015)</a></p>
<li><p><a class='doclink' href='#5.1.0.17'>5.1.0.17 (Aug 3, 2015)</a></p>
<li><p><a class='doclink' href='#5.1.0.16'>5.1.0.16 (June 28, 2015)</a></p>
<li><p><a class='doclink' href='#5.1.0.15'>5.1.0.15 (May 24, 2015)</a></p>
<li><p><a class='doclink' href='#5.1.0.14'>5.1.0.14 (May 10, 2015)</a></p>
<li><p><a class='doclink' href='#5.1.0.13'>5.1.0.13 (Apr 24, 2015)</a></p>
<li><p><a class='doclink' href='#5.1.0.12'>5.1.0.12 (Mar 28, 2015)</a></p>
<li><p><a class='doclink' href='#5.1.0.11'>5.1.0.11 (Feb 14, 2015)</a></p>
<li><p><a class='doclink' href='#5.1.0.10'>5.1.0.10 (Dec 23, 2014)</a></p>
<li><p><a class='doclink' href='#5.1.0.9'>5.1.0.9 (Dec 1, 2014)</a></p>
<li><p><a class='doclink' href='#5.1.0.8'>5.1.0.8 (Oct 25, 2014)</a></p>
<li><p><a class='doclink' href='#5.1.0.7'>5.1.0.7 (Oct 5, 2014)</a></p>
<li><p><a class='doclink' href='#5.1.0.6'>5.1.0.6 (Sept 21, 2014)</a></p>
<li><p><a class='doclink' href='#5.1.0.5'>5.1.0.5 (Sept 1, 2014)</a></p>
<li><p><a class='doclink' href='#5.1.0.4'>5.1.0.4 (Aug 25, 2014)</a></p>
<li><p><a class='doclink' href='#5.1.0.3'>5.1.0.3 (Jun 28, 2014)</a></p>
<li><p><a class='doclink' href='#5.1.0.2'>5.1.0.2 (Apr 27, 2014)</a></p>
<li><p><a class='doclink' href='#5.1.0.1'>5.1.0.1 (Jan 25, 2014)</a></p>
<li><p><a class='doclink' href='#5.1.0.0'>5.1.0.0 (Jan 18, 2014)</a></p>
<li><p><a class='doclink' href='#5.0.0.36'>5.0.0.36 (Dec 18, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.35'>5.0.0.35 (Nov 26, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.34'>5.0.0.34 (Nov 10, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.33'>5.0.0.33 (Oct 20, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.32'>5.0.0.32 (Oct 5, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.31'>5.0.0.31 (Aug 9, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.30'>5.0.0.30 (Aug 8, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.29'>5.0.0.29 (Aug 2, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.28'>5.0.0.28 (July 9, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.27'>5.0.0.27 (July 7, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.26'>5.0.0.26 (Jun 5, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.25'>5.0.0.25 (May 11, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.24'>5.0.0.24 (May 9, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.23'>5.0.0.23 (Apr 14, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.22'>5.0.0.22 (Apr 12, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.21'>5.0.0.21 (Apr 9, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.20'>5.0.0.20 (Apr 7, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.19'>5.0.0.19 (Apr 1, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.18'>5.0.0.18 (Mar 27, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.17'>5.0.0.17 (Mar 25, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.16'>5.0.0.16 (Mar 25, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.15'>5.0.0.15 (Mar 24, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.14'>5.0.0.14 (Mar 23, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.13'>5.0.0.13 (Mar 14, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.12'>5.0.0.12 (Mar 10, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.11'>5.0.0.11 (Mar 8, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.10'>5.0.0.10 (Mar 7, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.9'>5.0.0.9 (Feb 26, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.8'>5.0.0.8 (Jan 30, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.7'>5.0.0.7 (Jan 20, 2013)</a></p>
<li><p><a class='doclink' href='#5.0.0.6'>5.0.0.6 (Oct 30, 2012)</a></p>
<li><p><a class='doclink' href='#5.0.0.5'>5.0.0.5 (Oct 29, 2012)</a></p>
<li><p><a class='doclink' href='#5.0.0.4'>5.0.0.4 (Oct 7, 2012)</a></p>
<li><p><a class='doclink' href='#5.0.0.3'>5.0.0.3 (Oct 3, 2012)</a></p>
<li><p><a class='doclink' href='#5.0.0.2'>5.0.0.2 (Sept 28, 2012)</a></p>
<li><p><a class='doclink' href='#5.0.0.1'>5.0.0.1 (Jun 14, 2012)</a></p>
<li><p><a class='doclink' href='#5.0.0.0'>5.0.0.0 (Jun 11, 2012)</a></p>
</ul>
<!-- ======================================================================================================== -->
<a id="6.3.0"></a>
<h3 class='topic' onclick='toggle(this)'>6.3.0 (TBD)</h3>
<div class='topic'>
<p>
</p>
<h6 class='topic'>org.apache.juneau</h6>
<ul class='spaced-list'>
<li>New package: {@link org.apache.juneau.http}.
<li>Support for dynamic beans. See {@link org.apache.juneau.annotation.BeanProperty#name() @BeanProperty.name()}.
<li>New doc: <a class='doclink' href='#Core.VirtualBeans'>2.8 - Virtual Beans</a>
<li>New doc: <a class='doclink' href='#Core.JacksonComparison'>2.13 - Comparison with Jackson</a>
<li>All parsers now allow for numeric types with <js>'K'</js>/<js>'M'</js>/<js>'G'</js> suffixes to represent
kilobytes, megabytes, and gigabytes.
<p class='bcode'>
<jc>// Example</jc>
<jk>int</jk> i = JsonParser.<jsf>DEFAULT</jsf>.parse(<js>"123M"</js>); <jc>// 123MB</jc>
</p>
<li>New/modified methods on {@link org.apache.juneau.ini.ConfigFile}:
<ul>
<li>{@link org.apache.juneau.ini.ConfigFile#put(String,String,String,boolean) put(String,String,String,boolean)}
<li>{@link org.apache.juneau.ini.ConfigFile#put(String,String,Object,Serializer,boolean,boolean) put(String,String,Object,boolean,boolean)}
<li>{@link org.apache.juneau.ini.ConfigFile#getObject(String,Type,Type...) getObject(String,Type,Type...)}
<li>{@link org.apache.juneau.ini.ConfigFile#getObject(String,Parser,Type,Type...) getObject(String,Parser,Type,Type...)}
<li>{@link org.apache.juneau.ini.ConfigFile#getObject(String,Class) getObject(String,Class)}
<li>{@link org.apache.juneau.ini.ConfigFile#getObject(String,Parser,Class) getObject(String,Parser,Class)}
<li>{@link org.apache.juneau.ini.ConfigFile#getObject(String,String,Type,Type...) getObject(String,String,Type,Type...)}
<li>{@link org.apache.juneau.ini.ConfigFile#getObject(String,String,Parser,Type,Type...) getObject(String,String,Parser,Type,Type...)}
<li>{@link org.apache.juneau.ini.ConfigFile#getObject(String,String,Class) getObject(String,String,Class)}
<li>{@link org.apache.juneau.ini.ConfigFile#getObject(String,String,Parser,Class) getObject(String,String,Parser,Class)}
<li>{@link org.apache.juneau.ini.ConfigFile#getObjectWithDefault(String,Object,Type,Type...) getObjectWithDefault(String,Object,Type,Type)}
<li>{@link org.apache.juneau.ini.ConfigFile#getObjectWithDefault(String,Parser,Object,Type,Type...) getObjectWithDefault(String,Parser,Object,Type,Type)}
<li>{@link org.apache.juneau.ini.ConfigFile#getObjectWithDefault(String,Object,Class) getObjectWithDefault(String,Object,Class)}
<li>{@link org.apache.juneau.ini.ConfigFile#getObjectWithDefault(String,Parser,Object,Class) getObjectWithDefault(String,Parser,Object,Class)}
</ul>
<li>New ability to interact with config file sections with proxy interfaces with new method {@link org.apache.juneau.ini.ConfigFile#getSectionAsInterface(String,Class)}.
<li>{@link org.apache.juneau.annotation.BeanProperty @BeanProperty} annotation can now be applied to getters
and setters defined on interfaces.
<li>New methods on {@link org.apache.juneau.serializer.SerializerSession} and {@link org.apache.juneau.parser.ParserSession}
for retrieving context and runtime-override properties:
<ul>
<li>{@link org.apache.juneau.Session#getProperty(String)}
<li>{@link org.apache.juneau.Session#getProperty(String,String)}
<li>{@link org.apache.juneau.Session#getProperty(Class,String)}
<li>{@link org.apache.juneau.Session#getProperty(Class,String,Object)}
</ul>
<li>New {@link org.apache.juneau.serializer.PartSerializer} interface particularly tailored to HTTP
headers, query parameters, form-data parameters, and path variables.
<br>Allows easy user-defined serialization of these objects.
<br>The interface can be used in the following locations:
<ul>
<li>{@link org.apache.juneau.rest.client.RestClientBuilder#partSerializer(Class)}
<li>{@link org.apache.juneau.remoteable.Path#serializer}
<li>{@link org.apache.juneau.remoteable.Query#serializer}
<li>{@link org.apache.juneau.remoteable.QueryIfNE#serializer}
<li>{@link org.apache.juneau.remoteable.FormData#serializer}
<li>{@link org.apache.juneau.remoteable.FormDataIfNE#serializer}
<li>{@link org.apache.juneau.remoteable.Header#serializer}
<li>{@link org.apache.juneau.remoteable.HeaderIfNE#serializer}
</ul>
<li>Across-the-board improvements to the URI-resolution support (i.e. how URIs get serialized).
<ul>
<li>New support for resolving URIs with the following newly-recognized protocols:
<ul>
<li><js>"context:/..."</js> - Relative to context-root of the application.
<li><js>"servlet:/..."</js> - Relative to the servlet URI.
<li><js>"request:/..."</js> - Relative to the request URI.
</ul>
For example, currently we define HTML page links using variables and servlet-relative URIs...
<p class='bcode'>
pages=<js>"{up:'$R{requestParentURI}', options:'?method=OPTIONS', upload:'upload'}"</js>
</p>
With these new protocols, we can define them like so:
<p class='bcode'>
links=<js>"{top:'context:/', up:'request:/..' ,options:'servlet:/?method=OPTIONS', upload:'servlet:/upload'}"</js>
</p>
The old method of using variables and servlet-relative URIs will still be supported, but using
these new protocols should (hopefully) be easier to understand.
<br>
These protocols work on all serialized URL and URI objects, as well as classes and properties
annotated with {@link org.apache.juneau.annotation.URI @URI}.
<li>New classes:
<ul>
<li>{@link org.apache.juneau.UriContext}
<li>{@link org.apache.juneau.UriRelativity}
<li>{@link org.apache.juneau.UriResolution}
<li>{@link org.apache.juneau.UriResolver}
</ul>
<li>New configuration properties:
<li>{@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_uriContext}
<li>{@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_uriRelativity}
<li>{@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_uriResolution}
<li>{@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_maxIndent}
</ul>
<li>New annotation property: {@link org.apache.juneau.annotation.BeanProperty#value()}.
<br>The following two annotations are considered equivalent:
<p class='bcode'>
<ja>@BeanProperty</ja>(name=<js>"foo"</js>)
<ja>@BeanProperty</ja>(<js>"foo"</js>)
</p>
<li>Fixed a race condition in ClassMeta.
<li><jsf>URLENC_paramFormat</jsf> has been moved to {@link org.apache.juneau.uon.UonSerializerContext#UON_paramFormat},
and the UON/URL-Encoding serializers will now always serialize all values as plain text.
<br>This means that arrays and maps are converted to simple comma-delimited lists.
<li>Listener APIs added to serializers and parsers:
<ul>
<li>{@link org.apache.juneau.serializer.SerializerListener}
<li>{@link org.apache.juneau.serializer.SerializerBuilder#listener(Class)}
<li>{@link org.apache.juneau.rest.annotation.RestResource#serializerListener()}
<li>{@link org.apache.juneau.rest.RestConfig#serializerListener(Class)}
<li>{@link org.apache.juneau.parser.ParserListener}
<li>{@link org.apache.juneau.parser.ParserBuilder#listener(Class)}
<li>{@link org.apache.juneau.rest.annotation.RestResource#parserListener()}
<li>{@link org.apache.juneau.rest.RestConfig#parserListener(Class)}
<li>{@link org.apache.juneau.rest.client.RestClientBuilder#listeners(Class,Class)}
</ul>
<li>The {@link org.apache.juneau.BeanContext#BEAN_debug} flag will now capture parser input and make it
available through the {@link org.apache.juneau.parser.ParserSession#getInputAsString()} method so that it can be used
in the listeners.
<li>Significant new functionality introduced to the HTML serializer.
<br>Lots of new options for customizing the HTML output.
<ul>
<li>New {@link org.apache.juneau.html.annotation.Html#render() @Html.render()} annotation and {@link org.apache.juneau.html.HtmlRender} class that allows you
to customize the HTML output and CSS style on bean properties:
<br><img class='bordered' src='doc-files/HtmlRender_1.png'>
<br>Annotation can be applied to POJO classes and bean properties.
<li>Several new properties for customizing parts of the HTML page:
<ul>
<li>{@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_title}
<li>{@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_description}
<li>{@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_branding}
<li>{@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_header}
<li>{@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_nav}
<li>{@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_aside}
<li>{@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_footer}
<li>{@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_noResultsMessage}
<li>{@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_cssUrl}
<li>{@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_css}
<li>{@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_template}
</ul>
<li>New interface {@link org.apache.juneau.html.HtmlDocTemplate} that allows full control over rendering
of HTML produced by {@link org.apache.juneau.html.HtmlDocSerializer}.
</ul>
<li>{@link org.apache.juneau.annotation.NameProperty @NameProperty} and {@link org.apache.juneau.annotation.ParentProperty @ParentProperty}
can now be applied to fields.
<li>New properties on {@link org.apache.juneau.BeanContext}:
<ul>
<li>{@link org.apache.juneau.BeanContext#BEAN_includeProperties BEAN_includeProperties}
<li>{@link org.apache.juneau.BeanContext#BEAN_excludeProperties BEAN_excludeProperties}
</ul>
<li>New annotation property: {@link org.apache.juneau.annotation.BeanProperty#format()}.
</ul>
<h6 class='topic'>org.apache.juneau.rest</h6>
<ul class='spaced-list'>
<li>MAJOR enhancements made to the REST API.
<li>The {@link org.apache.juneau.rest.RestRequest} class functionality has been broken up into the following
functional pieces to reduce its complexity:
<ul>
<li>{@link org.apache.juneau.rest.RestRequest#getBody()} - The request body.
<li>{@link org.apache.juneau.rest.RestRequest#getHeaders()} - The request headers.
<li>{@link org.apache.juneau.rest.RestRequest#getQuery()} - The request query parameters.
<li>{@link org.apache.juneau.rest.RestRequest#getFormData()} - The request form data parameters.
<li>{@link org.apache.juneau.rest.RestRequest#getPathMatch()} - The path variables and remainder.
</ul>
The following classes have been introduced:
<ul>
<li>{@link org.apache.juneau.rest.RequestBody}
<li>{@link org.apache.juneau.rest.RequestHeaders}
<li>{@link org.apache.juneau.rest.RequestQuery}
<li>{@link org.apache.juneau.rest.RequestFormData}
<li>{@link org.apache.juneau.rest.RequestPathMatch}
</ul>
<li>The unannotated parameter types that can be passed in through REST Java methods has been significantly expanded.
<br>For reference, the previous supported types were:
<ul>
<li>{@link org.apache.juneau.rest.RestRequest} - The request object.
<li>{@link javax.servlet.http.HttpServletRequest} - The superclass of <code>RestRequest</code>.
<li>{@link org.apache.juneau.rest.RestResponse} - The response object.
<li>{@link javax.servlet.http.HttpServletResponse} - The superclass of <code>RestResponse</code>.
</ul>
The new supported types are:
<ul>
<li>{@link org.apache.juneau.http.Accept}
<li>{@link org.apache.juneau.http.AcceptCharset}
<li>{@link org.apache.juneau.http.AcceptEncoding}
<li>{@link org.apache.juneau.http.AcceptLanguage}
<li>{@link org.apache.juneau.http.Authorization}
<li>{@link org.apache.juneau.http.CacheControl}
<li>{@link org.apache.juneau.http.Connection}
<li>{@link org.apache.juneau.http.ContentLength}
<li>{@link org.apache.juneau.http.ContentType}
<li>{@link org.apache.juneau.http.Date}
<li>{@link org.apache.juneau.http.Expect}
<li>{@link org.apache.juneau.http.From}
<li>{@link org.apache.juneau.http.Host}
<li>{@link org.apache.juneau.http.IfMatch}
<li>{@link org.apache.juneau.http.IfModifiedSince}
<li>{@link org.apache.juneau.http.IfNoneMatch}
<li>{@link org.apache.juneau.http.IfRange}
<li>{@link org.apache.juneau.http.IfUnmodifiedSince}
<li>{@link org.apache.juneau.http.MaxForwards}
<li>{@link org.apache.juneau.http.Pragma}
<li>{@link org.apache.juneau.http.ProxyAuthorization}
<li>{@link org.apache.juneau.http.Range}
<li>{@link org.apache.juneau.http.Referer}
<li>{@link org.apache.juneau.http.TE}
<li>{@link org.apache.juneau.http.UserAgent}
<li>{@link org.apache.juneau.http.Upgrade}
<li>{@link org.apache.juneau.http.Via}
<li>{@link org.apache.juneau.http.Warning}
<li>{@link java.util.TimeZone}
<li>{@link java.io.InputStream}
<li>{@link javax.servlet.ServletInputStream}
<li>{@link java.io.Reader}
<li>{@link java.io.OutputStream}
<li>{@link javax.servlet.ServletOutputStream}
<li>{@link java.io.Writer}
<li>{@link java.util.ResourceBundle} - Client-localized resource bundle.
<li>{@link org.apache.juneau.utils.MessageBundle} - A resource bundle with additional features.
<li>{@link java.util.Locale} - Client locale.
<li>{@link org.apache.juneau.rest.RequestHeaders} - API for accessing request headers.
<li>{@link org.apache.juneau.rest.RequestQuery} - API for accessing request query parameters.
<li>{@link org.apache.juneau.rest.RequestFormData} - API for accessing request form data.
<li>{@link org.apache.juneau.rest.RequestPathMatch} - API for accessing path variables.
<li>{@link org.apache.juneau.rest.RequestBody} - API for accessing request body.
<li>{@link org.apache.juneau.http.HttpMethod} - The method name matched (when using <code><ja>@RestMethod</ja>(name=<js>"*"</js>)</code>)
<li>{@link java.util.logging.Logger} - The logger to use for logging.
<li>{@link org.apache.juneau.internal.JuneauLogger} - Logger with additional features.
<li>{@link org.apache.juneau.rest.RestContext} - The resource read-only context.
<li>{@link org.apache.juneau.parser.Parser} - The parser matching the request content type.
<li>{@link org.apache.juneau.dto.swagger.Swagger} - The auto-generated Swagger doc.
<li>{@link org.apache.juneau.ini.ConfigFile} - The external config file for the resource.
</ul>
So, for example...
<p class='bcode'>
<jd>/** Old way */</jd>
<ja>@RestMethod</ja>(name=<js>"*"</js>, path=<js>"/example1/{a1}/{a2}/{a3}/*"</js>)
<jk>public</jk> String example1(
<ja>@Method</ja> String method,
<ja>@Path</ja> String a1,
<ja>@Path</ja> <jk>int</jk> a2,
<ja>@Path</ja> UUID a3,
<ja>@Query</ja>(<js>"p1"</js>) <jk>int</jk> p1,
<ja>@Query</ja>(<js>"p2"</js>) String p2,
<ja>@Query</ja>(<js>"p3"</js>) UUID p3,
<ja>@Header</ja>(<js>"Accept-Language"</js>) String lang,
<ja>@Header</ja>(<js>"Accept"</js>) String accept
)
<jd>/** New way */</jd>
<ja>@RestMethod</ja>(name=<js>"*"</js>, path=<js>"/example2/{a1}/{a2}/{a3}/*"</js>)
<jk>public</jk> String example2(
HttpMethod httpMethod,
RequestPathParams pathParams,
RequestQuery query,
AcceptLanguage acceptLanguage,
Accept accept
)
</p>
<li>A new annotation {@link org.apache.juneau.rest.annotation.RestResource#paramResolvers() @RestResource.paramResolvers()}
that allows you to define your own custom Java method parameter resolvers.
<li>Fixed bug where Writer returned by {@link org.apache.juneau.rest.RestResponse#getWriter()} was not being flushed automatically
at the end of the HTTP call.
<li>New anntotations added to {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod}:
<ul>
<li>{@link org.apache.juneau.rest.annotation.RestMethod#defaultQuery() defaultQuery()}
<li>{@link org.apache.juneau.rest.annotation.RestMethod#defaultFormData() defaultFormData()}
<li>{@link org.apache.juneau.rest.annotation.RestMethod#bpIncludes() bpIncludes()}
<li>{@link org.apache.juneau.rest.annotation.RestMethod#bpExcludes() bpExcludes()}
</ul>
<li>Default values on header, query, and form-data annotations:
<ul>
<li>{@link org.apache.juneau.rest.annotation.Header#def @Header.def()} - Default header value.
<li>{@link org.apache.juneau.rest.annotation.Query#def @Query.def()} - Default query parameter value.
<li>{@link org.apache.juneau.rest.annotation.FormData#def @FormData.def()} - Default form data parameter value.
</ul>
<li>New attributes on {@link org.apache.juneau.rest.annotation.RestResource @RestResource}:
<ul>
<li>{@link org.apache.juneau.rest.annotation.RestResource#serializerListener() serializerListener()}
<li>{@link org.apache.juneau.rest.annotation.RestResource#parserListener() parserListener()}
<li>{@link org.apache.juneau.rest.annotation.RestResource#widgets() widgets()}
<li>{@link org.apache.juneau.rest.annotation.RestResource#swagger() swagger()}
<li>{@link org.apache.juneau.rest.annotation.RestResource#htmldoc() htmldoc()}
</ul>
<li>New attributes on {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod}:
<ul>
<li>{@link org.apache.juneau.rest.annotation.RestMethod#widgets() widgets()}
<li>{@link org.apache.juneau.rest.annotation.RestMethod#swagger() swagger()}
<li>{@link org.apache.juneau.rest.annotation.RestMethod#htmldoc() htmldoc()}
</ul>
<li>New string vars:
<ul>
<li>{@link org.apache.juneau.rest.vars.UrlVar} - Resolve <js>"$U{...}"</js> variables to URLs.
<li>{@link org.apache.juneau.rest.vars.WidgetVar} - Resolve <js>"$W{...}"</js> variables to widget contents.
</ul>
<li>New methods on {@link org.apache.juneau.rest.RestConfig}:
<ul>
<li>{@link org.apache.juneau.rest.RestConfig#setHtmlTitle(String) setHtmlTitle(String)}
<li>{@link org.apache.juneau.rest.RestConfig#setHtmlDescription(String) setHtmlDescription(String)}
<li>{@link org.apache.juneau.rest.RestConfig#setHtmlBranding(String) setHtmlBranding(String)}
<li>{@link org.apache.juneau.rest.RestConfig#setHtmlHeader(String) setHtmlHeader(String)}
<li>{@link org.apache.juneau.rest.RestConfig#setHtmlLinks(String) setHtmlLinks(String)}
<li>{@link org.apache.juneau.rest.RestConfig#setHtmlNav(String) setHtmlNav(String)}
<li>{@link org.apache.juneau.rest.RestConfig#setHtmlAside(String) setHtmlAside(String)}
<li>{@link org.apache.juneau.rest.RestConfig#setHtmlFooter(String) setHtmlFooter(String)}
<li>{@link org.apache.juneau.rest.RestConfig#setHtmlCss(String) setHtmlCss(String)}
<li>{@link org.apache.juneau.rest.RestConfig#setHtmlCssUrl(String) setHtmlCssUrl(String)}
<li>{@link org.apache.juneau.rest.RestConfig#setHtmlNoWrap(boolean) setHtmlNoWrap(boolean)}
<li>{@link org.apache.juneau.rest.RestConfig#setHtmlNoResultsMessage(String) setHtmlNoResultsMessage(String)}
<li>{@link org.apache.juneau.rest.RestConfig#setHtmlTemplate(Class) setHtmlTemplate(Class)}
<li>{@link org.apache.juneau.rest.RestConfig#setHtmlTemplate(HtmlDocTemplate) setHtmlTemplate(HtmlDocTemplate)}
<li>{@link org.apache.juneau.rest.RestConfig#addWidget(Class) addWidget(Class)}
</ul>
<li>New methods on {@link org.apache.juneau.rest.RestResponse}:
<ul>
<li>{@link org.apache.juneau.rest.RestResponse#setHtmlTitle(Object) setHtmlTitle(Object)}
<li>{@link org.apache.juneau.rest.RestResponse#setHtmlDescription(Object) setHtmlDescription(Object)}
<li>{@link org.apache.juneau.rest.RestResponse#setHtmlBranding(Object) setHtmlBranding(Object)}
<li>{@link org.apache.juneau.rest.RestResponse#setHtmlHeader(Object) setHtmlHeader(Object)}
<li>{@link org.apache.juneau.rest.RestResponse#setHtmlLinks(Object) setHtmlLinks(Object)}
<li>{@link org.apache.juneau.rest.RestResponse#setHtmlNav(Object) setHtmlNav(Object)}
<li>{@link org.apache.juneau.rest.RestResponse#setHtmlAside(Object) setHtmlAside(Object)}
<li>{@link org.apache.juneau.rest.RestResponse#setHtmlFooter(Object) setHtmlFooter(Object)}
<li>{@link org.apache.juneau.rest.RestResponse#setHtmlCss(Object) setHtmlCss(Object)}
<li>{@link org.apache.juneau.rest.RestResponse#setHtmlCssUrl(Object) setHtmlCssUrl(Object)}
<li>{@link org.apache.juneau.rest.RestResponse#setHtmlNoWrap(boolean) setHtmlNoWrap(boolean)}
<li>{@link org.apache.juneau.rest.RestResponse#setHtmlNoResultsMessage(Object) setHtmlNoResultsMessage(Object)}
<li>{@link org.apache.juneau.rest.RestResponse#setHtmlTemplate(Class) setHtmlTemplate(Class)}
<li>{@link org.apache.juneau.rest.RestResponse#setHtmlTemplate(HtmlDocTemplate) setHtmlTemplate(HtmlDocTemplate)}
</ul>
<li><code>&amp;plainText=true</code> parameter now works on byte-based serializers by converting the output to hex.
<li>New classes for widget support:
<ul>
<li>{@link org.apache.juneau.rest.widget.Widget}
<li>{@link org.apache.juneau.rest.widget.PoweredByJuneauWidget}
<li>{@link org.apache.juneau.rest.widget.ContentTypeLinksColumnWidget}
<li>{@link org.apache.juneau.rest.widget.ContentTypeLinksRowWidget}
<li>{@link org.apache.juneau.rest.widget.QueryWidget}
</ul>
<li><code>devops.css</code> cleaned up.
<li>Removed a bunch of URL-related methods from {@link org.apache.juneau.rest.RestRequest}.
These all have equivalents in {@link org.apache.juneau.rest.RestRequest#getUriContext()}.
<li>New annotation attributes:
<ul>
<li>{@link org.apache.juneau.rest.annotation.Query#name() @Query.name()}
<li>{@link org.apache.juneau.rest.annotation.FormData#name() @FormData.name()}
<li>{@link org.apache.juneau.rest.annotation.Header#name() @Header.name()}
<li>{@link org.apache.juneau.rest.annotation.Path#name() @Path.name()}
<li>{@link org.apache.juneau.rest.annotation.HasQuery#name() @HasQuery.name()}
<li>{@link org.apache.juneau.rest.annotation.HasFormData#name() @HasFormData.name()}
</ul>
</ul>
<h6 class='topic'>org.apache.juneau.rest.client</h6>
<ul class='spaced-list'>
<li>New {@link org.apache.juneau.remoteable.Path @Path} annotation for specifying path variables on remoteable interfaces.
<li>New {@link org.apache.juneau.remoteable.RequestBean @RequestBean} annotation for specifying beans with remoteable annotations
defined on properties.
<li>The following annotations (and related methods on RestCall) can now take <code>NameValuePairs</code> and beans as input
when using <js>"*"</js> as the name.
<br>{@link org.apache.juneau.remoteable.FormData @FormData},{@link org.apache.juneau.remoteable.FormDataIfNE @FormDataIfNE},
{@link org.apache.juneau.remoteable.Query @Query},{@link org.apache.juneau.remoteable.QueryIfNE @QueryIfNE},
{@link org.apache.juneau.remoteable.Header @Header},{@link org.apache.juneau.remoteable.HeaderIfNE @HeaderIfNE},
</ul>
<h6 class='topic'>org.apache.juneau.microservice</h6>
<ul class='spaced-list'>
</ul>
<h6 class='topic'>org.apache.juneau.examples.rest</h6>
<ul class='spaced-list'>
<li>Many code enhancements make to examples to reflect new functionality.
<li>All pages now render aside comments to help explain what feature they're trying to explain using the
new features that allow you to customize various elements of the page.
<br><img class='bordered' width="50%" src='doc-files/NewExamplesPage.png'>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="6.2.0"></a>
<h3 class='topic' onclick='toggle(this)'>6.2.0 (Apr 28, 2017)</h3>
<div class='topic'>
<p>
Juneau 6.2.0 is a major update.
</p>
<h6 class='topic'>org.apache.juneau</h6>
<ul class='spaced-list'>
<li>Revamped the serializer, parser classes to use builders for creation.
Serializers and parsers are now unmodifiable objects once they are created.
This is a breaking code change that will require adoption.
<p class='bcode'>
<jc>/* Creating a new serializer or parser */ </jc>
<jc>// Old way</jc>
WriterSerializer s = <jk>new</jk> JsonSerializer().setUseWhitespace(<jk>true</jk>).pojoSwaps(BSwap.<jk>class</jk>).lock();
<jc>// New way</jc>
WriterSerializer s = <jk>new</jk> JsonSerializerBuilder().ws().pojoSwaps(BSwap.<jk>class</jk>).build();
<jc>/* Cloning an existing serializer or parser */ </jc>
<jc>// Old way</jc>
WriterSerializer s = JsonSerializer.<jsf>DEFAULT_LAX</jsf>.clone().setUseWhitespace(<jk>true</jk>).pojoSwaps(BSwap.<jk>class</jk>).lock();
<jc>// New way</jc>
WriterSerializer s = JsonSerializer.<jsf>DEFAULT_LAX</jsf>.builder().ws().pojoSwaps(BSwap.<jk>class</jk>).build();
</p>
<li>Also introduced the following builder classes and related architecture changes to make the built objects unmodifiable:
<ul>
<li>{@link org.apache.juneau.serializer.SerializerGroupBuilder}
<li>{@link org.apache.juneau.parser.ParserGroupBuilder}
<li>{@link org.apache.juneau.encoders.EncoderGroupBuilder}
</ul>
<li>Revamped the config file API to use a build: {@link org.apache.juneau.ini.ConfigFileBuilder}.
<li>Removed the <code><del>Lockable</del></code> interface.
<li>New <code>addBeanTypeProperties</code> setting added to serializers to override the
{@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_addBeanTypeProperties} setting
for individual serializers in a serializer group:
<ul>
<li>{@link org.apache.juneau.html.HtmlSerializerContext#HTML_addBeanTypeProperties}
<li>{@link org.apache.juneau.json.JsonSerializerContext#JSON_addBeanTypeProperties}
<li>{@link org.apache.juneau.msgpack.MsgPackSerializerContext#MSGPACK_addBeanTypeProperties}
<li>{@link org.apache.juneau.uon.UonSerializerContext#UON_addBeanTypeProperties}
<li>{@link org.apache.juneau.xml.XmlSerializerContext#XML_addBeanTypeProperties}
<li>{@link org.apache.juneau.jena.RdfSerializerContext#RDF_addBeanTypeProperties}
</ul>
<li>UON notation serializers and parsers moved into the new <code>org.apache.juneau.uon</code> package.
<li>New {@link org.apache.juneau.xml.annotation.XmlFormat#VOID} format to identify HTML void elements.
<li>Tweaks to HTML5 support.
<ul>
<li>Fixed handling of empty non-void elements in HTML serializer.
<li>Added <code>style()</code> override methods to all elements.
</ul>
<li>Improvements to Swagger support.
<ul>
<li>New {@link org.apache.juneau.dto.swagger.SwaggerBuilder} class.
<li>Fluent-style setters added to the Swagger beans.
<li>Added Swagger examples <a href="#DTOs.Swagger">here</a> and in the <a class='doclink' href='org/apache/juneau/dto/swagger/package-summary.html#TOC'>org.apache.juneau.dto.swagger</a> javadocs.
</ul>
<li>Improvements to {@link org.apache.juneau.svl.VarResolver}.
<ul>
<li>New {@link org.apache.juneau.svl.vars.IfVar $IF} variable for if-else block logic.
<li>New {@link org.apache.juneau.svl.vars.SwitchVar $SWITCH} variable for switch block logic.
<li>Whitespace wasn't being ignored in some cases.
</ul>
<li>{@link org.apache.juneau.html.HtmlParser} can now parse full body contents generated by {@link org.apache.juneau.html.HtmlDocSerializer}.
<li>Parse-args supported added to {@link org.apache.juneau.msgpack.MsgPackParser} to allow it to be used in remoteable proxies.
<li>Added some convenience classes for constructing collections using a fluent interface:
<ul>
<li>{@link org.apache.juneau.utils.AList}
<li>{@link org.apache.juneau.utils.ASet}
<li>{@link org.apache.juneau.utils.AMap}
</ul>
<li>New {@link org.apache.juneau.annotation.Bean#typePropertyName @Bean.typePropertyName()} annotation allows you to
specify the name of the <js>"_type"</js> property at the class level.
<li>New methods added to HTML5 container beans:
<ul>
<li>{@link org.apache.juneau.dto.html5.HtmlElementContainer#getChild(int...)}
<li>{@link org.apache.juneau.dto.html5.HtmlElementMixed#getChild(int...)}
</ul>
<li>New common serializer setting: {@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_abridged}.
<li>Support for defining interface proxies against 3rd-party REST interfaces.
<br>New package {@link org.apache.juneau.remoteable} for all remoteable proxy interface annotations.
<br><ja>@Remoteable</ja> annotation has been moved to this package.
<li>Updated doc: <a class='doclink' href='#Remoteable'>6 - Remoteable Services</a>
<li>New doc: <a class='doclink' href='#Remoteable.3rdParty'>6.1 - Interface proxies against 3rd-party REST interfaces</a>
<li>New URL-encoding serializer setting: <code><del>UrlEncodingSerializerContext.URLENC_paramFormat</del></code>.
<li>New methods on {@link org.apache.juneau.urlencoding.UrlEncodingSerializerBuilder}:
<ul>
<li>{@link org.apache.juneau.urlencoding.UrlEncodingSerializerBuilder#paramFormat(String) paramFormat(String)}
<li><code><del>UrlEncodingSerializerBuilder.plainTextParams()</del></code>
</ul>
</ul>
<h6 class='topic'>org.apache.juneau.rest</h6>
<ul class='spaced-list'>
<li>{@link org.apache.juneau.rest.annotation.RestResource @RestResource} annotation can now be applied to
any class! You're no longer restricted to subclassing your resources from {@link org.apache.juneau.rest.RestServlet}.
<br>This is a major enhancement in the API. Anything you could do by subclassing from <code>RestServlet</code>
should have an equivalent for non-<code>RestServlet</code> classes.
<br>The only restriction is that the top-level resource must subclass from <code>RestServlet</code>.
Child resources do not.
<br><br>
The majority of code has been split up into two separate classes:
<ul>
<li>{@link org.apache.juneau.rest.RestConfig} - A modifiable configuration of a resource. Subclasses from {@link javax.servlet.ServletConfig}.
<li>{@link org.apache.juneau.rest.RestContext} - A read-only configuration that's the result of a snapshot of the config.
</ul>
<br><br>
The {@link org.apache.juneau.rest.RestServlet} class now has the following initialization method that allows you to override
the config settings define via annotations:
<ul>
<li>{@link org.apache.juneau.rest.RestServlet#init(RestConfig)} - A modifiable configuration of a resource.
</ul>
Non-<code>RestServlet</code> classes must have one of the following to allow it to be instantiated:
<ul>
<li>A <code><jk>public</jk> T(RestConfig)</code> constructor.
<li>A <code><jk>public</jk> T()</code> constructor.
<li>The parent resource must have a customized {@link org.apache.juneau.rest.RestResourceResolver} for instantiating it.
</ul>
<br>
Non-<code>RestServlet</code> classes can optionally include the following init methods to gain access to the config and context:
<ul>
<li><code><jk>public</jk> init(RestConfig)</code>
<li><code><jk>public</jk> init(RestContext)</code>
</ul>
<li>New annotations added to {@link org.apache.juneau.rest.annotation.RestResource @RestResource} to allow non-<code>RestServlet</code>
resources to do the same as subclassing directly from <code>RestServlet</code>:
<ul>
<li>{@link org.apache.juneau.rest.annotation.RestResource#resourceResolver() resourceResolver()}
- Specify a {@link org.apache.juneau.rest.RestResourceResolver} class for resolving child resources.
<li>{@link org.apache.juneau.rest.annotation.RestResource#callHandler() callHandler()}
- Specify a {@link org.apache.juneau.rest.RestCallHandler} class for handling the lifecycle of a REST call.
<li>{@link org.apache.juneau.rest.annotation.RestResource#infoProvider() infoProvider()}
- Specify a {@link org.apache.juneau.rest.RestInfoProvider} class for customizing title/description/Swagger information on a REST resource.
<li>{@link org.apache.juneau.rest.annotation.RestResource#logger() logger()}
- Specify a {@link org.apache.juneau.rest.RestLogger} class for handling logging.
</ul>
<li>New annotations added to {@link org.apache.juneau.rest.annotation.RestResource @RestResource} and {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod}
to simplify defining page title, text, and links on HTML views:
<ul>
<li><code><del>@RestResource.pageTitle()</del></code>
<li><code><del>@RestMethod.pageTitle()</del></code>
<li><code><del>@RestResource.pageText()</del></code>
<li><code><del>@RestMethod.pageText()</del></code>
<li><code><del>@RestResource.pageLinks()</del></code>
<li><code><del>@RestMethod.pageLinks()</del></code>
</ul>
<p class='bcode'>
<jc>// Old method</jc>
<ja>@RestResource</ja>(
properties={
<ja>@Property</ja>(name=<jsf>HTMLDOC_title</jsf>, value=<js>"System properties resource"</js>),
<ja>@Property</ja>(name=<jsf>HTMLDOC_description</jsf>, value=<js>"REST interface for performing CRUD operations on system properties."</js>),
<ja>@Property</ja>(name=<jsf>HTMLDOC_links</jsf>, value=<js>"{up:'$R{requestParentURI}',options:'?method=OPTIONS'}"</js>)
}
)
<jc>// New method</jc>
<ja>@RestResource</ja>(
pageTitle=<js>"System properties resource"</js>,
pageDescription=<js>"REST interface for performing CRUD operations on system properties."</js>,
pageLinks=<js>"{up:'$R{requestParentURI}',options:'?method=OPTIONS'}"</js>
)
</p>
<p>
Typically you're going to simply want to use the <code>title</code> and <code>description</code> annotations
which apply to both the page title/text and the swagger doc:
</p>
<p class='bcode'>
<ja>@RestResource</ja>(
title=<js>"System properties resource"</js>,
description=<js>"REST interface for performing CRUD operations on system properties."</js>,
pageLinks=<js>"{up:'$R{requestParentURI}',options:'?method=OPTIONS'}"</js>
)
</p>
<li>{@link org.apache.juneau.rest.annotation.RestResource#stylesheet()} can now take in a comma-delimited list of stylesheet paths.
<li>{@link org.apache.juneau.rest.StreamResource} can now contain multiple sources from a variety of source types (e.g. <code><jk>byte</jk>[]</code> arrays, <code>InputStreams</code>, <code>Files</code>, etc...)
and is now immutable. It also includes a new {@link org.apache.juneau.rest.StreamResource.Builder} class.
<li>Simplified remoteable proxies using the <code><ja>@RestMethod</ja>(name=<js>"PROXY"</js>)</code> annotation on REST methods.
Used to expose interface proxies without the need for {@link org.apache.juneau.rest.remoteable.RemoteableServlet}.
<p class='bcode'>
<jc>// Server side</jc>
<ja>@RestMethod</ja>(name=<js>"PROXY"</js>, path=<js>"/myproxy/*"</js>)
<jk>public</jk> IAddressBook getProxy() {
<jk>return</jk> <jf>addressBook</jf>;
}
<jc>// Client side</jc>
RestClient client = <jk>new</jk> RestClientBuilder().rootUrl(<jf>samplesUrl</jf>).build();
IAddressBook ab = client.getRemoteableProxy(IAddressBook.<jk>class</jk>, <js>"/addressBook/myproxy"</js>);
</p>
See {@link org.apache.juneau.rest.annotation.RestMethod#name()} for more information.
<li>{@link org.apache.juneau.rest.RestRequest#toString()} can be called at any time to view the headers and content of the request
without affecting functionality. Very useful for debugging.
<li>You can now use numeric values in path annotations.
<br>When using numeric variable names, you don't need to specify the variable name in the <ja>@Path</ja> annoation:
<p class='bcode'>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/myurl/{0}/{1}/{2}/*"</js>)
<jk>public void</jk> doGet(RestRequest req, RestResponse res,
<ja>@Path</ja> String foo, <ja>@Path</ja> <jk>int</jk> bar, <ja>@Path</ja> UUID baz) {
...
}
</p>
<li>{@link org.apache.juneau.rest.annotation.RestMethod#name() @RestMethod.name()} annotation is now optional. Defaults to <js>"GET"</js>.
</ul>
<h6 class='topic'>org.apache.juneau.rest.client</h6>
<ul class='spaced-list'>
<li>Revamped the client API to use builders.
<li>New doc: <a class='doclink' href='org/apache/juneau/rest/client/package-summary.html#Debugging'>1.5 - Debugging</a>
<li>The <code>RestClient</code> class <code>doX(Object url)</code> methods now handle HttpClient <code>URIBuilder</code> instances.
<li>New methods added/updated to {@link org.apache.juneau.rest.client.RestClient}:
<ul>
<li>{@link org.apache.juneau.rest.client.RestClient#getRemoteableProxy(Class,Object) getRemoteableProxy(Class,Object)} - For interface proxies defined using <code><ja>@RestMethod</ja>(name=<js>"PROXY"</js>)</code>.
<li>{@link org.apache.juneau.rest.client.RestClient#getRemoteableProxy(Class,Object,Serializer,Parser) getRemoteableProxy(Class,Object,Serializer,Parser)} - Same as above, but overrides the serializer and parser defined on the client.
<li>{@link org.apache.juneau.rest.client.RestClient#doPost(Object) doPost(Object)}
<li>{@link org.apache.juneau.rest.client.RestClient#doCall(HttpMethod,Object,Object) doCall(HttpMethod,Object,Object)} - Can now pass in instances of {@link org.apache.juneau.rest.client.NameValuePairs} for easy form posts.
<br>This extends to all methods that take in the input.
</ul>
<li>New methods on {@link org.apache.juneau.rest.client.RestCall}:
<ul>
<li>{@link org.apache.juneau.rest.client.RestCall#uri(Object) uri(Object)}
<li>{@link org.apache.juneau.rest.client.RestCall#query(String,Object,boolean,PartSerializer) query(String,Object,boolean,PartSerializer)}
<li>{@link org.apache.juneau.rest.client.RestCall#query(String,Object) query(String,Object)}
<li>{@link org.apache.juneau.rest.client.RestCall#queryIfNE(String,Object) queryIfNE(String,Object)}
<li>{@link org.apache.juneau.rest.client.RestCall#query(Map) query(Map)}
<li>{@link org.apache.juneau.rest.client.RestCall#queryIfNE(Map) queryIfNE(Map)}
<li>{@link org.apache.juneau.rest.client.RestCall#query(String) query(String)}
<li>{@link org.apache.juneau.rest.client.RestCall#formData(String,Object,boolean,PartSerializer) formData(String,Object,boolean,PartSerializer)}
<li>{@link org.apache.juneau.rest.client.RestCall#formData(String,Object) formData(String,Object)}
<li>{@link org.apache.juneau.rest.client.RestCall#formDataIfNE(String,Object) formDataIfNE(String,Object)}
<li>{@link org.apache.juneau.rest.client.RestCall#formData(Map) formData(Map)}
<li>{@link org.apache.juneau.rest.client.RestCall#formDataIfNE(Map) formDataIfNE(Map)}
<li>{@link org.apache.juneau.rest.client.RestCall#header(String,Object,boolean,PartSerializer) header(String,Object,boolean,PartSerializer)}
<li>{@link org.apache.juneau.rest.client.RestCall#header(String,Object) header(String,Object)}
<li>{@link org.apache.juneau.rest.client.RestCall#headerIfNE(String,Object) headerIfNE(String,Object)}
<li>{@link org.apache.juneau.rest.client.RestCall#headers(Map) headers(Map)}
<li>{@link org.apache.juneau.rest.client.RestCall#headersIfNE(Map) headersIfNE(Map)}
<li>{@link org.apache.juneau.rest.client.RestCall#host(String) host(String)}
<li>{@link org.apache.juneau.rest.client.RestCall#port(int) port(int)}
<li>{@link org.apache.juneau.rest.client.RestCall#userInfo(String,String) userInfo(String,String)}
<li>{@link org.apache.juneau.rest.client.RestCall#userInfo(String) userInfo(String)}
<li>{@link org.apache.juneau.rest.client.RestCall#scheme(String) scheme(String)}
</ul>
<li>New methods added to {@link org.apache.juneau.rest.client.RestClientBuilder}:
<ul>
<li>{@link org.apache.juneau.rest.client.RestClientBuilder#executorService(ExecutorService,boolean) executorService(ExecutorService,boolean)}
<li>{@link org.apache.juneau.rest.client.RestClientBuilder#paramFormat(String) paramFormat(ExecutorService,boolean)}
<li><code><del>RestClientBuilder.plainTextParams()</del></code>
<li>{@link org.apache.juneau.rest.client.RestClientBuilder#noTrace() noTrace()} - Adds a <code>No-Trace: true</code> header on all requests to prevent
the servlet from logging errors.
<br>Useful for testing scenarios when you don't want the console to end up showing errors done on purpose.
<li>{@link org.apache.juneau.rest.client.RestClientBuilder#debug() debug()} now adds a <code>Debug: true</code> header on all requests.
</ul>
<li>New methods added/updated to {@link org.apache.juneau.rest.client.RestCall}:
<ul>
<li>{@link org.apache.juneau.rest.client.RestCall#runFuture() runFuture()}
<li>{@link org.apache.juneau.rest.client.RestCall#getResponseFuture(Class) getResponseFuture(Class)}
<li>{@link org.apache.juneau.rest.client.RestCall#getResponseFuture(Type,Type...) getResponseFuture(Type,Type...)}
<li>{@link org.apache.juneau.rest.client.RestCall#getResponseAsStringFuture() getResponseAsStringFuture()}
<li>{@link org.apache.juneau.rest.client.RestCall#serializer(Serializer) serializer(Serializer)} - Override the serializer defined on the client for a single call.
<li>{@link org.apache.juneau.rest.client.RestCall#parser(Parser) parser(Parser)} - Override the parser defined on the client for a single call.
<li>{@link org.apache.juneau.rest.client.RestCall#input(Object) input(Object)} - Now accepts instances of {@link org.apache.juneau.rest.client.NameValuePairs}.
<li>{@link org.apache.juneau.rest.client.RestCall#getResponse(Class) getResponse(Class)} - Can now pass in any of the following:
<ul>
<li>{@link org.apache.http.HttpResponse} - Returns the raw <code>HttpResponse</code> returned by the inner <code>HttpClient</code>.
<li>{@link java.io.Reader} - Returns access to the raw reader of the response.
<li>{@link java.io.InputStream} - Returns access to the raw input stream of the response.
</ul>
</ul>
<li>New methods added to {@link org.apache.juneau.rest.client.NameValuePairs}:
<ul>
<li>{@link org.apache.juneau.rest.client.NameValuePairs#append(String,Object) append(String,Object)}
<li>{@link org.apache.juneau.rest.client.NameValuePairs#append(String,Object,PartSerializer) append(String,Object,PartSerializer)}
</ul>
<li>{@link org.apache.juneau.rest.client.RetryOn} is now an abstract class with an additional method:
<ul>
<li>{@link org.apache.juneau.rest.client.RetryOn#onResponse(HttpResponse) onResponse(HttpResponse)}
</ul>
</ul>
<h6 class='topic'>org.apache.juneau.microservice</h6>
<ul class='spaced-list'>
<li><js>"REST/port"</js> configuration setting can now be a comma-limited list of port numbers to try.
<br>You can also specify one or more <code>0</code>s to try a random port.
<li>Methods added to {@link org.apache.juneau.microservice.RestMicroservice} class:
<ul>
<li>{@link org.apache.juneau.microservice.RestMicroservice#getPort()}
<li>{@link org.apache.juneau.microservice.RestMicroservice#getURI()}
<li>Override methods added from {@link org.apache.juneau.microservice.Microservice} class for easier method chaining.
</ul>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="6.1.0"></a>
<h3 class='topic' onclick='toggle(this)'>6.1.0 (Feb 25, 2017)</h3>
<div class='topic'>
<p>
Juneau 6.1.0 is a major update.
</p>
<p>
In particular, this release cleans up the {@link org.apache.juneau.BeanContext} API to match
the {@link org.apache.juneau.PropertyStore}/{@link org.apache.juneau.Context}/{@link org.apache.juneau.Session} paradigm
previously used in the serializer and parser APIs.
It also makes several improvements to the HTML and XML serialization support and introduces HTML5 DTO beans.
</p>
<h6 class='topic'>org.apache.juneau</h6>
<ul class='spaced-list'>
<li>Improvements to XML serialization support.
<ul>
<li>New supported XML formats:
<ul>
<li>{@link org.apache.juneau.xml.annotation.XmlFormat#ATTRS} format can now be applied to bean classes to have all bean properties serialized
as attributes instead of elements by default.
<li>{@link org.apache.juneau.xml.annotation.XmlFormat#ELEMENT} format can now be applied to bean properties to override the {@link org.apache.juneau.xml.annotation.XmlFormat#ATTRS}
setting above on specific bean properties.
<li>New {@link org.apache.juneau.xml.annotation.XmlFormat#ELEMENTS} format can be applied to a bean property of type array/Collection to represent the child elements.
<li>New {@link org.apache.juneau.xml.annotation.XmlFormat#MIXED} format can be applied to a bean property of type array/Collection to represent mixed content (text + child elements).
<li>New {@link org.apache.juneau.xml.annotation.XmlFormat#MIXED_PWS} format. Identical to <jsf>MIXED</jsf> except preserves whitespace.
<li>New {@link org.apache.juneau.xml.annotation.XmlFormat#TEXT} format can be applied to a bean property of a single object to represent a text node as a child.
<li>New {@link org.apache.juneau.xml.annotation.XmlFormat#TEXT_PWS} format. Identical to <jsf>TEXT</jsf> except preserves whitespace.
<li>New {@link org.apache.juneau.xml.annotation.XmlFormat#XMLTEXT} format that's identical to {@link org.apache.juneau.xml.annotation.XmlFormat#TEXT} except
XML content is not escaped and serialized directly as the child content. The parser will reconvert this to the original XML text during parsing.
</ul>
<li>New support methodology and other improvements to <a class='doclink' href='org/apache/juneau/xml/package-summary.html#TOC'>org.apache.juneau.xml</a> documentation.
<li>Eliminated unnecessary <xt>&lt;string&gt;</xt> elements.
<li>Eliminated <code><del>XmlContentHandler</del></code> class.
<li>Parser efficiency improvements through reuse of string builders.
<li>Reworked and simplified the default XML serializers. The {@link org.apache.juneau.xml.XmlSerializer#DEFAULT} serializer now has namespaces disabled,
and {@link org.apache.juneau.xml.XmlSerializer#DEFAULT_NS} has namespaces enabled. The 'XML-JSON' serializers have been eliminated.
<li>Eliminated the <code>addJsonTypeAttrs</code> and <code>addJsonStringTypeAttrs</code> settings.
<li>Namespace support is now disabled by default.
</ul>
<li>Significant modifications and improvements to HTML serialization support.
<ul>
<li>Parser converted from <code>XMLEventReader</code>-based to <code>XMLStreamReader</code>.
<li>Eliminated many unnecessary type tags and <xt>&lt;string&gt;</xt> elements and improved the readable layout.
The new format is much leaner.
<li>New exhaustive support methodology section added to <a class='doclink' href='org/apache/juneau/html/package-summary.html#TOC'>org.apache.juneau.html</a> documentation.
</ul>
<li>New HTML5 DTO support: <a class='doclink' href='org/apache/juneau/dto/html5/package-summary.html#TOC'>org.apache.juneau.dto.html5</a>.
<li>{@link org.apache.juneau.BeanContext} class split into separate {@link org.apache.juneau.BeanContext} and {@link org.apache.juneau.BeanSession} classes.
<ul>
<li>Session object meant to be single-use that can be discarded after use and contains session-level object cache and overridable Locale and TimeZone.
</ul>
<li>{@link org.apache.juneau.serializer.SerializerContext} and {@link org.apache.juneau.parser.ParserContext}
now extend directly from {@link org.apache.juneau.BeanContext}.
<li>{@link org.apache.juneau.serializer.SerializerSession} and {@link org.apache.juneau.parser.ParserSession}
now extend directly from {@link org.apache.juneau.BeanSession}.
<li>New settings in {@link org.apache.juneau.BeanContext}:
<ul>
<li>{@link org.apache.juneau.BeanContext#BEAN_debug} - Debug setting. Replaces individual debug properties in the serializer and parser contexts.
<li>{@link org.apache.juneau.BeanContext#BEAN_locale} - Specifies a default locale at the context level.
<li>{@link org.apache.juneau.BeanContext#BEAN_timeZone} - Specifies a default timezone at the context level.
<li>{@link org.apache.juneau.BeanContext#BEAN_mediaType} - Specifies a default media type at the context level.
</ul>
<li>Improvements to Parser class:
<ul>
<li>Simplified the parse methods (e.g. <code>parseMap()</code>, <code>parseCollection()</code>)
by replacing them with two simple methods:
<ul>
<li>{@link org.apache.juneau.parser.Parser#parse(Object,Class)} - Normal method.
<li>{@link org.apache.juneau.parser.Parser#parse(Object,Type,Type...)} - Method for parsing into parameterized maps and collections.
</ul>
Using these methods, you can construct arbitrarily complex objects consisting of maps and collections.
You could do this before, but it required constructing a <code>ClassMeta</code> object.
<br>For example:
<p class='bcode'>
<jc>// Old way:</jc>
ClassMeta&lt;?&gt; cm = parser.getMapClassMeta(
HashMap.<jk>class</jk>,
String.<jk>class</jk>,
parser.getCollectionClassMeta(
LinkedList.<jk>class</jk>,
MyBean.<jk>class</jk>
)
);
Map&lt;String,List&lt;MyBean&gt;&gt; map = (Map&lt;String,List&lt;MyBean&gt;&gt;)parser.parse(input, cm);
<jc>// New way:</jc>
Map&lt;String,List&lt;MyBean&gt;&gt; map = parser.parse(input, HashMap.<jk>class</jk>, String.<jk>class</jk>, LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
</p>
<li>Arbitrarily-complex parameterized maps and collections can now be parsed without the need for creating intermediate <code>ClassMeta</code> objects.
<li>No need for casting anymore if you were using the old <code>parseMap()</code> and <code>parseCollection()</code> methods!
<li>Changes allow me to eliminate <code>BeanContext.normalizeClassMeta()</code> method.
<li>Convenience methods added for setting parser properties:
<p class='bcode'>
<jc>// Old way:</jc>
<jk>new</jk> JsonParser().setProperty(<jsf>PARSER_strict</jsf>, <jk>true</jk>).setProperty(<jsf>BEAN_locale</jsf>, mylocale);
<jc>// New way:</jc>
<jk>new</jk> JsonParser().setStrict(<jk>true</jk>).setLocale(mylocale);
</p>
</ul>
<li>Improvements to Serializer class:
<ul>
<li>Convenience methods added for setting serializer properties:
<p class='bcode'>
<jc>// Old way:</jc>
<jk>new</jk> JsonSerializer().setProperty(<jsf>JSON_simpleMode</jsf>, <jk>true</jk>).setProperty(<jsf>SERIALIZER_quoteChar</jsf>, <js>'"'</js>);
<jc>// New way:</jc>
<jk>new</jk> JsonSerializer().setSimpleMode(<jk>true</jk>).setQuoteChar(<js>'"'</js>);
</p>
</ul>
<li>Simplified {@link org.apache.juneau.transform.PojoSwap} class. Now just two methods:
<ul>
<li>{@link org.apache.juneau.transform.PojoSwap#swap(BeanSession,Object)}
<li>{@link org.apache.juneau.transform.PojoSwap#unswap(BeanSession,Object,ClassMeta)}
</ul>
<li>General code improvements made to {@link org.apache.juneau.ClassMeta} class.
<ul>
<li>All fields are now final which should improve overall performance.
<li>Replaced support for <code>toObjectMap()</code> and <code>fromObjectMap()/T(ObjectMap)</code> methods with
generalized <code>swap(BeanSession)</code>/<code>unswap(BeanSession,X)</code>/<code>T(BeanSession,X)</code> methods.<br>
See new section <a class='doclink' href='#Core.SwapMethods'>Swap methods</a> for information.
</ul>
<li>Session-level media type now available through {@link org.apache.juneau.BeanSession#getMediaType()} method.
Allows for swaps and serializer/parser behavior to be tailored to individual media types.
<li>Several new {@link java.util.Calendar} and {@link java.util.Date} swaps:
<ul>
<li>{@link org.apache.juneau.transforms.CalendarSwap.ToString},{@link org.apache.juneau.transforms.DateSwap.ToString} - To {@link java.lang.String Strings} using the {@code Date.toString()} method.
<li>{@link org.apache.juneau.transforms.CalendarSwap.ISO8601DT},{@link org.apache.juneau.transforms.DateSwap.ISO8601DT} - To ISO8601 date-time strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.ISO8601DTZ},{@link org.apache.juneau.transforms.DateSwap.ISO8601DTZ} - Same as <jsf>ISO8601DT</jsf>, except always serializes in GMT.
<li>{@link org.apache.juneau.transforms.CalendarSwap.ISO8601DTP},{@link org.apache.juneau.transforms.DateSwap.ISO8601DTP} - Same as <jsf>ISO8601DT</jsf> except with millisecond precision.
<li>{@link org.apache.juneau.transforms.CalendarSwap.ISO8601DTPZ},{@link org.apache.juneau.transforms.DateSwap.ISO8601DTPZ} - Same as <jsf>ISO8601DTZ</jsf> except with millisecond precision.
<li>{@link org.apache.juneau.transforms.CalendarSwap.RFC2822DT},{@link org.apache.juneau.transforms.DateSwap.RFC2822DT} - To RFC2822 date-time strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.RFC2822DTZ},{@link org.apache.juneau.transforms.DateSwap.RFC2822DTZ} - Same as <jsf>RFC2822DT</jsf>, except always serializes in GMT.
<li>{@link org.apache.juneau.transforms.CalendarSwap.RFC2822D},{@link org.apache.juneau.transforms.DateSwap.RFC2822D} - To RFC2822 date strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.DateTimeSimple},{@link org.apache.juneau.transforms.DateSwap.DateTimeSimple} - To simple <js>"yyyy/MM/dd HH:mm:ss"</js> date-time strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.DateSimple},{@link org.apache.juneau.transforms.DateSwap.DateSimple} - To simple <js>"yyyy/MM/dd"</js> date strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.TimeSimple},{@link org.apache.juneau.transforms.DateSwap.TimeSimple} - To simple <js>"HH:mm:ss"</js> time strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.DateFull},{@link org.apache.juneau.transforms.DateSwap.DateFull} - To {@link java.text.DateFormat#FULL} date strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.DateLong},{@link org.apache.juneau.transforms.DateSwap.DateLong} - To {@link java.text.DateFormat#LONG} date strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.DateMedium},{@link org.apache.juneau.transforms.DateSwap.DateMedium} - To {@link java.text.DateFormat#MEDIUM} date strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.DateShort},{@link org.apache.juneau.transforms.DateSwap.DateShort} - To {@link java.text.DateFormat#SHORT} date strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.TimeFull},{@link org.apache.juneau.transforms.DateSwap.TimeFull} - To {@link java.text.DateFormat#FULL} time strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.TimeLong},{@link org.apache.juneau.transforms.DateSwap.TimeLong} - To {@link java.text.DateFormat#LONG} time strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.TimeMedium},{@link org.apache.juneau.transforms.DateSwap.TimeMedium} - To {@link java.text.DateFormat#MEDIUM} time strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.TimeShort},{@link org.apache.juneau.transforms.DateSwap.TimeShort} - To {@link java.text.DateFormat#SHORT} time strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.DateTimeFull},{@link org.apache.juneau.transforms.DateSwap.DateTimeFull} - To {@link java.text.DateFormat#FULL} date-time strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.DateTimeLong},{@link org.apache.juneau.transforms.DateSwap.DateTimeLong} - To {@link java.text.DateFormat#LONG} date-time strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.DateTimeMedium},{@link org.apache.juneau.transforms.DateSwap.DateTimeMedium} - To {@link java.text.DateFormat#MEDIUM} date-time strings.
<li>{@link org.apache.juneau.transforms.CalendarSwap.DateTimeShort},{@link org.apache.juneau.transforms.DateSwap.DateTimeShort} - To {@link java.text.DateFormat#SHORT} date-time strings.
</ul>
<li>New method {@link org.apache.juneau.serializer.SerializerGroup#getSerializerMatch(String)} that returns the matched serializer and media type.
<li>New method {@link org.apache.juneau.parser.ParserGroup#getParserMatch(String)} that returns the matched parser and media type.
<li>New method {@link org.apache.juneau.encoders.EncoderGroup#getEncoderMatch(String)} that returns the matched encoder and encoding.
<li>General improvements to Bean Dictionary support.
<ul>
<li>New {@link org.apache.juneau.BeanDictionaryList} class can be used for defining reusable sets of bean dictionaries consisting
of classes annotated with {@link org.apache.juneau.annotation.Bean#typeName()}.
<li>New {@link org.apache.juneau.BeanDictionaryMap} class can be used for defining reusable sets of bean dictionaries consisting
of classes not annotated with {@link org.apache.juneau.annotation.Bean#typeName()}.
<li>New {@link org.apache.juneau.annotation.Bean#beanDictionary()} annotation.
</ul>
<li>Removed restriction on getters and setters to be prefixed with "getX/setX/isX" if a {@link org.apache.juneau.annotation.BeanProperty#name()} annotation is used.
<li>Improvements to ATOM DTO:
<ul>
<li>New {@link org.apache.juneau.dto.atom.AtomBuilder} class.
<li>New setter method names for a better fluent design.
<li>Updated <a class='doclink' href='org/apache/juneau/dto/atom/package-summary.html#TOC'>org.apache.juneau.dto.atom</a> documentation.
</ul>
<li>New {@link org.apache.juneau.transform.MapSwap} and {@link org.apache.juneau.transform.StringSwap} classes.
<li>New {@link org.apache.juneau.serializer.WriterSerializer#println(Object)} method. Useful for debugging purposes.
<li>New {@link org.apache.juneau.BeanContext#getClassMeta(Type,Type...)} and {@link org.apache.juneau.BeanSession#getClassMeta(Type,Type...)}
methods for retrieving Map and Collection class metas.
Replaces the various <code>getMapClassMeta()</code>/<code>getCollectionClassMeta()</code> methods.
<li>New section added to this document: <a class='doclink' href='#DTOs'>Juneau Data Transfer Objects (org.apache.juneau.dto)</a>
<li>Modified the UON specification to work with mixed content.
<ul>
<li>The new specification is considerably cleaner and eliminates the need for separate normal/simple modes.
<br>It also allows for arbitrary whitespace to be added to the output without any confusion.
<li>Eliminated the <code>UonParser.<jsf>DEFAULT_WS_AWARE</jsf></code> and <code>UrlEncodingParser.<jsf>DEFAULT_WS_AWARE</jsf></code> parsers.
<br>The normal {@link org.apache.juneau.uon.UonParser#DEFAULT} and {@link org.apache.juneau.urlencoding.UrlEncodingParser#DEFAULT} parsers will now handle whitespace.
<li>Eliminated the <code>UonParserContext.<jsf>UON_whitespaceAware</jsf></code> configuration setting.
<li>Eliminated the <code>UonSerializer.<jsf>DEFAULT_SIMPLE</jsf></code>, <code>UonSerializer.<jsf>DEFAULT_SIMPLE_ENCODING</jsf></code>
and <code>UrlEncodingSerializer.<jsf>DEFAULT_SIMPLE</jsf></code>
serializers since there is no separate simple mode anymore.
<li>Eliminated the <code>UonParserContext.<jsf>UON_simpleMode</jsf></code> configuration setting.
</ul>
<li>Added new {@link org.apache.juneau.serializer.OutputStreamSerializer#serializeToHex(Object)} method.
<br>Useful mostly for testing purposes.
<br>Equivalently, the {@link org.apache.juneau.parser.InputStreamParser#parse(Object,Class)} method can now
read the output from this method.
<li>Eliminated the <code><ja>@Bean</ja>(subTypeProperty)</code> and <code><ja>@Bean</ja>(subTypes)</code> annotations
and replaced them with the ability to define subtypes using the existing {@link org.apache.juneau.annotation.Bean#beanDictionary() @Bean.beanDictionary()}
annotation on parent classes and interfaces.
<br>This has the added benefit of simplifying the overall code.
<li>The {@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_addBeanTypeProperties} setting is now enabled by default.
<li>Combined the <code>SERIALIZER_addIndentation</code>/<code>JSON_addWhitespace</code>/<code>UON_addWhitespace</code>
properties into a single {@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_useWhitespace} setting.
</ul>
<h6 class='topic'>org.apache.juneau.rest</h6>
<ul class='spaced-list'>
<li>{@link org.apache.juneau.rest.RestRequest} now passes locale and timezone to serializers/parsers/transforms.
<li><code><del>RestRequest.getTimeZone()</del></code> method.
<li>Standardized the following methods in {@link org.apache.juneau.rest.RestRequest} to remove dependency on <code>ClassMeta</code>
objects and eliminate the need for casts:
<ul>
<li><code><del>RestRequest.getHeader(String,Class)</del></code>
<li><code><del>RestRequest.getHeader(String,Object,Class)</del></code>
<li><code><del>RestRequest.getHeader(String,Type,Type...)</del></code>
<li><code><del>RestRequest.getQueryParameter(String,Class)</del></code>
<li><code><del>RestRequest.getQueryParameter(String,Object,Class)</del></code>
<li><code><del>RestRequest.getQueryParameter(String,Type,Type...)</del></code>
<li><code><del>RestRequest.getQueryParameter(String,Object,Type,Type...)</del></code>
<li><code><del>RestRequest.getQueryParameters(String,Class)</del></code>
<li><code><del>RestRequest.getQueryParameters(String,Type,Type...)</del></code>
<li><code><del>RestRequest.getFormDataParameter(String,Class)</del></code>
<li><code><del>RestRequest.getFormDataParameter(String,Object,Class)</del></code>
<li><code><del>RestRequest.getFormDataParameters(String,Class)</del></code>
<li><code><del>RestRequest.getFormDataParameter(String,Type,Type...)</del></code>
<li><code><del>RestRequest.getFormDataParameters(String,Type,Type...)</del></code>
<li><code><del>RestRequest.getPathParameter(String,Class)</del></code>
<li><code><del>RestRequest.getPathParameter(String,Type,Type...)</del></code>
<li><code><del>RestRequest.getBody(Class)</del></code>
<li><code><del>RestRequest.getBody(Type,Type...)</del></code>
</ul>
<li>New methods on {@link org.apache.juneau.rest.client.NameValuePairs}
<li>Fixed issue where whitespace was not added to UON/URL-Encoding output when <code>&amp;plainText=true</code> specified.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="6.0.1"></a>
<h3 class='topic' onclick='toggle(this)'>6.0.1 (Jan 3, 2017)</h3>
<div class='topic'>
<p>
Juneau 6.0.1 is a minor update.
</p>
<h6 class='topic'>org.apache.juneau</h6>
<ul class='spaced-list'>
<li>General improvements to JSON parser.
<ul>
<li>Several fixes to handle obscure edge cases.
</ul>
<li>New properties in {@link org.apache.juneau.parser.ParserContext}.
<ul>
<li>{@link org.apache.juneau.parser.ParserContext#PARSER_strict}
<li>{@link org.apache.juneau.parser.ParserContext#PARSER_inputStreamCharset}
<li>{@link org.apache.juneau.parser.ParserContext#PARSER_fileCharset}
</ul>
<li>Removed <code>JsonParserContext.JSON_strictMode</code>. Replaced by <code>PARSER_strict</code>.
<li><code><jk>byte[]</jk></code> arrays can now be passed to {@link org.apache.juneau.parser.Parser#parse(Object,Class)} for reader-based parsers.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="6.0.0"></a>
<h3 class='topic' onclick='toggle(this)'>6.0.0 (Oct 3, 2016)</h3>
<div class='topic'>
<p>
Juneau 6.0.0 is a major update.
</p>
<p>
The major change is rebranding from "Juno" to "Juneau" in preparation for donation to the Apache Foundation.
</p>
<h6 class='topic'>org.apache.juneau</h6>
<ul class='spaced-list'>
<li>Major changes around how serializer and parser class properties are defined to improve performance
and concurrency.
<ul>
<li>New {@link org.apache.juneau.PropertyStore} class - Used for creating context objects.
<li>New {@link org.apache.juneau.Context} class - Read-only configurations for serializers and parsers.
<li>New {@link org.apache.juneau.Session} class - One-time use objects used by serializers and parsers.
<li>All context context properties can now also be specified via system properties.
</ul>
</li>
<li>Refactored serializer and parser APIs for more consistency between stream-based and character-based serializers
and parsers.
<ul>
<li>More consistent handling of exceptions.
<li>More consistent method declarations.
</ul>
<li>Refactored var resolver API and added them to a new package - <a class='doclink' href='org/apache/juneau/svl/package-summary.html#TOC'>org.apache.juneau.svl</a>.
<ul>
<li>Support for stream-based variables - {@link org.apache.juneau.svl.StreamedVar}.
<li>Added support for context and session objects.
</ul>
<li>Eliminated <js>"_class"</js> properties and replaced them with <js>"_type"</js> properties.
The class properties were a little-used feature where we would serialize fully-qualified class names when the class type could not be inferred through reflection.
It's been replaced with bean type names and bean dictionaries.
Instead of class names, we serialize <js>"_type"</js> properties whose name is the type name defined on the bean being serialized.
The parsers use a 'dictionary' of bean classes to resolve those names to actual bean classes.
The following features were added to enable this support:
<ul>
<li>{@link org.apache.juneau.annotation.Bean#typeName() @Bean.typeName()} - Annotation that defines an identifying name for a bean class.
<li>{@link org.apache.juneau.transform.BeanFilterBuilder#typeName(String)} - Programmatic equivalent to annotation above.
<li>{@link org.apache.juneau.BeanContext#BEAN_beanDictionary} - List of bean classes that make up the bean dictionary for lookup
during parsing.
<li>{@link org.apache.juneau.BeanContext#BEAN_beanTypePropertyName} - The overridable type property name. Default is <js>"_type"</js>.
<li>{@link org.apache.juneau.annotation.BeanProperty#beanDictionary() @BeanProperty.beanDictionary()} - Define a type dictionary
for a particular bean property value. This overrides the value specified using {@link org.apache.juneau.BeanContext#BEAN_beanDictionary}.
<li>{@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_addBeanTypeProperties} - Controls whether type properties are serialized.
</ul>
In addition, the {@link org.apache.juneau.annotation.Bean#typeName() @Bean.typeName()} value replaces the <code>@Xml.name()</code> annotation, and the
<js>"type"</js> and <js>"_class"</js> attributes in the XML and HTML serializers have been standardized on a single <js>"_type"</js> attribute.
<li>Refactor bean filter support to use {@link org.apache.juneau.transform.BeanFilterBuilder} class.
Allows the <code>BeanFilter</code> class to use final fields.
<li>{@link org.apache.juneau.msgpack MessagePack} support.
<li>Serializers can now serialize directly to {@link java.io.File Files}.
See {@link org.apache.juneau.serializer.Serializer#serialize(Object,Object)}
<li>Parsers can now parse directly from {@link java.io.File Files} and other types.
See {@link org.apache.juneau.parser.Parser#parse(Object,ClassMeta)}
<li>Parsers will automatically covert numeric input to POJOs that have numeric constructors (e.g. <code>java.util.Date</code>).
<li>Renamed 'Filters' to 'BeanFilters' and 'PojoSwaps'. Filters is just too overloaded a term.
<li>Internal utility classes moved to a new <code>org.apache.juneau.internal</code> package.
These internal utility classes are not meant for consumption outside the Juneau codebase.
<li>New methods on {@link org.apache.juneau.parser.Parser}:
<ul>
<li><code>org.apache.juneau.parser.Parser.createSession(ObjectMap,Method,Object)</code>
<li><code><del>Parser.getMediaRanges()</del></code>
</ul>
</li>
<li>New methods on {@link org.apache.juneau.serializer.Serializer}:
<ul>
<li><code>org.apache.juneau.serializer.Serializer.createSession(ObjectMap,Method)</code>
<li><code><del>Serializer.getMediaRanges()</del></code>
</ul>
</li>
<li>New {@link org.apache.juneau.annotation.Bean#sort() @Bean.sort()} annotation.
<li>Added <ja>@Bean.properties</ja> annotations on various DTO beans to make the ordering consistent
between IBM and Oracle JVMs.<br>
IBM JVMs maintain the order of methods in a class, whereas Oracle JVMs do not.
<li>Serializers and parsers now automatically convert {@link java.lang.Class} objects to readable names via {@link org.apache.juneau.internal.ClassUtils#getReadableClassName(Class)}.
<li>Eliminated the <code>ClassFilter</code> class since it's no longer needed.
<li>Code and concurrency improvements to {@link org.apache.juneau.serializer.SerializerGroup} and {@link org.apache.juneau.parser.ParserGroup}.
<li>Various enhancements to <code><del>BeanContext.convertToType(Object,Class)</del></code>.
<li>New properties on {@link org.apache.juneau.html.HtmlSerializer}:
<ul>
<li>{@link org.apache.juneau.html.HtmlSerializerContext#HTML_detectLinksInStrings} - Automatically detect hyperlinks in strings.
<li>{@link org.apache.juneau.html.HtmlSerializerContext#HTML_lookForLabelParameters} - Specify anchor text by appending <code>&amp;label=MyLabel</code> to URL.
<li>{@link org.apache.juneau.html.HtmlSerializerContext#HTML_labelParameter} - Specify what URL parameter to use as the anchor text label.
<li>New {@link org.apache.juneau.html.HtmlSerializerContext#URI_ANCHOR} option for {@link org.apache.juneau.html.HtmlSerializerContext#HTML_uriAnchorText}.
</ul>
</li>
<li>Removed generics from {@link org.apache.juneau.BeanPropertyMeta}.
<li>Introduced new classes to eliminate the references to language-specific metadata in the core metadata classes:
<ul>
<li>{@link org.apache.juneau.ClassMetaExtended} / {@link org.apache.juneau.ClassMeta#getExtendedMeta(Class)}
<li>{@link org.apache.juneau.BeanMetaExtended} / {@link org.apache.juneau.BeanMeta#getExtendedMeta(Class)}
<li>{@link org.apache.juneau.BeanPropertyMetaExtended} / {@link org.apache.juneau.BeanPropertyMeta#getExtendedMeta(Class)}
</ul>
</li>
<li>Renamed <code>@Transform</code> annotation to {@link org.apache.juneau.annotation.Pojo @Pojo} so that it can be used for various POJO-related behavior, not just associating transforms.
<li>Introduced {@link org.apache.juneau.dto.swagger Swagger DTOs}.
</ul>
<h6 class='topic'>org.apache.juneau.rest</h6>
<ul class='spaced-list'>
<li>OPTIONS pages replaced with Swagger documents.
Lots of changes related to supporting Swagger.
<ul>
<li>Annotation name changes to conform to Swagger specs: <ja>@Attr</ja>-&gt;<ja>@Path</ja>, <ja>@QParam</ja>-&gt;<ja>@Query</ja>, <ja>@Param</ja>-&gt;<ja>@FormData</ja>, <ja>@Content</ja>-&gt;<ja>@Body</ja>
<li>Eliminated <code>ResourceOptions</code> and related code.
<li>New annotations and related methods:
<ul>
<li>{@link org.apache.juneau.rest.annotation.RestResource#title() @RestResource.title()} / {@link org.apache.juneau.rest.RestInfoProvider#getTitle(RestRequest)}
<li>{@link org.apache.juneau.rest.annotation.RestResource#description() @RestResource.description()} / {@link org.apache.juneau.rest.RestInfoProvider#getDescription(RestRequest)}
<li><code><del>@RestResource.termsOfService()</del></code> / {@link org.apache.juneau.rest.RestInfoProvider#getTermsOfService(RestRequest)}
<li><code><del>@RestResource.contact()</del></code> / {@link org.apache.juneau.rest.RestInfoProvider#getContact(RestRequest)}
<li><code><del>@RestResource.license()</del></code> / {@link org.apache.juneau.rest.RestInfoProvider#getLicense(RestRequest)}
<li><code><del>@RestResource.version()</del></code> / {@link org.apache.juneau.rest.RestInfoProvider#getVersion(RestRequest)}
<li><code><del>@RestResource.tags()</del></code> / {@link org.apache.juneau.rest.RestInfoProvider#getTags(RestRequest)}
<li><code><del>@RestResource.externalDocs()</del></code> / {@link org.apache.juneau.rest.RestInfoProvider#getExternalDocs(RestRequest)}
<li>{@link org.apache.juneau.rest.annotation.RestMethod#summary() @RestMethod.summary()} / {@link org.apache.juneau.rest.RestInfoProvider#getMethodSummary(String,RestRequest)}
<li>{@link org.apache.juneau.rest.annotation.RestMethod#description() @RestMethod.description()} / {@link org.apache.juneau.rest.RestInfoProvider#getMethodDescription(String,RestRequest)}
<li><code><del>@RestMethod.externalDocs()</del></code>
<li><code><del>@RestMethod.tags()</del></code>
<li><code><del>@RestMethod.deprecated()</del></code>
<li><code><del>@RestMethod.parameters()</del></code>
<li><code><del>@RestMethod.responses()</del></code>
</ul>
</li>
</ul>
<li>New <code><del>RestServletContext.paramFormat</del></code> context property.
<li>New/updated methods on {@link org.apache.juneau.rest.RestServlet}:
<ul>
<li><code><del>RestServlet.createProperties()</del></code>
<li><code><del>RestServlet.createBeanContext(ObjectMap,Class[],Class[])</del></code>
<li><code><del>RestServlet.createBeanFilters()</del></code>
<li><code><del>RestServlet.createPojoSwaps()</del></code>
<li><code><del>RestServlet.createParsers(ObjectMap,Class[],Class[])</del></code>
<li><code><del>RestServlet.createUrlEncodingSerializer(ObjectMap,Class[],Class[])</del></code>
<li><code><del>RestServlet.createUrlEncodingParser(ObjectMap,Class[],Class[])</del></code>
<li><code><del>RestServlet.createConverters(ObjectMap)</del></code>
<li><code><del>RestServlet.createDefaultRequestHeaders(ObjectMap)</del></code>
<li><code><del>RestServlet.createDefaultResponseHeaders(ObjectMap)</del></code>
<li><code><del>RestServlet.createEncoders(ObjectMap)</del></code>
<li><code><del>RestServlet.createGuards(ObjectMap)</del></code>
<li><code><del>RestServlet.createMimetypesFileTypeMap(ObjectMap)</del></code>
<li><code><del>RestServlet.createResponseHandlers(ObjectMap)</del></code>
</ul>
</li>
<li>New client-version annotations:
<ul>
<li>{@link org.apache.juneau.rest.annotation.RestResource#clientVersionHeader} - The name of the header used to identify the client version.
<li>{@link org.apache.juneau.rest.annotation.RestMethod#clientVersion} - The client version range applied to a Java method.
</ul>
</li>
</ul>
<h6 class='topic'>org.apache.juneau.rest.client</h6>
<ul class='spaced-list'>
<li>Removed the <code>JazzRestClient</code> class.
<li>New method <code><del>RestClient.setClientVersion(String)</del></code>.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.2.0.1"></a>
<h3 class='topic' onclick='toggle(this)'>5.2.0.1 (Mar 23, 2016)</h3>
<div class='topic'>
<p>
Juno 5.2.0.1 is a moderate update.
</p>
<h6 class='topic'>com.ibm.team.juno</h6>
<ul class='spaced-list'>
<li>Improved support for multi-line values in config files.
Any line that begins with whitespace is interpreted as a continuation of the previous line.
<li>Support for <js>'\uXXXX'</js> character sequences in config files.
<li>Fixed issue in {@link org.apache.juneau.xml.XmlSerializer} where <js>'\r'</js> and <js>'\n'</js> characters were not being handled per XML specs.
<li>New methods on {@link org.apache.juneau.ObjectList}:
<ul>
<li>{@link org.apache.juneau.ObjectList#getAt(Class,String)}
<li>{@link org.apache.juneau.ObjectList#putAt(String,Object)}
<li>{@link org.apache.juneau.ObjectList#postAt(String,Object)}
<li>{@link org.apache.juneau.ObjectList#deleteAt(String)}
</ul>
<li>New methods on {@link org.apache.juneau.ObjectMap}:
<ul>
<li>{@link org.apache.juneau.ObjectMap#getAt(Class,String)}
<li>{@link org.apache.juneau.ObjectMap#putAt(String,Object)}
<li>{@link org.apache.juneau.ObjectMap#postAt(String,Object)}
<li>{@link org.apache.juneau.ObjectMap#deleteAt(String)}
</ul>
<li>New {@link org.apache.juneau.annotation.ThreadSafe @ThreadSafe} annotation.
<li>New <code>ClassFilter</code> class.
<li><del><code>ConfigFile.getResolving(StringVarResolver,boolean)</code></del> method.
<li><del><code>ConfigFile.getStringVar()</code></del> method.
<li>New {@link org.apache.juneau.parser.ParserContext#PARSER_trimStrings} property.
<li>New {@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_trimStrings} property.
<li><del><code>Args.getStringVar()}</code></del> method.
<li>New {@link org.apache.juneau.utils.ManifestFile} class
<li>New {@link org.apache.juneau.utils.MessageBundle} class. Replaces <l>SafeResourceBundle</l>/<l>SafeResourceMultiBundle</l>/<l>RestNls</l>.
<li>New <del><code>StringMapVar</code></del> class.
<li>New <del><code>StringVars</code></del> class with reusable common <del><code>StringVar</code></del> instances.
<li>New {@link org.apache.juneau.internal.JuneauLogger} class.
<li>Default value for <code><del>XmlParserContext.XML_trimWhitespace</del></code> changed to <jk>true</jk>.
</ul>
<h6 class='topic'>Server</h6>
<ul class='spaced-list'>
<li>New methods on {@link org.apache.juneau.rest.RestContext}:
<ul>
<li>{@link org.apache.juneau.rest.RestContext#getMessages()}
</ul>
</ul>
<h6 class='topic'>Client</h6>
<ul class='spaced-list'>
<li>Fixed potential issue in {@link org.apache.juneau.rest.client.RestClient} where the HTTP connection pool could end up exhausted if an error occurred.
<li>Improved thread safety on {@link org.apache.juneau.rest.client.RestClient}.
<li>New warning message is logged if a {@link org.apache.juneau.rest.client.RestClient} is garbage collected without being closed:
<js>"WARNING: RestClient garbage collected before it was finalized."</js>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.2.0.0"></a>
<h3 class='topic' onclick='toggle(this)'>5.2.0.0 (Dec 30, 2015)</h3>
<div class='topic'>
<p>
Juno 5.2.0.0 is a major update.
Major changes have been made to the microservice architecture and config INI file APIs.
</p>
<h6 class='topic'>Core</h6>
<ul class='spaced-list'>
<li>Significant changes and enhancements to the <a class='doclink' href='org/apache/juneau/ini/package-summary.html#TOC'>org.apache.juneau.ini</a> API.
<ul>
<li>More consistent handling of comma-delimited lists of objects.
<li>New methods in {@link org.apache.juneau.ini.ConfigFile}:
<ul>
<li>{@link org.apache.juneau.ini.ConfigFile#getStringArray(String)},{@link org.apache.juneau.ini.ConfigFile#getStringArray(String,String[])}
<li>{@link org.apache.juneau.ini.ConfigFile#getSectionAsBean(String,Class)} - Instantiate a new bean with property values in the specfied section..
<li>{@link org.apache.juneau.ini.ConfigFile#writeProperties(String,Object,boolean,Class[])} - Copy the properties in a config file section into properties on an existing bean or POJO.
<li>{@link org.apache.juneau.ini.ConfigFile#getSectionMap(String)} - Get all the resolved values in a section.
<li>{@link org.apache.juneau.ini.ConfigFile#containsNonEmptyValue(String)}
<li>{@link org.apache.juneau.ini.ConfigFile#isEncoded(String)}
<li>{@link org.apache.juneau.ini.ConfigFile#addListener(ConfigFileListener)} - Listen for modification events on the config file.
<li>{@link org.apache.juneau.ini.ConfigFile#merge(ConfigFile)} - Merge the contents of another config file into this config file.
<li>{@link org.apache.juneau.ini.ConfigFile#getResolving()}, <del><code>ConfigFile.getResolving(StringVarResolver)</code></del> - Return an instance of the config file that resolves string variables.
Much more efficient than the previous design since the same underlying config file object is shared.
<li>{@link org.apache.juneau.ini.ConfigFile#toWritable()} - Wraps the config file in a {@link org.apache.juneau.Writable} interface so that it can be serialized by the REST interface as a plain-text INI file instead of as a serialized POJO.
<li>{@link org.apache.juneau.ini.ConfigFile#getInt(String)} - Now supports <js>"M"</js> and <js>"K"</js> to identify millions and thousands.
</ul>
<li>New methods in <code><del>ConfigMgr</del></code>:
<ul>
<li><code><del>ConfigMgr.create()</del></code>, <code><del>ConfigMgr.create(Reader)</del></code>, <code><del>ConfigMgr.create(File)</del></code>
<li><code><del>ConfigMgr.deleteAll()</del></code>
</ul>
<li>New methods in {@link org.apache.juneau.ini.Section}:
<ul>
<li>{@link org.apache.juneau.ini.Section#setParent(ConfigFileImpl)} - Used by parsers to set the config file for this section.
<li>{@link org.apache.juneau.ini.Section#setName(String)} - Used by parsers to set the name for this section.
</ul>
<li>New interfaces:
<ul>
<li>{@link org.apache.juneau.ini.ConfigFileListener}
<li>{@link org.apache.juneau.ini.SectionListener}
<li>{@link org.apache.juneau.ini.EntryListener}
</ul>
<li>{@link org.apache.juneau.ini.Encoder} methods have access to field names to use them as salt values.
<li>The name of the default section is now <js>"default"</js>. Before it was just <jk>null</jk>.
<li>{@link org.apache.juneau.ini.XorEncoder} XOR key can be overridden through the <js>"org.apache.juneau.ini.XorEncoder.key"</js> system property.
</ul>
<li>Support for converting Strings to POJOs if the POJO class has any of the following static methods:
<ul>
<li><code>fromString(String)</code>
<li><code>valueOf(String)</code> (e.g. enums)
<li><code>parse(String)</code> (e.g. logging <code>Level</code> class)
<li><code>parseString(String)</code>
<li><code>forName(String)</code> (e.g. <code>Class</code> and <code>Charset</code> classes)
</ul>
<li>Support for parsing into objects with unbound type variables.
For example, if you have a class <code>Pair&lt;S,T&gt;</code> and you try to parse into this
class (e.g. <code>parser.parse(in, Pair.<jk>class</jk>)</code>), the unbound type variables
is interpreted as <code>Object</code> instead of throwing an exception.
<li>Support for serializing/parsing the following new types:
<ul>
<li><code>AtomicInteger</code>
<li><code>AtomicLong</code>
<li><code>BigInteger</code>
<li><code>BigDecimal</code>
</ul>
<li>Parsers have been enhanced to allow parent POJOs and field names to be passed into child POJOs.
New {@link org.apache.juneau.annotation.NameProperty @NameProperty} and {@link org.apache.juneau.annotation.ParentProperty @ParentProperty}
annotations are provided for identifying methods for setting names and parent POJOs on child POJOs.
For example, the config file {@link org.apache.juneau.ini.Section} class represents a section
in a config file. It needs to know it's own name and have a link to the {@link org.apache.juneau.ini.ConfigFile}
that it belongs to. With these new annotations, config files can be reconstructed using any of the parsers.
<li>New classes and interfaces:
<ul>
<li>{@link org.apache.juneau.Streamable} interface for identifying objects that can be serialized directly to an output stream.
<li>{@link org.apache.juneau.Writable} interface for identifying objects that can be serialized directly to a writer.
<li><code><del>StringObject</del></code> class that can be used for delayed object serialization.
<li>{@link org.apache.juneau.internal.ByteArrayCache}
<li>{@link org.apache.juneau.internal.ByteArrayInOutStream}
<li>{@link org.apache.juneau.internal.FileUtils}
<li>{@link org.apache.juneau.internal.ThrowableUtils}
<li><del><code>StringVarMultipart</code></del>
<li><del><code>StringVarWithDefault</code></del>
</ul>
<li>New fields on {@link org.apache.juneau.ObjectList}:
<ul>
<li>{@link org.apache.juneau.ObjectList#EMPTY_LIST}
</ul>
<li>New fields and methods on {@link org.apache.juneau.ObjectMap}:
<ul>
<li>{@link org.apache.juneau.ObjectMap#EMPTY_MAP}
<li>{@link org.apache.juneau.ObjectMap#getStringArray(String)}
<li>{@link org.apache.juneau.ObjectMap#getStringArray(String,String[])}
<li>{@link org.apache.juneau.ObjectMap#putIfNull(String,Object)}
<li>{@link org.apache.juneau.ObjectMap#putIfEmpty(String,Object)}
</ul>
<li>New methods in {@link org.apache.juneau.internal.ArrayUtils}:
<ul>
<li>{@link org.apache.juneau.internal.ArrayUtils#contains(Object,Object[])}
<li>{@link org.apache.juneau.internal.ArrayUtils#indexOf(Object,Object[])}
<li>{@link org.apache.juneau.internal.ArrayUtils#toPrimitiveArray(Object)}
</ul>
<li>New methods in {@link org.apache.juneau.internal.IOUtils}:
<ul>
<li>{@link org.apache.juneau.internal.IOUtils#pipe(Reader,Writer)}
<li>{@link org.apache.juneau.internal.IOUtils#read(File)}
<li>{@link org.apache.juneau.internal.IOUtils#readFile(String)}
<li>{@link org.apache.juneau.internal.IOUtils#write(File,Reader)}
</ul>
<li>New methods on {@link org.apache.juneau.utils.PojoRest}:
<ul>
<li>{@link org.apache.juneau.utils.PojoRest#get(Class,String,Object)}
<li>{@link org.apache.juneau.utils.PojoRest#getString(String)}
<li>{@link org.apache.juneau.utils.PojoRest#getString(String,String)}
<li>{@link org.apache.juneau.utils.PojoRest#getInt(String)}
<li>{@link org.apache.juneau.utils.PojoRest#getInt(String,Integer)}
<li>{@link org.apache.juneau.utils.PojoRest#getLong(String)}
<li>{@link org.apache.juneau.utils.PojoRest#getLong(String,Long)}
<li>{@link org.apache.juneau.utils.PojoRest#getBoolean(String)}
<li>{@link org.apache.juneau.utils.PojoRest#getBoolean(String,Boolean)}
<li>{@link org.apache.juneau.utils.PojoRest#getMap(String)}
<li>{@link org.apache.juneau.utils.PojoRest#getMap(String,Map)}
<li>{@link org.apache.juneau.utils.PojoRest#getList(String)}
<li>{@link org.apache.juneau.utils.PojoRest#getList(String,List)}
<li>{@link org.apache.juneau.utils.PojoRest#getObjectMap(String)}
<li>{@link org.apache.juneau.utils.PojoRest#getObjectMap(String,ObjectMap)}
<li>{@link org.apache.juneau.utils.PojoRest#getObjectList(String)}
<li>{@link org.apache.juneau.utils.PojoRest#getObjectList(String,ObjectList)}
</ul>
<li>New methods on {@link org.apache.juneau.utils.ProcBuilder}:
<ul>
<li>{@link org.apache.juneau.utils.ProcBuilder#pipeTo(Writer,boolean)}
<li>{@link org.apache.juneau.utils.ProcBuilder#pipeTo(Writer)}
<li>{@link org.apache.juneau.utils.ProcBuilder#logTo(Writer,boolean)}
<li>{@link org.apache.juneau.utils.ProcBuilder#logTo(Writer)}
<li>{@link org.apache.juneau.utils.ProcBuilder#logTo(Level,Logger)}
<li>{@link org.apache.juneau.utils.ProcBuilder#maxExitStatus(int)}
</ul>
<li>New methods on {@link org.apache.juneau.internal.StringUtils}:
<ul>
<li>{@link org.apache.juneau.internal.StringUtils#isEmpty(Object)}
<li>{@link org.apache.juneau.internal.StringUtils#nullIfEmpty(String)}
<li>{@link org.apache.juneau.internal.StringUtils#base64EncodeToString(String)}
<li>{@link org.apache.juneau.internal.StringUtils#base64Encode(byte[])}
<li>{@link org.apache.juneau.internal.StringUtils#base64DecodeToString(String)}
<li>{@link org.apache.juneau.internal.StringUtils#base64Decode(String)}
<li>{@link org.apache.juneau.internal.StringUtils#generateUUID(int)}
<li>{@link org.apache.juneau.internal.StringUtils#trim(String)}
<li>{@link org.apache.juneau.internal.StringUtils#parseISO8601Date(String)}
<li>{@link org.apache.juneau.internal.StringUtils#replaceVars(String,Map)}
<li>{@link org.apache.juneau.internal.StringUtils#pathStartsWith(String,String)}
<li>{@link org.apache.juneau.internal.StringUtils#pathStartsWith(String,String[])}
</ul>
<li>New <del><code>StringVar.doResolve(String)</code></del> method.
<li>New <del><code>StringVarResolver.DEFAULT</code></del> field.
<li>Eliminated dependency on <code>javax.mail.internet.MimeUtility</code> by implementing our own {@link org.apache.juneau.internal.StringUtils#base64Encode(byte[])} method.
<li>{@link org.apache.juneau.transforms.CalendarSwap} and {@link org.apache.juneau.transforms.DateSwap} classes now handle blank input better. Returns <jk>null</jk> instead of throwing an exception.
<li>{@link org.apache.juneau.html.HtmlDocSerializer} specifies the default CSS location as <code>/servletPath/style.css</code> instead of <code>/servletPath/htdocs/juneau.css</code>.
This coincides with enhancements made in the server code for specifying styles.
<li>{@link org.apache.juneau.html.HtmlDocSerializer} wraps output in two div tags instead of one (e.g. <code>&lt;div class='outerdata'&gt;&lt;div class='data' id='data'&gt;...&lt;/div&gt;&lt;/div&gt;</code>).
Needed for supporting the new devops look-and-feel.
<li>Fixed indentation inconsistencies in {@link org.apache.juneau.html.HtmlDocSerializer}.
<li>Renamed <del>HtmlSchemaSerializer</del> to {@link org.apache.juneau.html.HtmlSchemaDocSerializer}.
<li>RDF serializers and parsers now support <code>RdfProperties.RDF_looseCollection</code> loose collections.
<li>RDF parser handles case where resources point to themselves (an unfortunate behavior in JFS RDF documents).
<li>JSON parser with throw an exception in strict mode if it encounters numbers that are valid in Java but invalid in JSON (e.g. octal, hexadecimal numbers).
<li>{@link org.apache.juneau.parser.Parser} methods now check for <jk>null</jk> input.
<li>{@link org.apache.juneau.serializer.SerializerGroup} and {@link org.apache.juneau.parser.ParserGroup} ignores serializers and parsers if they throw <code>NoClassDefFoundErrors</code>.
<li>{@link org.apache.juneau.urlencoding.UrlEncodingParser} creates lists if the same attribute name is encountered more than once. Before it would just replace the previous value with the new value.
<li>New <code><del>UrlEncodingSerializer.DEFAULT_SIMPLE_EXPANDED</del></code> serializer.
<li>Changes to {@link org.apache.juneau.utils.Args}:
<ul>
<li><code>getMainArg(int)</code> changed to {@link org.apache.juneau.utils.Args#getArg(int)}.
Non-existent arguments are returned as <jk>null</jk> instead of blank strings.
This is more inline with the behavior of the rest of the library.
<li>New {@link org.apache.juneau.utils.Args#hasArg(int)} method.
</ul>
<li>Removed <code>org.apache.juneau.utils.CharsetUtils</code> class.
<li>Removed <code>org.apache.juneau.utils.ConcurrentIdentityList</code> class.
<li>Fixed bug in {@link org.apache.juneau.internal.MultiIterable} class.
<li>{@link org.apache.juneau.utils.PojoIntrospector} must now be instantiated with a <code>ReaderParser</code>.
Simplifies the API on the class.
<li>{@link org.apache.juneau.utils.PojoRest} must now be instantiated with a <code>ReaderParser</code>.
Simplifies the API on the class.
<li>{@link org.apache.juneau.utils.MessageBundle} and <code>SafeResourceMultiBundle</code> moved from server component.
<li>Several bug fixes and performance improvements in <del><code>StringVarResolver</code></del>.
<li>Various enhancements to {@link org.apache.juneau.internal.TeeWriter} and {@link org.apache.juneau.internal.TeeOutputStream}.
<li>Renamed <del>CharSet</del> to {@link org.apache.juneau.internal.AsciiSet}.
<li>{@link org.apache.juneau.serializer.SerializerGroup} and {@link org.apache.juneau.parser.ParserGroup} now ignores <code>NoClassDefFoundErrors</code>
so that resources that include Jena support can continue to operate even if the Jena libraries are not present.
<li>New {@link org.apache.juneau.internal.FileUtils#createTempFile(String)} method.
<li>New {@link org.apache.juneau.utils.PojoQuery} modified to handle bean getters that throw exceptions.
</ul>
<h6 class='topic'>Client</h6>
<ul class='spaced-list'>
<li>Upgraded to use Apache HttpClient 4.5.
<li>New classes:
<ul>
<li>{@link org.apache.juneau.rest.client.AllowAllRedirects}
<li>{@link org.apache.juneau.rest.client.HttpMethod}
<li>{@link org.apache.juneau.rest.client.ResponsePattern}
<li>{@link org.apache.juneau.rest.client.SimpleX509TrustManager}
<li>{@link org.apache.juneau.rest.client.SSLOpts}
</ul>
<li>Removed <code>org.apache.juneau.rest.client.LaxRedirectStrategy</code>. Use HTTP Client equivalent.
<li>New methods on {@link org.apache.juneau.rest.client.RestCall}:
<ul>
<li><code><del>RestCall#addInterceptor(RestCallInterceptor)</del></code>
<li>{@link org.apache.juneau.rest.client.RestCall#pipeTo(Writer)}
<li>{@link org.apache.juneau.rest.client.RestCall#pipeTo(Writer,boolean)}
<li>{@link org.apache.juneau.rest.client.RestCall#pipeTo(String,Writer,boolean)}
<li>{@link org.apache.juneau.rest.client.RestCall#getWriter(String)}
<li>{@link org.apache.juneau.rest.client.RestCall#pipeTo(OutputStream)}
<li>{@link org.apache.juneau.rest.client.RestCall#pipeTo(OutputStream,boolean)}
<li>{@link org.apache.juneau.rest.client.RestCall#pipeTo(String,OutputStream,boolean)}
<li>{@link org.apache.juneau.rest.client.RestCall#getOutputStream(String)}
<li>{@link org.apache.juneau.rest.client.RestCall#byLines()}
<li>{@link org.apache.juneau.rest.client.RestCall#captureResponse()}
<li>{@link org.apache.juneau.rest.client.RestCall#successPattern(String)}
<li>{@link org.apache.juneau.rest.client.RestCall#failurePattern(String)}
<li><code><del>RestCall#addResponsePattern(ResponsePattern)</del></code>
<li>{@link org.apache.juneau.rest.client.RestCall#run()} - Renamed from <code>execute()</code>.
<li>{@link org.apache.juneau.rest.client.RestCall#getCapturedResponse()}
<li>{@link org.apache.juneau.rest.client.RestCall#getResponsePojoRest(Class)}
<li>{@link org.apache.juneau.rest.client.RestCall#getResponsePojoRest()}
<li>{@link org.apache.juneau.rest.client.RestCall#logTo(Level,Logger)}
<li>{@link org.apache.juneau.rest.client.RestCall#setConfig(RequestConfig)}
</ul>
<li>New lifecycle listener methods on {@link org.apache.juneau.rest.client.RestCallInterceptor}:
<ul>
<li>{@link org.apache.juneau.rest.client.RestCallInterceptor#onInit(RestCall)}
<li>{@link org.apache.juneau.rest.client.RestCallInterceptor#onClose(RestCall)}
</ul>
<li>New methods on {@link org.apache.juneau.rest.client.RestClient}:
<ul>
<li><code><del>RestClient.setBasicAuth(String,int,String,String)</del></code>
<li><code><del>RestClient.logTo(Level,Logger)</del></code>
<li><code><del>RestClient.setRootUrl(String)</del></code>
<li><code><del>RestClient.enableSSL(SSLOpts)</del></code>
<li><code><del>RestClient.enableLaxSSL()</del></code>
<li>{@link org.apache.juneau.rest.client.RestClient#doCall(HttpMethod,Object,Object)}
<li><code><del>RestClient.createHttpClientBuilder()</del></code>
</ul>
<li>New passthrough methods on {@link org.apache.juneau.rest.client.RestClient} defined on <code>HttpClientBuilder</code>:
<ul>
<li><code><del>RestClient.setRedirectStrategy(RedirectStrategy)</del></code>
<li><code><del>RestClient.setDefaultCookieSpecRegistry(Lookup)</del></code>
<li><code><del>RestClient.setRequestExecutor(HttpRequestExecutor)</del></code>
<li><code><del>RestClient.setSSLHostnameVerifier(HostnameVerifier)</del></code>
<li><code><del>RestClient.setPublicSuffixMatcher(PublicSuffixMatcher)</del></code>
<li><code><del>RestClient.setSSLContext(SSLContext)</del></code>
<li><code><del>RestClient.setSSLSocketFactory(LayeredConnectionSocketFactory)</del></code>
<li><code><del>RestClient.setMaxConnTotal(int)</del></code>
<li><code><del>RestClient.setMaxConnPerRoute(int)</del></code>
<li><code><del>RestClient.setDefaultSocketConfig(SocketConfig)</del></code>
<li><code><del>RestClient.setDefaultConnectionConfig(ConnectionConfig)</del></code>
<li><code><del>RestClient.setConnectionTimeToLive(long,TimeUnit)</del></code>
<li><code><del>RestClient.setConnectionManager(HttpClientConnectionManager)</del></code>
<li><code><del>RestClient.setConnectionManagerShared(boolean)</del></code>
<li><code><del>RestClient.setConnectionReuseStrategy(ConnectionReuseStrategy)</del></code>
<li><code><del>RestClient.setKeepAliveStrategy(ConnectionKeepAliveStrategy)</del></code>
<li><code><del>RestClient.setTargetAuthenticationStrategy(AuthenticationStrategy)</del></code>
<li><code><del>RestClient.setProxyAuthenticationStrategy(AuthenticationStrategy)</del></code>
<li><code><del>RestClient.setUserTokenHandler(UserTokenHandler)</del></code>
<li><code><del>RestClient.disableConnectionState()</del></code>
<li><code><del>RestClient.setSchemePortResolver(SchemePortResolver)</del></code>
<li><code><del>RestClient.setUserAgent(String userAgent)</del></code>
<li><code><del>RestClient.setDefaultHeaders(Collection)</del></code>
<li><code><del>RestClient.addInterceptorFirst(HttpResponseInterceptor)</del></code>
<li><code><del>RestClient.addInterceptorLast(HttpResponseInterceptor)</del></code>
<li><code><del>RestClient.addInterceptorFirst(HttpRequestInterceptor)</del></code>
<li><code><del>RestClient.addInterceptorLast(HttpRequestInterceptor)</del></code>
<li><code><del>RestClient.disableCookieManagement()</del></code>
<li><code><del>RestClient.disableContentCompression()</del></code>
<li><code><del>RestClient.disableAuthCaching()</del></code>
<li><code><del>RestClient.setHttpProcessor(HttpProcessor)</del></code>
<li><code><del>RestClient.setRetryHandler(HttpRequestRetryHandler)</del></code>
<li><code><del>RestClient.disableAutomaticRetries()</del></code>
<li><code><del>RestClient.setProxy(HttpHost)</del></code>
<li><code><del>RestClient.setRoutePlanner(HttpRoutePlanner)</del></code>
<li><code><del>RestClient.disableRedirectHandling()</del></code>
<li><code><del>RestClient.setConnectionBackoffStrategy(ConnectionBackoffStrategy)</del></code>
<li><code><del>RestClient.setBackoffManager(BackoffManager)</del></code>
<li><code><del>RestClient.setServiceUnavailableRetryStrategy(ServiceUnavailableRetryStrategy)</del></code>
<li><code><del>RestClient.setDefaultCookieStore(CookieStore)</del></code>
<li><code><del>RestClient.setDefaultCredentialsProvider(CredentialsProvider)</del></code>
<li><code><del>RestClient.setDefaultAuthSchemeRegistry(Lookup)</del></code>
<li><code><del>RestClient.setContentDecoderRegistry(Map)</del></code>
<li><code><del>RestClient.setDefaultRequestConfig(RequestConfig)</del></code>
<li><code><del>RestClient.useSystemProperties()</del></code>
<li><code><del>RestClient.evictExpiredConnections()</del></code>
<li><code><del>RestClient.evictIdleConnections(long,TimeUnit)</del></code>
</ul>
<li><code>JazzRestClient</code> now supports OIDC authentication.
<li>These classes are now deprecated and will be removed in a future release:
<ul>
<li><code>org.apache.juneau.rest.client.jazz.CertificateStore</code>
<li><code>org.apache.juneau.rest.client.jazz.ICertificateValidator</code>
<li><code>org.apache.juneau.rest.client.jazz.ITrustStoreProvider</code>
<li><code>org.apache.juneau.rest.client.jazz.LenientCertificateValidator</code>
<li><code>org.apache.juneau.rest.client.jazz.SharedTrustStoreProvider</code>
<li><code>org.apache.juneau.rest.client.jazz.ValidatingX509TrustManager</code>
</ul>
</ul>
<h6 class='topic'>Server</h6>
<ul class='spaced-list'>
<li>New {@link org.apache.juneau.rest.ReaderResource} class.
Represents the contents of a text file with convenience methods for resolving
<del><code>StringVar</code></del> variables and adding HTTP response headers.
REST Java methods can return instances of these to serialize <code>Readers</code>
containing text with <del><code>StringVarResolver</code></del> variables in them.
<li>New {@link org.apache.juneau.rest.StreamResource} class.
REST Java methods can return instances of these to serialize <code>OutputStreams</code>.
<li>Fixed a bug in the stack trace hash algorithm in {@link org.apache.juneau.rest.RestException}.
<li>New methods in {@link org.apache.juneau.rest.RestRequest}:
<ul>
<li>{@link org.apache.juneau.rest.RestRequest#getReaderResource(String)} - Replaces <code>getVarResource(String)</code>.
<li>{@link org.apache.juneau.rest.RestRequest#getReaderResource(String,boolean)}
<li><code><del>RestRequest.getReaderResource(String,boolean,String)</del></code>
</ul>
<li>Changes in {@link org.apache.juneau.rest.RestResponse}:
<ul>
<li>Don't set <code>Content-Encoding: identity</code> when no encoding is used. Some clients don't interpret it correctly.
</ul>
<li>New methods in {@link org.apache.juneau.rest.RestServlet}:
<ul>
<li><code><del>RestServlet.getChildClasses()</del></code> - Programmatic equivalent to {@link org.apache.juneau.rest.annotation.RestResource#children()} annotation.
<li><code><del>RestServlet.shouldLog(HttpServletRequest,HttpServletResponse,RestException)</del></code>
<li><code><del>RestServlet.shouldLogStackTrace(HttpServletRequest,HttpServletResponse,RestException)</del></code>
<li><code><del>RestServlet.logObjects(Level,String,Object[])</del></code>
<li><code><del>RestServlet.resolveStaticFile(String)</del></code>
<li><code><del>RestServlet.createStyleSheet()</del></code>
<li><code><del>RestServlet.createFavIcon()</del></code>
<li><code><del>RestServlet.createStaticFilesMap()</del></code>
<li><code><del>RestServlet.getConfigMgr()</del></code>
</ul>
<li>Removed {@link org.apache.juneau.jso.JsoParser}
from {@link org.apache.juneau.rest.RestServletDefault} and {@link org.apache.juneau.rest.jena.RestServletJenaDefault}.
These may represent a security risk if not handled correctly, so removed
them as a precaution.
<li>Removed <code>RestServletProperties.REST_htDocsFolder</code>. Replaced with {@link org.apache.juneau.rest.annotation.RestResource#staticFiles()}.
<li>New annotations on {@link org.apache.juneau.rest.annotation.RestResource}.
<ul>
<li>{@link org.apache.juneau.rest.annotation.RestResource#stylesheet()}
<li>{@link org.apache.juneau.rest.annotation.RestResource#favicon()}
<li>{@link org.apache.juneau.rest.annotation.RestResource#staticFiles()}
</ul>
<li>Eliminated <code>org.apache.juneau.rest.jaxrs.JsonProvider</code> class.
Some JAX-RS implementations use code scanning to find providers, so if you were using <code>DefaultJenaProvider</code>, it would
pick up <code>JsonProvider</code> as well. It's easy enough to create your own implementation if needed.
<li>OPTIONS pages now specify <code>consumes</code> and <code>produces</code> fields instead of <code>accept</code> and <code>contentType</code> which was confusing.
<li>Eliminated <code>properties</code> from OPTIONS pages.
<li>New <code><del>ResourceLink.ResourceLink(String,RestRequest,String,Object[])</del></code> constructor.
<li>New response handlers:
<ul>
<li>{@link org.apache.juneau.rest.response.StreamableHandler} - Allows REST Java methods to return instances of {@link org.apache.juneau.Streamable}.
<li>{@link org.apache.juneau.rest.response.WritableHandler} - Allows REST Java methods to return instances of {@link org.apache.juneau.Writable}.
</ul>
<li>New DevOps stylesheet.
<li>Servlet initialization and HTTP requests are now logged at <JSF>FINE</JSF> level.
<li>Added <jk>abstract</jk> modifier on various <l>RestServlet</l> subclasses to indicate that they're meant to be subclassed.
<li>New {@link org.apache.juneau.rest.RestUtils#trimPathInfo(StringBuffer,String,String)} method.
</ul>
<h6 class='topic'>Microservice</h6>
<ul class='spaced-list'>
<li>Completely revamped API.
<li>New {@link org.apache.juneau.microservice.Microservice} class that serves as a generic
interface for microservices and their lifecycles.
<li>New {@link org.apache.juneau.microservice.RestMicroservice} class that implements a microservice
consisting of a REST interface.
<ul>
<li>REST resources and configuration settings can be defined through either manifest files
or config files.
<li>Enhanced logging support.
<li>Easy-to-configure SSL support.
<li>BASIC auth support.
<li>Automatic restartability if the config file changes.
</ul>
<li>Eliminated <code>org.apache.juneau.microservice.Main</code> class. This is replaced by
the microservice classes defined above.
<li>{@link org.apache.juneau.microservice.Resource} and {@link org.apache.juneau.microservice.ResourceGroup}
classes now support the following new string variables:
<ul>
<li><js>"$ARG{key,default}""</js> - Command line arguments.
<li><js>"$MF{key,default}""</js> - Manifest file entries.
</ul>
<li>CSS stylesheet now configurable through config file entry <js>"REST/stylesheet"</js>.
<li>New {@link org.apache.juneau.microservice.ResourceJena} class if you want your REST interface to support RDF.
<li>Eliminated the following classes:
<ul>
<li><code>org.apache.juneau.microservice.RootResource</code>
<li><code>org.apache.juneau.microservice.SampleResource</code>
</ul>
<li>New predefined reusable resources:
<ul>
<li>{@link org.apache.juneau.microservice.resources.ConfigResource} - REST resource for viewing and editing microservice config file.
<li>{@link org.apache.juneau.microservice.resources.LogsResource} - REST resource for viewing log files.
<li>{@link org.apache.juneau.microservice.resources.SampleRootResource} - Sample REST resource that contains the config and logs resource as children.
<li>{@link org.apache.juneau.microservice.resources.ShutdownResource} - REST resource for stopping the microservice JVM. Useful for testing purposes.
</ul>
</ul>
<h6 class='topic'>Samples</h6>
<ul class='spaced-list'>
<li>Converted to a REST microservice.
<li>Look-and-feel changed to IBM DevOps.
</ul>
<h6 class='topic'>Documentation Updates</h6>
<ul class='spaced-list'>
<li><a href='org/apache/juneau/microservice/package-summary.html#TOC'>org.apache.juneau.microservice</a> - New package-level javadoc.
<li><a href='org/apache/juneau/ini/package-summary.html#TOC'>org.apache.juneau.ini</a> - New package-level javadoc.
<li><del><code>StringVarResolver</code></del> - New documentation.
<li><a href='org/apache/juneau/client/package-summary.html#TOC'>org.apache.juneau.rest.client</a> - New package-level javadoc.
<li><a href='#Samples'>Overview / Samples</a> - New section.
<li><a href='org/apache/juneau/transform/package-summary.html#StopClasses'>org.apache.juneau.transform / Stop Classes</a> - New section.
<li><a href='org/apache/juneau/server/package-summary.html#TOC'>org.apache.juneau.rest</a> - Extensive updates.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.20"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.20 (Sept 5, 2015)</h3>
<div class='topic'>
<p>
Juno 5.1.0.20 is a moderate update.
The biggest improvement is the ability to associate external INI config files with REST servlets using the {@link org.apache.juneau.ini.ConfigFile} functionality.
</p>
<h6 class='topic'>Core</h6>
<ul class='spaced-list'>
<li>Significant API changes to <a class='doclink' href='org/apache/juneau/ini/package-summary.html#TOC'>org.apache.juneau.ini</a> API.
<ul>
<li>{@link org.apache.juneau.ini.ConfigFile} is now thread safe and can be shared across multiple threads.
<li>New <code><del>ConfigMgr</del></code> class for managing configuration files.
<li>Serializers and parsers can be associated with config files for storing and retrieving POJOs.
Default support provided for JSON.
</ul>
</li>
<li>New {@link org.apache.juneau.html.SimpleHtmlWriter} class.
Can be used for simple HTML DOM construction.
<li>New {@link org.apache.juneau.utils.ProcBuilder} class for calling external processes.
<li>New {@link org.apache.juneau.ObjectMap#remove(Class,String,Object)} method.
<li><js>"class='link'"</js> added to links generated by {@link org.apache.juneau.html.HtmlDocSerializer}.
<li>New <code><del>EncoderGroup#append(EncoderGroup)</del></code> method.
<li>New <code>HtmlDocSerializerContext.HTMLDOC_addLinks</code> configuration property.
<li>Modified the <code>Parser.createContext(ObjectMap,Method,Object)</code> method.
Outer context objects can be passed in to create instances of non-static inner classes.
<li>Fixed bug in {@link org.apache.juneau.html.HtmlStrippedDocSerializer} where exception was thrown when trying to serialize primitive arrays.
<li>{@link org.apache.juneau.json.JsonParser} now handles parsing JSON boolean/numeric values as strings to bean properties of type boolean or number.
<li>{@link org.apache.juneau.urlencoding.UrlEncodingSerializer} and {@link org.apache.juneau.urlencoding.UrlEncodingParser} now
represent arrays and collections as key-value pairs where the keys are numbers (e.g. <js>"?0=foo&amp;1=bar"</js>).
<li>Various internal improvements to {@link org.apache.juneau.utils.IOPipe}.
<li>New {@link org.apache.juneau.internal.ReflectionUtils#getResource(Class,String)} method.
<li>{@link org.apache.juneau.internal.StringUtils#parseNumber(String,Class)} now returns zero for empty strings.
This affects the way most parsers handle blank values.
</ul>
<h6 class='topic'>Server</h6>
<ul class='spaced-list'>
<li>You can now parse into non-static inner classes of a servlet for parameters/attributes/content.
Useful if you like to define your marshaller beans inside your servlet.
<li>Changes to {@link org.apache.juneau.rest.RestServlet}:
<ul>
<li>New methods for accessing external INI config files:<br>
<code><del>RestServlet.getConfig()</del></code><br>
<code><del>RestServlet.createConfigFile()</del></code>
<li>New <js>"$C{...}"</js> variable that resolve to INI config file values.
<li>New <js>"$UE{...}"</js> variable that URL-encodes the value inside the variable.
<li>New convenience methods for retrieving classpath resource files:<br>
<del><code>RestServlet.getResource(String)</code></del><br>
<del><code>RestServlet.getResourceAsString(String)</code></del><br>
<del><code>RestServlet.getResource(Class,String,String)</code></del>.
Useful if you want to load predefined POJOs from JSON files in your classpath.
<li>New <code><del>RestServlet.handleNotFound(int,RestRequest,RestResponse)</del></code> method for customized handling
of when a resource or method was not found.
</ul>
<li>{@link org.apache.juneau.rest.RestServletDefault} now automatically processes <js>"/favicon.ico"</js> requests by
overriding the new <code><del>RestServlet.handleNotFound(int,RestRequest,RestResponse)</del></code> method.
<li>New {@link org.apache.juneau.rest.RestRequest} methods:
<ul>
<li>{@link org.apache.juneau.rest.RestRequest#resolveVars(String)}
<li><code>RestRequest.getVarResource(String)</code>
<li><code><del>RestRequest.getConfig()</del></code>
</ul>
<li>New {@link org.apache.juneau.rest.RestResponse} methods:
<ul>
<li>{@link org.apache.juneau.rest.RestResponse#getDirectWriter(String)}.
<li>{@link org.apache.juneau.rest.RestResponse#getNegotiatedWriter()}.
<code>getWriter()</code> now returns an unnegotiated writer.
<code>getUnbufferedWriter()</code> has been removed.
</ul>
<li>New {@link org.apache.juneau.rest.annotation.RestMethod#encoders() @RestMethod.encoders()} and
{@link org.apache.juneau.rest.annotation.RestMethod#inheritEncoders() @RestMethod.inheritEncoders} annotations.
Allows encoders to be fine-tuned at the method level.
<li>New {@link org.apache.juneau.rest.annotation.RestResource#config() @RestResource.config()} annotation for associating external {@link org.apache.juneau.ini.ConfigFile} config files with servlets.
<li><code><del>ResourceLink</del></code>.
<li>New <a class='doclink' href='org/apache/juneau/rest/matchers/package-summary.html#TOC'>org.apache.juneau.rest.matchers</a> package for commonly-used {@link org.apache.juneau.rest.RestMatcher RestMatchers}:
<ul>
<li>{@link org.apache.juneau.rest.matchers#MultipartFormDataMatcher}
<li>{@link org.apache.juneau.rest.matchers#UrlEncodedFormMatcher}
</ul>
</ul>
<h6 class='topic'>Microservice</h6>
<ul class='spaced-list'>
<li>New juneau-microservice.jar file that encapsulates all 3 juneau jars with code necessary for creating fast and efficent jetty-powered REST microservices.<br>
Contains the following:
<ul>
<li>Jetty 8.0
<li>Apache HttpClient 4.3.5
<li>Apache Commons FileUpload 1.3.1
</ul>
<li>Microservice now supports Java 6 (previously required Java 7)
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.19"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.19 (Aug 15, 2015)</h3>
<div class='topic'>
<p>
Juno 5.1.0.19 is a minor update in terms of core functionality.
But it introduces a <a class='doclink' href='#Microservices'>Microservices</a> project for building REST microservices and docker containers.
</p>
<h6 class='topic'>Core</h6>
<ul class='spaced-list'>
<li>Beans can now be serialized to and parsed from {@link org.apache.juneau.ObjectMap ObjectMaps}.
See <a class='doclink' href='org/apache/juneau/transform/package-summary.html#ToObjectMaps'>Serializing to ObjectMaps</a> for details.
<li>New {@link org.apache.juneau.ObjectMap#include(String[])} and {@link org.apache.juneau.ObjectMap#exclude(String[])} methods.
<li>{@link org.apache.juneau.html.annotation.Html @Html} annotations can now be applied to bean properties.
<li>New {@link org.apache.juneau.utils.IOPipe} utility class.
<li>Behavior change on <del><code>StringVarResolver</code></del>. <jk>null</jk> input now results in blank strings instead of <jk>null</jk>.
</ul>
<h6 class='topic'>Client</h6>
<ul class='spaced-list'>
<li>New {@link org.apache.juneau.rest.client.RestClient#doCallback(String)} method.
</ul>
<h6 class='topic'>Server</h6>
<ul class='spaced-list'>
<li>New {@link org.apache.juneau.rest.RestRequest#getHeaders()} method.
<li>New <code>RestResponse.getUnbufferedWriter()</code> method.
<li>Fixed bug that was preventing <code>x-response-headers</code> parameter from working correctly.
<li>Added {@link org.apache.juneau.annotation.Bean#properties() @Bean.properties} annotations to the various
classes in <a class='doclink' href='org/apache/juneau/rest/labels/package-summary.html#TOC'>org.apache.juneau.rest.labels</a> so that the order of the bean properties are consistent
on all JVMs. On IBM JVMs this is unnecessary because the order of the properties as defined in the class
are stored in the bytecode. Other JVMs such as OpenJRE do not implement this feature causing the bean
properties to be in random order.
<li>New <code><del>ResourceDescription.ResourceDescription(RestRequest,String,String)</del></code> constructor.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.18"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.18 (Aug 5, 2015)</h3>
<div class='topic'>
<p>
Juno 5.1.0.18 is a minor update affecting the server component only.
</p>
<h6 class='topic'>Server</h6>
<ul class='spaced-list'>
<li>Fixed bug where localized strings weren't resolving when using chained resource bundles.
<li>Servlet and method labels and descriptions can now contain embedded string variables.
<li>New <del><code>RestMethod.input()</code></del> and <code><del>RestMethod.responses()</del></code>
annotations.
These replace the various <code>description</code> annotations added 2 days ago with a simpler design.
<li>New methods on {@link org.apache.juneau.rest.RestServlet}:
<ul>
<li><code><del>RestServlet.getMethodDescription(String,RestRequest)</del></code> so that subclasses
can override the method description in the OPTIONS page.
<li><del><code>RestServlet.createRequestVarResolver(RestRequest)</code></del> so that subclasses
can override and augment the variable resolver.
<li><code><del>RestServlet.resolveChild(Class)</del></code> and <code><del>RestServlet.replaceChild(RestServlet)</del></code>
classes that allows customized resolution of servlet instances (e.g. if services are defined in OSGi).
</ul>
<li>Reverted the <del><code>MethodDescription</code></del> back to 5.1.0.16 since it was being used by someone.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.17"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.17 (Aug 3, 2015)</h3>
<div class='topic'>
<p>
Juno 5.1.0.17 is a major update.
</p>
<h6 class='topic'>Core</h6>
<ul class='spaced-list'>
<li>{@link org.apache.juneau.BeanMap#get(Object)} and {@link org.apache.juneau.BeanMap#put(String,Object)} now
automatically performs filtering if filters are defined on the bean property or bean property class.
<ul>
<li>Deleted the following methods which are now unnecessary:
<ul>
<li><code>BeanMap.getFiltered(String)</code>
<li><code>BeanMap.putFiltered(String,Object)</code>
<li><code>BeanMapEntry.getFiltered(String)</code>
<li><code>BeanMapEntry.putFiltered(String,Object)</code>
<li><code>BeanMapEntry.putFiltered(String,Object)</code>
<li><code>BeanPropertyMeta.getFiltered()</code>
<li><code>BeanPropertyMeta.setFiltered(Object)</code>
<li><code>BeanPropertyMeta.getTransformedClassMeta()</code>
</ul>
<li>{@link org.apache.juneau.BeanPropertyMeta#getClassMeta()} now returns the filtered type of the property.
</ul>
<li><del><code>StringVarResolver</code></del> now has support for chained resolvers.
<li><del><code>StringVarResolver</code></del> now resolves variables inside resolved values.
i.e. if a resolved variable value itself contains a variable, it now resolves that variable too.
<li>Fixed bug where inner interface classes being used in <code>RestResource.filters()</code> were being
interpreted as surrogate classes because they have hidden 1-arg constructors due to being inner classes.
<li>Fixed bug in {@link org.apache.juneau.internal.MultiSet} where exception was being thrown if last set was empty.
<li>New {@link org.apache.juneau.utils.ZipFileList} class for providing efficiently zipped directories through the REST interface.
<li>New <code>RdfProperties.RDF_useXmlNamespaces</code> property.
<li>New {@link org.apache.juneau.xml.XmlParserContext#XML_preserveRootElement} property.
<li>Worked around bug in Sun VM on OS/X where XML parser was throwing an exception when trying to set a reporter.
</ul>
<h6 class='topic'>Server</h6>
<ul class='spaced-list'>
<li>New {@link org.apache.juneau.rest.response.ZipFileListResponseHandler} class.
<li>Simplified lables in servlet resource bundles:
<ul>
<li><code>"[ClassName].ResourceDescription"</code> is now <code>"[ClassName].label"</code>.
<li><code>"[ClassName].MethodDescription.[methodName]"</code> is now <code>"[ClassName].[methodName]"</code>.
</ul>
<li>Several changes to {@link org.apache.juneau.rest.RestRequest}:
<ul>
<li>Added new methods:
<ul>
<li><code><del>RestRequest.getQueryParameterMap()</del></code>
<li><code><del>RestRequest.getQueryParameterNames()</del></code>
<li><code><del>RestRequest.getPathInfoUndecoded()</del></code>
<li><code><del>RestRequest.getPathRemainderUndecoded()</del></code>
<li><code><del>RestRequest.getTrimmedRequestURI()</del></code>
<li><code><del>RestRequest.getTrimmedRequestURL()</del></code>
<li>{@link org.apache.juneau.rest.RestRequest#getServletTitle()}
<li>{@link org.apache.juneau.rest.RestRequest#getServletDescription()}
<li>{@link org.apache.juneau.rest.RestRequest#getMethodDescription()}
</ul>
<li>Behavior changes to {@link org.apache.juneau.rest.RestRequest#getPathInfo()} to follow Servlet specs.
Returns <jk>null</jk> instead of blank for no path info.
<li><code><del>RestRequest.getPathRemainder()</del></code> now automatically decodes the path remainder.
Use <code><del>RestRequest.getPathRemainderUndecoded()</del></code> to get the unencoded path remainder.
<li>Bug fixes in <code><del>RestRequest.getRequestParentURI()</del></code> when servlet is mapped to <js>"/*"</js>.
<li>Bug fixes in <code><del>RestRequest.getServletURI()</del></code> when servlet is mapped to <js>"/*"</js>.
</ul>
<li>New string replacement variables:
<ul>
<li><code>$R{contextPath}</code> - Returns value from {@link org.apache.juneau.rest.RestRequest#getContextPath()}
<li><code>$R{methodDescription}</code> - Returns value from {@link org.apache.juneau.rest.RestRequest#getMethodDescription()}
<li><code>$R{servletTitle}</code> - Returns value from {@link org.apache.juneau.rest.RestRequest#getServletTitle()}
<li><code>$R{servletDescription}</code> - Returns value from {@link org.apache.juneau.rest.RestRequest#getServletDescription()}
<li><code>$R{trimmedRequestURI}</code> - Returns value from <code><del>RestRequest.getTrimmedRequestURI()</del></code>
<li><code>$E{var}</code> - Environment variables.
</ul>
<li>Added methods <code><del>RestServlet.getDescription(RestRequest)</del></code> and <del><code>RestServlet.getLabel(RestRequest)</code></del>.
<li>{@link org.apache.juneau.rest.RestServletDefault} and {@link org.apache.juneau.rest.jena.RestServletJenaDefault} now provide default HTML titles
and descriptions:
<p class='bcode'>
<ja>@Property</ja>(name=<jsf>HTMLDOC_title</jsf>, value=<js>"$R{servletTitle}"</js>),
<ja>@Property</ja>(name=<jsf>HTMLDOC_description</jsf>, value=<js>"$R{servletDescription}"</js>)
</p>
<li>Options pages on {@link org.apache.juneau.rest.RestServletDefault} and {@link org.apache.juneau.rest.jena.RestServletJenaDefault} now provide default descriptions and back links:
and descriptions:
<p class='bcode'>
<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>)
</p>
<li>New {@link org.apache.juneau.rest.RestServletGroupDefault} class.
<li>Removed <code>RestServletProperties.REST_trimTrailingUriSlashes</code> and <code>RestServletProperties.REST_pathInfoBlankForNull</code>.
<li>New annotations for providing labels and descriptions. Useful if you don't plan on having to support other languages, so you don't
want to provide labels in resource bundles.
<ul>
<li><del><code>RestResource.label()</code></del>
<li>{@link org.apache.juneau.rest.annotation.RestResource#description()}
<li>{@link org.apache.juneau.rest.annotation.RestMethod#description()}
<li><del><code>RestMethod#responses()</code></del>
<li><del><code>Attr.description()</code></del>
<li><del><code>Content.description()</code></del>
<li><del><code>HasParam.description()</code></del>
<li><del><code>HasQParam.description()</code></del>
<li><del><code>Header.description()</code></del>
<li><del><code>Param.description()</code></del>
<li><del><code>QParam.description()</code></del>
</ul>
<li>Support for sorting resources by name in {@link org.apache.juneau.rest.labels.ChildResourceDescriptions}.
</ul>
<h6 class='topic'>Samples</h6>
<ul class='spaced-list'>
<li>Added <code>/tempDir/upload</code> showing how to use <code>ServletFileUpload</code> with multipart form posts.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.16"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.16 (June 28, 2015)</h3>
<div class='topic'>
<p>
Juno 5.1.0.16 is a moderate update.
</p>
<h6 class='topic'>Core</h6>
<ul class='spaced-list'>
<li>New methods on {@link org.apache.juneau.ClassMeta} that eliminates language-specific code in
the general class metadata.
<ul>
<li><del><code>ClassMeta.getXmlMeta()</code></del>
<li><del><code>ClassMeta.getJsonMeta()</code></del>
<li><del><code>ClassMeta.getHtmlMeta()</code></del>
<li><del><code>ClassMeta.getUrlEncodingMeta()</code></del>
<li><del><code>ClassMeta.getRdfMeta()</code></del>
</ul>
<li>New {@link org.apache.juneau.dto.jsonschema.JsonType#ANY} enum.
<li>New {@link org.apache.juneau.html.annotation.Html#asPlainText @Html.asPlainText()} annotation.
<li>New <code><del>HtmlDocSerializerContext.HTMLDOC_cssImports</del></code> property.
<li>Signifant changes to RDF support.
<ul>
<li>New {@link org.apache.juneau.jena.annotation.Rdf @Rdf} and {@link org.apache.juneau.jena.annotation.RdfSchema @RdfSchema}
annotations. These replace the use of defining namespaced through the XML annotations, and allows XML and RDF to be
serialized using different namespaces.
<li>Support for serializing arrays/collections as RDF bags, RDF lists, and multi-valued properties.
<li>Fixed warning message about <js>"tab"</js> setting when using the N3/Turtle serializers.
</ul>
<li>New {@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_sortCollections} and
{@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_sortMaps} properties.
<li>
<li>FindBug fixes.
</ul>
<h6 class='topic'>Server</h6>
<ul class='spaced-list'>
<li>New <code><del>RestRequest.getServletParentURI()</del></code> method.
<li>New <code>$R{servletParentURI}</code> variable.
<li>Removed final modifier from {@link org.apache.juneau.rest.labels.ChildResourceDescriptions}.
</ul>
<h6 class='topic'>Samples</h6>
<ul class='spaced-list'>
<li>Added source code links to examples.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.15"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.15 (May 24, 2015)</h3>
<div class='topic'>
<p>
Juno 5.1.0.15 is a minor update.
</p>
<h6 class='topic'>Core</h6>
<ul class='spaced-list'>
<li>New properties in {@link org.apache.juneau.serializer.SerializerContext}:
<ol>
<li><code><del>SerializerContext.SERIALIZER_relativeUriBase</del></code>
<li><code><del>SerializerContext.SERIALIZER_absolutePathUriBase</del></code>
</ol>
These replace the <code>SERIALIZER_uriAuthority</code> and <code>SERIALIZER_uriContext</code> properties.
</li>
<li>Improvements in {@link org.apache.juneau.csv.CsvSerializer}.
</ul>
<h6 class='topic'>Server</h6>
<ul class='spaced-list'>
<li>New properties in <code>RestServletProperties</code>:
<ol>
<li><code>REST_defaultCharset</code>
<li><code>REST_servletURI</code>
<li><code>REST_relativeServletURI</code>
</ol>
<li>Improvements involving path calculations when servlets deployed outside of a war file with a context root.
</ul>
<h6 class='topic'>Client</h6>
<ul class='spaced-list'>
<li>New methods in {@link org.apache.juneau.rest.client.RestCall}:
<ol>
<li><code><del>RestRequest.getHeader(String,Class)</del></code>
<li><code><del>RestRequest.getHeader(String,Object,Class)</del></code>
<li><code><del>RestRequest.getHeader(String,Type,Type...)</del></code>
<li><code><del>RestRequest.getQueryParameter(String,Class)</del></code>
<li><code><del>RestRequest.getQueryParameter(String,Object,Class)</del></code>
<li><code><del>RestRequest.getQueryParameter(String,Type,Type...)</del></code>
<li><code><del>RestRequest.getQueryParameter(String,Object,Type,Type...)</del></code>
<li><code><del>RestRequest.getQueryParameters(String,Class)</del></code>
<li><code><del>RestRequest.getQueryParameters(String,Type,Type...)</del></code>
<li><code><del>RestRequest.getFormDataParameter(String,Class)</del></code>
<li><code><del>RestRequest.getFormDataParameter(String,Object,Class)</del></code>
<li><code><del>RestRequest.getFormDataParameters(String,Class)</del></code>
<li><code><del>RestRequest.getFormDataParameter(String,Type,Type...)</del></code>
<li><code><del>RestRequest.getFormDataParameters(String,Type,Type...)</del></code>
<li><code><del>RestRequest.getPathParameter(String,Class)</del></code>
<li><code><del>RestRequest.getPathParameter(String,Type,Type...)</del></code>
<li><code><del>RestRequest.getBody(Class)</del></code>
<li><code><del>RestRequest.getBody(Type,Type...)</del></code>
</ol>
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.14"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.14 (May 10, 2015)</h3>
<div class='topic'>
<p>
Juno 5.1.0.14 is a moderate update.
</p>
<p>
The major addition is support for {@link org.apache.juneau.rest.remoteable Remoteable Services}, the ability
to invoke server-side POJO methods through client-side proxy interfaces.
</p>
<h6 class='topic'>Core</h6>
<ul class='spaced-list'>
<li>Simplified {@link org.apache.juneau.utils.PojoIntrospector} class.
<li>New {@link org.apache.juneau.internal.ClassUtils#getMethodSignature(Method)} method.
</ul>
<h6 class='topic'>Client</h6>
<ul class='spaced-list'>
<li>New methods in {@link org.apache.juneau.rest.client.RestClient} for working with remoteable services:
<ul>
<li><code><del>RestClient.setRemoteableServletUri(String)</del></code>
<li>{@link org.apache.juneau.rest.client.RestClient#getRemoteableProxy(Class)}
</ul>
</ul>
<h6 class='topic'>Server</h6>
<ul class='spaced-list'>
<li>Added a default OPTIONS page to {@link org.apache.juneau.rest.RestServletDefault} and {@link org.apache.juneau.rest.jena.RestServletJenaDefault}.
<li><code>RestServletProperties.REST_allowMethodParam</code> has been enhanced to allow you to
explicitely specify which HTTP methods can be used in the <code>&amp;method</code> parameter.
<li>New methods added to {@link org.apache.juneau.rest.RestRequest}:
<ul>
<li><code><del>RestRequest.getParser()</del></code>
<li><code><del>RestRequest.getReaderParser()</del></code>
</ul>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.13"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.13 (Apr 24, 2015)</h3>
<div class='topic'>
<p>
Juno 5.1.0.13 is a minor update.
</p>
<h6 class='topic'>Core</h6>
<ul class='spaced-list'>
<li>{@link org.apache.juneau.ClassMeta#newInstance()} method can now create new instances of arrays.
<li>Arguments passed to {@link org.apache.juneau.dto.Link} are now serialized using {@link org.apache.juneau.urlencoding.UrlEncodingSerializer}, so arbitrary POJOs can now be passed as arguments.
<li>New date filters: <code>org.apache.juneau.transforms.Datefilter.ISO8601DTZP</code> and <code>org.apache.juneau.transforms.Datefilter.SimpleP</code>.
<li>New {@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_nowrap} setting for {@link org.apache.juneau.html.HtmlDocSerializer} class.
Adds <js>"* {white-space:nowrap}"</js> to the style header to prevent word wrapping.
<li>Fixed bug in {@link org.apache.juneau.uon.UonParser} where passing in a blank value on an array or collection type in a form post would cause a <code>ClassCastException</code>.
New behavior creates an empty array or <code>Collection</code>.
<li>Improved implementation of <del><code>UrlEncodingSerializer.serializeUrlPart(Object)</code></del> method.
</ul>
<h6 class='topic'>Server</h6>
<ul class='spaced-list'>
<li>{@link org.apache.juneau.rest.RestConverter} API fixed to handle the existence of POJO filters.
{@link org.apache.juneau.rest.converters.Introspectable}/{@link org.apache.juneau.rest.converters.Queryable}/{@link org.apache.juneau.rest.converters.Traversable} classes can now work with filtered POJOs.
<li>{@link org.apache.juneau.rest.annotation.RestResource#messages()} annotation can now be defined on super and subclasses so that NLS messages can be defined in multiple resource bundles.
<li>Performance improvements in <code>RestServletNls</code> class.
<li>Fixed bug where two REST java methods mapped to the same path pattern wasn't triggering an exception when it was supposed to.
</ul>
<h6 class='topic'>Client</h6>
<ul class='spaced-list'>
<li>New <code><del>RestCall.setRedirectMaxAttempts(int)</del></code> method to prevent endless redirection loops.
<li>New <code><del>RestCall#setRetryable(int,long,RetryOn)</del></code> method to automatically retry on failed connection attempts.
<li>New <code>RestCallInterceptor.onRetry(RestCall,int,HttpRequest,HttpResponse)</code> method for listening in on retry attempts.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.12"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.12 (Mar 28, 2015)</h3>
<div class='topic'>
<p>
Juno 5.1.0.12 is a minor update.
</p>
<h6 class='topic'>Core</h6>
<ul class='spaced-list'>
<li>Fixed {@link org.apache.juneau.ini.ConfigFile#isEmpty()} method.
<li>Changed behavior on {@link org.apache.juneau.uon.UonParser} to not treat <js>'~'</js> characters as escapes
unless followed by one of the following characters: <code>( ) , $ = ~</code>.
</ul>
<h6 class='topic'>Client</h6>
<ul class='spaced-list'>
<li>New class {@link org.apache.juneau.rest.client.RestCallInterceptor}.
Allows responses to be inspected and modified before being processed.
Replaces <code>RestClientListener</code> class.
<li>Minor connection cleanup fixes.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.11"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.11 (Feb 14, 2015)</h3>
<div class='topic'>
<p>
Juno 5.1.0.11 is a moderate update.
</p>
<h6 class='topic'>Core</h6>
<ul class='spaced-list'>
<li>Additions to {@link org.apache.juneau.html.annotation.Html @Html} bean annotation.
<ul>
<li>New {@link org.apache.juneau.html.annotation.Html#noTables() @Html.noTables()} annotation that prevents
arrays/Collections from being serialized as tables.
<li>New {@link org.apache.juneau.html.annotation.Html#noTableHeaders() @Html.noTableHeaders()} annotation that prevents
HTML tables from having header rows.
</ul>
</li>
<li>Several improvements to URL-Encoding support.
<ul>
<li>Improved whitespace handling in {@link org.apache.juneau.uon.UonParser}.
<li>New <code><del>UonParserContext.UON_whitespaceAware</del></code> property for controlling whether whitespace is ignored.
<li>New {@link org.apache.juneau.urlencoding.UrlEncodingContext#URLENC_expandedParams} property for controlling whether arrays/Collections
should be serialized/parsed as multi-part parameters.
<li>New {@link org.apache.juneau.urlencoding.annotation.UrlEncoding#expandedParams() @UrlEncoding.expandedParams()}
annotation that specifies that bean properties of type array/Collection be serialized as multi-part parameters (e.g. <code>&amp;key=val1&amp;key=val2</code>).
</ul>
</li>
<li>New {@link org.apache.juneau.json.JsonSerializerContext#JSON_escapeSolidus} property for controlling whether slash characters should be escaped.
<li>New {@link org.apache.juneau.internal.TeeOutputStream} and {@link org.apache.juneau.internal.TeeWriter} classes.
<li>New {@link org.apache.juneau.ClassMeta#isInstance(Object)} method.
<li>Performance improvements when using the {@link org.apache.juneau.BeanMap#add(String,Object)} method.
Array properties are stored in a temporary list cache until {@link org.apache.juneau.BeanMap#getBean()} is called.
<li>New <code><del>BeanPropertyMeta.add(BeanMap,Object)</del></code> method for adding values to Collection and array properties.
<li>Config INI files now support keys with name <js>"*"</js>.
</ul>
<h6 class='topic'>Server</h6>
<ul class='spaced-list'>
<li>REST method parameters can now be generic types (e.g. <del><ja>@Param</ja>(<js>"foo"</js>) Map&lt;String,Integer&gt; foo</del>).
This applies to headers, attributes, and parameters.
<li>New <del><code>@Param.multipart()</code></del>
and <del><code>@Query.multipart()</code></del> annotations
for handling multi-part GET and POST parameters.
<li>GET parameters are now CASE-SENSITIVE per W3C standards.
<ul>
<li>
<li><code>&amp;Content</code> must now be specified as <code>&amp;content</code>.
<li><code>&amp;Method</code> must now be specified as <code>&amp;method</code>.
<li><code>&amp;debug</code> must now be specified as <code>&amp;debug=true</code>.
<li><code>&amp;plainText</code> must now be specified as <code>&amp;plainText=true</code>.
<li><code>&amp;notrace</code> must now be specified as <code>&amp;noTrace=true</code>.
</ul>
</li>
<li>Performance improvements around query parameters.
<li>New methods on {@link org.apache.juneau.rest.RestRequest} for handling multi-part parameters:
<ul>
<li><del><code>RestRequest.getParameters(String,Class)</code></del>
<li><code><del>RestRequest#getQueryParameters(String,Class)</del></code>
</ul>
</li>
<li>Fixed Jetty issue in {@link org.apache.juneau.rest.RestResponse#setHeader(String,String)} where setting
the <code>Content-Type</code> through this method was inconsistent with the behavior in WAS/Tomcat.
<li><code>&amp;noTrace=true</code> now prevents any errors from being logged in log file.
<li>Workaround for Jetty issue where <code>ServletContext.getContextPath()</code> always ends with <js>"null"</js>.
<li><code>RestServletProperties.REST_allowMethodParam</code> is now <jk>true</jk> by default on all subclasses
of {@link org.apache.juneau.rest.RestServletDefault} and {@link org.apache.juneau.rest.jena.RestServletJenaDefault}.
</ul>
<h6 class='topic'>Client</h6>
<ul class='spaced-list'>
<li>New method {@link org.apache.juneau.rest.client.RestCall#allowRedirectsOnPosts(boolean)}.
<li>New method <code>RestCall.peekInputStream()</code> allows you to read response bodies without interrupting execution flow.
<li>New method {@link org.apache.juneau.rest.client.RestCall#toString()} now useful for debugging purposes.
Shows all request/response headers and bodies.
<li>{@link org.apache.juneau.rest.client.RestCallException} now includes <code>HttpResponse</code> object for easier debugging.
<li>New method <code>RestClient.addListener(RestClientListener)</code> for registering request/response listeners.
<li>New <code><del>RestClient.setClassLoader(ClassLoader)</del></code> method.
<li>TLS support in <code>JazzRestClient</code>.
</ul>
<h6 class='topic'>Other changes</h6>
<ul class='spaced-list'>
<li><code>samples.ear</code> and <code>samples.war</code> projects
have been replaced with an OSGi bundle with activated servlets in <code>juno.samples</code>.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.10"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.10 (Dec 23, 2014)</h3>
<div class='topic'>
<p>
Juno 5.1.0.10 is a moderate update.
</p>
<h6 class='topic'>Core</h6>
<ul class='spaced-list'>
<li>Major changes to URL-Encoded serializer and parser.
<ul>
<li>Logic for serializing and parsing URL-Encoded key-value pairs moved to {@link org.apache.juneau.urlencoding.UrlEncodingSerializer} and {@link org.apache.juneau.urlencoding.UrlEncodingParser} classes.
<li>Logic for serializing and parsing URL-Encoded values moved to new {@link org.apache.juneau.uon.UonSerializer} and {@link org.apache.juneau.uon.UonParser} classes.
</ul>
</li>
<li>Fix bug where <code>BeanRuntimeExceptions</code> weren't being thrown on subsequent calls to {@link org.apache.juneau.BeanContext#getClassMeta(Class)}.
<li>Moved logic for <code>BeanContext.getPrimitiveDefault(Class)</code> to new {@link org.apache.juneau.ClassMeta#getPrimitiveDefault()} method for performance reasons.
<li>Fixed bug in <del><code>BeanContext.addTransforms(Class[])</code></del> that would cause filter order to get messed up.
<li>{@link org.apache.juneau.ClassMeta#newInstance()} can now create array instances.
<li>Fixed indentation bugs in {@link org.apache.juneau.html.HtmlSerializer}.
<li>Fixed issue in {@link org.apache.juneau.html.HtmlSerializer} where newlines were not being converted into line breaks.
<li>New {@link org.apache.juneau.serializer.WriterSerializer#toString(Object)} method that's identical to the serialize method but throws <code>RuntimeExceptions</code> to make the serializer easier to use for debugging.
</ul>
<h6 class='topic'>Server</h6>
<ul class='spaced-list'>
<li>Fixed major issue that prevented parsing URL-Encoded form posts into POJOs.
Calling <del><code>HttpServlet.getParameter(String)</code></del> was forcing the underlying servlet code to process the HTTP body itself, preventing the <code>UrlEncodingSerializer</code>
class from being able to parse the content. Updated code no longer inadvertantly calls this method.
<li>New <code><del>RestRequest.getQueryParameter(String)</del></code>, <code><del>RestRequest.hasQueryParameter(String)</del></code>, and <code><del>RestRequest.hasAnyQueryParameters(String[])</del></code>
methods that only look for parameters in the URL query string to prevent loading and parsing of URL-Encoded form posts.
<li>New <del><code>@QParam</code></del> and <del><code>@HasQParam</code></del> annotations for accessing query parameters from the URL query string.
<li><code>&amp;plainText</code> parameter can now specify a false value.
<li>Removed properties parameters from {@link org.apache.juneau.rest.RestServlet#onPreCall(RestRequest)} and {@link org.apache.juneau.rest.RestServlet#onPostCall(RestRequest,RestResponse)} methods
since the properties are already accessible through <code>RestRequest.getProperties()</code>.
<li>Added {@link org.apache.juneau.uon.UonSerializer} and {@link org.apache.juneau.uon.UonParser} to serializer and parser lists on
{@link org.apache.juneau.rest.RestServletDefault} and {@link org.apache.juneau.rest.jena.RestServletJenaDefault}.
</ul>
<h6 class='topic'>Client</h6>
<ul class='spaced-list'>
<li>Moved to Apache HttpClient 4.3 to match Jazz 6.0.
<li>Renamed <code>RestResponseEntity</code> to {@link org.apache.juneau.rest.client.RestRequestEntity}.
<li>Improved performance on URL-Encoded form posts by serializing directly to output stream instead of serialized to string first.
<li>New methods on {@link org.apache.juneau.rest.client.RestClient} class that makes it easier to associate serializer and parser attributes with registered serializer and parser:
<ul>
<li><code><del>RestClient#setProperty(String,Object)</del></code>
<li><code><del>RestClient#setProperties(ObjectMap)</del></code>
<li><code><del>RestClient#addNotBeanClasses(Class[])</del></code>
<li><del><code>RestClient.addTransforms(Class[])</code></del>
<li><code><del>RestClient#addImplClass(Class,Class)</del></code>
</ul>
<li>Renamed <code>RestClient.shutdown()</code> to {@link org.apache.juneau.rest.client.RestClient#close()} to mirror change in Apache API.
</ul>
<h6 class='topic'>Samples</h6>
<ul class='spaced-list'>
<li>New <code>CodeFormatterResource</code> for quickly formatting Java and XML code samples in Javadocs.
<li>New <code>UrlEncodedFormResource</code> for showing how to work with URL-Encoded form posts.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.9"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.9 (Dec 1, 2014)</h3>
<div class='topic'>
<p>
Juno 5.1.0.9 is a major update.
There weren't very many code changes, but the source has been made a part of Jazz Foundation.
This required some restructuring of the project.
The project on Jazz Hub will eventually be discontinued.
However, the libraries on IBM Community Source will continue to be updated regularly.
</p>
<ul class='spaced-list'>
<li>Project split up into 3 separate bundles:
<ul>
<li><code>org.apache.juneau</code> - Core serializers and parsers.
<li><code>org.apache.juneau.rest</code> - REST server component.
<li><code>org.apache.juneau.rest.client</code> - REST client component.
</ul>
<li>Code changes to facilitate breaking up bundles:
<ul>
<li><code>org.apache.juneau.rest.labels.Link</code> class moved to {@link org.apache.juneau.dto.Link}.
<li>References to <code>org.apache.juneau.rest.RestException</code> in {@link org.apache.juneau.encoders.Encoder} class changed to <code>IOException</code>.
</ul>
<li>Changed configuration names for consistency with Jazz Framework.
<li>New {@link org.apache.juneau.rest.client.RestClient#execute(HttpUriRequest)} method that allows subclasses to handle their own HTTP request execution.
<li>Changes in <code>JazzRestClient</code> to handle introduction of SSO support in v6.
<li><code>&amp;plainText</code> debug feature was broken.
<li>Removed double-buffering in <code>RestRequest</code>.
<li>Metadata cleanup, Find Bug fixes.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.8"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.8 (Oct 25, 2014)</h3>
<div class='topic'>
<p>
Juno 5.1.0.8 is a moderate update, focused primarily on performance improvements.
</p>
<ul class='spaced-list'>
<li>Improved performance on JSON and URL-Encoding parsers by approximately 50% on large data sets.
<ul>
<li>Rewrote {@link org.apache.juneau.parser.ParserReader} class to handle it's own buffering.
The change allowed several optimizations to be made when dealing with JSON and URL-Encoding
text by avoiding char array copies.
<li>Added a <code>estimatedSize</code> parameter to the {@link org.apache.juneau.parser.Parser} parse methods to
optimize buffering when the input size is known beforehand.
</ul>
</li>
<li>Revamped the {@link org.apache.juneau.BeanContext} API to perform better in multi-threaded environments.
<ul>
<li>Introduced a new <code>BeanPropertyStore</code> class that handles creation of {@link org.apache.juneau.BeanContext} objects.
This allows <code>BeanContext</code> objects to be considered immutable, and therefore cacheable/reusable by the framework.
While this was technically possible to cache these objects beforehand, it relied on a locking mechanism to prevent bean contexts
from being modified after being created. The new mechanism is much more straightforward.
</ul>
</li>
<li>Modifications to the <a class='doclink' href='org/apache/juneau/rest/client/package-summary.html#TOC'>org.apache.juneau.rest.client</a> APIs to make it easier to work with custom Apache HTTP clients.
<ul>
<li>Added overridable <code><del>RestClient#createHttpClient()</del></code> to allow customized subclasses to construct customized HTTP clients.
<li>Removed the <code>DefaultRestClient</code> class since it's now fully redundant with <code>RestClient</code>.
<li>Added <code>RestClient.shutdown()</code> method for cleaning up the internal HTTP client when you're done using a REST client.
</ul>
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.7"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.7 (Oct 5, 2014)</h3>
<div class='topic'>
<p>
Juno 5.1.0.7 is a moderate update.
</p>
<ul class='spaced-list'>
<li>Improved error handling.
<li>New <code><del>ParserContext.PARSER_debug</del></code> and <code><del>SerializerContext.SERIALIZER_debug</del></code>.
settings for logging additional information for debugging problems.
<li>New {@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_ignoreRecursions} setting for explicitely ignoring recursions when
serializing models. Previously, the <jsf>SERIALIZER_detectRecursions</jsf> setting did this, but now it simply looks for recursions
and throws exceptions when they occur.
<li>Improved handling of <code>StackOverflowErrors</code>. When <jsf>SERIALIZER_detectRecursions</jsf> is enabled, a useful error message
is displayed showing the exact chain of objects that resulted in the stack overflow.
<li>Bug fixes in {@link org.apache.juneau.dto.ResultSetList} for Oracle and SQL Server.
<li>Serializers and parsers can now access HTTP request attributes, parameters, and headers through <code>SerializerContext.getProperties()</code> and
<code>ParserContext.getProperties()</code>.
<li>Removed media-type and encoding attributes from {@link org.apache.juneau.serializer.SerializerContext} and {@link org.apache.juneau.parser.ParserContext}
since these are now available through context properties, and are typically not used.
<li>{@link org.apache.juneau.xml.XmlParser} now accepts <code>application/xml</code>.
<li>Improved handling of bean property serialization when multiple matching pojo filters for the bean property class exist.
<li>Improved concurrency on BeanContext class.
<li>Fixed bug in {@link org.apache.juneau.rest.converters.Traversable} that was causing it to be executed even if the servlet extra path info was empty.
<li>Fixed bug in {@link org.apache.juneau.rest.converters.Traversable} where it was not picking up filters and properties defined on REST Java methods.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.6"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.6 (Sept 21, 2014)</h3>
<div class='topic'>
<p>
Juno 5.1.0.6 is a moderate update.
</p>
<ul class='spaced-list'>
<li>Simplified API for {@link org.apache.juneau.transform.PojoSwap}.
Since it's rarely used, the <code>beanContext</code> parameter was replaced with a <del><code>PojoSwap#getBeanContext()</code></del> method on
the class.
<li>New simplified way of defining POJO filters without needing to extend {@link org.apache.juneau.transform.PojoSwap}.
See {@link org.apache.juneau.transform.SurrogateSwap} for details.
<li>New {@link org.apache.juneau.html.annotation.Html @Html} annotation.
Will allow the definition of standard XHTML DTOs in future releases.
For now, <del><code>Img</code></del> is an example of defining an XHTML element using Juno DTOs.
<li>{@link org.apache.juneau.json.JsonParser} now ignores trailing <code>';'</code> characters in input so that it can
parse strings of the form <js>"var x = {'foo':'bar'};"</js>.
<li>New <code>TumblrParserResource</code> in the samples war file showing how to combine the REST client and server APIs into a single
resource in order to download Tumblr blogs and convert the response into any supported response content type.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.5"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.5 (Sept 1, 2014)</h3>
<div class='topic'>
<p>
Juno 5.1.0.5 is a moderate update.
</p>
<ul class='spaced-list'>
<li>New {@link org.apache.juneau.rest.Redirect} class that simplifies performing redirections in REST methods.
<li>New pluggable {@link org.apache.juneau.rest.ResponseHandler} class and {@link org.apache.juneau.rest.annotation.RestResource#responseHandlers()} annotation
for defining customer response handlers for special kinds of POJOs.
<li>New method <del><code>UrlEncodingSerializer.serializeUrlPart(Object)</code></del> method.
<li>New method <code><del>RestRequest.getServletURIBuilder()</del></code> for construcing servlet-based URLs more efficiently.
<li>New method {@link org.apache.juneau.rest.RestResponse#getNegotiatedOutputStream()} that uses encoders if a match is found,
and {@link org.apache.juneau.rest.RestResponse#getOutputStream()} that just return the underlying output stream without any modifications.
<li>Fixed bug where some properties were not being propagated correctly when using <code><del>CoreObject.setProperties(ObjectMap)</del></code>
on serializer and parser subclasses.
<li>Fixed bug in {@link org.apache.juneau.html.HtmlSerializer} where URL keys in Maps were not being serialized as hyperlinks.
<li>Fixed bug in {@link org.apache.juneau.json.JsonSerializer} where <js>"_class"</js> and <js>"items"</js> attributes were not quoted in strict mode when using SERIALIZER_addClassAttrs feature.
<li>Fixed bug where <code>Content-Encoding</code> and<code>Character-Encoding</code> headers were being set when calling {@link org.apache.juneau.rest.RestResponse#getOutputStream()}.
These should not be set if interacting with the output streams at a low level.
<li>Eliminated various convenience <code>RestResponse.sendRedirect(...)</code> methods due to the introduction of the {@link org.apache.juneau.rest.Redirect} class.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.4"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.4 (Aug 25, 2014)</h3>
<div class='topic'>
<p>
Juno 5.1.0.4 is a minor update.
</p>
<ul class='spaced-list'>
<li>New <code><del>RestServlet.getPath()</del></code> method.
<li>New <code>SerializerContext.getJavaMethod()</code> and <code>ParserContext.getJavaMethod()</code>
to allow access to REST methods that invoked the serializers or parsers.
For example, can be used to access additional annotations on REST methods to perform special handing
during serialization or parsing.
<li>Better behavior on overriding of filters in <code>BeanContext.addTransforms(Class[])</code>.
Previously, adding multiple conflicting filters resulted in random behavior.
Now filters are overridden when multiple matching filters are applied.
<li>Allow {@link org.apache.juneau.html.HtmlDocSerializerContext} properties to be set via <code><del>Serializer.setProperty(String,Object)</del></code>.
Previously, these could only be defined through override properties (e.g. through REST class and method annotations).
<li>Fixed memory leak in XML parser.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.3"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.3 (Jun 28, 2014)</h3>
<div class='topic'>
<p>
Juno 5.1.0.3 is a moderate update.
</p>
<h6 class='topic'>Core API updates</h6>
<ul class='spaced-list'>
<li>Ability to detect and use non-public bean classes, getters/setters, and fields using the following new properties:
<ul>
<li>{@link org.apache.juneau.BeanContext#BEAN_beanConstructorVisibility} - Control which bean constructors are visible to Juno.
<li>{@link org.apache.juneau.BeanContext#BEAN_beanClassVisibility} - Control which bean classes are interpreted as beans to Juno.
<li>{@link org.apache.juneau.BeanContext#BEAN_beanFieldVisibility} - Control which fields are visible to Juno as bean properties.
<li>{@link org.apache.juneau.BeanContext#BEAN_methodVisibility} - Control which getters/setters are visible to Juno as bean properties.
</ul>
Removed <code>BeanContext.<jsf>INCLUDE_BEAN_FIELD_PROPERTIES</jsf></code> and <code>BeanContext.<jsf>INCLUDE_BEAN_METHOD_PROPERTIES</jsf></code> properties, since ignoring fields and methods
can be accomplished by setting the appropriate properties above to {@link org.apache.juneau.Visibility#NONE NONE}.
Also, the {@link org.apache.juneau.annotation.BeanProperty @BeanProperty} annotation can now be used on non-public fields/getters/setters to override
the default behavior defined by the <code>VISIBILITY</code> properties identified above. This is a convenient way of identifying protected or
private fields or methods as bean properties. Previously, you could only identify public fields/getters/setters using this annotation.
</li>
<li>New {@link org.apache.juneau.BeanContext#BEAN_useJavaBeanIntrospector} property that lets Juno use the Java bean <code>Introspector</code>
class to determine bean properties. In the previous release, the method for determining bean properties was a mixture of Juno-based and Introspector-based.
Now it's either pure Juno-based or pure Introspector-based. The result is considerably cleaner code and consistent behavior.
<li>New {@link org.apache.juneau.annotation.BeanIgnore @BeanIgnore} annotation. Replaces the previous <code><ja>@BeanProperty</ja>(hidden=<jk>true</jk>)</code> annotation
for ignoring bean properties. Can also be used on classes that look like beans so that they're not treated as beans.
<li>Support for parsing into non-static member classes. This applies to all parsers.
<li>New {@link org.apache.juneau.json.annotation.Json#wrapperAttr() @Json.wrapperAttr()} annotation that automatically wraps beans and objects in a wrapper
attribute when serializing to or parsing from JSON.
<li>Changed the default ordering of bean properties to be in parent-to-child class order.
<li>New {@link org.apache.juneau.transform.BeanFilter#readProperty(Object,String,Object) readProperty()} and {@link org.apache.juneau.transform.BeanFilter#writeProperty(Object,String,Object) writeProperty()}
methods added to {@link org.apache.juneau.transform.BeanFilter} class to allow individualized serialization and parsing behavior on a class-by-class basis.
<li>Eliminated previous restriction where bean subtype attributes had to be listed first in JSON objects when using the <code><del>Bean.subTypeProperty()</del></code> annotation.
The previous behavior was not strictly JSON-compliant since JSON objects are supposed to consist of unordered lists of key/value pairs.
While targeted for JSON, the restriction is also lifted for all other parsers.
<li>New fluent-style {@link org.apache.juneau.BeanMap#load(String) BeanMap.load()} methods for initializing bean maps.
<li>{@link org.apache.juneau.html.HtmlDocSerializer} will now embed the data portion of the output in a <code><xt>&lt;div</xt> <xa>id</xa>=<xs>'data'</xs><xt>&gt;</xt></code> element to make it easier to extract the data portion of the page in Javascript in browsers.
</ul>
<h6 class='topic'>REST Server API updates</h6>
<ul class='spaced-list'>
<li>New {@link org.apache.juneau.rest.RestRequest#getJavaMethod()} method for getting access to the method used to handle a request.
Useful for accessing the method name or annotations during requests, such as in calls to {@link org.apache.juneau.rest.RestGuard#guard(RestRequest,RestResponse)}.
<li>Fixed bug when using Jetty where you tried to read text input after a header was written.
<li>Added new string variables <del><code>$A{...}</code></del> (request attributes) and <del><code>$P{...}</code></del> (request parameters) to <code>RestServlet.createRequestVarResolver(RestRequest)</code>.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.2"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.2 (Apr 27, 2014)</h3>
<div class='topic'>
<p>
Juno 5.1.0.2 is a minor update.
</p>
<ul class='spaced-list'>
<li>Fixed issue preventing <code>&amp;Accept-Language</code> from being used as a GET parameter.
<li>Minor XSS vulnerability fix.
<li>Empty results on HTML pages now shows <js>"no results"</js> instead of a blank page.
<li>Fixed issues preventing REST pages from rendering HTML in newer versions of Internet Explorer.
<li>Changed <code>RestServletProperties.REST_allowMethodParam</code> to be disabled by default.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.1"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.1 (Jan 25, 2014)</h3>
<div class='topic'>
<p>
Juno 5.1.0.1 is a minor update.
</p>
<ul class='spaced-list'>
<li>Addressed some behavioral differences between Tomcat and WAS.
<ul>
<li>Query parameter lookup is now always case-insensitive (per WAS behavior).
<li>Consistent handling of redirect requests (Tomcat and WAS handle relative redirect paths differently).
</ul>
<li>Fixed bug involving incorrect resolution of overlapping URL match patterns.
<li>Overall improvements in HTTP request parameter and header value resolution.
<li>Made workspace changes so as not to be dependent on the WAS test environment being loaded.
<li>Renamed <ja>@Remainder</ja> annotation to {@link org.apache.juneau.rest.annotation.PathRemainder @PathRemainder}.
<li>Fixed bug involving incorrect calculation of <code>pathInfo</code> on child resources.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.1.0.0"></a>
<h3 class='topic' onclick='toggle(this)'>5.1.0.0 (Jan 18, 2014)</h3>
<div class='topic'>
<p>
Juno 5.1.0.0 is a major update.
</p>
<h6 class='topic'>Major changes</h6>
<ul class='spaced-list'>
<li>Brand new REST client API that uses Apache HttpClient for HTTP communication.<br>
The new client API is simply a thin layer on top of <code>HttpClient</code> that performs
serialization and parsing using Juno parsers, but leaves all the details of the HTTP connection
to the Apache code. <br>
See the <a class='doclink' href='org/apache/juneau/rest/client/package-summary.html#TOC'>org.apache.juneau.rest.client</a> package for details.
<li>New <code>org.apache.juneau.rest.client.jazz</code> package and <code>org.apache.juneau.rest.client.jazz.JazzRestClient</code> class
for performing REST operations against Jazz servers.<br>
Includes improved support for FORM authentication, and better SSL certificate validation.
<li>Completely redesigned URL-Encoding support.<br>
See <a class='doclink' href='org/apache/juneau/urlencoding/package-summary.html#TOC'>org.apache.juneau.urlencoding</a> package for details.
<li>Changes to Parser API.
<ul>
<li>Removal of <code>ExtendedReaderParser</code> abstract class and moved methods into
{@link org.apache.juneau.parser.ReaderParser} class.
<li>Removal of <code>DataFormat</code> class from API since it was no longer necessary
due to API change above.
<li>Removal of <code>ParserStringReader</code> class.<br>
This was a reader optimized to work with <code>String</code> input.<br>
However, it could interfere with garbage collection of the original string object.<br>
Instead, the existing {@link org.apache.juneau.parser.ParserReader} was enhanced to work
well with <code>String</code> input, and tests show no significant performance differences.
<li>New <code>org.apache.juneau.parser.Parser.parse(Object,int,ClassMeta)</code> convenience method added.
</ul>
</ul>
<h6 class='topic'>Other changes</h6>
<ul class='spaced-list'>
<li>Various new methods added to {@link org.apache.juneau.internal.StringUtils} and {@link org.apache.juneau.internal.ClassUtils}.
<li>Improved support on <code><del>BeanContext.getClassMetaFromString(String)</del></code>.<br>
Now supports resolving <code>"long[]"</code>, and so forth.
<li>{@link org.apache.juneau.rest.labels.ResourceDescription} name parameter is now automatically URL-encoded in links.
<li>{@link org.apache.juneau.rest.RestRequest} now correctly handles cases involving URL-encoded characters in the
path info portion of URLs (e.g. <code>http://host/contextRoot/foo%2Fbar</code>).
<li>Removed lazy-initialization that required locking in {@link org.apache.juneau.ClassMeta}.
<li>New <code>BeanContext.setDefaultParser(ReaderParser)</code> method added for specifying
a default parser to use in a bean context (used when converting beans to <code>Strings</code> using
<code><del>BeanContext.convertToType(Object,Class)</del></code>.
Old behavior simply used the default JSON serializer in these cases.
<li>More consistent handling of exceptions across all parsers.
<li>Minor changes to {@link org.apache.juneau.rest.RestRequest} class.
<ul>
<li>Changed the order of parameters on <del><code>RestRequest#getParameter(String,Class)</code></del>.
<li>Added <code>RestRequest.getMapParameter(String,Class,Class,Class)</code> and
<code>RestRequest.getCollectionParameter(String,Class,Class)}</code> methods.
</ul>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.36"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.36 (Dec 18, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.36 is a minor update.
</p>
<ul class='spaced-list'>
<li>Implemented <code>org.apache.juneau.urlencoding.UrlEncodingParser.parseArgs(Reader,int,ClassMeta[])</code>.
<li><code>name</code> parameter of <code><del>ResourceDescription#ResourceDescription(String,String,String)</del></code>.
is now automatically URL-encoded so that the name can contain special characters (e.g. <js>"foo/bar(baz)"</js>).
<li>Support for URL-matching and path info containing encoded characters (e.g. <js>'/'</js>) now supported.
<li>Removed some lazy-initialization of bean information in {@link org.apache.juneau.ClassMeta} that allowed the removal of
some synchronized blocks.
<li>Improved support of <code><del>BeanContext.getClassMetaFromString(String)</del></code>.
Now supports primitive arrays such as <js>"long[]"</js> in addition to the previous support for the equivalent <js>"[J"</js>.
<li>Various new convenience methods added to {@link org.apache.juneau.internal.StringUtils} and {@link org.apache.juneau.internal.ClassUtils}.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.35"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.35 (Nov 26, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.35 is a minor update.
</p>
<ul class='spaced-list'>
<li>{@link org.apache.juneau.rest.RestGuard#guard(RestRequest,RestResponse)} now returns a boolean to allow redirects to login pages.
<li>Fixed bug in RestServlet where occasional false positive "duplicate method with same name and path" errors were occurring.
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.34"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.34 (Nov 10, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.34 is a moderate update.
</p>
<ul class='spaced-list'>
<li>
New support for runtime-replaced variables in REST resource properties:
<p class='bcode'>
<ja>@RestResource</ja>(
messages=<js>"nls/Messages"</js>,
properties={
<ja>@Property</ja>(name=<js>"label"</js>,value=<js>"$L{servletTitle}"</js>), <jc>// Localized variable in Messages.properties</jc>
<ja>@Property</ja>(name=<js>"javaVendor"</js>,value=<js>"$S{java.vendor}"</js>), <jc>// System property</jc>
<ja>@Property</ja>(name=<js>"foo"</js>,value=<js>"bar"</js>),
<ja>@Property</ja>(name=<js>"bar"</js>,value=<js>"baz"</js>),
<ja>@Property</ja>(name=<js>"v1"</js>,value=<js>"$R{foo}"</js>), <jc>// Request variable. value="bar"</jc>
<ja>@Property</ja>(name=<js>"v2"</js>,value=<js>"$R{$R{foo}}"</js>) <jc>// Nested request variable. value="baz"</jc>
}
)
</p>
See <code>RestServlet.createRequestVarResolver(RestRequest)</code> for more information.
</li>
<li>
Eliminated <ja>@Property.type</ja> annotation which was the old way of specifying NLS variables that got resolved at runtime.
</li>
<li>
New methods on {@link org.apache.juneau.rest.RestRequest}:
<ul>
<li><del><code>RestRequest.getVarResolver()</code></del></li>
<li><code><del>RestRequest.getServletURI()</del></code></li>
<li><code><del>RestRequest.getRequestParentURI()</del></code></li>
</ul>
</li>
<li>
New methods on {@link org.apache.juneau.rest.RestResponse}:
<ul>
<li><code>RestResponse.sendRedirect(CharSequence)</code>
</ul>
</li>
<li>
New methods on {@link org.apache.juneau.rest.RestServlet} that allow easier customization by subclasses:
<ul>
<li><code><del>RestServlet.createConfigFactory()</del></code></li>
<li><code><del>RestServlet.createConverters()</del></code></li>
<li><code><del>RestServlet.createDefaultRequestHeaders()</del></code></li>
<li><code><del>RestServlet.createDefaultResponseHeaders()</del></code></li>
<li><code><del>RestServlet.createEncoders()</del></code></li>
<li><code><del>RestServlet.createFilters()</del></code></li>
<li><code><del>RestServlet.createGuards()</del></code></li>
<li><code><del>RestServlet.createMimetypesFileTypeMap()</del></code></li>
<li><code><del>RestServlet.createParsers()</del></code></li>
<li><code><del>RestServlet.createProperties()</del></code></li>
<li><code><del>RestServlet.createRequestProperties(ObjectMap,RestRequest)</del></code></li>
<li><code><del>RestServlet.createRequestVarResolver(RestRequest)</del></code></li>
<li><code><del>RestServlet.createSerializers()</del></code></li>
<li><code><del>RestServlet.createUrlEncodingParser()</del></code></li>
</ul>
</li>
<li>
Changed <code>RestServletNls</code> to use <code>ResourceDescription/MethodDescription</code>
instead of <code>RestResource/RestMethod</code>
</li>
<li>
New property <code>RestServletProperties.REST_htDocsFolder</code>.<br>
New support for serving up static documents from classpath through REST interface.
</li>
<li>
Exception APIs now use {@link java.text.MessageFormat} (e.g. <js>"{0}"</js>) for message variables instead of <js>"%s"</js>.
</li>
<li>
New {@link org.apache.juneau.annotation.Bean#stopClass @Bean.stopClass} annotation for specifying stop classes for bean properties.
</li>
<li>
New <del><code>BeanFilter.setStopClass(Class)</code></del> which is the program equivalent to the annotation above.
</li>
<li>
New methods on {@link org.apache.juneau.dto.ResultSetList}:
<ul>
<li><code>ResultSetList.handleBlob(Blob)</code></li>
<li><code>ResultSetList.handleClob(Clob)</code></li>
</ul>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.33"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.33 (Oct 20, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.33 is a moderate update.
</p>
<ul class='spaced-list'>
<li>
Removed generic parameter from {@link org.apache.juneau.serializer.WriterSerializer} class.
<ul>
<li>
Many of the examples in the documentation were written as follows, which resulted in "unchecked" compile warnings:<br>
<code>WriterSerializer s = <jk>new</jk> JsonSerializer();</code><br>
These compile warnings will now go away.
</li>
</ul>
</li>
<li>
New settings in BeanContext. These can be applied to all serializers/parsers.
<ul>
<li>{@link org.apache.juneau.BeanContext#BEAN_ignoreInvocationExceptionsOnGetters}
<li>{@link org.apache.juneau.BeanContext#BEAN_ignoreInvocationExceptionsOnSetters}
<li>{@link org.apache.juneau.BeanContext#BEAN_notBeanPackages_add}
<li>{@link org.apache.juneau.BeanContext#BEAN_notBeanPackages_remove}
</ul>
</li>
<li>
Eliminated <code>addNotBeanClassPatterns(String...)</code> methods throughout API since these are now controlled by {@link org.apache.juneau.BeanContext#BEAN_notBeanPackages_add} / {@link org.apache.juneau.BeanContext#BEAN_notBeanPackages_remove} properties.
</li>
<li>
New settings in <code>RestServletProperties</code>.
<ul>
<li><code>RestServletProperties.REST_trimTrailingUriSlashes</code><br>
Also removed <code>RestRequest.getRequestURI(boolean trimTrailingSlashes)</code> method which is now redundant with this property.
<li><code>RestServletProperties.REST_pathInfoBlankForNull</code><br>
Also removed <code>RestRequest.getPathInfo(boolean returnBlankForNull)</code> method which is now redundant with this property.
</ul>
</li>
<li>
New JSON-Schema {@link org.apache.juneau.dto.jsonschema.SchemaMap} class for supporting linked schemas.
</li>
<li>
Serializers will no longer throw an exception when <code>maxDepth</code> setting is reached, and will instead simply ignore content below the specified depth.<br>
While the old behavior was as-designed, the new behavior is more in-line with expected behavior.
</li>
<li>
Added support for HTTP header <js>"X-Response-Headers"</js> to {@link org.apache.juneau.rest.RestServlet}. <br>
Allows you to specify one or more headers that should be returned on the response from the servlet.<br>
For example, to get a page to automatically refresh every 1 second, you can append the following to a URL: <code>?x-response-headers={Refresh=1}</code>
</li>
<li>
Removed <code>HtmlDocSerializerContext.<jsf>HTML_REFRESH</jsf></code> setting that added a Refresh meta tag to HTML documents, since this can now be controlled through <code>X-Response-Headers</code>.
</li>
<li>
Small improvements to samples.
<ul>
<li><code>PhotosResource</code> now includes a default entry.
</ul>
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.32"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.32 (Oct 5, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.32 is a moderate update.
</p>
<ul class='spaced-list'>
<li>
New support for generating and consuming fully-compliant JSON-Schema documents.<br>
See <a class='doclink' href='org/apache/juneau/dto/jsonschema/package-summary.html#TOC'>org.apache.juneau.dto.jsonschema</a> for information.
</li>
<li>
New methods added to {@link org.apache.juneau.parser.Parser}:
<ul>
<li><code>org.apache.juneau.parser.Parser.parseMap(Object,int,Class,Class,Class)</code></li>
<li><code>org.apache.juneau.parser.Parser.parseCollection(Object,int,Class,Class)</code></li>
</ul>
</li>
<li>
{@link org.apache.juneau.annotation.Bean @Bean} annotation can now be defined on interfaces and inherited by subclasses.
</li>
<li>
Support for customizing serialized values for <code>Enums</code> through overriding <code>toString()</code> and <code>fromString()</code> on the enum class.<br>
Previously used <code>Enum.valueOf()</code> to convert strings back into <code>Enums</code>.<br>
Used for JSON-Schema support to allow {@link org.apache.juneau.dto.jsonschema.JsonType} enum to be serialized to lowercase per the specification (e.g. <js>"string"</js> instead of <js>"STRING"</js>).
</li>
<li>
{@link org.apache.juneau.dto.cognos Cognos} DTOs now have fluent-style bean setters.
</li>
<li>
Support for generic bean objects whose type was erased at compile time.<br>
Previous behavior gave you an error message that the type could not be determined.<br>
New behavior assumes a type of <code>Object</code> when the type is erased.
</li>
<li>
Bug fixes:
<ul>
<li>
When duplicate fluent-style setters were defined with different parameter types (e.g. <code>setFoo(Foo f)</code>, <code>setFoo(Bar b)</code>), the {@link org.apache.juneau.BeanMap} API would sometime choose the wrong setter as the bean property setter. <br>
Now validates that the setter being chosen is the one whose return type matches the property getter.
</li>
<li>
Passing in <code>Accept</code> GET parameters with <js>'+'</js> (e.g. <code>&amp;Accept=text/json+simple</code>) wasn't working anymore.<br>
The <code>Accept</code> parameter is supposed to interpret spaces as <js>'+'</js> to allow you to not have to write <code>&amp;Accept=text/json%2Bsimple</code>.
</li>
<li>
Parsers would not set bean properties of abstract type {@link java.lang.Number}.<br>
Now it detects the numeric type based on input and sets the value accordingly.
</li>
</ul>
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.31"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.31 (Aug 9, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.31 is a moderate update.
</p>
<ul class='spaced-list'>
<li>
Simplified the {@link org.apache.juneau.serializer.Serializer} and {@link org.apache.juneau.parser.Parser} class hierarchies.<br>
This reverses a previous change that added a bunch of interfaces in these APIs (and subsequently required compiling with Java 7 to get around a compiler bug).<br>
The new class hierarchy is much simpler to understand.
</li>
<li>
Added {@link org.apache.juneau.transforms.XMLGregorianCalendarSwap} to convert these to ISO8601 strings during serialization, and vice versa during parsing.
</li>
<li>
Added a strict mode to {@link org.apache.juneau.json.JsonParser}.
</li>
<li>
Added default {@link org.apache.juneau.json.JsonParser#DEFAULT_STRICT} parser.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.30"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.30 (Aug 8, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.30 is a minor update.
</p>
<ul class='spaced-list'>
<li>
Fixed bug involving beans using <code><del>Bean.subTypes()</del></code> annotation in addition to <code>subTypes</code> property.
</li>
<li>
Modified the JSON parser to handle non-existent JSON values to get around an issue where Cognos was generating invalid JSON.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.29"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.29 (Aug 2, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.29 is a moderate update.
</p>
<ul class='spaced-list'>
<li>
Revamped the API for filter support:
<ul>
<li>Updated {@link org.apache.juneau.transform.BeanFilter} class to mirror the {@link org.apache.juneau.annotation.Bean @Bean} annotation.</li>
<li>Introduced support for bean <code><del>Bean.subTypeProperty() subtypes</del></code>. </li>
<li>Replaced <code><ja>@Bean</ja>(filter=xxx)</code> with new <del><code>@Transform</code></del> annotation.</li>
</ul>
</li>
<li>
Revamped URL-Encoding support.<br>
The old URL-Encoding serializer and parser simply used the JSON serializer/parser with a thin URL-encoding top layer.<br>
The new URL-Encoding serialize and parser was written from scratch and is considerably more consistent in design and output.
</li>
<li>
Improved number parsing.<br>
The new number parser should handle any valid numeric syntax for decimals and floats that Java itself supports.
</li>
<li>
{@link org.apache.juneau.json.JsonSerializer} LAX mode now quotes reserved word attributes.
</li>
<li>
New predefined DateFilters with millisecond precision:
<ul>
<li><code>org.apache.juneau.transforms.DateSwap.ISO8601DTP</code></li>
<li><code>org.apache.juneau.transforms.DateSwap.ISO8601DTZP</code></li>
</ul>
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.28"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.28 (July 9, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.28 is a moderate update.
</p>
<ul class='spaced-list'>
<li>
Fixes an <code>OutOfMemoryError</code> and performance issue caused by incorrect caching of class metadata.
</li>
<li>
Added <code>WriterSerializer.serialize(Object,Writer)</code> convenience method for serializing directly to a writer.<br>
Applies to all serializers.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.27"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.27 (July 7, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.27 is a moderate update.
</p>
<ul class='spaced-list'>
<li>
Fixed some HTML formatting issues in {@link org.apache.juneau.html.HtmlSerializer}.
</li>
<li>
{@link org.apache.juneau.rest.RestServletDefault} now includes {@link org.apache.juneau.plaintext.PlainTextSerializer} and {@link org.apache.juneau.plaintext.PlainTextParser} for plain-text support.
</li>
<li>
Child resources now render on default <code>OPTIONS</code> pages through new method <del><code>ResourceOptions.getChildren()</code></del>.
</li>
<li>
Changes to {@link org.apache.juneau.urlencoding.UrlEncodingSerializer}/{@link org.apache.juneau.urlencoding.UrlEncodingParser} to reduce the need for quoted string values.<br>
More changes are likely in this area of the code to support multipart form posts.
</li>
<li>
FindBugs fixes.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.26"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.26 (Jun 5, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.26 is a minor update.
</p>
<ul class='spaced-list'>
<li>
FindBug fixes.
</li>
<li>
Changed the way child REST resources are defined.<br>
Eliminated the <ja>@RestChild</ja> annotation on getter methods and replaced it with {@link org.apache.juneau.rest.annotation.RestResource#children() @RestResource.children()} defined on the resource class itself.<br>
Child resource paths are specified through {@link org.apache.juneau.rest.annotation.RestResource#path() @RestResource.path()}.
</li>
<li>
New {@link org.apache.juneau.rest.labels.ChildResourceDescriptions} bean for automatically generating the contents of router resource pages.
</li>
<li>
Changed <code><ja>@RestMethod</ja>.pattern()</code> to {@link org.apache.juneau.rest.annotation.RestMethod#path() @RestMethod.path()} for naming consistency.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.25"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.25 (May 11, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.25 is a minor update.
</p>
<h6 class='topic'>Core API updates</h6>
<ul class='spaced-list'>
<li>
New {@link org.apache.juneau.dto.ResultSetList} DTO for serializing SQL result sets to JSON/XML/HTML and so forth.
</li>
<li>
New <code>SqlQueryResource</code> class in the sample war for demonstrating the <code>ResultSetList</code> DTO.
</li>
</ul>
<h6 class='topic'>Server API updates</h6>
<ul class='spaced-list'>
<li>
Fixed issue with media type for CSS files being reported as <js>"text/plain"</js> instead of <js>"text/css"</js>.
</li>
<li>
Moved initialization of class properties to before the call to <code>Servlet.init()</code> so that <code>getProperties()</code> can be called during servlet initialization.
</li>
<li>
New <code><ja>@Property</ja>.type</code> annotation with support for using system properties as resource properties.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.24"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.24 (May 9, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.24 is a major update.
</p>
<h6 class='topic'>Core API updates</h6>
<ul class='spaced-list'>
<li>
New support for {@link org.apache.juneau.dto.atom ATOM}.
<ul>
<li>New <code>AtomFeedResource</code> class added to sample war.
</ul>
</li>
<li>
New <code><del>XmlFormat.CONTENT</del></code> enum value.<br>
Allows bean properties to be persisted as XML element text.
</li>
<li>
New <code><del>XmlContentHandler</del></code> class and <code><del>@Xml.contentHandler</del></code> annotation.<br>
Allows customized serialization and parsing of beans to XML element text.<br>
Added for support of ATOM text content that must support both plain text and embedded XHTML.
</li>
<li>
New {@link org.apache.juneau.xml.annotation.XmlSchema @XmlSchema} and updated {@link org.apache.juneau.xml.annotation.XmlNs @XmlNs} annotations to better mimic JAXB.
</li>
<li>
Removed <code><ja>@Xml</ja>.valAttr</code> annotation since it's now redundant with <code><ja>@Xml</ja>(format=<jsf>CONTENT</jsf>)</code>.
</li>
<li>
Fixed timezone bug in {@link org.apache.juneau.transforms.CalendarSwap}.
</li>
<li>
Simplified <code>Serializer.serialize(Object,Object,SerializerContext)</code> method.
</li>
<li>
Fixed bug where lists returned by {@link org.apache.juneau.ObjectMap#getObjectList(String)} were not updatable.
</li>
<li>
Eliminated old RDF/XML serializer.
</li>
</ul>
<h6 class='topic'>Documentation updates</h6>
<ul>
<li>New {@link org.apache.juneau.json JSON Support Overview} document.</li>
<li>New {@link org.apache.juneau.xml XML Support Overview} document.</li>
<li>New {@link org.apache.juneau.jena RDF Languages Support Overview} document.</li>
<li>New {@link org.apache.juneau.dto.atom ATOM Support Overview} document.</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.23"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.23 (Apr 14, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.23 is a minor update.
</p>
<ul class='spaced-list'>
<li>
Simplified {@link org.apache.juneau.dto.cognos Cognos} support.
</li>
<li>
Fixed bug where <code><ja>@Xml</ja></code> annotation was not being inherited by inner classes.
</li>
<li>
Javadoc stylesheet improvements.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.22"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.22 (Apr 12, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.22 is a minor update.
</p>
<h6 class='topic'>Core API changes</h6>
<ul class='spaced-list'>
<li>
New <code><ja>@Property</ja>.nls()</code> annotation for specifying localized property values.<br>
For example, allows you to set the <jsf>HTMLDOC_title</jsf> and <jsf>HTMLDOC_description</jsf> properties to localized values pulled from a resource bundle.<br>
See the <code>AddressBookResource</code> class for an example.
</li>
</ul>
<h6 class='topic'>REST Servlet API changes</h6>
<ul class='spaced-list'>
<li>Fix a bug where the <code>&amp;Content</code> query parameter was not always parsed correctly.</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.21"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.21 (Apr 9, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.21 is a minor update.
</p>
<h6 class='topic'>Core API changes</h6>
<ul class='spaced-list'>
<li>
New {@link org.apache.juneau.html.HtmlDocSerializerContext#HTMLDOC_links} annotation for addint links to HTML page views.
</li>
<li>
Renamed the properties in {@link org.apache.juneau.html.HtmlDocSerializerContext} for clarity.
</li>
</ul>
<h6 class='topic'>Servlet API changes</h6>
<ul class='spaced-list'>
<li>
Added new <code>RestServlet.addDefaultProperties(ObjectMap,RestRequest)</code> method for programatically adding properties to the property map per request.
</li>
<li>
Added the following new properties in the properties map to make them easily available to serializers and parsers (since they don't have access to the HTTP request object).<br>
Note that the <code>SerializerContext.SERIALIZER_uriAuthority</code> and <code>SerializerContext.SERIALIZER_uriContext</code> properties were previously available.
<ul>
<li><code>RestServletProperties.REST_servletPath</code></li>
<li><code>RestServletProperties.REST_pathInfo</code></li>
<li><code>RestServletProperties.REST_method</code></li>
</ul>
</li>
<li>
Path variables annotated with <del><code>@Attr</code></del> are now automatically URL-decoded.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.20"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.20 (Apr 7, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.20 is a major update.
</p>
<h6 class='topic'>Core API changes</h6>
<ul class='spaced-list'>
<li>
New Jena-based {@link org.apache.juneau.jena.RdfSerializer} for serializing POJOs to RDF/XML, RDF/XML-ABBREV, N-Triple, Turtle, and N3.<br>
Serializes ANY POJOs to RDF, even simple objects and primitives.
</li>
<li>
New Jena-based {@link org.apache.juneau.jena.RdfParser} for parsing RDF/XML, RDF/XML-ABBREV, N3, Turtle, and N-Triple back into POJOs.
</li>
<li>
{@link org.apache.juneau.xml.XmlSerializerContext#XML_autoDetectNamespaces} default changed to <jk>true</jk>.<br>
The old default value would cause XML with unmapped namespaces if you didn't manually specify them via the {@link org.apache.juneau.xml.XmlSerializerContext#XML_namespaces} annotation.<br>
While setting the default to <jk>true</jk> is somewhat slower (since the serializer must crawl the POJO tree to find namespaces), the benefits of having it work out-of-the-box outweighs the performance concerns.<br>
For developers concerned about performance, they can always change it back to false and specify the namespaces themselves.
</li>
</ul>
<h6 class='topic'>REST server API changes</h6>
<ul class='spaced-list'>
<li>
Allow inheritance of {@link org.apache.juneau.rest.annotation.RestResource @RestResource} annotation.<br>
Serializers, parsers, filters, properties , guards, and converters definitions are automatically inherited from parent classes and interfaces.
</li>
<li>
Enhancements to {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod} annotation:
<ul>
<li>
New <code>RestMethod.filters()</code> annotation for defining POJO filters at the method level.
</li>
<li>
New {@link org.apache.juneau.rest.annotation.RestMethod#serializersInherit()} and {@link org.apache.juneau.rest.annotation.RestMethod#parsersInherit()} annotations for controlling how serializers and parsers (and associated filters and properties) are inherited from the class.<br>
This replaces the previous <code>addSerializers</code> and <code>addParsers</code> annotations.
</ul>
</li>
<li>
New {@link org.apache.juneau.rest.jena.RestServletJenaDefault} servlet that includes serialization/parsing support for all Jena-based serializers and parsers.
</li>
<li>
New {@link org.apache.juneau.rest.jaxrs.rdf.DefaultJenaProvider} JAX-RS provider that includes serialization/parsing support for all Jena-based serializers and parsers.
</li>
<li>
Eliminated <code>RestServletChild</code> class.<br>
It's redundant with the introduction of inheritable annotations.
</li>
<li>
New methods on {@link org.apache.juneau.rest.RestServlet}:
<ul>
<li><code>RestServlet.createConfigFactory()</code></li>
<li><code>RestServlet.createSerializers()</code></li>
<li><code>RestServlet.createParsers()</code></li>
</ul>
These augment the existing <code>getBeanContext()</code> / <code>getSerializers()</code> / <code>getParsers()</code> methods.
</li>
</ul>
<h6 class='topic'>REST client API changes</h6>
<ul class='spaced-list'>
<li>
New <code>RestCall.setDateHeader(String,Object)</code> method for setting ISO8601 datetime headers.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.19"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.19 (Apr 1, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.19 is a minor update.
</p>
<ul class='spaced-list'>
<li>
New methods on {@link org.apache.juneau.rest.RestServlet}:
<ul>
<li>{@link org.apache.juneau.rest.RestServlet#onPreCall(RestRequest)}</li>
<li>{@link org.apache.juneau.rest.RestServlet#onPostCall(RestRequest,RestResponse)}</li>
</ul>
</li>
<li>
<jsf>TRIM_NULLS</jsf> setting changed to {@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_trimNullProperties}.<br>
New property default is <jk>true</jk>.
Only applies to bean properties, not map or collection entries.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.18"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.18 (Mar 27, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.18 is a moderate update.
</p>
<p>
The biggest change is the introduction of the {@link org.apache.juneau.jena.RdfSerializer} class that uses Jena to generate RDF/XML, RDF/XML-ABBREV, N-Tuple, N3, and Turtle output.
</p>
<p>
This code should be considered prototype-quality, and subject to change in the future.<br>
There are plans of adding an equivalent <code>RdfParser</code> class in the future, so the serializer logic may need to be tweaked to allow POJOs to be reconstituted correctly in the parser.
</p>
<p>
The <code>RdfXmlSerializer</code> class should be considered deprecated for now.<br>
However, I'm keeping it around, since it's considerably faster and uses far less memory than the Jena-based serializer since it serializes directly from POJOs to RDF/XML.<br>
It may or may not be removed in the future depending on demand.
</p>
<h6 class='topic'>Other changes</h6>
<ul class='spaced-list'>
<li>
New {@link org.apache.juneau.jso.JsoParser} class.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.17"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.17 (Mar 25, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.17 is a minor update.
</p>
<ul class='spaced-list'>
<li>
Charset now passed as a parameter to <code>IOutputStreamSerializer.serialize()</code> and <code>IInputStreamParser.parse()</code>.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.16"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.16 (Mar 25, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.16 is a minor update.
</p>
<ul class='spaced-list'>
<li>
New {@link org.apache.juneau.rest.annotation.Properties @Properties} REST method parameter annotation that can be used to get the runtime properties map through a parameter instead of through {@link org.apache.juneau.rest.RestResponse}.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.15"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.15 (Mar 24, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.15 is a moderate update.
</p>
<ul class='spaced-list'>
<li>
Juno-Wink integration components that have been requested my many for a long time!<br>
Refer to <a class='doclink' href='org/apache/juneau/rest/jaxrs/package-summary.html#TOC'>org.apache.juneau.rest.jaxrs</a> for information.
</li>
<li>
New {@link org.apache.juneau.annotation.Produces @Produces} annotation in place of <code>ISerializer.getMediaTypes()</code> for specifying what media types a serializer produces.<br>
Available when subclassing from {@link org.apache.juneau.serializer.Serializer}.
</li>
<li>
New {@link org.apache.juneau.annotation.Consumes @Consumes} annotation in place of <code>IParser.getMediaTypes()</code> for specifying what media types a parser consumes.<br>
Available when subclassing from {@link org.apache.juneau.parser.Parser}.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.14"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.14 (Mar 23, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.14 is a major update.
</p>
<p>
The biggest change is that the <code>RestSerializer</code>, <code>RestParser</code>, <code>RestSerializerGroup</code>, and <code>RestParserGroup</code> classes have been eliminated entirely.<br>
Instead, the existing {@link org.apache.juneau.serializer.Serializer}, {@link org.apache.juneau.parser.Parser}, {@link org.apache.juneau.serializer.SerializerGroup}, and {@link org.apache.juneau.parser.ParserGroup} classes of the core API have been augmented to replace them.
</p>
<p>
Adoptions will be required if you have previously used these classes.
</p>
<h6 class='topic'>Core API changes</h6>
<ul class='spaced-list'>
<li>
New <a class='doclink' href='org/apache/juneau/serializer/package-summary.html#TOC'>org.apache.juneau.serializer</a> package.
<ul>
<li>Entirely reworked class hierarchy to make it easier to define new serializers.</li>
<li>New {@link org.apache.juneau.serializer.WriterSerializer} base class for defining character-based serializers.</li>
<li>New {@link org.apache.juneau.serializer.OutputStreamSerializer} base class for defining byte-based serializers.</li>
<li>Updated {@link org.apache.juneau.serializer.SerializerGroup} class with full support for RFC2616 <code>Accept-Content</code> headers.</li>
<li>Improved cloning support on serializers and serializer groups.</li>
</ul>
</li>
<li>
New <a class='doclink' href='org/apache/juneau/parser/package-summary.html#TOC'>org.apache.juneau.parser</a> package.
<ul>
<li>Entirely reworked class hierarchy to make it easier to define new parsers.</li>
<li>New {@link org.apache.juneau.parser.ReaderParser} base class for defining character-based parsers.</li>
<li>New {@link org.apache.juneau.parser.InputStreamParser} base class for defining byte-based parsers.</li>
<li>Improved cloning support on parsers and parser groups.</li>
</ul>
</li>
<li>
New <a class='doclink' href='org/apache/juneau/transform/package-summary.html#TOC'>org.apache.juneau.transform</a> package.
<ul>
<li>Cleaner class structure.</li>
<li>Improved {@link org.apache.juneau.transform.BeanFilter} class for defining property filters on beans.</li>
<li>Improved {@link org.apache.juneau.utils.PojoQuery} class for defining filters on objects (previously called <code>ObjectFilter</code>).</li>
</ul>
</li>
<li>
New <a class='doclink' href='org/apache/juneau/encoders/package-summary.html#TOC'>org.apache.juneau.encoders</a> package.
<ul>
<li>Defines API for {@link org.apache.juneau.encoders.Encoder Encoders} for enabling compression in REST servlets and clients.</li>
<li>Previously, gzip compression was enabled by default. This new API allows you to plug in your own compression algorithms.</li>
<li>New {@link org.apache.juneau.encoders.GzipEncoder} class for enabling gzip compression.</li>
<li>New {@link org.apache.juneau.encoders.EncoderGroup} class for managing multiple encoders and finding them based on RFC2616 <code>Accept-Encoding</code> header values.</li>
</ul>
</li>
<li>
New <a class='doclink' href='org/apache/juneau/plaintext/package-summary.html#TOC'>org.apache.juneau.plaintext</a> package.
<ul>
<li>New {@link org.apache.juneau.plaintext.PlainTextSerializer} and {@link org.apache.juneau.plaintext.PlainTextParser} classes for serializing/parsing text/plain content.</li>
</ul>
</li>
<li>
New <a class='doclink' href='org/apache/juneau/jso/package-summary.html#TOC'>org.apache.juneau.jso</a> package.
<ul>
<li>New {@link org.apache.juneau.jso.JsoSerializer} class for serializing <code>application/x-java-serialized-object</code> content.</li>
</ul>
</li>
<li>
New <a class='doclink' href='org/apache/juneau/soap/package-summary.html#TOC'>org.apache.juneau.soap</a> package.
<ul>
<li>New {@link org.apache.juneau.soap.SoapXmlSerializer} class for serializing <code>text/xml+soap</code> content.</li>
</ul>
</li>
<li>
Improved cloning support on the {@link org.apache.juneau.BeanContext} class.
<ul>
<li>Better caching. Improved caching performance.</li>
</ul>
</li>
<li>
<code>JsonMap</code> and <code>JsonList</code> changed to {@link org.apache.juneau.ObjectMap} and {@link org.apache.juneau.ObjectList} to better reflect that they're not limited to just JSON support.
</li>
<li>
Renamed <code>PojoSwap</code> to {@link org.apache.juneau.utils.PojoQuery} to not confuse it with the new Filter API.
</li>
</ul>
<h6 class='topic'>REST server API changes</h6>
<ul class='spaced-list'>
<li>
Eliminated <code>org.apache.juneau.rest.serializers</code> and <code>org.apache.juneau.rest.parsers</code> packages.
<ul>
<li>All existing REST serializers and parsers merged into the core API.</li>
</ul>
</li>
</ul>
<h6 class='topic'>REST client API changes</h6>
<ul class='spaced-list'>
<li>
Simplified {@link org.apache.juneau.rest.client.RestClient} API.
<ul>
<li>You can now only specify a single serializer or parser per client. This significantly simplifies the code.</li>
<li>Support for {@link org.apache.juneau.encoders.Encoder Encoders}.</li>
</ul>
</li>
<li>
Eliminated <code>RestCmdLine</code> (since it's essentially redundant with CURL).
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.13"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.13 (Mar 14, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.13 is a minor update.
</p>
<h6 class='topic'>Core API changes</h6>
<ul class='spaced-list'>
<li>
New support for relative URIs.
<ul>
<li>URIs of the form <js>"foo/bar"</js> are interpreted as relative to the context root of the web application.</li>
<li>URIs of the form <js>"/foo/bar"</js> are interpreted as relative to the HTTP authority (e.g. <js>"http://myhost:9080"</js>).</li>
</ul>
</li>
<li>
New <code>SerializerContext.SERIALIZER_uriContext</code> and <code>SerializerContext.SERIALIZER_uriAuthority</code> serializer properties for specifying values for relative URIs.
</li>
<li>
New {@link org.apache.juneau.annotation.URI @URI} annotation that allows you to specify classes and bean properties as URLs that aren't <code>java.net.URI</code> or <code>java.net.URL</code>.
</li>
<li>
New {@link org.apache.juneau.html.HtmlSerializerContext#HTML_uriAnchorText} HTML serializer property for tailoring how anchor text is rendered.
</li>
<li>
Renamed <code>BeanProperty#uri</code> annotation to <code>BeanProperty#beanUri</code> to make it clear that this property represents the URI of the bean itself instead of an arbitrary property containing a URI.
</li>
<li>
Removed <code>BeanProperty#id</code> annotation.
</li>
</ul>
<h6 class='topic'>REST server API changes</h6>
<ul class='spaced-list'>
<li>
Improvements to {@link org.apache.juneau.rest.RestServlet} to automatically handle relative URIs in POJOs.
<ul>
<li><code>SerializerContext.SERIALIZER_uriContext</code> property set by default to web app context root.</li>
<li><code>SerializerContext.SERIALIZER_uriAuthority</code> property set by default to the request scheme+hostname+port.</li>
</ul>
</li>
<li>
Fixed bug involving <code>Accept-Charset</code> header in Chrome that prevented HTML output from rendering correctly in that browser.<br>
<code>Accept-Charset</code> handling should now be fully W3C compliant.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.12"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.12 (Mar 10, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.12 is a minor update.
</p>
<h6 class='topic'>Core API changes</h6>
<ul class='spaced-list'>
<li>
Relaxed method naming conventions when using {@link org.apache.juneau.annotation.BeanProperty @BeanProperty} annotation.<br>
Methods with zero parameters are interpreted as getters, and methods with one parameter are interpreted as setters.<br>
Eliminated the <code>BeanProperty.method</code> annotation, since it's now unnecessary.
</li>
</ul>
<h6 class='topic'>REST server API changes</h6>
<ul class='spaced-list'>
<li>
Significantly improved response error messages.<br>
Older messages were rather cryptic. Error conditions should be much easier to debug now.
</li>
<li>
New <code>PlainTextRestSerializer</code> class for serializing <js>"plain/text"</js> requests.<br>
Useful for debugging purposes.
</li>
<li>
<code>Readers</code> and <code>InputStreams</code> can now be passed in as <del><code>@Content</code></del> parameters if you need direct access to the HTTP body content without involving the parsers.<br>
Equivalent to previously calling {@link org.apache.juneau.rest.RestRequest#getInputStream()} and {@link org.apache.juneau.rest.RestRequest#getReader()}.
</li>
<li>
Improved support for the <code>?debug</code> parameter.<br>
Dumps better information to the log file, such as all header parameters.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.11"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.11 (Mar 8, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.11 is a moderate update.
</p>
<h6 class='topic'>REST server API changes</h6>
<ul class='spaced-list'>
<li>
New <code>UrlEncodingRestSerializer</code> and <code>UrlEncodingRestParser</code> classes.<br>
Allows parsing form posts directly to POJOs.
</li>
<li>
Support for <code>Accept</code> and <code>Content-Type</code> <js>"application/x-www-form-urlencoded"</js> added by default on {@link org.apache.juneau.rest.RestServletDefault}.
</li>
<li>
New <code><del>RestServlet.renderError(HttpServletRequest,HttpServletResponse,RestException)</del></code> method to allow customized handling of response errors.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.10"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.10 (Mar 7, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.10 is a minor update.
</p>
<h6 class='topic'>Core API changes</h6>
<ul class='spaced-list'>
<li>New {@link org.apache.juneau.ObjectMap#findKeyIgnoreCase(String)} method.
<li>HtmlSerializer will now create 2-dimensional tables for collections of mixed beans/maps if all object have the same set of property names/keys.</li>
</ul>
<h6 class='topic'>REST server API changes</h6>
<ul class='spaced-list'>
<li>New <code>RestServletProperties</code> class that defines all the class-level properties that can be set on the servlet.</li>
<li>Properties can be set through {@link org.apache.juneau.rest.annotation.RestResource#properties() @RestResource.properties} annotation, or new <code><del>RestServlet.setProperty(String,Object)</del></code> method.</li>
<li>New <js>"?noTrace"</js> URL parameter to prevent stack traces from being logged (for JUnit testing of error conditions).</li>
<li>New <code>RestServletProperties.REST_useStackTraceHashes</code> property to prevent the same stack trace from being logged multiple times.</li>
<li>New <code>RestServletProperties.REST_renderResponseStackTraces</code> property for preventing stack traces in responses for security reasons.</li>
<li>New overridable <code>RestServlet.onError(HttpServletRequest,HttpServletResponse,RestException,boolean)</code> and {@link org.apache.juneau.rest.RestServlet#onSuccess(RestRequest,RestResponse,long)} methods for plugging in your own logging and peformance monitoring.</li>
<li>Eliminated <code>RestServlet.getInitParams()</code> method, since it's now redundant with {@link org.apache.juneau.rest.RestServlet#getProperties()}.</li>
<li>Header parameters passed as URL parameters are now case-insensitive.</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.9"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.9 (Feb 26, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.9 is a moderate update.
</p>
<h6 class='topic'>Core API changes</h6>
<ul class='spaced-list'>
<li>
{@link org.apache.juneau.ini INI config file support}:
<ul>
<li>A convenient API for reading, writing, and manipulating INI files.</li>
<li>Ability to convert INI files to batch and shell environment variables.</li>
<li>Command-line interface for updating INI files.</li>
<li>Support for encoded INI file values.</li>
</ul>
</li>
<li>Support for fluent-style bean setters (setters that return the bean itself).</li>
<li>Ability to use {@link org.apache.juneau.annotation.Bean @Bean} annotation to override bean identification settings.</li>
<li>New {@link org.apache.juneau.ObjectMap#cast(Class)} method to convert <code>ObjectMaps</code> directly to beans.</li>
</ul>
<h6 class='topic'>REST server API changes</h6>
<ul class='spaced-list'>
<li>Build-in default <code>OPTIONS</code> pages.</li>
<li>New {@link org.apache.juneau.rest.annotation.RestResource#defaultRequestHeaders() @RestResource.defaultRequestHeaders} and {@link org.apache.juneau.rest.annotation.RestResource#defaultResponseHeaders() @RestResource.defaultResponseHeaders} annotations.</li>
<li>New {@link org.apache.juneau.rest.annotation.RestMethod#serializers() @RestMethod.serializers} and {@link org.apache.juneau.rest.annotation.RestMethod#parsers() @RestMethod.parsers} annotations.</li>
<li>New {@link org.apache.juneau.rest.annotation.RestMethod#properties() @RestMethod.properties} annotation.</li>
<li>New {@link org.apache.juneau.rest.annotation.RestMethod#defaultRequestHeaders() @RestMethod.defaultRequestHeaders} annotation.</li>
<li>New {@link org.apache.juneau.rest.annotation.RestMethod#matchers() @RestMethod.matchers} annotation and {@link org.apache.juneau.rest.RestMatcher} class.</li>
<li><code>Readers</code> and <code>InputStreams</code> can be specified on <del><code>@Content</code></del> annotated parameters.</li>
<li>New <del><code>@HasParam</code></del> annotation.</li>
<li>Full RFC2616 support for matching <code>Accept</code> headers to serializers.</li>
</ul>
<h6 class='topic'>Other notes</h6>
<ul class='spaced-list'>
<li>Smaller library size (460kB).</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.8"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.8 (Jan 30, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.8 is a minor update.
</p>
<ul class='spaced-list'>
<li>
New {@link org.apache.juneau.ini INI file} support.
<ul>
<li>Makes reading, updating, and manipulating INI configuration files a snap. </li>
<li>Supports automatic conversion of data types in line with the functionality of the rest of the product.</li>
<li>Comments and layout of INI files are persisted during saves. </li>
</ul>
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.7"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.7 (Jan 20, 2013)</h3>
<div class='topic'>
<p>
Juno 5.0.0.7 is a major update.
</p>
<h6 class='topic'>Core API updates</h6>
<ul class='spaced-list'>
<li>Combined previous 3 libraries into a single library.</li>
<li>
New {@link org.apache.juneau.parser.ParserListener} class.<br>
Adds ability to find and process unknown bean properties during parsing.
</li>
<li>
Enhancements to {@link org.apache.juneau.xml.XmlParser}:
<ul>
<li>Coalescing support</li>
<li>Validations support</li>
<li>Support for replacing entity references</li>
<li>Resolver support</li>
<li>Event allocator support</li>
<li>Trim-whitespace support</li>
</ul>
</li>
<li>
Enhanced XML support:
<ul>
<li>
New {@link org.apache.juneau.xml.annotation.Xml#format() @Xml.format} annotation.<br>
Controls how POJOs get serialized to XML.<br>
Also allows you to collapse collections and arrays.
</li>
<li>
New <code>@Xml.namespaces</code> annotation.<br>
Namespaces can be defined at package, class, method, or field levels.
</li>
<li>
New <code>@Xml.nsUri</code> annotation.<br>
Shortcut for specifying namespace URIs.
</li>
<li>
New <code>@Xml.valAttr</code> annotation.<br>
Serializes a bean property value as an attribute.
</li>
<li>Ability to override XS and XSI namespaces on XML and RDF/XML serializers.</li>
<li>Ability to override RDF namespace on RDF/XML serializer.</li>
<li>New more-efficient namespace resolution.</li>
</ul>
</li>
<li>
New configurable property classes for everything are now structured better and easier to locate and identify through the following new classes:
<ul>
<li>{@link org.apache.juneau.BeanContext}</li>
<li>{@link org.apache.juneau.serializer.SerializerContext}</li>
<li>{@link org.apache.juneau.parser.ParserContext}</li>
</ul>
</li>
<li>
Enhancements to {@link org.apache.juneau.BeanContext}:
<ul>
<li>
Ability to mark bean properties as hidden using <code>@BeanProperty.hidden()</code> so that they don't get serialized.
</li>
<li>
Simplified <code>ClassType</code> {@link org.apache.juneau.ClassMeta} API.<br>
Combined 4 classes into a single class.
</li>
<li>
New <del><code>@Bean.filter</code></del> and <del><code>@BeanProperty.filter</code></del> annotations.<br>
Used for defining filters on bean classes and bean properties instead of just globally through <code>BeanContext.addTransforms(Class[])</code>.
</li>
<li>
New {@link org.apache.juneau.PropertyNamer} API / {@link org.apache.juneau.annotation.Bean#propertyNamer() @Bean.propertyNamer} annotation.<br>
Used for customizing bean property names.
</li>
<li>
New <del><code>@BeanProperty.beanUri</code></del> and <del><code>@BeanProperty.id</code></del> annotations.<br>
Used for associating beans with URLs and IDs.<br>
Used by XML serializer to add a url attribute on a bean element.<br>
Used by RDF/XML serializer to construct <code>rdf:resource</code> attributes.
</li>
<li>
New {@link org.apache.juneau.annotation.BeanProperty#properties() @BeanProperty.properties} annotation.
Used for limiting properties on child elements.
</li>
</ul>
</li>
<li>
Automatic support for {@link java.net.URL} and {@link java.net.URI} objects.
<ul>
<li>Converted to hrefs in HTML.</li>
<li>Converted to url attributes in XML.</li>
<li>Converted to resource:about attributes in RDF/XML.</li>
</ul>
</li>
<li>
Improvements to Javadocs.
</li>
<li>
Improved {@link org.apache.juneau.utils.PojoQuery} support.
</li>
</ul>
<h6 class='topic'>REST client updates</h6>
<ul class='spaced-list'>
<li>GZIP compression support.</li>
<li>Bug fixes.</li>
</ul>
<h6 class='topic'>REST server updates</h6>
<ul class='spaced-list'>
<li>
Support for overriding bean context and serializer properties in a REST method call through new {@link org.apache.juneau.rest.RestResponse#setProperty(String,Object)} method.<br>
For example, allows you to control whitespace options on a per-request basis.
</li>
<li>
Several new annotations on REST servlets:
<ul>
<li><code>@RestResource.filters()</code> - Associate post-formatting filters on a resource level.</li>
<li>{@link org.apache.juneau.rest.annotation.RestResource#guards() @RestResource.guards} - Associate resource-level guards.</li>
<li>{@link org.apache.juneau.rest.annotation.RestResource#messages() @RestResource.messages} - Associate a resource bundle with a REST servlet. Comes with several convenience methods for looking up messages for the client locale.</li>
<li>{@link org.apache.juneau.rest.annotation.RestResource#properties() @RestResource.properties} - Override default bean context, serializer, and parser properties though an annotation.</li>
</ul>
</li>
<li>
Several new annotations on REST methods:
<ul>
<li><code>@RestMethod.filters()</code> - Associate post-formatting filters on a method level.</li>
<li>{@link org.apache.juneau.rest.annotation.RestMethod#guards() @RestMethod.guards} - Associate method-level guards.</li>
</ul>
</li>
<li>
New annotations on REST method parameters with automatic conversion:
<ul>
<li><del><code>@Attr</code></del> - A parameter or URL variable value as a parsed POJO.</li>
<li><del><code>@Param</code></del> - A query parameter value as a parsed POJO.</li>
<li>{@link org.apache.juneau.rest.annotation.PathRemainder @PathRemainder} - The remainder after a URL pattern match as a String.</li>
<li>{@link org.apache.juneau.rest.annotation.Header @Header} - An HTTP header value as a parsed POJO.</li>
<li><del><code>@Content</code></del> - The HTTP content as a parsed POJO.</li>
<li>{@link org.apache.juneau.rest.annotation.Method @Method} - The HTTP method name as a String.</li>
</ul>
</li>
<li>
HTTP response content POJOs can now simply be returned from methods instead of calling {@link org.apache.juneau.rest.RestResponse#setOutput(Object)}.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.6"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.6 (Oct 30, 2012)</h3>
<div class='topic'>
<p>
Juno 5.0.0.6 is a minor update that fixes a small bug in 5.0.0.5.
</p>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.5"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.5 (Oct 29, 2012)</h3>
<div class='topic'>
<p>
Juno 5.0.0.5 is a major update.
</p>
<ul class='spaced-list'>
<li>New <code><ja>@RestChild</ja></code> annotation for identifying child resources.</li>
<li>
New <code>traversable</code> and <code>filterable</code> attributes added to {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod} annotation.<br>
Eliminates the need for <code>PojoResource</code> and <code>FilteredRestResource</code> classes.
</li>
<li>Simplified client API. Easier to use when making multiple connections to the same server.</li>
<li>Support for pluggable authentication in the client API.</li>
<li>Support for authenticating against Jazz Team Servers.</li>
<li>Support for rendering package-level Javadocs in REST resources.</li>
<li>Support for parsing of header values into specific object types.</li>
<li>Changed default XML representation to not include JSON-type attributes. Produces cleaner XML.</li>
<li>
New <code>resourceUri</code> attributed added to <ja>@Bean</ja> annotation to associate beans with resource URIs.
<ul>
<li>Used for automatically creating hyperlinks in {@link org.apache.juneau.html.HtmlSerializer}.</li>
<li>Used for automatically creating <xa>uri</xa> attributes in {@link org.apache.juneau.xml.XmlSerializer}.</li>
<li>Used for automatically creating <xa>rdf:about</xa> attributes in <code>RdfXmlSerializer</code>.</li>
</ul>
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.4"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.4 (Oct 7, 2012)</h3>
<div class='topic'>
<p>
Juno 5.0.0.4 is a minor update.
</p>
<ul class='spaced-list'>
<li>
New {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod} annoation on {@link org.apache.juneau.rest.RestServlet} methods.<br>
Allows the usage of URL pattern matching and automatic conversion of URL variables to arguments passed to method handlers.<br>
See {@link org.apache.juneau.rest.RestServlet} for more information.
</li>
<li>
Enhancements to <code><del>BeanContext.convertToType(Object,Class)</del></code> to be able to convert <code>Strings</code> to classes with
<code>fromString(String)</code>/<code>valueOf(String)</code> static methods or <code>T(String)</code> constructors.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.3"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.3 (Oct 3, 2012)</h3>
<div class='topic'>
<p>
Juno 5.0.0.3 is a minor update.
</p>
<ul class='spaced-list'>
<li>
Support for parsing into read-only beans (i.e. beans with only getters, property values set through constructor args).<br>
To support this, the {@link org.apache.juneau.annotation.BeanConstructor @BeanConstructor} annotation has been added.
</li>
<li>
Merged separate settings classes back into their base classes (simplifies the API).
</li>
<li>
{@link org.apache.juneau.serializer.SerializerGroup SerializerGroups} and {@link org.apache.juneau.parser.ParserGroup ParserGroups} now share {@link org.apache.juneau.BeanContext BeanContexts} to reduce memory consumption of class type metadata.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.2"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.2 (Sept 28, 2012)</h3>
<div class='topic'>
<p>
Juno 5.0.0.2 is a minor update.
</p>
<ul class='spaced-list'>
<li>
Improvements to Javadocs. Most of the information in the Juno Starters Guide wiki has been moved into the overview and package-level javadocs.<br>
Since the information is now written in HTML, you can now copy and paste the code examples directly from the Javadocs.<br>
The code examples are also syntax-highlighted using CSS.
</li>
<li>
Support for defining default XML namespaces on packages and classes for the XML and RDF serializers.
</li>
<li>
Restructured the packages along content type support (e.g. all JSON support moved to <code>org.apache.juneau.json</code>).
</li>
<li>
Automatic support for parsing maps with <code>Enum</code> keys, and parsing <code>Enum</code> strings.<br>
This was previously possible using filters, but now it's built-in for all the parsers.
</li>
<li>
Replaced the <code>ObjectList.toXArray()</code> methods with a new <code>elements(Class&lt;T&gt; type)</code> method that's more efficient and avoids creating an unnecessary array.
</li>
<li>
Support for parsing into beans with read-only properties.<br>
New {@link org.apache.juneau.annotation.BeanConstructor @BeanConstructor} annotation allows you to specify bean property values to be passed in through a constructor.
</li>
<li>
Separated the rest library into separate independent client and server libraries.<br>
Use one, use both, it's up to you.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.1"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.1 (Jun 14, 2012)</h3>
<div class='topic'>
<p>
Juno 5.0.0.1 is a moderate update.
</p>
<ul class='spaced-list'>
<li>
New support for generating XML-Schema documents from POJO models.
</li>
<li>
New support for serializing to RDF/XML.
</li>
</ul>
</div>
<!-- ======================================================================================================== -->
<a id="5.0.0.0"></a>
<h3 class='topic' onclick='toggle(this)'>5.0.0.0 (Jun 11, 2012)</h3>
<div class='topic'>
<p>
Version 5.0 marks a major release milestone for the Juno/JJSON library.
It is now available for download from iRAM under the name "Juno (previously JJSON)".
The Juno Starters Guide has been updated to reflect new functionality in this release.
</p>
<ul class='spaced-list'>
<li>
New name.<br>
Unfortunately, "JJSON" was already trademarked by another similar library.
Therefore, it's been renamed "Juno" (after the Roman goddess and wife of Jupiter) which does not appear to have any similar trademark issues (crosses fingers).
The name is also a play on the word "Uno", indicating that this is a single simple unifying interface of several kinds of technology.
</li>
<li>
Simplified APIs for working with beans.<br>
Significant improvements have been made to the parsers to make it easier to convert serialized POJOs back into their original forms.
</li>
<li>
Serializer/Parser classes now directly subclass from {@link org.apache.juneau.BeanContext}.<br>
In previous releases, if you wanted to change the way beans were handled by the serializers and parsers, you had to construct a separate bean map factory and pass it to the serializer or parser.
Now, you can call the bean map factory methods directly on the serializer or parser class.
</li>
<li>
Simplified Filter API for handling non-standard POJOs.<br>
The API for handling non-standard POJOs has been simplified by introducing the concept of a <del><code>Transform</code></del> class, which is associated with the <code>BeanContext</code> class (and thus the Serializer and Parser classes too) through the <code>BeanContext.addTransforms(Class[])</code> method.<br>
Two new subclasses of <del><code>Transform</code></del>:
<ul>
<li>{@link org.apache.juneau.transform.BeanFilter} - Filter POJO beans.</li>
<li>{@link org.apache.juneau.transform.PojoSwap} - Filter POJOs that aren't beans.</li>
</ul>
This new API replaces the previous separate <code>Cast</code> and <code>BeanFilter</code> APIs which were considerably more complicated and puts them under a common API.
</li>
<li>
Elimination of <code>_class</code> attributes in parsable output.<br>
One of the complaints about the previous version of JJSON was that if you wanted to have the resulting JSON or XML be parsable back into beans, you had to enable the <js>"addClassAttrs"</js> property on the bean map factory class so that <js>"_class"</js> attributes could be added to the output.<br>
This requirement is virtually eliminated in v5. In many cases, the parsers are able to determine through reflection what the correct target type is based on the top-level class passed in on the parse method.
</li>
<li>
Performance improvements.<br>
Several significant performance improvements have been made in this release.
<ul>
<li>
New Reader-based JSON parser.<br>
Previously, the JSON parser required that the entire JSON text be loaded into memory as a String before being parsed.
The new JSON parser is Reader-based which significantly reduces memory consumption.
</li>
<li>
New StAX-based XML parser.<br>
The old XML parser was based on DOM. The new XML parser uses a StAX parser which significantly reduces memory consumption.
</li>
<li>
Caching of reflection data in the <code>BeanMap</code> API.<br>
The number of reflection calls have been significantly reduced in the <code>BeanMap</code> API code.
Reflection is used to determine the class types of property values on beans.
This information is now cached and persisted so that the reflection API calls to determine class types are only performed the first time a bean type is encountered.
</li>
<li>
Automatic support for GZIP compression/decompression in <code>RestServlets</code>.<br>
This is completely transparent to the developer.
The output writer is negotiated by the framework to automatically handle compression and charset requests without the developer needing to know anything about it.
</li>
</ul>
</li>
<li>
Cognos/XML support.
</li>
<li>
JSON-schema support.
</li>
<li>
New {@link org.apache.juneau.utils.PojoIntrospector} class.
</li>
<li>
Significant REST servlet API improvements.
<ul>
<li>
Defining child resources is considerably simpler now.
In addition to the standard doX() methods for handling the requests for the current resource, you can also define getX() methods for returning child resources which automatically become available under the child URL specified by the getter name.
</li>
<li>
Initialization of the child resources occurs automatically when the parent resource initialization occurs.
</li>
<li>
Other improvments have been made in the area of automatic negotiation of input and output type streams.
For example, automatic support is provided for GZIP (<code>Accept-Encoding: gzip</code>) and charsets (e.g <code>Accept-Charset: SJIS</code>) on both incoming and outgoing data.
It's all transparent from a developers perspective.
The developer simply working with POJOs, and all details about content types, encoding, charsets, and so forth are handled by the framework.
</li>
<li>
Support for generating complex <code>OPTIONS</code> pages for resources.
</li>
</ul>
</li>
<li>
Automatic support for SOAP XML output on <js>"text/soap+xml"</js> requests against <code>RestServlet</code>.
</li>
<li>
Support for XML namespaces.
</li>
<li>
Support for setting the XML root element name by either passing in a parameter on the serializer, or by specifying it via a <ja>@Bean</ja> annotation.
</li>
<li>
Support for loading beans directly from Readers and Strings.
</li>
<li>
Parsing support for POJOs of type <code>Enum</code>.
</li>
<li>
Significant improved support for various flavors of parameterized types, such as subclasses of parameterized types (e.g. <code>MyBeanList <jk>extends</jk> LinkedList&lt;MyBean&gt;</code>).
</li>
<li>
Improved ordering of bean properties (should now be ordered as they are defined in the class).
</li>
<li>
Various default filters provided:
<ul>
<li>byte[]&lt;--&gt;Base64 encoded strings</li>
<li>Date/Calendar&lt;--&gt;ISO8601/RFC822/Long</li>
</ul>
</li>
<li>
New {@link org.apache.juneau.html.HtmlParser} and {@link org.apache.juneau.urlencoding.UrlEncodingParser} classes.
</li>
<li>
HtmlSerializer now produces XHTML.
</li>
</ul>
</div>
</div>
</body>