blob: 134e6c0d5477b4c2baa326bf9275f1034a4c8959 [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'>
<link rel='icon' type='image/png' href='http://www.apache.org/favicons/favicon-32x32.png' sizes='32x32'>
<link rel='icon' type='image/png' href='http://www.apache.org/favicons/favicon-194x194.png' sizes='194x194'>
<link rel='icon' type='image/png' href='http://www.apache.org/favicons/favicon-96x96.png' sizes='96x96'>
<link rel='icon' type='image/png' href='http://www.apache.org/favicons/android-chrome-192x192.png' sizes='192x192'>
<link rel='icon' type='image/png' href='http://www.apache.org/favicons/favicon-16x16.png' sizes='16x16'>
<link rel='shortcut icon' href='http://www.apache.org/favicons/favicon.ico'>
<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>
<h1 class='title'>Apache Juneau {@property juneauVersion} Documentation</h1>
<h1 class='preview-title'>Apache Juneau {@property juneauVersion} Documentation Preview</h1>
<h2 class='preview-section todo'>Documentation in progress</h2>
<h2 class='preview-section new'>New documentation in {@property juneauVersion}</h2>
<h2 class='preview-section updated'>Updated documentation in {@property juneauVersion}</h2>
<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>
<p>
Apache Juneau&trade; is a single cohesive Java ecosystem consisting of the following parts:
</p>
<table class='styled w800'>
<tr>
<th>Group</th><th>Component</th><th>Description</th>
</tr>
<tr class='dark bb'>
<td rowspan="4" style='text-align:center;font-weight:bold;padding:20px;'>Juneau Core</td>
<td class='code'><a class='doclink' href='#juneau-marshall'>juneau-marshall</a></td>
<td>
A universal toolkit for marshalling POJOs to a wide variety of content types using a common framework with no external library dependencies.
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='#juneau-marshall-rdf'>juneau-marshall-rdf</a></td>
<td>
Extended marshalling support for RDF languages.
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='#juneau-dto'>juneau-dto</a></td>
<td>
A variety of predefined DTOs for serializing and parsing languages such as HTML5, Swagger and ATOM.
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='#juneau-config'>juneau-config</a></td>
<td>
A sophisticated configuration file API.
</td>
</tr>
<tr class='light bb'>
<td rowspan="5" style='text-align:center;font-weight:bold;padding:20px;'>Juneau REST</td>
<td class='code'><a class='doclink' href='#juneau-rest-server'>juneau-rest-server</a></td>
<td>
A universal REST server API for creating Swagger-based self-documenting REST interfaces using POJOs, simply deployed as
one or more top-level servlets in any Servlet 3.1.0+ container.
</td>
</tr>
<tr class='light bb'>
<td class='code'><a class='doclink' href='#juneau-rest-server-springboot'>juneau-rest-server-springboot</a></td>
<td>
Spring boot integration support.
</td>
</tr>
<tr class='light bb'>
<td class='code'><a class='doclink' href='#juneau-rest-server-jaxrs'>juneau-rest-server-jaxrs</a></td>
<td>
JAX/RS integration support.
</td>
</tr>
<tr class='light bb'>
<td class='code'><a class='doclink' href='#juneau-rest-client'>juneau-rest-client</a></td>
<td>
A universal REST client API for interacting with Juneau or 3rd-party REST interfaces using POJOs and proxy interfaces.
</td>
</tr>
<tr class='light bb'>
<td class='code'><a class='doclink' href='#juneau-rest-mock'>juneau-rest-mock</a></td>
<td>
Mocking APIs for server-less end-to-end testing of REST server and client APIs.
</td>
</tr>
<tr class='dark bb'>
<td rowspan="4" style='text-align:center;font-weight:bold;padding:20px;'>Examples</td>
<td class='code'><a class='doclink' href='#juneau-examples-core'>juneau-examples-core</a></td>
<td>
Juneau Core API examples.
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='#juneau-examples-rest'>juneau-examples-rest</a></td>
<td>
Juneau REST API examples.
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='#juneau-examples-rest-jetty'>juneau-examples-rest-jetty</a></td>
<td>
Juneau REST API examples using Jetty deployment.
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='#juneau-examples-rest-springboot'>juneau-examples-rest-springboot</a></td>
<td>
Juneau REST API examples using Spring Boot deployment.
</td>
</tr>
</table>
<a href='#TOC' id='TOC'></a><h5 class='toc'>Table of Contents</h5>
<ol class='toc'>
<li><p class='toc2'><a class='doclink' href='#Introduction'>Introduction</a></p>
<ol>
<li><p class=''><a class='doclink' href='#Introduction.Features'>Features</a></p>
<li><p class=''><a class='doclink' href='#Introduction.Components'>Components</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-marshall'>juneau-marshall</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.Serializers'>Serializers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Parsers'>Parsers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Marshalls'>Marshalls</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.HttpPartSerializers'>HTTP Part Serializers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.HttpPartParsers'>HTTP Part Parsers</a></p>
<li><p class='updated'><a class='doclink' href='#juneau-marshall.ConfigurableProperties'>Configurable Properties</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.ConfigurableProperties.Common'>Common Serializer Properties</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.ConfigurableProperties.CommonSerializer'>Common Serializer Properties</a></p>
<li><p class='update'><a class='doclink' href='#juneau-marshall.ConfigurableProperties.CommonParser'>Common Parser Properties</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.ConfigurableAnnotations'>Configurable Annotations</a></p>
<li><p class='todo'><a class='doclink' href='#juneau-marshall.ClassMethodAnnotations'>Class/Method Annotations</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.ObjectMap'>ObjectMap and ObjectList</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Groups'>SerializerGroups and ParserGroups</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.ContextsBuildersSessionsPropertyStores'>Contexts, Builders, Sessions, and PropertyStores</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms'>Transforms</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.PojoSwaps'>PojoSwaps</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.DefaultPojoSwaps'>Default PojoSwaps</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.AutoPojoSwaps'>Auto-detected POJO swaps</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.PerMediaTypePojoSwaps'>Per-media-type PojoSwaps</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.OneWayPojoSwaps'>One-way PojoSwaps</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.SwapAnnotation'>@Swap Annotation</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.TemplatedSwaps'>Templated Swaps</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.SurrogateClasses'>Surrogate Classes</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.BeanAnnotation'>@Bean Annotation</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.BeanpAnnotation'>@Beanp Annotation</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.BeancAnnotation'>@Beanc Annotation</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.BeanIgnoreAnnotation'>@BeanIgnore Annotation</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.NamePropertyAnnotation'>@NameProperty Annotation</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.ParentPropertyAnnotation'>@ParentProperty Annotation</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.PojoBuilders'>POJO Builders</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.BeanFilters'>BeanFilter Class</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.InterfaceFilters'>Interface Filters</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.StopClasses'>Stop Classes</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Transforms.BypassSerialization'>Bypass Serialization using Readers and InputStreams</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.BeanDictionaries'>Bean Names and Dictionaries</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.BeanDictionaries.BeanSubTypes'>Bean Subtypes</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.VirtualBeans'>Virtual Beans</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.Recursion'>Non-Tree Models and Recursion Detection</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.ParsingIntoGenericModels'>Parsing into Generic Models</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.ReadingContinuousStreams'>Reading Continuous Streams</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.URIs'>URIs</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.JacksonComparison'>Comparison with Jackson</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.PojoCategories'>POJO Categories</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.JsonDetails'>JSON Details</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.JsonDetails.Methodology'>JSON Methodology</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.JsonDetails.Serializers'>JSON Serializers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.JsonDetails.SimplifiedJson'>Simplified JSON</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.JsonDetails.Parsers'>JSON Parsers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.JsonDetails.JsonAnnotation'>@Json Annotation</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.JsonDetails.JsonSchema'>JSON-Schema Support</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.XmlDetails'>XML Details</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.XmlDetails.Methodology'>XML Methodology</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.XmlDetails.Serializers'>XML Serializers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.XmlDetails.Parsers'>XML Parsers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.XmlDetails.BeanTypeNameAnnotation'>@Bean(typeName) Annotation</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.XmlDetails.XmlChildNameAnnotation'>@Xml(childName) Annotation</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.XmlDetails.XmlFormatAnnotation'>@Xml(format) Annotation</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.XmlDetails.Namespaces'>Namespaces</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.XmlDetails.XmlSchema'>XML-Schema Support</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.HtmlDetails'>HTML Details</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.HtmlDetails.Methodology'>HTML Methodology</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.HtmlDetails.Serializers'>HTML Serializers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.HtmlDetails.Parsers'>HTML Parsers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.HtmlDetails.HtmlAnnotation'>@Html Annotation</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.HtmlDetails.HtmlRenderAnnotation'>@Html(render) Annotation</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.HtmlDetails.HtmlDocSerializer'>HtmlDocSerializer</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.HtmlDetails.BasicHtmlDocTemplate'>BasicHtmlDocTemplate</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.HtmlDetails.CustomTemplates'>Custom Templates</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.HtmlDetails.HtmlSchema'>HTML-Schema Support</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.UonDetails'>UON Details</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.UonDetails.Methodology'>UON Methodology</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.UonDetails.Serializers'>UON Serializers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.UonDetails.Parsers'>UON Parsers</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.UrlEncodingDetails'>URL-Encoding Details</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.UrlEncodingDetails.Methodology'>URL-Encoding Methodology</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.UrlEncodingDetails.Serializers'>URL-Encoding Serializers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.UrlEncodingDetails.Parsers'>URL-Encoding Parsers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.UrlEncodingDetails.UrlEncodingAnnotation'>@UrlEncoding Annotation</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.MsgPackDetails'>MessagePack Details</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.MsgPackDetails.Serializers'>MessagePack Serializers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.MsgPackDetails.Parsers'>MessagePack Parsers</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.OpenApiDetails'>OpenAPI Details</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.OpenApiDetails.Methodology'>OpenAPI Methodology</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.OpenApiDetails.Serializers'>OpenAPI Serializers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.OpenApiDetails.Parsers'>OpenAPI Parsers</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.SimpleVariableLanguage'>Simple Variable Language</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.SimpleVariableLanguage.SvlVariables'>SVL Variables</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.SimpleVariableLanguage.VarResolvers'>VarResolvers and VarResolverSessions</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.SimpleVariableLanguage.DefaultVarResolver'>VarResolver.DEFAULT</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall.SimpleVariableLanguage.OtherNotes'>Other Notes</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-marshall.BestPractices'>Best Practices</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-marshall-rdf'>juneau-marshall-rdf</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-marshall-rdf.RdfDetails'>RDF Details</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-marshall-rdf.RdfDetails.Serializers'>RDF Serializers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall-rdf.RdfDetails.Parsers'>RDF Parsers</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall-rdf.RdfDetails.RdfAnnotation'>@Rdf Annotation</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall-rdf.RdfDetails.Namespaces'>Namespaces</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall-rdf.RdfDetails.UriProperties'>URI Properties</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall-rdf.RdfDetails.RootProperty'>Root Property</a></p>
<li><p class=''><a class='doclink' href='#juneau-marshall-rdf.RdfDetails.TypedLiterals'>Typed Literals</a></p>
</ol>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-dto'>juneau-dto</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-dto.HTML5'>HTML5</a></p>
<li><p class=''><a class='doclink' href='#juneau-dto.Atom'>Atom</a></p>
<li><p class=''><a class='doclink' href='#juneau-dto.Swagger'>Swagger</a></p>
<li><p class=''><a class='doclink' href='#juneau-dto.SwaggerUI'>Swagger UI</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-config'>juneau-config</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-config.Overview'>Overview</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-config.Overview.SyntaxRules'>Syntax Rules</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-config.EntryTypes'>Entry Types</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-config.EntryTypes.PrimitiveTypes'>Primitive Types</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.EntryTypes.POJOs'>POJOs</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.EntryTypes.Arrays'>Arrays</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.EntryTypes.Collections'>Collections</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.EntryTypes.BinaryData'>Binary Data</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-config.Variables'>Variables</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-config.Variables.LogicVariables'>Logic Variables</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-config.EncodedEntries'>Encoded Entries</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.SectionMaps'>Section Maps</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.SectionBeans'>Section Beans</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.SectionInterfaces'>Section Interfaces</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.SettingValues'>Setting Values</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-config.SettingValues.FileSystemChanges'>File System Changes</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.SettingValues.CustomEntrySerialization'>Custom Entry Serialization</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.SettingValues.BulkSettingValues'>Setting Values in Bulk</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-config.Listeners'>Listeners</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.Serializing'>Serializing</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.Imports'>Imports</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.ConfigStores'>Config Stores</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-config.ConfigStores.ConfigMemoryStore'>ConfigMemoryStore</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.ConfigStores.ConfigFileStore'>ConfigFileStore</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.ConfigStores.CustomConfigStores'>Custom ConfigStores</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.ConfigStores.ConfigStoreListeners'>ConfigStore Listeners</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-config.ReadOnlyConfigs'>Read-only Configs</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.ClosingConfigs'>Closing Configs</a></p>
<li><p class=''><a class='doclink' href='#juneau-config.SystemDefaultConfig'>System Default Config</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-rest-server'>juneau-rest-server</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HelloWorldExample'>Hello World Example</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.ClassHierarchy'>Class Hierarchy</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Instantiation'>Instantiation</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Instantiation.RestServlet'>RestServlet</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Instantiation.BasicRestServlet'>BasicRestServlet</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Instantiation.BasicRest'>BasicRest</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Instantiation.Children'>Children</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Instantiation.BasicRestServletGroup'>BasicRestServletGroup</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Instantiation.BasicRestGroup'>BasicRestGroup</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Instantiation.ResourceResolvers'>Resource Resolvers</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Instantiation.LifecycleHooks'>Lifecycle Hooks</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Rest'>@Rest</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Rest.AnnotationInheritance'>Annotation Inheritance</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Rest.RestPath'>@Rest(path)</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestContext'>RestContext</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod'>@RestMethod</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.MethodParameters'>Java Method Parameters</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.RestRequest'>RestRequest</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.RestResponse'>RestResponse</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.RequestBody'>RequestBody</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.RequestHeaders'>RequestHeaders</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.RequestAttributes'>RequestAttributes</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.RequestQuery'>RequestQuery</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.RequestFormData'>RequestFormData</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.RestMethodPath'>@RestMethod(path)</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.RequestPathMatch'>RequestPathMatch</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.MethodReturnTypes'>Method Return Types</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.ReaderResource'>ReaderResource</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.StreamResource'>StreamResource</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.RestMethodMatchers'>@RestMethod(matchers)</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.PredefinedResponses'>Predefined Responses</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.PredefinedExceptions'>Predefined Exceptions</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestMethod.PredefinedHelperBeans'>Predefined Helper Beans</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.restRPC'>restRPC</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.OpenApiSchemaPartParsing'>OpenAPI Schema Part Parsing</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.OpenApiSchemaPartSerializing'>OpenAPI Schema Part Serializing</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HttpPartAnnotations'>HTTP-Part Annotations</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HttpPartAnnotations.Body'>@Body</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HttpPartAnnotations.FormData'>@FormData</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HttpPartAnnotations.HasFormData'>@HasFormData</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HttpPartAnnotations.Query'>@Query</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HttpPartAnnotations.HasQuery'>@HasQuery</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HttpPartAnnotations.Header'>@Header</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HttpPartAnnotations.Path'>@Path</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HttpPartAnnotations.Request'>@Request</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HttpPartAnnotations.Response'>@Response</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HttpPartAnnotations.ResponseHeader'>@ResponseHeader</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HttpPartAnnotations.ResponseStatus'>@ResponseStatus</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HandlingFormPosts'>Handling Form Posts</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HandlingMultiPartFormPosts'>Handling Multi-Part Form Posts</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Serializers'>Serializers</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Parsers'>Parsers</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.ConfigurableProperties'>Configurable Properties</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.ConfigurableAnnotations'>Configurable Annotations</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Transforms'>Transforms</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.URIs'>URIs</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Guards'>Guards</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RoleGuards'>Role guards</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Converters'>Converters</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Messages'>Messages</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Encoders'>Encoders</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.SvlVariables'>SVL Variables</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.ConfigurationFiles'>Configuration Files</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.StaticFiles'>Static files</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.ClientVersioning'>Client Versioning</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestInfoProvider'>RestInfoProvider</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.RestInfoProvider.BasicRestInfoProvider'>BasicRestInfoProvider</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Swagger'>Swagger</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Swagger.BasicRestServlet'>BasicRestServlet</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Swagger.BasicSwaggerInfo'>Basic Swagger Info</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Swagger.Tags'>Tags</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Swagger.Operations'>Operations</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Swagger.Parameters'>Parameters</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Swagger.ParameterExamples'>Parameter Examples</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Swagger.Responses'>Responses</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Swagger.ResponseExamples'>Response Examples</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Swagger.Models'>Models</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Swagger.Stylesheet'>SwaggerUI.css</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HtmlDocAnnotation'>@HtmlDocConfig</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HtmlDocAnnotation.UIvsDI'>User Interfaces (UI) vs. Developer Interfaces (DI)</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HtmlDocAnnotation.Widgets'>Widgets</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets'>Predefined Widgets</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HtmlDocAnnotation.UiCustomization'>UI Customization</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HtmlDocAnnotation.Stylesheets'>Stylesheets</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server.DefaultHeaders'>Default Headers</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.LoggingAndDebugging'>Logging / Debugging</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HttpStatusCodes'>HTTP Status Codes</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.OverloadingHttpMethods'>Overloading HTTP Methods</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.BuiltInParameters'>Built-in Parameters</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.CustomSerializersAndParsers'>Custom Serializers and Parsers</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.UsingWithOsgi'>Using with OSGi</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.Injection'>Using with Spring and Injection frameworks</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.HTTP2'>Using HTTP/2 features</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server.OtherNotes'>Other Notes</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-rest-server-jaxrs'>juneau-rest-server-jaxrs</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server-jaxrs.BaseProvider'>Juneau JAX-RS Provider</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-rest-server-springboot'>juneau-rest-server-springboot</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-rest-server-springboot.Overview'>Overview</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-server-springboot.ChildResources'>Child Resources</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-rest-client'>juneau-rest-client</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-rest-client.RestProxies'>REST Proxies</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-rest-client.RestProxies.Remote'>@Remote</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.RestProxies.RemoteMethod'>@RemoteMethod</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.RestProxies.Body'>@Body</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.RestProxies.FormData'>@FormData</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.RestProxies.Query'>@Query</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.RestProxies.Header'>@Header</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.RestProxies.Path'>@Path</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.RestProxies.Request'>@Request</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.RestProxies.Response'>@Response</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.RestProxies.DualPurposeInterfaces'>Dual-purpose (end-to-end) interfaces</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-rest-client.SSL'>SSL Support</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.Authentication'>Authentication</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-rest-client.Authentication.BASIC'>BASIC Authentication</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.Authentication.FORM'>FORM-based Authentication</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.Authentication.OIDC'>OIDC Authentication</a></p>
</ol>
<li><p class=''><a class='doclink' href='#juneau-rest-client.ResponsePatterns'>Using Response Patterns</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.PipingOutput'>Piping Response Output</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.Debugging'>Debugging</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.Logging'>Logging</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.Interceptors'>Interceptors</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-client.Other'>Other Useful Methods</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-rest-mock'>juneau-rest-mock</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-rest-mock.MockRest'>MockRest</a></p>
<li><p class=''><a class='doclink' href='#juneau-rest-mock.MockRemote'>MockRemote</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-microservice-core'>juneau-microservice-core</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-microservice-core.Overview'>Microservice Overview</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-core.LifecycleMethods'>Lifecycle Methods</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-core.Args'>Args</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-core.Manifest'>Manifest</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-core.Config'>Config</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-core.SystemProperties'>System properties</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-core.VarResolver'>VarResolver</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-core.ConsoleCommands'>Console Commands</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-core.Logging'>Logging</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-core.Listeners'>Listeners</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-microservice-jetty'>juneau-microservice-jetty</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-microservice-jetty.Overview'>Overview</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-jetty.LifecycleMethods'>Lifecycle Methods</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-jetty.ResourceClasses'>Resource Classes</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-jetty.PredefinedResourceClasses'>Predefined Resource Classes</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-jetty.Config'>Config</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-jetty.JettyXml'>Jetty.xml file</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-jetty.UiCustomization'>UI Customization</a></p>
<li><p class=''><a class='doclink' href='#juneau-microservice-jetty.Extending'>Extending JettyMicroservice</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#my-jetty-microservice'>my-jetty-microservice</a></p>
<ol>
<li><p class=''><a class='doclink' href='#my-jetty-microservice.Installing'>Installing in Eclipse</a></p>
<li><p class=''><a class='doclink' href='#my-jetty-microservice.Running'>Running in Eclipse</a></p>
<li><p class=''><a class='doclink' href='#my-jetty-microservice.Building'>Building and Running from Command-Line</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#my-springboot-microservice'>my-springboot-microservice</a></p>
<ol>
<li><p class=''><a class='doclink' href='#my-springboot-microservice.Installing'>Installing in Eclipse</a></p>
<li><p class=''><a class='doclink' href='#my-springboot-microservice.Running'>Running in Eclipse</a></p>
<li><p class=''><a class='doclink' href='#my-springboot-microservice.Building'>Building and Running from Command-Line</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-examples-core'>juneau-examples-core</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-examples-core.Installing'>Installing in Eclipse</a></p>
<li><p class=''><a class='doclink' href='#juneau-examples-core.Examples'>Examples</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-examples-rest'>juneau-examples-rest</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-examples-rest.RootResources'>RootResources</a></p>
<li><p class=''><a class='doclink' href='#juneau-examples-rest.HelloWorldResource'>HelloWorldResource</a></p>
<li><p class=''><a class='doclink' href='#juneau-examples-rest.DtoExamples'>DtoExamples</a></p>
<li><p class=''><a class='doclink' href='#juneau-examples-rest.ConfigResource'>ConfigResource</a></p>
<li><p class=''><a class='doclink' href='#juneau-examples-rest.LogsResource'>LogsResource</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-examples-rest-jetty'>juneau-examples-rest-jetty</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-examples-rest-jetty.Installing'>Installing in Eclipse</a></p>
<li><p class=''><a class='doclink' href='#juneau-examples-rest-jetty.Running'>Running in Eclipse</a></p>
<li><p class=''><a class='doclink' href='#juneau-examples-rest-jetty.Building'>Building and Running from Command-Line</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#juneau-examples-rest-springboot'>juneau-examples-rest-springboot</a></p>
<ol>
<li><p class=''><a class='doclink' href='#juneau-examples-rest-springboot.Installing'>Installing in Eclipse</a></p>
<li><p class=''><a class='doclink' href='#juneau-examples-rest-springboot.Running'>Running in Eclipse</a></p>
<li><p class=''><a class='doclink' href='#juneau-examples-rest-springboot.Building'>Building and Running from Command-Line</a></p>
<li><p class=''><a class='doclink' href='#juneau-examples-rest-springboot.DeployingToHeroku'>Deploying to Heroku</a></p>
</ol>
<li><p class='new'><a class='doclink' href='#Glossaries'>Glossaries</a></p>
<ol>
<li><p class='new'><a class='doclink' href='#Glossaries.ConfigurablePropertiesGlossary'>Configurable Properties Glossary</a></p>
</ol>
<li><p class='toc2'><a class='doclink' href='#Security'>Security Best-Practices</a></p>
<ol>
<li><p class=''><a class='doclink' href='#Security.juneau-marshall'>juneau-marshall</a></p>
<li><p class=''><a class='doclink' href='#Security.juneau-svl'>juneau-svl</a></p>
<li><p class=''><a class='doclink' href='#Security.juneau-rest-server'>juneau-rest-server</a></p>
</ol>
</ol>
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#Introduction' id='Introduction'>1 - Introduction</a></h2>
<div class='topic'><!-- START: 1 - Introduction -->
<p>
Apache Juneau&trade; is a single cohesive Java ecosystem consisting of the following parts:
</p>
<table class='styled w800'>
<tr>
<th>Group</th><th>Component</th><th>Description</th>
</tr>
<tr class='dark bb'>
<td rowspan="4" style='text-align:center;font-weight:bold;padding:20px;'>Juneau Core</td>
<td class='code'><a class='doclink' href='http://juneau.apache.org/site/apidocs-{@property juneauVersion}/overview-summary.html#juneau-marshall'>juneau-marshall</a></td>
<td>
A universal toolkit for marshalling POJOs to a wide variety of content types using a common framework with no external library dependencies.
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='http://juneau.apache.org/site/apidocs-{@property juneauVersion}/overview-summary.html#juneau-marshall-rdf'>juneau-marshall-rdf</a></td>
<td>
Extended marshalling support for RDF languages.
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='http://juneau.apache.org/site/apidocs-{@property juneauVersion}/overview-summary.html#juneau-dto'>juneau-dto</a></td>
<td>
A variety of predefined DTOs for serializing and parsing languages such as HTML5, Swagger and ATOM.
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='http://juneau.apache.org/site/apidocs-{@property juneauVersion}/overview-summary.html#juneau-config'>juneau-config</a></td>
<td>
A sophisticated configuration file API.
</td>
</tr>
<tr class='light bb'>
<td rowspan="5" style='text-align:center;font-weight:bold;padding:20px;'>Juneau REST</td>
<td class='code'><a class='doclink' href='http://juneau.apache.org/site/apidocs-{@property juneauVersion}/overview-summary.html#juneau-rest-server'>juneau-rest-server</a></td>
<td>
A universal REST server API for creating Swagger-based self-documenting REST interfaces using POJOs, simply deployed as
one or more top-level servlets in any Servlet 3.1.0+ container.
</td>
</tr>
<tr class='light bb'>
<td class='code'><a class='doclink' href='http://juneau.apache.org/site/apidocs-{@property juneauVersion}/overview-summary.html#juneau-rest-server-springboot'>juneau-rest-server-springboot</a></td>
<td>
Spring boot integration support.
</td>
</tr>
<tr class='light bb'>
<td class='code'><a class='doclink' href='http://juneau.apache.org/site/apidocs-{@property juneauVersion}/overview-summary.html#juneau-rest-server-jaxrs'>juneau-rest-server-jaxrs</a></td>
<td>
JAX/RS integration support.
</td>
</tr>
<tr class='light bb'>
<td class='code'><a class='doclink' href='http://juneau.apache.org/site/apidocs-{@property juneauVersion}/overview-summary.html#juneau-rest-client'>juneau-rest-client</a></td>
<td>
A universal REST client API for interacting with Juneau or 3rd-party REST interfaces using POJOs and proxy interfaces.
</td>
</tr>
<tr class='light bb'>
<td class='code'><a class='doclink' href='http://juneau.apache.org/site/apidocs-{@property juneauVersion}/overview-summary.html#juneau-rest-mock'>juneau-rest-mock</a></td>
<td>
Mocking APIs for server-less end-to-end testing of REST server and client APIs.
</td>
</tr>
<tr class='dark bb'>
<td rowspan="4" style='text-align:center;font-weight:bold;padding:20px;'>Examples</td>
<td class='code'><a class='doclink' href='http://juneau.apache.org/site/apidocs-{@property juneauVersion}/overview-summary.html#juneau-examples-core'>juneau-examples-core</a></td>
<td>
Juneau Core API examples.
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='http://juneau.apache.org/site/apidocs-{@property juneauVersion}/overview-summary.html#juneau-examples-rest'>juneau-examples-rest</a></td>
<td>
Juneau REST API examples.
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='http://juneau.apache.org/site/apidocs-{@property juneauVersion}/overview-summary.html#juneau-examples-rest-jetty'>juneau-examples-rest-jetty</a></td>
<td>
Juneau REST API examples using Jetty deployment.
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='http://juneau.apache.org/site/apidocs-{@property juneauVersion}/overview-summary.html#juneau-examples-rest-springboot'>juneau-examples-rest-springboot</a></td>
<td>
Juneau REST API examples using Spring Boot deployment.
</td>
</tr>
</table>
<p>
Questions via email to <a class='doclink' href='mailto:dev@juneau.apache.org?Subject=Apache%20Juneau%20question'>dev@juneau.apache.org</a> are always welcome.
</p>
<p>
Juneau is packed with features that may not be obvious at first.
Users are encouraged to ask for code reviews by providing links to specific source files such as through GitHub.
Not only can we help you with feedback, but it helps us understand usage patterns to further improve the product.
</p>
<h5 class='topic'>History</h5>
<p>
Juneau started off as a popular internal IBM toolkit called Juno.
Originally used for serializing POJOs to and from JSON (at a time when the concept was new), 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 June of 2016, the code was donated to the Apache Foundation under the project <l>Apache Juneau</l> where it
has continued to evolve to where it is today.
</p>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#Introduction.Features' id='Introduction.Features'>1.1 - Features</a></h3>
<div class='topic'><!-- START: 1.1 - Introduction.Features -->
<ul class='spaced-list'>
<li>
Fast memory-efficient serialization.
<li>
Fast, safe, memory-efficient parsing. Parsers are not susceptible to deserialization attacks.
<li>
KISS is our mantra! No auto-wiring. No code generation. No dependency injection. Just add it to your classpath and use it. Extremely simple unit testing!
<li>
Enjoyable to use
<li>
Tiny - ~1MB
<li>
Exhaustively tested
<li>
Lots of up-to-date documentation and examples
<li>
Minimal library dependencies:
<ul>
<li><b>juneau-marshall</b>, <b>juneau-dto</b>, <b>juneau-svl</b>, <b>juneau-config</b> - No external dependencies. Entirely self-contained.
<li><b>juneau-marshall-rdf</b> - Optional RDF support. Requires Apache Jena 2.7.1+.
<li><b>juneau-rest-server</b> - Any Servlet 3.1.0+ container.
<li><b>juneau-rest-client</b> - Apache HttpClient 4.5+.
<li><b>juneau-microservice</b> - Eclipse Jetty.
</ul>
<li>
Built on top of Servlet and Apache HttpClient APIs that allow you to use the newest HTTP/2 features
such as request/response multiplexing and server push.
</ul>
</div><!-- END: 1.1 - Introduction.Features -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#Introduction.Components' id='Introduction.Components'>1.2 - Components</a></h3>
<div class='topic'><!-- START: 1.2 - Introduction.Components -->
<p>
We've strived to keep prerequisites to an absolute minimum in order to make adoption as easy as possible.
</p>
<p>
The library consists of the following artifacts found in the Maven group <c>"org.apache.juneau"</c>:
</p>
<table class='styled w800'>
<tr>
<th>Category</th><th>Maven Artifacts</th><th>Description</th><th>Prereqs</th>
</tr>
<tr class='dark bb'>
<td rowspan="4" style='text-align:center;font-weight:bold;padding:20px;' class='code'>juneau-core</td>
<td class='code'><a class='doclink' href='#juneau-marshall'>juneau-marshall</a></td>
<td>Serializers and parsers for:
<ul style='margin:0px 10px;'>
<li>JSON
<li>XML
<li>HTML
<li>UON
<li>URL-Encoding
<li>MessagePack
<li>OpenAPI
<li>SOAP/XML
<li>CSV
<li>BSON (coming soon)
<li>YAML (coming soon)
<li>Protobuf (coming soon)
<li>Amazon Ion (coming soon)
</ul>
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 8
</ul>
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='#juneau-marshall-rdf'>juneau-marshall-rdf</a></td>
<td>
Serializers and parsers for:
<ul style='margin:0px 10px;'>
<li>RDF/XML
<li>RDF/XML-Abbrev
<li>N-Triple
<li>Turtle
<li>N3
</ul>
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 8
<li>Apache Jena 2.7.1
</ul>
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='#juneau-dto'>juneau-dto</a></td>
<td>
Data Transfer Objects for:
<ul style='margin:0px 10px;'>
<li>HTML5
<li>Atom
<li>Cognos
<li>JSON-Schema
<li>Swagger 2.0
</ul>
</td>
<td><ul style='margin:0px 10px;'><li>Java 8+</li></ul></td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='#juneau-config'>juneau-config</a></td>
<td>
Configuration file API
</td>
<td><ul style='margin:0px 10px;'><li>Java 8+</li></ul></td>
</tr>
<tr class='light bb'>
<td rowspan="4" style='text-align:center;font-weight:bold;padding:20px;' class='code'>juneau-rest</td>
<td class='code'><a class='doclink' href='#juneau-rest-server'>juneau-rest-server</a></td>
<td>
REST Servlet API
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 8
<li>Servlet 3.1+
</ul>
</td>
</tr>
<tr class='light bb'>
<td class='code'><a class='doclink' href='#juneau-rest-server-springboot'>juneau-rest-server-springboot</a></td>
<td>
Spring Boot integration support
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 8+
<li>Spring Boot 2.0+
</ul>
</td>
</tr>
<tr class='light bb'>
<td class='code'><a class='doclink' href='#juneau-rest-server-jaxrs'>juneau-rest-server-jaxrs</a></td>
<td>
JAX-RS support
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 8+
<li>JAX-RS 2.0
</ul>
</td>
</tr>
<tr class='light bb'>
<td class='code'><a class='doclink' href='#juneau-rest-client'>juneau-rest-client</a></td>
<td>
REST Client API
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 8+
<li>Apache HttpClient 4.5+
</ul>
</td>
</tr>
<tr class='dark bb'>
<td rowspan="4" style='text-align:center;font-weight:bold;padding:20px;' class='code'>juneau-microservice</td>
<td class='code'><a class='doclink' href='#juneau-microservice-core'>juneau-microservice-core</a></td>
<td>
Microservice API
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 8+
</ul>
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='#juneau-microservice-jetty'>juneau-microservice-jetty</a></td>
<td>
Jetty Microservice API
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 8+
<li>Eclipse Jetty 9.4+
</ul>
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='#my-jetty-microservice'>my-jetty-microservice</a></td>
<td>
Developer template project for Jetty-based microservices.
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 8+
<li>Eclipse Jetty 9.4+
</ul>
</td>
</tr>
<tr class='dark bb'>
<td class='code'><a class='doclink' href='#my-springboot-microservice'>my-springboot-microservice</a></td>
<td>
Developer template project for Spring-Boot-based microservices.
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 8+
<li>Spring Boot 2.0+
</ul>
</td>
</tr>
<tr class='light bb'>
<td rowspan="4" style='text-align:center;font-weight:bold;padding:20px;' class='code'>juneau-examples</td>
<td class='code'><a class='doclink' href='#juneau-examples-core'>juneau-examples-core</a></td>
<td>
Core code examples
</td>
<td></td>
</tr>
<tr class='light bb'>
<td class='code'><a class='doclink' href='#juneau-examples-rest'>juneau-examples-rest</a></td>
<td>
REST code examples
</td>
<td></td>
</tr>
<tr class='light bb'>
<td class='code'><a class='doclink' href='#juneau-examples-rest-jetty'>juneau-examples-rest-jetty</a></td>
<td>
REST code examples deployed using Jetty
</td>
<td></td>
</tr>
<tr class='light bb'>
<td class='code'><a class='doclink' href='#juneau-examples-rest-springboot'>juneau-examples-rest-springboot</a></td>
<td>
REST code examples deployed using Spring Boot
</td>
<td></td>
</tr>
<tr class='dark bb'>
<td rowspan="1" style='text-align:center;font-weight:bold;padding:20px;' class='code'>juneau-all</td>
<td class='code'><c>juneau-all</c></td>
<td>
Combination of the following:
<ul style='margin:0px 10px;'>
<li>juneau-marshall
<li>juneau-dto
<li>juneau-config
<li>juneau-rest-server
<li>juneau-rest-client
</ul>
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 8+
<li>Servlet 3.1+
<li>Apache HttpClient 4.5+
</ul>
</td>
</tr>
</table>
<p>
The current version of Juneau is <c>{@property juneauVersion}</c>.
The easiest way to pull in the library is through the following maven dependency:
</p>
<p class='bpcode w800'>
<xt>&lt;dependency&gt;</xt>
<xt>&lt;groupId&gt;</xt>org.apache.juneau<xt>&lt;/groupId&gt;</xt>
<xt>&lt;artifactId&gt;</xt>juneau-all<xt>&lt;/artifactId&gt;</xt>
<xt>&lt;version&gt;</xt>{@property juneauVersion}<xt>&lt;/version&gt;</xt>
<xt>&lt;/dependency&gt;</xt>
</p>
<p>
If you would like to work with the bleeding-edge code, you can access the <c>{@property juneauVersionNext}-SNAPSHOT</c>
version through the following repository:
</p>
<p class='bpcode w800'>
<xt>&lt;pluginRepositories&gt;
&lt;pluginRepository&gt;
&lt;id&gt;<xv>apache.snapshots</xv>&lt;/id&gt;
&lt;url&gt;<xv>http://repository.apache.org/snapshots/</xv>&lt;/url&gt;
&lt;snapshots&gt;
&lt;enabled&gt;<xv>true</xv>&lt;/enabled&gt;
&lt;updatePolicy&gt;<xv>always</xv>&lt;/updatePolicy&gt;
&lt;/snapshots&gt;
&lt;/pluginRepository&gt;
&lt;/pluginRepositories&gt;</xt>
</p>
<p>
Each of the components are also packaged as stand-alone OSGi modules.
</p>
</div><!-- END: 1.2 - Introduction.Components -->
</div><!-- END: 1 - Introduction -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall' id='juneau-marshall'>2 - juneau-marshall</a></h2>
<div class='topic'><!-- START: 2 - juneau-marshall -->
<h5 class='figure'>Maven Dependency</h5>
<p class='bpcode w500'>
<xt>&lt;dependency&gt;</xt>
<xt>&lt;groupId&gt;</xt>org.apache.juneau<xt>&lt;/groupId&gt;</xt>
<xt>&lt;artifactId&gt;</xt>juneau-marshall<xt>&lt;/artifactId&gt;</xt>
<xt>&lt;version&gt;</xt>{@property juneauVersion}<xt>&lt;/version&gt;</xt>
<xt>&lt;/dependency&gt;</xt>
</p>
<h5 class='figure'>Java Library</h5>
<p class='bpcode w500'>
juneau-marshall-{@property juneauVersion}.jar
</p>
<h5 class='figure'>OSGi Module</h5>
<p class='bpcode w500'>
org.apache.juneau.marshall_{@property juneauVersion}.jar
</p>
<p>
The <c>juneau-marshall</c> artifact contains the API for defining serializers and parsers, and
marshalling support for JSON, XML, HTML, URL-Encoding, UON and others.
</p>
<p>
It also defines many convenience utility classes used throughout the framework.
</p>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Serializers' id='juneau-marshall.Serializers'>2.1 - Serializers</a></h3>
<div class='topic'><!-- START: 2.1 - juneau-marshall.Serializers -->
<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>
<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='bpcode w800'>
<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:
// "{name:'John Smith',age:21}"</jc>
String json = SimpleJsonSerializer.<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='bpcode w800'>
<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 = JsonSerializer.<jsm>create</jsm>().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, <c>Maps</c>, <c>Collections</c>,
beans, and arrays.
Extensible support for other data types such as <c>Calendars</c>, <c>Dates</c>,
<c>Iterators</c> is available through the use of POJO swaps (described later).
</p>
<p>
The class hierarchy for the serializers (excluding specialized subclasses) are:
</p>
<ul class='javatree'>
<li class='jac'>{@link org.apache.juneau.serializer.Serializer}
<ul>
<li class='jac'>{@link org.apache.juneau.serializer.WriterSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.json.JsonSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.json.JsonSchemaSerializer}
<li class='jc'>{@link org.apache.juneau.json.SimpleJsonSerializer}
</ul>
<li class='jc'>{@link org.apache.juneau.plaintext.PlainTextSerializer}
<li class='jc'>{@link org.apache.juneau.jena.RdfSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.jena.N3Serializer}
<li class='jc'>{@link org.apache.juneau.jena.NTripleSerializer}
<li class='jc'>{@link org.apache.juneau.jena.RdfXmlSerializer}
<li class='jc'>{@link org.apache.juneau.jena.RdfXmlAbbrevSerializer}
<li class='jc'>{@link org.apache.juneau.jena.TurtleSerializer}
</ul>
<li class='jc'>{@link org.apache.juneau.uon.UonSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.oapi.OpenApiSerializer}
<li class='jc'>{@link org.apache.juneau.urlencoding.UrlEncodingSerializer}
</ul>
<li class='jc'>{@link org.apache.juneau.xml.XmlSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.html.HtmlSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.html.HtmlSchemaSerializer}
<li class='jc'>{@link org.apache.juneau.html.HtmlStrippedDocSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.html.HtmlDocSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.html.HtmlSchemaDocSerializer}
</ul>
</ul>
</ul>
<li class='jc'>{@link org.apache.juneau.soap.SoapXmlSerializer}
<li class='jc'>{@link org.apache.juneau.xml.XmlDocSerializer}
<li class='jc'>{@link org.apache.juneau.xmlschema.XmlSchemaSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.xmlschema.XmlSchemaDocSerializer}
</ul>
</ul>
</ul>
<li class='jac'>{@link org.apache.juneau.serializer.OutputStreamSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.jso.JsoSerializer}
<li class='jc'>{@link org.apache.juneau.msgpack.MsgPackSerializer}
</ul>
</ul>
</ul>
</div><!-- END: 2.1 - juneau-marshall.Serializers -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Parsers' id='juneau-marshall.Parsers'>2.2 - Parsers</a></h3>
<div class='topic'><!-- START: 2.2 - juneau-marshall.Parsers -->
<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='bpcode w800'>
<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='bpcode w800'>
<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>
<br>
<div 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).
It can also handle JSON fragments 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.
</div>
<p>
The class hierarchy for the parsers (excluding specialized subclasses) are:
</p>
<ul class='javatree'>
<li class='jac'>{@link org.apache.juneau.parser.Parser}
<ul>
<li class='jac'>{@link org.apache.juneau.parser.ReaderParser}
<ul>
<li class='jc'>{@link org.apache.juneau.json.JsonParser}
<li class='jc'>{@link org.apache.juneau.plaintext.PlainTextParser}
<li class='jc'>{@link org.apache.juneau.jena.RdfParser}
<ul>
<li class='jc'>{@link org.apache.juneau.jena.RdfXmlParser}
<li class='jc'>{@link org.apache.juneau.jena.N3Parser}
<li class='jc'>{@link org.apache.juneau.jena.NTripleParser}
<li class='jc'>{@link org.apache.juneau.jena.TurtleParser}
</ul>
<li class='jc'>{@link org.apache.juneau.uon.UonParser}
<ul>
<li class='jc'>{@link org.apache.juneau.oapi.OpenApiParser}
<li class='jc'>{@link org.apache.juneau.urlencoding.UrlEncodingParser}
</ul>
<li class='jc'>{@link org.apache.juneau.xml.XmlParser}
<ul>
<li class='jc'>{@link org.apache.juneau.html.HtmlParser}
</ul>
</ul>
<li class='jac'>{@link org.apache.juneau.parser.InputStreamParser}
<ul>
<li class='jc'>{@link org.apache.juneau.jso.JsoParser}
<li class='jc'>{@link org.apache.juneau.msgpack.MsgPackParser}
</ul>
</ul>
</ul>
</div><!-- END: 2.2 - juneau-marshall.Parsers -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Marshalls' id='juneau-marshall.Marshalls'>2.3 - Marshalls</a></h3>
<div class='topic'><!-- START: 2.3 - juneau-marshall.Marshalls -->
<p>
{@link org.apache.juneau.marshall.Marshall Marshalls} are simple pairings of a {@link org.apache.juneau.serializer.Serializer}
and {@link org.apache.juneau.parser.Parser} with convenience methods for serializing and parsing POJOs.
</p>
<ul class='javatree'>
<li class='jac'>{@link org.apache.juneau.marshall.Marshall}
<ul>
<li class='jm'>{@link org.apache.juneau.marshall.Marshall#read(Object,Class) read(Object,Class)}
<li class='jm'>{@link org.apache.juneau.marshall.Marshall#read(Object,Type,Type...) read(Object,Type,Type...)}
<li class='jm'>{@link org.apache.juneau.marshall.Marshall#write(Object) write(Object)}
<li class='jm'>{@link org.apache.juneau.marshall.Marshall#write(Object,Object) write(Object,Object)}
<li class='jm'>{@link org.apache.juneau.marshall.Marshall#toString(Object) toString(Object)}
<li class='jm'>{@link org.apache.juneau.marshall.Marshall#println(Object) println(Object)}
</ul>
</ul>
<p>
Marshalls are often cleaner to use on-the-fly since they have simplified names.
</p>
<p>
The following shows the {@link org.apache.juneau.marshall.Json} marshall in action:
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Using instance.</jc>
Json json = <jk>new</jk> Json();
MyPojo myPojo = json.read(string, MyPojo.<jk>class</jk>);
String string = json.write(myPojo);
</p>
<p class='bpcode w800'>
<jc>// Using DEFAULT instance.</jc>
MyPojo myPojo = Json.<jsf>DEFAULT</jsf>.read(string, MyPojo.<jk>class</jk>);
String string = Json.<jsf>DEFAULT</jsf>.write(myPojo);
</p>
<p>
Marshalls exist for all supported languages:
</p>
<ul class='javatree'>
<li class='jac'>{@link org.apache.juneau.marshall.Marshall}
<ul>
<li class='jac'>{@link org.apache.juneau.marshall.CharMarshall}
<ul>
<li class='jc'>{@link org.apache.juneau.marshall.Html}
<li class='jc'>{@link org.apache.juneau.marshall.Json}
<li class='jc'>{@link org.apache.juneau.marshall.PlainText}
<li class='jc'>{@link org.apache.juneau.marshall.SimpleJson}
<li class='jc'>{@link org.apache.juneau.marshall.Uon}
<li class='jc'>{@link org.apache.juneau.marshall.UrlEncoding}
<li class='jc'>{@link org.apache.juneau.marshall.Xml}
<li class='jc'>{@link org.apache.juneau.marshall.N3}
<li class='jc'>{@link org.apache.juneau.marshall.NTriple}
<li class='jc'>{@link org.apache.juneau.marshall.RdfXml}
<li class='jc'>{@link org.apache.juneau.marshall.RdfXmlAbbrev}
<li class='jc'>{@link org.apache.juneau.marshall.Turtle}
</ul>
<li class='jac'>{@link org.apache.juneau.marshall.StreamMarshall}
<ul>
<li class='jc'>{@link org.apache.juneau.marshall.Jso}
<li class='jc'>{@link org.apache.juneau.marshall.MsgPack}
</ul>
</ul>
</ul>
</div><!-- END: 2.3 - juneau-marshall.Marshalls -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.HttpPartSerializers' id='juneau-marshall.HttpPartSerializers'>2.4 - HTTP Part Serializers</a></h3>
<div class='topic'><!-- START: 2.4 - juneau-marshall.HttpPartSerializers -->
<p>
There is a separate set of serializers for serializing HTTP parts (query, form-data, headers, path variables, and plain-text request bodies).
The distinction is that these are designed to serialize directly to strings based on Open-API schema information.
</p>
<p class='bpcode w800'>
<jc>// Schema information about our part.</jc>
HttpPartSchema schema = HttpPartSchema
.<jsm>create</jsm>(<js>"array"</js>)
.collectionFormat(<js>"pipes"</js>)
.items(
HttpPartSchema
.<jsm>create</jsm>(<js>"array"</js>)
.collectionFormat(<js>"csv"</js>)
.items(
HttpPartSchema.<jsm>create</jsm>(<js>"integer"</js>,<js>"int64"</js>)
)
)
.build();
<jc>// Our value to serialize</jc>
Object value = <jk>new long</jk>[][]{{1,2,3},{4,5,6},{7,8,9}};
<jc>// Produces "1,2,3|4,5,6|7,8,9"</jc>
String output = OpenApiSerializer.<jsf>DEFAULT</jsf>.serialize(HttpPartType.<jsf>HEADER</jsf>, schema, value);
</p>
<p>
The class hierarchy for the part serializers are:
</p>
<ul class='javatree'>
<li class='jic'>{@link org.apache.juneau.httppart.HttpPartSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.httppart.SimplePartSerializer} - Serializes directly to strings.
<li class='jc'>{@link org.apache.juneau.uon.UonSerializer} - Serializes to UON notation.
<ul>
<li class='jc'>{@link org.apache.juneau.oapi.OpenApiSerializer} - Serializes using Open-API schema rules.
</ul>
</ul>
</ul>
</div><!-- END: 2.4 - juneau-marshall.HttpPartSerializers -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.HttpPartParsers' id='juneau-marshall.HttpPartParsers'>2.5 - HTTP Part Parsers</a></h3>
<div class='topic'><!-- START: 2.5 - juneau-marshall.HttpPartParsers -->
<p>
There is a separate set of parsers for parsing HTTP parts (query, form-data, headers, path variables, and plain-text request bodies).
The distinction is that these are designed to parse directly from strings based on Open-API schema information.
</p>
<p class='bpcode w800'>
<jc>// Schema information about our part.</jc>
HttpPartSchema schema = HttpPartSchema
.<jsm>create</jsm>(<js>"array"</js>)
.collectionFormat(<js>"pipes"</js>)
.items(
HttpPartSchema
.<jsm>create</jsm>(<js>"array"</js>)
.collectionFormat(<js>"csv"</js>)
.items(
HttpPartSchema.<jsm>create</jsm>(<js>"integer"</js>,<js>"int64"</js>)
)
)
.build();
<jc>// Our input to parse.</jc>
String input = <js>"1,2,3|4,5,6|7,8,9"</js>;
<jc>// Produces "[[1,2,3],[4,5,6],[7,8,9]]</jc>
<jk>long</jk>[][] value = OpenApiParser.<jsf>DEFAULT</jsf>.parse(HttpPartType.<jsf>HEADER</jsf>, schema, input, <jk>long</jk>[][].<jk>class</jk>);
</p>
<p>
The class hierarchy for the part serializers are:
</p>
<ul class='javatree'>
<li class='jic'>{@link org.apache.juneau.httppart.HttpPartParser}
<ul>
<li class='jc'>{@link org.apache.juneau.httppart.SimplePartParser} - Parses directly from strings.
<li class='jc'>{@link org.apache.juneau.uon.UonParser} - Parses from UON notation.
<ul>
<li class='jc'>{@link org.apache.juneau.oapi.OpenApiParser} - Parses using Open-API schema rules.
</ul>
</ul>
</ul>
</div><!-- END: 2.5 - juneau-marshall.HttpPartParsers -->
<!-- ==================================================================================================== -->
<h3 class='topic updated' onclick='toggle(this)'><a href='#juneau-marshall.ConfigurableProperties' id='juneau-marshall.ConfigurableProperties'>2.6 - Configurable Properties</a></h3>
<div class='topic'><!-- START: 2.6 - juneau-marshall.ConfigurableProperties -->
<p>
Serializers and parsers have a wide variety of configurable properties. They all extend from the
{@link org.apache.juneau.BeanContextBuilder} class that allows you to easily construct new instances from scratch or build upon existing instances.
For example, the following code shows how to configure a JSON serializer:
</p>
<p class='bpcode w800'>
WriterSerializer s = JsonSerializer
.<jsm>create</jsm>() <jc>// Create a JsonSerializerBuilder</jc>
.simple() <jc>// Simple mode</jc>
.ws() <jc>// Use whitespace</jc>
.sq() <jc>// Use single quotes </jc>
.build(); <jc>// Create a JsonSerializer</jc>
</p>
<p>
Configurable settings can also be set declaratively.
The following produces the same serializer.
</p>
<p class='bpcode w800'>
WriterSerializer s = JsonSerializer
.<jsm>create</jsm>()
.set(<jsf>JSON_simpleMode</jsf>, <jk>true</jk>)
.set(<jsf>WSERIALIZER_useWhitespace</jsf>, <jk>true</jk>)
.set(<jsf>WSERIALIZER_quoteChar</jsf>, <js>"'"</js>)
.build();
</p>
<p>
However, each of the serializers and parsers already contain reusable instances with common configurations.
For example, JSON has the following predefined reusable serializers and parsers:
</p>
<ul class='javatree'>
<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_READABLE DEFAULT_READABLE}
</ul>
</li>
<li class='jc'>{@link org.apache.juneau.json.SimpleJsonSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.json.SimpleJsonSerializer#DEFAULT DEFAULT}
<li class='jf'>{@link org.apache.juneau.json.SimpleJsonSerializer#DEFAULT_READABLE DEFAULT_READABLE}
</ul>
</li>
<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>
</li>
</ul>
<p>
These can be used directly, as follows:
</p>
<p class='bpcode w800'>
<jc>// Serialize a POJO to LAX JSON.</jc>
String json = SimpleJsonSerializer.<jsf>DEFAULT</jsf>.serialize(myPojo);
</p>
<p>
For performance reasons, serializers and parsers are immutable.
However, they can be 'copied' and modified using the <c>builder()</c> method.
</p>
<p class='bpcode w800'>
<jc>// Clone and customize an existing serializer.</jc>
WriterSerializer s = SimpleJsonSerializer.<jsf>DEFAULT</jsf>
.builder() <jc>// Create a new builder with copied settings.</jc>
.quoteChar(<js>'"'</js>) <jc>// Use a different quote character.</jc>
.build();
</p>
<p>
Configurable properties can be set globally using either system properties or environment variables.
<br>For example, the <jsf>WSERIALIZER_useWhitespace</jsf> variable resolves to the string <js>"WriterSerializer.useWhitespace.b"</js>.
This setting can be enabled by setting the system property <js>"WriterSerializer.useWhitespace"</js> or environment
variables <js>"WriterSerializer_useWhitespace"</js> or <js>"WRITERSERIALIZER_USEWHITESPACE"</js> to <js>"true"</js>.
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.ConfigurableProperties.Common' id='juneau-marshall.ConfigurableProperties.Common'>2.6.1 - Common Serializer Properties</a></h4>
<div class='topic'><!-- START: 2.6.1 - juneau-marshall.ConfigurableProperties.Common -->
<p>
All serializers and parsers extend from the {@link org.apache.juneau.BeanContext} class.
Therefore, the following properties are common to all serializers and parsers:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.BeanContext}
<ul>
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanClassVisibility BEAN_beanClassVisibility}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanConstructorVisibility BEAN_beanConstructorVisibility}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanDictionary BEAN_beanDictionary}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanFieldVisibility BEAN_beanFieldVisibility}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanFilters BEAN_beanFilters}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanMapPutReturnsOldValue BEAN_beanMapPutReturnsOldValue}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanMethodVisibility BEAN_beanMethodVisibility}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beansRequireDefaultConstructor BEAN_beansRequireDefaultConstructor}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beansRequireSerializable BEAN_beansRequireSerializable}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beansRequireSettersForGetters BEAN_beansRequireSettersForGetters}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beansRequireSomeProperties BEAN_beansRequireSomeProperties}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanTypePropertyName BEAN_beanTypePropertyName}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_bpi BEAN_bpi}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_bpx BEAN_bpx}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_debug BEAN_debug}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_examples BEAN_examples}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_fluentSetters BEAN_fluentSetters}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_ignoreInvocationExceptionsOnGetters BEAN_ignoreInvocationExceptionsOnGetters}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_ignoreInvocationExceptionsOnSetters BEAN_ignoreInvocationExceptionsOnSetters}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_ignorePropertiesWithoutSetters BEAN_ignorePropertiesWithoutSetters}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_ignoreUnknownBeanProperties BEAN_ignoreUnknownBeanProperties}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_ignoreUnknownNullBeanProperties BEAN_ignoreUnknownNullBeanProperties}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_implClasses BEAN_implClasses}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_locale BEAN_locale}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_mediaType BEAN_mediaType}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_notBeanClasses BEAN_notBeanClasses}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_notBeanPackages BEAN_notBeanPackages}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_pojoSwaps BEAN_pojoSwaps}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_propertyNamer BEAN_propertyNamer}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_sortProperties BEAN_sortProperties}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_timeZone BEAN_timeZone}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_useEnumNames BEAN_useEnumNames}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_useInterfaceProxies BEAN_useInterfaceProxies}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_useJavaBeanIntrospector BEAN_useJavaBeanIntrospector}
</ul>
</ul>
</div><!-- END: 2.6.1 - juneau-marshall.ConfigurableProperties.Common -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.ConfigurableProperties.CommonSerializer' id='juneau-marshall.ConfigurableProperties.CommonSerializer'>2.6.2 - Common Serializer Properties</a></h4>
<div class='topic'><!-- START: 2.6.2 - juneau-marshall.ConfigurableProperties.CommonSerializer -->
<p>
In addition to the common properties above, the following properties are common to all serializers:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.BeanTraverseContext}
<ul>
<li class='jf'>{@link org.apache.juneau.BeanTraverseContext#BEANTRAVERSE_detectRecursions BEANTRAVERSE_detectRecursions}
<li class='jf'>{@link org.apache.juneau.BeanTraverseContext#BEANTRAVERSE_ignoreRecursions BEANTRAVERSE_ignoreRecursions}
<li class='jf'>{@link org.apache.juneau.BeanTraverseContext#BEANTRAVERSE_initialDepth BEANTRAVERSE_initialDepth}
<li class='jf'>{@link org.apache.juneau.BeanTraverseContext#BEANTRAVERSE_maxDepth BEANTRAVERSE_maxDepth}
<li class='jc'>{@link org.apache.juneau.serializer.Serializer}
<ul>
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_addBeanTypes SERIALIZER_addBeanTypes}
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_addRootType SERIALIZER_addRootType}
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_listener SERIALIZER_listener}
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_sortCollections SERIALIZER_sortCollections}
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_sortMaps SERIALIZER_sortMaps}
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_trimEmptyCollections SERIALIZER_trimEmptyCollections}
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_trimEmptyMaps SERIALIZER_trimEmptyMaps}
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_trimNullProperties SERIALIZER_trimNullProperties}
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_trimStrings SERIALIZER_trimStrings}
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriContext SERIALIZER_uriContext}
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriRelativity SERIALIZER_uriRelativity}
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriResolution SERIALIZER_uriResolution}
<li class='jc'>{@link org.apache.juneau.serializer.WriterSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.serializer.WriterSerializer#WSERIALIZER_fileCharset WSERIALIZER_fileCharset}
<li class='jf'>{@link org.apache.juneau.serializer.WriterSerializer#WSERIALIZER_maxIndent WSERIALIZER_maxIndent}
<li class='jf'>{@link org.apache.juneau.serializer.WriterSerializer#WSERIALIZER_quoteChar WSERIALIZER_quoteChar}
<li class='jf'>{@link org.apache.juneau.serializer.WriterSerializer#WSERIALIZER_streamCharset WSERIALIZER_streamCharset}
<li class='jf'>{@link org.apache.juneau.serializer.WriterSerializer#WSERIALIZER_useWhitespace WSERIALIZER_useWhitespace}
</ul>
<li class='jc'>{@link org.apache.juneau.serializer.OutputStreamSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.serializer.OutputStreamSerializer#OSSERIALIZER_binaryFormat OSSERIALIZER_binaryFormat}
</ul>
</ul>
</ul>
</ul>
</div><!-- END: 2.6.2 - juneau-marshall.ConfigurableProperties.CommonSerializer -->
<!-- ==================================================================================================== -->
<h4 class='topic update' onclick='toggle(this)'><a href='#juneau-marshall.ConfigurableProperties.CommonParser' id='juneau-marshall.ConfigurableProperties.CommonParser'>2.6.3 - Common Parser Properties</a></h4>
<div class='topic'><!-- START: 2.6.3 - juneau-marshall.ConfigurableProperties.CommonParser -->
<p>
In addition to the common properties above, the following properties are common to all parsers:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.parser.Parser}
<ul>
<li class='jf'>{@link org.apache.juneau.parser.Parser#PARSER_autoCloseStreams PARSER_autoCloseStreams}
<li class='jf'>{@link org.apache.juneau.parser.Parser#PARSER_debugOutputLines PARSER_debugOutputLines}
<li class='jf'>{@link org.apache.juneau.parser.Parser#PARSER_listener PARSER_listener}
<li class='jf'>{@link org.apache.juneau.parser.Parser#PARSER_strict PARSER_strict}
<li class='jf'>{@link org.apache.juneau.parser.Parser#PARSER_trimStrings PARSER_trimStrings}
<li class='jf'>{@link org.apache.juneau.parser.Parser#PARSER_unbuffered PARSER_unbuffered}
<li class='jc'>{@link org.apache.juneau.parser.ReaderParser}
<ul>
<li class='jf'>{@link org.apache.juneau.parser.ReaderParser#RPARSER_fileCharset RPARSER_fileCharset}
<li class='jf'>{@link org.apache.juneau.parser.ReaderParser#RPARSER_streamCharset RPARSER_streamCharset}
</ul>
<li class='jc'>{@link org.apache.juneau.parser.InputStreamParser}
<ul>
<li class='jf'>{@link org.apache.juneau.parser.InputStreamParser#ISPARSER_binaryFormat ISPARSER_binaryFormat}
</ul>
</ul>
</ul>
</div><!-- END: 2.6.3 - juneau-marshall.ConfigurableProperties.CommonParser -->
</div><!-- END: 2.6 - juneau-marshall.ConfigurableProperties -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.ConfigurableAnnotations' id='juneau-marshall.ConfigurableAnnotations'>2.7 - Configurable Annotations</a></h3>
<div class='topic'><!-- START: 2.7 - juneau-marshall.ConfigurableAnnotations -->
<p>
All configurable properties described in the previous section have annotation equivalents that can be applied on
classes or methods.
</p>
<p>
In the section on the REST server API, we describe how to configure serializers and parsers using <ja>@Property</ja>
annotations such as shown below:
</p>
<p class='bpcode w800'>
<jc>// Configuring serializers/parsers using @Property annotations.</jc>
<ja>@Rest</ja>(
path=<js>"/atom"</js>,
title=<js>"Sample ATOM feed resource"</js>,
properties={
<ja>@Property</ja>(name=<jsf>WSERIALIZER_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>),
<ja>@Property</ja>(name=<jsf>BEAN_examples</jsf>, value=<js>"{'org.apache.juneau.dto.atom.Feed': $F{AtomFeedResource_example.json}}"</js>)
}
...
)
<jk>public class</jk> AtomFeedResource <jk>extends</jk> BasicRestServletJena {
...
}
</p>
<p>
However, an even easier way to configure serializers and parsers are to used provided specialized <ja>@XConfig</ja>
annotations like those shown below:
</p>
<p class='bpcode w800'>
<jc>// Same as above but using specialized annotations.</jc>
<ja>@Rest</ja>(
path=<js>"/atom"</js>,
title=<js>"Sample ATOM feed resource"</js>
...
)
<ja>@SerializerConfig</ja>(quoteChar=<js>"'"</js>)
<ja>@RdfConfig</ja>(rdfxml_tab=<js>"5"</js>, addRootProperty=<js>"true"</js>)
<ja>@BeanConfig</ja>(examples=<js>"Feed: $F{AtomFeedResource_example.json}"</js>)
<jk>public class</jk> AtomFeedResource <jk>extends</jk> BasicRestServletJena {
...
}
</p>
<p>
Config annotations are provided for all serializers and parsers:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.annotation.BeanConfig BeanConfig}
<li class='ja'>{@link org.apache.juneau.csv.annotation.CsvConfig CsvConfig}
<li class='ja'>{@link org.apache.juneau.html.annotation.HtmlConfig HtmlConfig}
<li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig HtmlDocConfig}
<li class='ja'>{@link org.apache.juneau.jso.annotation.JsoConfig JsoConfig}
<li class='ja'>{@link org.apache.juneau.json.annotation.JsonConfig JsonConfig}
<li class='ja'>{@link org.apache.juneau.jsonschema.annotation.JsonSchemaConfig JsonSchemaConfig}
<li class='ja'>{@link org.apache.juneau.msgpack.annotation.MsgPackConfig MsgPackConfig}
<li class='ja'>{@link org.apache.juneau.oapi.annotation.OpenApiConfig OpenApiConfig}
<li class='ja'>{@link org.apache.juneau.parser.annotation.ParserConfig ParserConfig}
<li class='ja'>{@link org.apache.juneau.plaintext.annotation.PlainTextConfig PlainTextConfig}
<li class='ja'>{@link org.apache.juneau.jena.annotation.RdfConfig RdfConfig}
<li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig SerializerConfig}
<li class='ja'>{@link org.apache.juneau.soap.annotation.SoapXmlConfig SoapXmlConfig}
<li class='ja'>{@link org.apache.juneau.uon.annotation.UonConfig UonConfig}
<li class='ja'>{@link org.apache.juneau.urlencoding.annotation.UrlEncodingConfig UrlEncodingConfig}
<li class='ja'>{@link org.apache.juneau.xml.annotation.XmlConfig XmlConfig}
</ul>
<p>
Config annotations defined on classes and methods can be applied to serializers and parsers using the following methods:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.BeanContextBuilder}
<ul>
<li class='jm'>{@link org.apache.juneau.BeanContextBuilder#applyAnnotations(Class) applyAnnotations(Class)} - Apply annotations from class and all parent classes.
<li class='jm'>{@link org.apache.juneau.BeanContextBuilder#applyAnnotations(Method) applyAnnotations(Method)} - Apply annotations from method and parent methods.
</ul>
</ul>
</div><!-- END: 2.7 - juneau-marshall.ConfigurableAnnotations -->
<!-- ==================================================================================================== -->
<h3 class='topic todo' onclick='toggle(this)'><a href='#juneau-marshall.ClassMethodAnnotations' id='juneau-marshall.ClassMethodAnnotations'>2.8 - Class/Method Annotations</a></h3>
<div class='topic'><!-- START: 2.8 - juneau-marshall.ClassMethodAnnotations -->
<p>
TODO
</p>
</div><!-- END: 2.8 - juneau-marshall.ClassMethodAnnotations -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.ObjectMap' id='juneau-marshall.ObjectMap'>2.9 - ObjectMap and ObjectList</a></h3>
<div class='topic'><!-- START: 2.9 - juneau-marshall.ObjectMap -->
<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='javatree'>
<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>
<li class='jc'>
{@link java.util.LinkedList java.util.LinkedList}
<ul>
<li class='jc'>
{@link org.apache.juneau.ObjectMap org.apache.juneau.ObjectList}
</ul>
</li>
</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.
<li>
Simply calling the {@link org.apache.juneau.ObjectMap#toString()} or {@link org.apache.juneau.ObjectList#toString()}
methods which will serialize it as Simplified JSON.
</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.
(In theory, any valid XML can also be parsed into an unstructured model, although this has not been
officially 'tested')
</p>
<p class='bpcode w800'>
<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);
<jc>// Or just use toString().</jc>
json = m.toString();
</p>
<p>
The <c>ObjectMap</c> and <c>ObjectList</c> classes have many convenience features:
</p>
<p class='bpcode w800'>
<jc>// Convert the map to a bean.</jc>
MyBean m = objectMap.cast(MyBean.<jk>class</jk>);
<jc>// Find entries by multiple keys.</jc>
MyBean m = objectMap.find(MyBean.<jk>class</jk>, <js>"key1"</js>, <js>"key2"</js>);
<jc>// Fluent-style appenders.</jc>
objectMap.append(<js>"key1"</js>, <js>"val1"</js>).append(<js>"key2"</js>, <js>"val2"</js>);
<jc>// REST-like functions for manipulating nodes in the data structure using URL-like notation.</jc>
objectMap.getAt(<js>"foo/bar/myBean"</js>, MyBean.<jk>class</jk>);
objectMap.putAt(<js>"foo/bar/myBean"</js>, MyBean.<jk>class</jk>);
objectMap.postAt(<js>"foo/bar/myListOfBeans"</js>, MyBean.<jk>class</jk>);
objectMap.deleteAt(<js>"foo/bar/myBean"</js>);
<jc>// Copy with inclusion or exclusion.</jc>
ObjectMap m2 = objectMap.include(<js>"key1"</js>, <js>"key2"</js>, <js>"key3"</js>);
ObjectMap m3 = objectMap.exclude(<js>"key1"</js>, <js>"key2"</js>, <js>"key3"</js>);
<jc>// Serialize using another serializer.</jc>
String xml = objectMap.serializeTo(XmlSerializer.<jsf>DEFAULT</jsf>);
<jc>// Nested maps.</jc>
objectMap.setInner(objectMapInner);
</p>
<div 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>.
</div>
</div><!-- END: 2.9 - juneau-marshall.ObjectMap -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Groups' id='juneau-marshall.Groups'>2.10 - SerializerGroups and ParserGroups</a></h3>
<div class='topic'><!-- START: 2.10 - juneau-marshall.Groups -->
<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 <c>Accept</c>
and <c>Content-Type</c> values...
</p>
<p class='bpcode w800'>
<jc>// Construct a new serializer group with configuration parameters that get applied to all serializers.</jc>
SerializerGroup sg = SerializerGroup.<jsm>create</jsm>()
.append(JsonSerializer.<jk>class</jk>, UrlEncodingSerializer.<jk>class</jk>);
.ws <jc>// or .useWhitespace(true)</jc>
.pojoSwaps(TemporalCalendarSwap.IsoLocalDateTime.<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 = ParserGroup.<jsm>create</jsm>()
.append(JsonSerializer.<jk>class</jk>, UrlEncodingSerializer.<jk>class</jk>);
.pojoSwaps(CalendarSwap.IsoLocalDateTime.<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 <c>SerializerGroup</c> and <c>ParserGroup</c> 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>
</div><!-- END: 2.10 - juneau-marshall.Groups -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.ContextsBuildersSessionsPropertyStores' id='juneau-marshall.ContextsBuildersSessionsPropertyStores'>2.11 - Contexts, Builders, Sessions, and PropertyStores</a></h3>
<div class='topic'><!-- START: 2.11 - juneau-marshall.ContextsBuildersSessionsPropertyStores -->
<p>
All the serializers, parsers, and REST server/client classes use the following design pattern:
</p>
<ul class='spaced-list'>
<li>
<l>Context</l> - A thread-safe read-only object.
<ul>
<li>Heavy to construct and designed to be cached and reused.
<li>Created by <l>ContextBuilder</l> classes.
<li>Examples: <c>BeanContext</c>, <c>JsonSerializer</c>
</ul>
<li>
<l>Session</l> - A non-thread-safe single-use object with configuration combined from context and
runtime args such as locale/timezone.
<ul>
<li>Lightweight objects that take a minimum amount of time to instantiate and are not typically reused.
<li>Created by <c>Context</c> objects.
<li>Examples: <c>BeanSession</c>, <c>JsonSerializerSession</c>
</ul>
<li>
<l>PropertyStore</l> - A thread-safe read-only set of configuration properties.
<ul>
<li>Heavier to create than <c>Sessions</c> but lighter than <c>Contexts</c>.
<li>Each <c>Context</c> contains one <c>PropertyStore</c> that defines all the configuration about that object.
<li>Created by <l>PropertyStoreBuilder</l> classes.
</ul>
</ul>
<p>
For example, the class hierarchy for <c>JsonSerializer</c> is:
</p>
<ul class='javatree'>
<li class='jc'><c>Object</c>
<ul>
<li class='jac'>{@link org.apache.juneau.Context}
<ul>
<li class='jc'>{@link org.apache.juneau.BeanContext}
<ul>
<li class='jac'>{@link org.apache.juneau.serializer.Serializer}
<ul>
<li class='jac'>{@link org.apache.juneau.serializer.WriterSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.json.JsonSerializer}
</ul>
</ul>
</ul>
</ul>
</ul>
</ul>
<p>
Each context object in the hierarchy define properties that can be stored in a <c>PropertyStore</c>
such as <jsf>WSERIALIZER_useWhitespace</jsf> or <jsf>JSON_simpleMode</jsf>.
</p>
<p>
The class hierarchy for <c>JsonSerializerBuilder</c> is:
</p>
<ul class='javatree'>
<li class='jc'><c>Object</c>
<ul>
<li class='jac'>{@link org.apache.juneau.ContextBuilder}
<ul>
<li class='jc'>{@link org.apache.juneau.BeanContextBuilder}
<ul>
<li class='jac'>{@link org.apache.juneau.serializer.SerializerBuilder}
<ul>
<li class='jac'>{@link org.apache.juneau.serializer.WriterSerializerBuilder}
<ul>
<li class='jc'>{@link org.apache.juneau.json.JsonSerializerBuilder}
</ul>
</ul>
</ul>
</ul>
</ul>
</ul>
<p>
The class hierarchy for <c>JsonSerializerSession</c> is:
</p>
<ul class='javatree'>
<li class='jc'><c>Object</c>
<ul>
<li class='jac'>{@link org.apache.juneau.Session}
<ul>
<li class='jc'>{@link org.apache.juneau.BeanSession}
<ul>
<li class='jac'>{@link org.apache.juneau.serializer.SerializerSession}
<ul>
<li class='jac'>{@link org.apache.juneau.serializer.WriterSerializerSession}
<ul>
<li class='jc'>{@link org.apache.juneau.json.JsonSerializerSession}
</ul>
</ul>
</ul>
</ul>
</ul>
</ul>
<p>
The general idea behind a {@link org.apache.juneau.PropertyStore} is to serve as a reusable configuration of an artifact
(such as a serializer) such that the artifact can be cached and reused if the property stores are 'equal'.
</p>
<p>
For example, two serializers of the same type created with the same configuration will always end up being
the same serializer:
</p>
<p class='bpcode w800'>
<jc>// Two serializers created with identical configurations will always be the same copy.</jc>
WriterSerializer s1 = JsonSerializer.<jsm>create</jsm>().pojoSwaps(MySwap.<jk>class</jk>).simple().build();
WriterSerializer s2 = JsonSerializer.<jsm>create</jsm>().set(<jsf>JSON_simpleMode</jsf>, <jk>true</jk>).pojoSwaps(MySwap.<jk>class</jk>).build();
<jk>assert</jk>(s1 == s2);
</p>
<p>
This has the effect of significantly improving performance especially if you're creating many
serializers and parsers.
</p>
<p>
The {@link org.apache.juneau.PropertyStoreBuilder} class is used to build up and instantiate immutable
<c>PropertyStore</c> objects.
</p>
<p>
In the example above, the property store being built looks like the following:
</p>
<p class='bpcode w800'>
PropertyStore ps = PropertyStore
.<jsm>create</jsm>()
.set(<js>"BeanContext.pojoSwaps.lc"</js>, MySwap.<jk>class</jk>)
.set(<js>"JsonSerializer.simpleMode.b"</js>, <jk>true</jk>)
.build();
</p>
<p>
Property stores are immutable, comparable, and their hashcodes are calculated exactly one time.
That makes them particularly suited for use as hashmap keys, and thus for caching reusable serializers and parsers.
</p>
<p>
Refer to the {@link org.apache.juneau.PropertyStore} javadoc for a detailed explaination on how
property stores work.
</p>
</div><!-- END: 2.11 - juneau-marshall.ContextsBuildersSessionsPropertyStores -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms' id='juneau-marshall.Transforms'>2.12 - Transforms</a></h3>
<div class='topic'><!-- START: 2.12 - juneau-marshall.Transforms -->
<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='javatree'>
<li class='jc'>{@link org.apache.juneau.transform.BeanFilter} - Transforms that alter the way beans are handled.
<li class='jac'>{@link org.apache.juneau.transform.PojoSwap} - Transforms that swap non-serializable POJOs with
serializable POJOs during serialization (and optionally vis-versa during parsing).
<ul>
<li class='jc'>{@link org.apache.juneau.transform.StringSwap} - Convenience subclass for swaps that convert
objects to strings.
<li class='jc'>{@link org.apache.juneau.transform.MapSwap} - Convenience subclass for swaps that convert
objects to maps.
</ul>
</li>
</ul>
<p>
Transforms are added to serializers and parsers (and REST clients) using the following configuration properties:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.BeanContext}
<ul>
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanFilters BEAN_beanFilters}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_pojoSwaps BEAN_pojoSwaps}
</ul>
</ul>
<p>
Annotations are also provided for specifying transforms directly on classes and methods (all described in later sections):
</p>
<ul class='javatree'>
<li class='ja'>
{@link org.apache.juneau.annotation.Swap}
- Used to tailor how non-bean POJOs get interpreted by the framework.
<li class='ja'>
{@link org.apache.juneau.annotation.Bean}
- Used to tailor how beans get interpreted by the framework.
<li class='ja'>
{@link org.apache.juneau.annotation.Beanc}
- Maps constructor arguments to property names on beans with read-only properties.
<li class='ja'>
{@link org.apache.juneau.annotation.Beanp}
- Used to tailor how bean properties get interpreted by the framework.
<li class='ja'>
{@link org.apache.juneau.annotation.BeanIgnore}
- Ignore classes, fields, and methods from being interpreted as bean or bean components.
<li class='ja'>
{@link org.apache.juneau.annotation.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}
- Identifies a setter as a method for adding a parent reference to a child object.
<li class='ja'>
{@link org.apache.juneau.annotation.URI}
- Used to identify a class or bean property as a URI.
</ul>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.PojoSwaps' id='juneau-marshall.Transforms.PojoSwaps'>2.12.1 - PojoSwaps</a></h4>
<div class='topic'><!-- START: 2.12.1 - juneau-marshall.Transforms.PojoSwaps -->
<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, simply put, '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 <c>File</c>, <c>Reader</c>,
<c>Iterable</c>, 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 <c>PojoSwap</c> that will swap in a bean of a particular type
with a map containing customized key-value pairs:
</p>
<p class='bpcode w800'>
<jc>// Sample swap for converting a bean to a specialized map of key-value pairs.</jc>
<jk>public class</jk> MyBeanSwap <jk>extends</jk> PojoSwap&lt;MyBean,ObjectMap&gt; {
<jc>// Converts a bean to a generic map.</jc>
<ja>@Override</ja> <jc>/* PojoSwap */</jc>
<jk>public</jk> ObjectMap swap(BeanSession session, MyBean o) {
<jk>return new</jk> ObjectMap().append(<js>"foo"</js>, o.getBar());
}
<jc>// Converts the generic map back into a bean.</jc>
<ja>@Override</ja> <jc>/* PojoSwap */</jc>
<jk>public</jk> MyBean unswap(BeanSession session, ObjectMap o, ClassMeta hint) <jk>throws</jk> Exception {
MyBean b = <jk>new</jk> MyBean();
b.setBar(o.getString(<js>"foo"</js>));
<jk>return</jk> b;
}
}
</p>
<p>
The swap can then be associated with serializers and parsers like so:
</p>
<p class='bpcode w800'>
<jc>// Create a new JSON serializer with our swap.</jc>
WriterSerializer s = JsonSerializer.<jsm>create</jsm>().simple().pojoSwaps(MyBeanSwap.<jk>class</jk>).build();
String json = s.serialize(<jk>new</jk> MyBean());
<jc>// Create a JSON parser with our swap.</jc>
ReaderParser p = JsonParser.<jsm>create</jsm>().pojoSwaps(MyBeanSwap.<jk>class</jk>).build();
MyBean bean = p.parse(json, MyBean.<jk>class</jk>);
</p>
<p>
Another example of a <c>PojoSwap</c> is one that converts <c><jk>byte</jk>[]</c> arrays to
BASE64-encoded strings:
</p>
<p class='bpcode w800'>
<jk>public class</jk> ByteArrayBase64Swap <jk>extends</jk> StringSwap&lt;<jk>byte</jk>[]&gt; {
<ja>@Override</ja> <jc>/* StringSwap */</jc>
<jk>public</jk> String swap(<jk>byte</jk>[] b) <jk>throws</jk> Exception {
ByteArrayOutputStream baos = <jk>new</jk> ByteArrayOutputStream();
OutputStream b64os = MimeUtility.encode(baos, <js>"base64"</js>);
b64os.write(b);
b64os.close();
<jk>return new</jk> String(baos.toByteArray());
}
<ja>@Override</ja> <jc>/* StringSwap */</jc>
<jk>public byte</jk>[] unswap(String s, ClassMeta&lt;?&gt; hint) <jk>throws</jk> Exception {
<jk>byte</jk>[] b = s.getBytes();
ByteArrayInputStream bais = <jk>new</jk> ByteArrayInputStream(b);
InputStream b64is = MimeUtility.decode(bais, <js>"base64"</js>);
<jk>byte</jk>[] tmp = <jk>new byte</jk>[b.length];
<jk>int</jk> n = b64is.read(tmp);
<jk>byte</jk>[] res = <jk>new byte</jk>[n];
System.<jsm>arraycopy</jsm>(tmp, 0, res, 0, n);
<jk>return</jk> res;
}
}
</p>
<p>
The following example shows the BASE64 swap in use:
</p>
<p class='bpcode w800'>
<jc>// Create a JSON serializer and register the BASE64 encoding swap with it.</jc>
WriterSerializer s = JsonSerializer.<jsm>create</jsm>().simple().pojoSwaps(ByteArrayBase64Swap.<jk>class</jk>).build();
ReaderParser p = JsonParser.<jsm>create</jsm>().pojoSwaps(ByteArrayBase64Swap.<jk>class</jk>).build();
<jk>byte</jk>[] bytes = {1,2,3};
String json = s.serialize(bytes); <jc>// Produces "'AQID'"</jc>
bytes = p.parse(json, <jk>byte</jk>[].<jk>class</jk>); <jc>// Reproduces {1,2,3}</jc>
<jk>byte</jk>[][] bytes2d = {{1,2,3},{4,5,6},<jk>null</jk>};
json = s.serialize(bytes2d); <jc>// Produces "['AQID','BAUG',null]"</jc>
bytes2d = p.parse(json, <jk>byte</jk>[][].<jk>class</jk>); <jc>// Reproduces {{1,2,3},{4,5,6},null}</jc>
</p>
</div><!-- END: 2.12.1 - juneau-marshall.Transforms.PojoSwaps -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.DefaultPojoSwaps' id='juneau-marshall.Transforms.DefaultPojoSwaps'>2.12.2 - Default PojoSwaps</a></h4>
<div class='topic'><!-- START: 2.12.2 - juneau-marshall.Transforms.DefaultPojoSwaps -->
<p>
By default, all serializers and parsers have built in <c>PojoSwaps</c> defined for the following common data types:
</p>
<ul class='javatree'>
<li class='jc'>{@link java.util.Enumeration}
<li class='jc'>{@link java.util.Iterator}
<li class='jc'>{@link java.util.Locale}
<li class='jc'>{@link java.util.Class}
<li class='jc'>{@link java.util.Calendar} - ISO offset date-time.
<li class='jc'>{@link java.util.Date} - Local date-time
<li class='jc'>{@link java.time.Instant} - ISO instant.
<li class='jc'>{@link java.time.ZonedDateTime} - ISO offset date-time.
<li class='jc'>{@link java.time.LocalDate} - ISO local date.
<li class='jc'>{@link java.time.LocalDateTime} - ISO local date-time.
<li class='jc'>{@link java.time.LocalTime} - ISO local time.
<li class='jc'>{@link java.time.OffsetDateTime} - ISO offset date-time.
<li class='jc'>{@link java.time.OffsetTime} - ISO offset time.
<li class='jc'>{@link java.time.Year} - ISO year.
<li class='jc'>{@link java.time.YearMonth} - ISO year-month.
<li class='jc'>{@link java.time.Temporal} - ISO instant.
<li class='jc'>{@link java.util.TimeZone}
<li class='jc'>{@link javax.xml.datatype.XMLGregorianCalendar}
<li class='jc'>{@link java.time.ZoneId}
</ul>
<p>
Various other swaps are provided in the <c>org.apache.juneau.transforms</c> package:
</p>
<ul class='javatree'>
<li class='jp'><jk>org.apache.juneau.transforms</jk>
<ul>
<li class='jac'>{@link org.apache.juneau.transforms.ByteArraySwap}
<ul>
<li class='jc'>{@link org.apache.juneau.transforms.ByteArraySwap.Base64}
<li class='jc'>{@link org.apache.juneau.transforms.ByteArraySwap.Hex}
<li class='jc'>{@link org.apache.juneau.transforms.ByteArraySwap.SpacedHex}
</ul>
<li class='jac'>{@link org.apache.juneau.transforms.InputStreamSwap}
<ul>
<li class='jc'>{@link org.apache.juneau.transforms.InputStreamSwap.Base64}
<li class='jc'>{@link org.apache.juneau.transforms.InputStreamSwap.Hex}
<li class='jc'>{@link org.apache.juneau.transforms.InputStreamSwap.SpacedHex}
</ul>
<li class='jc'>{@link org.apache.juneau.transforms.ReaderSwap}
<li class='jac'>{@link org.apache.juneau.transforms.TemporalCalendarSwap}
<ul>
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.BasicIsoDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.IsoDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.IsoDateTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.IsoInstant}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.IsoLocalDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.IsoLocalDateTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.IsoLocalTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.IsoOffsetDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.IsoOffsetDateTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.IsoOffsetTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.IsoOrdinalDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.IsoTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.IsoWeekDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.IsoZonedDateTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap.Rfc1123DateTime}
</ul>
<li class='jac'>{@link org.apache.juneau.transforms.TemporalDateSwap}
<ul>
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.BasicIsoDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.IsoDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.IsoDateTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.IsoInstant}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.IsoLocalDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.IsoLocalDateTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.IsoLocalTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.IsoOffsetDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.IsoOffsetDateTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.IsoOffsetTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.IsoOrdinalDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.IsoTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.IsoWeekDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.IsoZonedDateTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap.Rfc1123DateTime}
</ul>
<li class='jac'>{@link org.apache.juneau.transforms.TemporalSwap}
<ul>
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.BasicIsoDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoDateTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoInstant}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoLocalDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoLocalDateTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoLocalTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoOffsetDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoOffsetDateTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoOffsetTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoOrdinalDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoWeekDate}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoYear}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoYearMonth}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.IsoZonedDateTime}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap.Rfc1123DateTime}
</ul>
</ul>
</li>
</ul>
</div><!-- END: 2.12.2 - juneau-marshall.Transforms.DefaultPojoSwaps -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.AutoPojoSwaps' id='juneau-marshall.Transforms.AutoPojoSwaps'>2.12.3 - Auto-detected POJO swaps</a></h4>
<div class='topic'><!-- START: 2.12.3 - juneau-marshall.Transforms.AutoPojoSwaps -->
<p>
Various methods can be defined on a class directly to affect how it gets serialized.
This can often be simpler than using <c>PojoSwaps</c>.
</p>
<p>
Objects serialized as <c>Strings</c> can be parsed back into their original objects by
implementing one of the following methods on the class:
</p>
<ul class='spaced-list'>
<li>
<c><jk>public static</jk> T fromString(String)</c> method.
<br>Any of the following method names also work:
<ul>
<li><c>valueOf(String)</c>
<li><c>parse(String)</c>
<li><c>parseString(String)</c>
<li><c>forName(String)</c>
<li><c>forString(String)</c>
</ul>
<li>
<c><jk>public</jk> T(String)</c> 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><c>fromString(String)</c> - {@link java.util.UUID}
<li><c>valueOf(String)</c> - {@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><c>parse(String)</c> - {@link java.text.DateFormat}, {@link java.text.MessageFormat},
{@link java.text.NumberFormat}, {@link java.util.Date}, {@link java.util.logging.Level}
<li><c>parseString(String)</c> - {@link javax.xml.bind.DatatypeConverter}
<li><c>forName(String)</c> - {@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 <c>toString()</c> method.
</p>
<p>
Serializing to other intermediate objects can be accomplished by defining a swap method directly on the
class:
</p>
<ul>
<li><c><jk>public</jk> X swap()</c> method, where <c>X</c> is any serializable object.
<li><c><jk>public</jk> X swap(BeanSession)</c> method, where <c>X</c> is any serializable object.
<li><c><jk>public static</jk> MyPojo unswap(X)</c> method, where <c>X</c> is any serializable object.
<li><c><jk>public static</jk> MyPojo swap(X,BeanSession)</c> method, where <c>X</c> is any serializable object.
</ul>
<p>
Serializing to and from Maps can be accomplished by defining any of the following methods:
</p>
<ul>
<li><c><jk>public</jk> Map toMap()</c> method. Can be any type of map with string keys and object vals.
<li><c><jk>public</jk> ObjectMap toMap()</c> method.
<li><c><jk>public</jk> Map toMap(BeanSession)</c> method. Can be any type of map with string keys and object vals.
<li><c><jk>public</jk> ObjectMap toMap(BeanSession)</c> method.
<li><c><jk>public static</jk> MyPojo fromMap(Map)</c> method. Can be any type of map with string keys and object vals.
<li><c><jk>public static</jk> MyPojo fromMap(ObjectMap)</c> method.
<li><c><jk>public static</jk> MyPojo fromMap(Map,BeanSession)</c> method. Can be any type of map with string keys and object vals.
<li><c><jk>public static</jk> MyPojo fromMap(ObjectMap,BeanSession)</c> method.
</ul>
<p>
The <c>BeanSession</c> 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='bpcode w800'>
<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><c><jk>public static</jk> T unswap(BeanSession, X)</c> method where <c>X</c> is the
swap class type.
<li><c><jk>public</jk> T(X)</c> constructor where <c>X</c> 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='bpcode w800'>
<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>(dictionary=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>)
);
}
}
</p>
</div><!-- END: 2.12.3 - juneau-marshall.Transforms.AutoPojoSwaps -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.PerMediaTypePojoSwaps' id='juneau-marshall.Transforms.PerMediaTypePojoSwaps'>2.12.4 - Per-media-type PojoSwaps</a></h4>
<div class='topic'><!-- START: 2.12.4 - juneau-marshall.Transforms.PerMediaTypePojoSwaps -->
<p>
Swaps can also be defined per-media-type.
</p>
<p>
The {@link org.apache.juneau.transform.PojoSwap#forMediaTypes()} method can be overridden to
provide a set of media types that the swap is invoked on.
It's also possible to define multiple swaps against the same POJO as long as they're differentiated
by media type.
When multiple swaps are defined, the best-match media type is used.
</p>
<p>
In the following example, we define 3 swaps against the same POJO.
One for JSON, one for XML, and one for all other types.
</p>
<p class='bpcode w800'>
<jk>public class</jk> PojoSwapTest {
<jk>public static class</jk> MyPojo {}
<jk>public static class</jk> MyJsonSwap <jk>extends</jk> StringSwap&lt;MyPojo&gt; {
<ja>@Override</ja> <jc>/* PojoSwap */</jc>
<jk>public</jk> MediaType[] forMediaTypes() {
<jk>return</jk> MediaType.<jsm>forStrings</jsm>(<js>"&#42;/json"</js>);
}
<ja>@Override</ja> <jc>/* PojoSwap */</jc>
<jk>public</jk> String swap(BeanSession session, MyPojo o) <jk>throws</jk> Exception {
<jk>return</jk> <js>"It's JSON!"</js>;
}
}
<jk>public static class</jk> MyXmlSwap <jk>extends</jk> StringSwap&lt;MyPojo&gt; {
<ja>@Override</ja> <jc>/* PojoSwap */</jc>
<jk>public</jk> MediaType[] forMediaTypes() {
<jk>return</jk> MediaType.<jsm>forStrings</jsm>(<js>"&#42;/xml"</js>);
}
<ja>@Override</ja> <jc>/* PojoSwap */</jc>
<jk>public</jk> String swap(BeanSession session, MyPojo o) <jk>throws</jk> Exception {
<jk>return</jk> <js>"It's XML!"</js>;
}
}
<jk>public static class</jk> MyOtherSwap <jk>extends</jk> StringSwap&lt;MyPojo&gt; {
<ja>@Override</ja> <jc>/* PojoSwap */</jc>
<jk>public</jk> MediaType[] forMediaTypes() {
<jk>return</jk> MediaType.<jsm>forStrings</jsm>(<js>"&#42;/*"</js>);
}
<ja>@Override</ja> <jc>/* PojoSwap */</jc>
<jk>public</jk> String swap(BeanSession session, MyPojo o) <jk>throws</jk> Exception {
<jk>return</jk> <js>"It's something else!"</js>;
}
}
<ja>@Test</ja>
<jk>public void</jk> doTest() <jk>throws</jk> Exception {
SerializerGroup g = SerializerGroup.<jsm>create</jsm>()
.append(JsonSerializer.<jk>class</jk>, XmlSerializer.<jk>class</jk>, HtmlSerializer.<jk>class</jk>)
.sq()
.pojoSwaps(MyJsonSwap.<jk>class</jk>, MyXmlSwap.<jk>class</jk>, MyOtherSwap.<jk>class</jk>)
.build();
MyPojo myPojo = <jk>new</jk> MyPojo();
String json = g.getWriterSerializer(<js>"text/json"</js>).serialize(myPojo);
<jsm>assertEquals</jsm>(<js>"'It\\'s JSON!'"</js>, json);
String xml = g.getWriterSerializer(<js>"text/xml"</js>).serialize(myPojo);
<jsm>assertEquals</jsm>(<js>"&lt;string&gt;It's XML!&lt;/string&gt;"</js>, xml);
String html = g.getWriterSerializer(<js>"text/html"</js>).serialize(myPojo);
<jsm>assertEquals</jsm>(<js>"&lt;string&gt;It's something else!&lt;/string&gt;"</js>, html);
}
}
</p>
<p>
When multiple swaps match the same media type, a best-match algorithm is applied to find the correct
swap to use.
</p>
<p>
In later sections we describe how annotations can be used to shorten this syntax:
</p>
<p class='bpcode w800'>
<ja>@Swaps</ja>({MyJsonSwap.<jk>class</jk>,MyXmlSwap.<jk>class</jk>,MyOtherSwap.<jk>class</jk>})
<jk>public static class</jk> MyPojo {}
<ja>@Swap</ja>(mediaTypes=<js>"&#42;/json"</js>)
<jk>public static class</jk> MyJsonSwap <jk>extends</jk> PojoSwap&lt;MyPojo,String&gt; {...}
<ja>@Swap</ja>(mediaTypes=<js>"&#42;/xml"</js>)
<jk>public static class</jk> MyXmlSwap <jk>extends</jk> PojoSwap&lt;MyPojo,String&gt; {...}
<ja>@Swap</ja>(mediaTypes=<js>"&#42;/*"</js>)
<jk>public static class</jk> MyOtherSwap <jk>extends</jk> PojoSwap&lt;MyPojo,String&gt; {...}
</p>
</div><!-- END: 2.12.4 - juneau-marshall.Transforms.PerMediaTypePojoSwaps -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.OneWayPojoSwaps' id='juneau-marshall.Transforms.OneWayPojoSwaps'>2.12.5 - One-way PojoSwaps</a></h4>
<div class='topic'><!-- START: 2.12.5 - juneau-marshall.Transforms.OneWayPojoSwaps -->
<p>
In the previous sections, we defined two-way swaps, meaning swaps where the original objects could be
reconstructing during parsing.
However, there are certain kinds of POJOs that we may want to support for serializing, but that are not
possible to reconstruct during parsing.
For these, we can use one-way object swaps.
</p>
<p>
A one-way POJO swap is simply an object transform that only implements the {@code swap()} method.
The {@code unswap()} method is simply left unimplemented.
</p>
<p>
An example of a one-way swaps would be one that allows {@code Iterators} to be serialized as JSON arrays.
It can make sense to be able to render {@code Iterators} as arrays, but in general it's not possible to
reconstruct an {@code Iterator} during parsing.
</p>
<p class='bpcode w800'>
<jk>public class</jk> IteratorSwap <jk>extends</jk> PojoSwap&lt;Iterator,List&gt; {
<ja>@Override</ja> <jc>/* PojoSwap */</jc>
<jk>public</jk> List swap(Iterator o) {
List l = <jk>new</jk> LinkedList();
<jk>while</jk> (o.hasNext())
l.add(o.next());
<jk>return</jk> l;
}
}
</p>
<p>
Here is an example of our one-way swap being used.
Note that trying to parse the original object will cause a {@link org.apache.juneau.parser.ParseException}
to be thrown.
</p>
<p class='bpcode w800'>
<jc>// Create a JSON serializer that can serialize Iterators.</jc>
WriterSerializer s = JsonSerializer.<jsm>create</jsm>().simple().pojoSwaps(IteratorSwap.<jk>class</jk>).build();
<jc>// Construct an iterator we want to serialize.</jc>
Iterator i = <jk>new</jk> ObjectList(1,2,3).iterator();
<jc>// Serialize our Iterator</jc>
String json = s.serialize(i); <jc>// Produces "[1,2,3]"</jc>
<jc>// Try to parse it.</jc>
ReaderParser p = JsonParser.<jsm>create</jsm>().pojoSwaps(IteratorSwap.<jk>class</jk>).build();
i = p.parse(s, Iterator.<jk>class</jk>); <jc>// Throws ParseException!!!</jc>
</p>
</div><!-- END: 2.12.5 - juneau-marshall.Transforms.OneWayPojoSwaps -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.SwapAnnotation' id='juneau-marshall.Transforms.SwapAnnotation'>2.12.6 - @Swap Annotation</a></h4>
<div class='topic'><!-- START: 2.12.6 - juneau-marshall.Transforms.SwapAnnotation -->
<p>
{@link org.apache.juneau.annotation.Swap @Swap} can be used to associate a swap class using an
annotation.
This is often cleaner than using the builder <c>pojoSwaps()</c> method since you can keep
your swap class near your POJO class.
</p>
<p class='bpcode w800'>
<ja>@Swap</ja>(MyPojoSwap.<jk>class</jk>)
<jk>public class</jk> MyPojo {
...
}
<jc>// Sample swap for converting MyPojo classes to a simple string.</jc>
<jk>public class</jk> MyPojoSwap <jk>extends</jk> PojoSwap&lt;MyPojo,String&gt; {
<ja>@Override</ja> <jc>/* PojoSwap */</jc>
<jk>public</jk> String swap(BeanSession session, MyPojo o) {
<jk>return</jk> o.toSomeSerializableForm();
}
}
</p>
<p>
Multiple swaps can be associated with a POJO by using the {@link org.apache.juneau.annotation.Swaps @Swaps} annotation:
</p>
<p class='bpcode w800'>
<ja>@Swaps</ja>(
{
<ja>@Swap</ja>(MyJsonSwap.<jk>class</jk>),
<ja>@Swap</ja>(MyXmlSwap.<jk>class</jk>),
<ja>@Swap</ja>(MyOtherSwap.<jk>class</jk>)
}
)
<jk>public class</jk> MyPojo {}
</p>
<p>
<c>Readers</c> get serialized directly to the output of a serializer.
Therefore it's possible to implement a swap that provides fully-customized output.
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyJsonSwap <jk>extends</jk> PojoSwap&lt;MyPojo,Reader&gt; {
<jk>public</jk> MediaType[] forMediaTypes() {
<jk>return</jk> MediaType.<jsm>forStrings</jsm>(<js>"&#42;/json"</js>);
}
<jk>public</jk> Reader swap(BeanSession session, MyPojo o) <jk>throws</jk> Exception {
<jk>return new</jk> StringReader(<js>"{message:'Custom JSON!'}"</js>);
}
}
</p>
<p>
The <ja>@Swap</ja> annotation can also be used on getters and setters as well to apply a swap
to individual property values:
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
<jk>private</jk> MyPojo <jf>myPojo</jf>;
<jc>// Swap applied to bean property.
<ja>@Beanp</ja>(swap=MyPojoSwap.<jk>class</jk>)
<jk>public</jk> MyPojo getMyPojo() {
<jk>return</jk> <jf>myPojo</jf>;
}
}
</p>
<p>
When applied to bean properties, the swap annotation need only be applied to either the getter, setter, or field.
</p>
<p>
The swap annotation can also be applied to the private field of a bean property, like so:
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
<ja>@Beanp</ja>(swap=MyPojoSwap.<jk>class</jk>)
<jk>private</jk> MyPojo <jf>myPojo</jf>;
<jk>public</jk> MyPojo getMyPojo() {
<jk>return</jk> <jf>myPojo</jf>;
}
<jk>public</jk> MyBean setMyPojo(MyPojo myPojo) {
<jk>this</jk>.<jf>myPojo</jf> = myPojo;
<jk>return this</jk>;
}
}
</p>
</div><!-- END: 2.12.6 - juneau-marshall.Transforms.SwapAnnotation -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.TemplatedSwaps' id='juneau-marshall.Transforms.TemplatedSwaps'>2.12.7 - Templated Swaps</a></h4>
<div class='topic'><!-- START: 2.12.7 - juneau-marshall.Transforms.TemplatedSwaps -->
<p>
The {@link org.apache.juneau.annotation.Swap#template() @Swap(template)} annotation allows you to associate
arbitrary contextual strings with swaps.
The primary purpose is for providing template names, such as for Apache FreeMarker, therefore
the name 'template'.
However, the usage of the string is open-ended.
</p>
<p>
For example, you could pair a template string like so:
</p>
<p class='bpcode w800'>
<ja>@Swap</ja>(impl=FreeMarkerSwap.<jk>class</jk>, template=<js>"MyPojo.div.ftl"</js>)
<jk>public class</jk> MyPojo {}
</p>
<p>
The implementation of the FreeMarker swap would look something like this:
</p>
<p class='bpcode w800'>
<jc>// Our templated swap class.</jc>
<jk>public class</jk> FreeMarkerSwap <jk>extends</jk> PojoSwap&lt;Object,Reader&gt; {
<jk>public</jk> MediaType[] forMediaTypes() {
<jc>// Make sure this only applies to the HTML serializer.</jc>
<jk>return</jk> MediaType.<jsm>forStrings</jsm>(<js>"&#42;/html"</js>);
}
<jk>public</jk> Reader swap(BeanSession session, Object o, String template) <jk>throws</jk> Exception {
<jc>// Call some method that uses FreeMarker to convert 'o' to raw HTML using </jc>
<jc>// the 'MyPojo.div.ftl' template.</jc>
<jk>return</jk> getFreeMarkerReader(template, o);
}
}
</p>
</div><!-- END: 2.12.7 - juneau-marshall.Transforms.TemplatedSwaps -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.SurrogateClasses' id='juneau-marshall.Transforms.SurrogateClasses'>2.12.8 - Surrogate Classes</a></h4>
<div class='topic'><!-- START: 2.12.8 - juneau-marshall.Transforms.SurrogateClasses -->
<p>
<p>
Surrogate classes are very similar in concept to <c>PojoSwaps</c> except they're simpler to define.
</p>
<p>
For example, let's say we want to be able to serialize the following class, but it's not serializable for
some reason (for example, there are no properties exposed):
<p class='bpcode w800'>
<jc>// Not serializable because it's not a bean because it has no public properties.</jc>
<jk>public class</jk> MyNonSerializableClass {
<jk>protected</jk> String <jf>foo</jf>;
}
</p>
<p>
This could be solved with the following <c>PojoSwap</c>.
</p>
<p class='bpcode w800'>
<jc>// A serializable bean with 1 property.</jc>
<jk>public class</jk> MySerializableSurrogate {
<jk>public</jk> String <jf>foo</jf>;
}
<jc>// A PojoSwap that swaps out our non-serializable object with our serializable object.</jc>
<jk>public class</jk> MySwap <jk>extends</jk> PojoSwap&lt;MyNonSerializableClass,MySerializableSurrogate&gt; {
<ja>@Override</ja> <jc>/* PojoSwap */</jc>
<jk>public</jk> MySerializableSurrogate swap(MyNonSerializableClass o) {
<jc>// Create some serializable class and manually copy the data into it.</jc>
MySerializableSurrogate s = <jk>new</jk> MySerializableSurrogate();
s.<jf>foo</jf> = o.<jf>foo</jf>;
<jk>return</jk> s;
}
}
</p>
<p>
However, the same can be accomplished by using a surrogate class that simply contains a constructor with
the non-serializable class as an argument:
</p>
<p class='bpcode w800'>
<jk>public class</jk> MySerializableSurrogate {
<jk>public</jk> String <jf>foo</jf>;
<jc>// Constructor takes in our non-serializable object!</jc>
<jk>public</jk> MySerializableSurrogate(MyNonSerializableClass c) {
<jk>this</jk>.<jf>foo</jf> = c.<jf>foo</jf>;
}
}
</p>
<p>
The surrogate class is registered in the same way as a <c>PojoSwap</c>:
</p>
<p class='bpcode w800'>
<jc>// Create a JSON serializer that can serialize Iterators.</jc>
WriterSerializer s = JsonSerializer.<jsm>create</jsm>().pojoSwaps(MySerializableSurrogate.<jk>class</jk>).build();
</p>
<p>
When the serializer encounters the non-serializable class, it will serialize an instance of the surrogate
instead.
</p>
<ul class='seealso'>
<li class='jic'>{@link org.apache.juneau.transform.Surrogate}
</ul>
</div><!-- END: 2.12.8 - juneau-marshall.Transforms.SurrogateClasses -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.BeanAnnotation' id='juneau-marshall.Transforms.BeanAnnotation'>2.12.9 - @Bean Annotation</a></h4>
<div class='topic'><!-- START: 2.12.9 - juneau-marshall.Transforms.BeanAnnotation -->
<p>
The {@link org.apache.juneau.annotation.Bean @Bean} annotation is used to tailor how beans are
interpreted by the framework.
</p>
<p>
Bean property inclusion and ordering on a bean class can be done using the
{@link org.apache.juneau.annotation.Bean#properties() @Bean(properties)} annotation.
</p>
<p class='bpcode w800'>
<jc>// Address class with only street/city/state properties (in that order).</jc>
<jc>// All other properties are ignored.</jc>
<ja>@Bean</ja>(bpi=<js>"street,city,state"</js>)
<jk>public class</jk> Address { ... }
</p>
<p>
Bean properties can be excluded using the {@link org.apache.juneau.annotation.Bean#bpx() @Bean(bpx)}
annotation.
</p>
<p class='bpcode w800'>
<jc>// Address class with only street/city/state properties (in that order).</jc>
<jc>// All other properties are ignored.</jc>
<ja>@Bean</ja>(bpx=<js>"city,state"</js>})
<jk>public class</jk> Address { ... }
</p>
<p>
Bean properties can be sorted alphabetically using {@link org.apache.juneau.annotation.Bean#sort() @Bean(sort)}
</p>
<p class='bpcode w800'>
<jc>// Address class with only street/city/state properties (in that order).</jc>
<jc>// All other properties are ignored.</jc>
<ja>@Bean</ja>(sort=<jk>true</jk>)
<jk>public class</jk> MyBean { ... }
</p>
<p>
The {@link org.apache.juneau.annotation.Bean#propertyNamer() @Bean(propertyNamer)} annotation
is used to provide customized naming of properties.
</p>
<p>
Property namers are used to transform bean property names from standard form to some other form.
For example, the {@link org.apache.juneau.PropertyNamerDLC} will convert property names to
dashed-lowercase, and these will be used as attribute names in JSON and element names in XML.
</p>
<p class='bpcode w800'>
<jc>// Define a class with dashed-lowercase property names.</jc>
<ja>@Bean</ja>(propertyNamer=PropertyNamerDashedLC.<jk>class</jk>)
<jk>public class</jk> MyBean { ... }
</p>
<p>
The {@link org.apache.juneau.annotation.Bean#interfaceClass @Bean(interfaceClass)} annotation is used
to limit properties on beans to specific interface classes.
When specified, only the list of properties defined on the interface class will be used during
serialization.
Additional properties on subclasses will be ignored.
</p>
<p class='bpcode w800'>
<jc>// Parent class</jc>
<ja>@Bean</ja>(interfaceClass=A.<jk>class</jk>)
<jk>public abstract class</jk> A {
<jk>public</jk> String <jf>f0</jf> = <js>"f0"</js>;
}
<jc>// Child class</jc>
<jk>public class</jk> A1 <jk>extends</jk> A {
<jk>public</jk> String <jf>f1</jf> = <js>"f1"</js>;
}
JsonSerializer s = SimpleJsonSerializer.<jsf>DEFAULT</jsf>;
A1 a1 = <jk>new</jk> A1();
String r = s.serialize(a1);
<jsm>assertEquals</jsm>(<js>"{f0:'f0'}"</js>, r); <jc>// Note f1 is not serialized.</jc>
</p>
<p>
Note that this annotation can be used on the parent class so that it filters to all child classes.
Or can be set individually on the child classes.
</p>
<p>
The {@link org.apache.juneau.annotation.Bean#stopClass @Bean(stopClass)} annotation is another
way to limit which properties are serialized (except from the opposite direction).
It's identical in purpose to the stop class specified by {@link java.beans.Introspector#getBeanInfo(Class, Class)}.
Any properties in the stop class or in its base classes will be ignored during analysis.
</p>
<p>
For example, in the following class hierarchy, instances of <c>C3</c> will include property
<c>p3</c>, but not <c>p1</c> or <c>p2</c>.
</p>
<p class='bpcode w800'>
<jk>public class</jk> C1 {
<jk>public int</jk> getP1();
}
<jk>public class</jk> C2 <jk>extends</jk> C1 {
<jk>public int</jk> getP2();
}
<ja>@Bean</ja>(stopClass=C2.<jk>class</jk>)
<jk>public class</jk> C3 <jk>extends</jk> C2 {
<jk>public int</jk> getP3();
}
</p>
<p>
The {@link org.apache.juneau.annotation.Bean#propertyFilter() @Bean(propertyFilter)} annotation
and {@link org.apache.juneau.transform.PropertyFilter} class can be used to perform interception
and inline handling of bean getter and setter calls.
</p>
<p class='bpcode w800'>
<jc>// Register filter on bean class.</jc>
<ja>@Bean</ja>(propertyFilter=AddressPropertyFilter.<jk>class</jk>)
<jk>public class</jk> Address {
<jk>public</jk> String getTaxInfo() {...}
<jk>public void</jk> setTaxInfo(String s) {...}
}
<jc>// Property filter that strips out sensitive information in our bean.</jc>
<jk>public class</jk> AddressPropertyFilter <jk>extends</jk> PropertyFilter {
<ja>@Override</ja> <jc>/* PropertyFilter */</jc>
<jk>public</jk> Object readProperty(Object bean, String name, Object value) {
<jk>if</jk> (<js>"taxInfo"</js>.equals(name))
<jk>return</jk> <js>"redacted"</js>;
<jk>return</jk> value;
}
<ja>@Override</ja> <jc>/* PropertyFilter */</jc>
<jk>public</jk> Object writeProperty(Object bean, String name, Object value) {
AddressBook a = (Address)bean;
<jk>if</jk> (<js>"taxInfo"</js>.equals(name) &amp;&amp; <js>"redacted"</js>.equals(value))
<jk>return</jk> TaxInfoUtils.<jsm>lookUpByName</jsm>(a.getStreet(), a.getCity(), a.getState());
<jk>return</jk> value;
}
}
</p>
</div><!-- END: 2.12.9 - juneau-marshall.Transforms.BeanAnnotation -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.BeanpAnnotation' id='juneau-marshall.Transforms.BeanpAnnotation'>2.12.10 - @Beanp Annotation</a></h4>
<div class='topic'><!-- START: 2.12.10 - juneau-marshall.Transforms.BeanpAnnotation -->
<p>
The {@link org.apache.juneau.annotation.Beanp @Beanp} annotation is used to tailor how
individual bean properties are interpreted by the framework.
</p>
<p>
The {@link org.apache.juneau.annotation.Beanp#name() @Beanp(name)} annotation
is used to override the name of the bean property.
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
<ja>@Beanp</ja>(name=<js>"Bar"</js>)
<jk>public</jk> String getFoo() {...}
}
</p>
<p>
The {@link org.apache.juneau.annotation.Name @Name} annotation is a shortcut for specifying a bean property name:
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
<ja>@Name</ja>(<js>"Bar"</js>)
<jk>public</jk> String getFoo() {...}
}
</p>
<p>
If the {@link org.apache.juneau.BeanContext#BEAN_beanFieldVisibility} setting on the bean context excludes this field
(e.g. the visibility is set to the default of PUBLIC, but the field is PROTECTED), this annotation
can be used to force the field to be identified as a property.
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
<ja>@Beanp</ja>
<jk>protected</jk> String getFoo() {...}
}
</p>
<p>
The bean property named <js>"*"</js> is the designated "dynamic property" which allows for "extra" bean
properties not otherwise defined.
This is similar in concept to the Jackson <ja>@JsonGetterAll</ja> and <ja>@JsonSetterAll</ja>
annotations, but generalized for all supported marshall languages.
The primary purpose is for backwards compatibility in parsing newer streams with addition
information into older beans.
</p>
<p>
The following shows various ways of using dynamic bean properties.
</p>
<p class='bpcode w800'>
<jc>// Option #1 - A simple public Map field.</jc>
<jc>// The field name can be anything.</jc>
<jk>public class</jk> BeanWithDynaField {
<ja>@Beanp</ja>(name=<js>"*"</js>)
<jk>public</jk> Map&lt;String,Object&gt; extraStuff = <jk>new</jk> LinkedHashMap&lt;String,Object&gt;();
}
<jc>// Option #2 - Getters and setters.</jc>
<jc>// Method names can be anything.</jc>
<jc>// Getter must return a Map with String keys.</jc>
<jc>// Setter must take in two arguments, a String and Object.</jc>
<jk>public class</jk> BeanWithDynaMethods {
<ja>@Beanp</ja>(name=<js>"*"</js>)
<jk>public</jk> Map&lt;String,Object&gt; getMyExtraStuff() {
...
}
<ja>@Beanp</ja>(name=<js>"*"</js>)
<jk>public void</jk> setAnExtraField(String name, Object value) {
...
}
}
<jc>// Option #3 - Getter only.</jc>
<jc>// Properties will be added through the getter.</jc>
<jk>public class</jk> BeanWithDynaGetterOnly {
<ja>@Beanp</ja>(name=<js>"*"</js>)
<jk>public</jk> Map&lt;String,Object&gt; getMyExtraStuff() {
...
}
}
</p>
<p>
Similar rules apply for value types and swaps.
The property values optionally can be any serializable type or use swaps.
</p>
<p class='bpcode w800'>
<jc>// A serializable type other than Object.</jc>
<jk>public class</jk> BeanWithDynaFieldWithListValues {
<ja>@Beanp</ja>(name=<js>"*"</js>)
<jk>public</jk> Map&lt;String,List&lt;String&gt;&gt; getMyExtraStuff() {
...
}
}
<jc>// A swapped value.</jc>
<jk>public class</jk> BeanWithDynaFieldWithSwappedValues {
<ja>@Beanp</ja>(name=<js>"*"</js>, swap=TemporalCalendarSwap.IsoOffsetDateTime.<jk>class</jk>)
<jk>public</jk> Map&lt;String,Calendar&gt; getMyExtraStuff() {
...
}
}
</p>
<div class='info'>
Note that if you're not interested in these additional properties, you can also use the
{@link org.apache.juneau.BeanContext#BEAN_ignoreUnknownBeanProperties} setting to ignore values
that don't fit into existing properties.
</div>
<p>
The {@link org.apache.juneau.annotation.Beanp#value() @Beanp(value)} annotation
is a synonym for {@link org.apache.juneau.annotation.Beanp#name() @Beanp(name)}.
Use it in cases where you're only specifying a name so that you can shorten your annotation.
</p>
<p>
The following annotations are equivalent:
</p>
<p class='bpcode w800'>
<ja>@Beanp</ja>(name=<js>"foo"</js>)
<ja>@Beanp</ja>(<js>"foo"</js>)
</p>
<p>
The {@link org.apache.juneau.annotation.Beanp#type() @Beanp(type)} annotation
is used to identify a specialized class type for a generalized property.
Normally the type is inferred through reflection of the field type or getter return type.
However, you'll want to specify this value if you're parsing beans where the bean property class
is an interface or abstract class to identify the bean type to instantiate.
Otherwise, you may cause an {@link java.lang.InstantiationException} when trying to set these fields.
</p>
<p>
This property must denote a concrete class with a no-arg constructor.
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
<jc>// Identify concrete type as a HashMap.</jc>
<ja>@Beanp</ja>(type=HashMap.<jk>class</jk>)
<jk>public</jk> Map <jf>p1</jf>;
}
</p>
<p>
The {@link org.apache.juneau.annotation.BeanProperty#params() @Beanp(params)} annotation
is for bean properties of type map or collection.
It's used to identify the class types of the contents of the bean property object when
the general parameter types are interfaces or abstract classes.
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
<jc>// This is a HashMap&lt;String,Integer&gt;.</jc>
<ja>@Beanp</ja>(type=HashMap.<jk>class</jk>, params={String.<jk>class</jk>,Integer.<jk>class</jk>})
<jk>public</jk> Map <jf>p1</jf>;
}
</p>
<p>
The {@link org.apache.juneau.annotation.Beanp#bpi() @Beanp(bpi)}
annotation is used to limit which child properties are rendered by the serializers.
It can be used on any of the following bean property types:
</p>
<ul class='spaced-list'>
<li>Beans - Only render the specified properties of the bean.
<li>Maps - Only render the specified entries in the map.
<li>Bean/Map arrays - Same, but applied to each element in the array.
<li>Bean/Map collections - Same, but applied to each element in the collection.
</ul>
<p class='bpcode w800'>
<jk>public class</jk> MyClass {
<jc>// Only render 'f1' when serializing this bean property.</jc>
<ja>@Beanp</ja>(bpi={<js>"f1"</js>})
<jk>public</jk> MyChildClass x1 = <jk>new</jk> MyChildClass();
}
<jk>public class</jk> MyChildClass {
<jk>public int</jk> f1 = 1;
<jk>public int</jk> f2 = 2;
}
<jc>// Renders "{x1:{f1:1}}"</jc>
String json = JsonSerializer.<jsf>DEFAULT</jsf>.serialize(<jk>new</jk> MyClass());
</p>
<p>
The {@link org.apache.juneau.annotation.Beanp#format() @Beanp(format)}
annotation specifies a String format for converting a bean property value to a formatted string.
</p>
<p class='bpcode w800'>
<jc>// Serialize a float as a string with 2 decimal places.</jc>
<ja>@Beanp</ja>(format=<js>"$%.2f"</js>)
<jk>public float</jk> <jf>price</jf>;
</p>
</div><!-- END: 2.12.10 - juneau-marshall.Transforms.BeanpAnnotation -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.BeancAnnotation' id='juneau-marshall.Transforms.BeancAnnotation'>2.12.11 - @Beanc Annotation</a></h4>
<div class='topic'><!-- START: 2.12.11 - juneau-marshall.Transforms.BeancAnnotation -->
<p>
The {@link org.apache.juneau.annotation.Beanc @Beanc} annotation is used to
map constructor arguments to property names on bean with read-only properties.
Since method parameter names are lost during compilation, this annotation essentially redefines
them so that they are available at runtime.
</p>
<p>
The definition of a read-only bean is a bean with properties with only getters, like shown below:
</p>
<p class='bpcode w800'>
<jc>// Our read-only bean.</jc>
<jk>public class</jk> Person {
<jk>private final</jk> String <jf>name</jf>;
<jk>private final int</jk> <jf>age</jf>;
<ja>@Beanc</ja>(properties=<js>"name,age"</js>})
<jk>public</jk> Person(String name, <jk>int</jk> age) {
<jk>this</jk>.<jf>name</jf> = name;
<jk>this</jk>.<jf>age</jf> = age;
}
<jc>// Read only properties.</jc>
<jc>// Getters, but no setters.</jc>
<jk>public</jk> String getName() {
<jk>return</jk> <jf>name</jf>;
}
<jk>public int</jk> getAge() {
<jk>return</jk> <jf>age</jf>;
}
}
</p>
<p class='bpcode w800'>
<jc>// Parsing into a read-only bean.</jc>
String json = <js>"{name:'John Smith',age:45}"</js>;
Person p = JsonParser.<jsf>DEFAULT</jsf>.parse(json);
String name = p.getName(); <jc>// "John Smith"</jc>
<jk>int</jk> age = p.getAge(); <jc>// 45</jc>
</p>
<p>
Beans can also be defined with a combination of read-only and read-write properties.
</p>
<p>
The {@link org.apache.juneau.annotation.Name @Name} annotation can also be used instead of <c><ja>@Beanc</ja>(properties)</c>:
</p>
<p class='bpcode w800'>
<ja>@Beanc</ja>
<jk>public</jk> Person(<ja>@Name</ja>(<js>"name"</js>) String name, <ja>@Name</ja>(<js>"age"</js>) <jk>int</jk> age) {
<jk>this</jk>.<jf>name</jf> = name;
<jk>this</jk>.<jf>age</jf> = age;
}
</p>
<p>
If neither <c><ja>@Beanc</ja>(properties)</c> or <ja>@Name</ja> is used to identify the bean property names,
we will try to use the parameter names if they are available in the bytecode.
</p>
</div><!-- END: 2.12.11 - juneau-marshall.Transforms.BeancAnnotation -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.BeanIgnoreAnnotation' id='juneau-marshall.Transforms.BeanIgnoreAnnotation'>2.12.12 - @BeanIgnore Annotation</a></h4>
<div class='topic'><!-- START: 2.12.12 - juneau-marshall.Transforms.BeanIgnoreAnnotation -->
<p>
The {@link org.apache.juneau.annotation.BeanIgnore @BeanIgnore} annotation is used to
ignore classes, fields, and methods from being interpreted as beans or bean components.
</p>
<p>
When applied to classes, objects will be converted to strings even though they look like beans.
</p>
<p class='bpcode w800'>
<jc>// Not really a bean! Use toString() instead!</jc>
<ja>@BeanIgnore</ja>
<jk>public class</jk> MyBean {...}
</p>
<p>
When applied to fields and getters/setters, they will be ignored as bean properties.
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
<jc>// Not a bean property!</jc>
<ja>@BeanIgnore</ja>
<jk>public</jk> String <jf>foo</jf>;
<jc>// Not a bean property!</jc>
<ja>@BeanIgnore</ja>
<jk>public</jk> String getBar() {...}
}
</p>
</div><!-- END: 2.12.12 - juneau-marshall.Transforms.BeanIgnoreAnnotation -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.NamePropertyAnnotation' id='juneau-marshall.Transforms.NamePropertyAnnotation'>2.12.13 - @NameProperty Annotation</a></h4>
<div class='topic'><!-- START: 2.12.13 - juneau-marshall.Transforms.NamePropertyAnnotation -->
<p>
The {@link org.apache.juneau.annotation.NameProperty @NameProperty} annotation is used to
identify a setter as a method for setting the name of a POJO as it's known by its parent object.
</p>
<p>
A commonly-used case is when you're parsing a JSON map containing beans where one of the bean
properties is the key used in the map.
</p>
<p class='bpcode w800'>
<jc>// JSON</jc>
{
<jok>id1</jok>: {<jok>name</jok>: <jov>'John Smith'</jov>, <jok>sex</jok>: <jov>'M'</jov>},
<jok>id2</jok>: {<jok>name</jok>: <jov>'Jane Doe'</jov>, <jok>sex</jok>: <jov>'F'</jov>}
}
</p>
<p class='bpcode w800'>
<jk>public class</jk> Person {
<ja>@NameProperty</ja>
<jk>public</jk> String <jf>id</jf>; <jc>// Value gets assigned from object key</jc>
<jk>public</jk> String <jf>name</jf>;
<jk>public char</jk> <jf>sex</jf>;
}
</p>
</div><!-- END: 2.12.13 - juneau-marshall.Transforms.NamePropertyAnnotation -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.ParentPropertyAnnotation' id='juneau-marshall.Transforms.ParentPropertyAnnotation'>2.12.14 - @ParentProperty Annotation</a></h4>
<div class='topic'><!-- START: 2.12.14 - juneau-marshall.Transforms.ParentPropertyAnnotation -->
<p>
The {@link org.apache.juneau.annotation.ParentProperty @ParentProperty} annotation is used to
identify a setter as a method for adding a parent reference to a child object.
</p>
<p>
A commonly-used case is when you're parsing beans and a child bean has a reference to a parent bean.
</p>
<p class='bpcode w800'>
<jk>public class</jk> AddressBook {
<jk>public</jk> List&lt;Person&gt; <jf>people</jf>;
}
<jk>public class</jk> Person {
<ja>@ParentProperty</ja>
<jk>public</jk> AddressBook <jf>addressBook</jf>; <jc>// A reference to the containing address book.</jc>
<jk>public</jk> String <jf>name</jf>;
<jk>public char</jk> <jf>sex</jf>;
}
</p>
<p>
Parsers will automatically set this field for you in the child beans.
</p>
</div><!-- END: 2.12.14 - juneau-marshall.Transforms.ParentPropertyAnnotation -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.PojoBuilders' id='juneau-marshall.Transforms.PojoBuilders'>2.12.15 - POJO Builders</a></h4>
<div class='topic'><!-- START: 2.12.15 - juneau-marshall.Transforms.PojoBuilders -->
<p>
Juneau parsers can use builders to instantiate POJOs.
This is useful in cases where you want to create beans with read-only properties.
Note that while it's possible to do this using the {@link org.apache.juneau.annotation.Beanc @Beanc}
annotation, using builders can often be cleaner.
</p>
<p>
A typical builder usage is shown below:
</p>
<p class='bpcode w800'>
MyBean b = MyBean.<jsm>create</jsm>().foo(<js>"foo"</js>).bar(123).build();
</p>
<p>
The code for such a builder is shown below:
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
<jc>// Read-only properties.</jc>
<jk>public final</jk> String <jf>foo</jf>;
<jk>public final int</jk> <jf>bar</jf>;
<jc>// Private constructor.</jc>
<jk>private</jk> MyBean(MyBeanBuilder b) {
<jk>this</jk>.<jf>foo</jf> = b.foo;
<jk>this</jk>.<jf>bar</jf> = b.bar;
}
<jc>// Static method that creates a builder.</jc>
<jk>public static</jk> MyBeanBuilder <jsm>create</jsm>() {
<jk>return new</jk> MyBeanBuilder();
}
<jc>// Builder class.</jc>
<jk>public static class</jk> MyBeanBuilder {
<jk>private</jk> String <jf>foo</jf>;
<jk>private int</jk> <jf>bar</jf>;
<jc>// Method that creates the bean.</jc>
<jk>public</jk> MyBean build() {
<jk>return new</jk> MyBean(<jk>this</jk>);
}
<jc>// Bean property setters.</jc>
<ja>@Beanp</ja>
<jk>public</jk> MyBeanBuilder foo(String foo) {
<jk>this</jk>.<jf>foo</jf> = foo;
<jk>return this</jk>;
}
<ja>@Beanp</ja>
<jk>public</jk> MyBeanBuilder bar(<jk>int</jk> bar) {
<jk>this</jk>.<jf>bar</jf> = bar;
<jk>return this</jk>;
}
}
}
</p>
<p>
The POJO class can be any type including beans.
Builders MUST be beans with one or more writable properties.
The bean properties themselves do not need to be readable (i.e. getters are optional).
</p>
<p>
Builders require two parts:
</p>
<ol>
<li>A way to detect and instantiate a builder using reflection.
<li>A way to instantiate a POJO from a builder.
</ol>
<p>
The first can be accomplished through any of the following:
</p>
<ul class='spaced-list'>
<li>A static <c>create()</c> method on the POJO class that returns a builder instance.
<p class='bcode w800'>
<jk>public static</jk> MyBuilder <jsm>create</jsm>() {...}
</p>
<li>A public constructor on the POJO class that takes in a single parameter that implements the {@link org.apache.juneau.transform.Builder} interface.
<br>The builder class must have a public no-arg constructor.
<p class='bcode w800'>
<jk>public</jk> MyPojo(MyBuilder b) {...}
</p>
<li>A {@link org.apache.juneau.annotation.Builder @Builder} annotation on the POJO class.
<br>The builder class must have a public no-arg constructor.
<p class='bcode w800'>
<ja>@Builder</ja>(MyBuilder.<jk>class</jk>)
<jk>public class</jk> MyPojo {...}
</p>
</ul>
<p>
The second can be accomplished through any of the following:
</p>
<ul class='spaced-list'>
<li>The existence of a <c>build()</c> method on the builder class.
<p class='bcode w800'>
<jk>public</jk> MyPojo build() {...}
</p>
<li>The existence of a public constructor on the POJO class that takes in the builder instance.
<p class='bcode w800'>
<jk>public</jk> MyPojo(MyBuilder b) {...}
</p>
</ul>
<ul class='seealso'>
<li class='ja'>{@link org.apache.juneau.annotation.Builder}
<li class='jic'>{@link org.apache.juneau.transform.Builder}
</ul>
</div><!-- END: 2.12.15 - juneau-marshall.Transforms.PojoBuilders -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.BeanFilters' id='juneau-marshall.Transforms.BeanFilters'>2.12.16 - BeanFilter Class</a></h4>
<div class='topic'><!-- START: 2.12.16 - juneau-marshall.Transforms.BeanFilters -->
<p>
The {@link org.apache.juneau.transform.BeanFilter} class is the programmatic equivalent to the
{@link org.apache.juneau.annotation.Bean @Bean} annotation.
</p>
<p>
In practice, it's usually simpler to use the {@link org.apache.juneau.annotation.Bean @Bean} and
{@link org.apache.juneau.annotation.Beanp @Beanp} annotations on your bean classes.
However, bean filters make it possible to accomplish the same when you can't add annotations
to existing code.
</p>
<p>
Bean filters are defined through {@link org.apache.juneau.transform.BeanFilterBuilder BeanFilterBuilders}.
</p>
<p>
In the previous examples, we defined this bean annotation:
</p>
<p class='bpcode w800'>
<ja>@Bean</ja>(bpi=<js>"street,city,state"</js>)
<jk>public class</jk> Address { ... }
</p>
<p>
The programmatic equivalent would be:
</p>
<p class='bpcode w800'>
<jk>public class</jk> AddressFilter <jk>extends</jk> BeanFilterBuilder&lt;Address&gt; {
<jc>// Must provide a no-arg constructor!</jc>
<jk>public</jk> AddressFilter() {
bpi(<js>"street,city,state"</js>); <jc>// The properties we want exposed.</jc>
}
}
</p>
<p>
Bean filters are added to serializers and parsers using the following:
</p>
<ul class='javatree'>
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanFilters}
<li class='jm'>{@link org.apache.juneau.BeanContextBuilder#beanFilters(Object...)}
</ul>
<p>
For example:
</p>
<p class='bpcode w800'>
<jc>// Create a new JSON serializer and associate a bean filter with it.</jc>
WriterSerializer s = JsonSerializer
.<jsm>create</jsm>()
.beanFilters(AddressFilter.<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 {@link org.apache.juneau.BeanContextBuilder#beanFilters(Object...)} 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='bpcode w800'>
<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 {
<jk>public</jk> String getStreet() {...};
<jk>public</jk> String getCity() {...};
<jk>public</jk> String getState() {...};
<jk>public</jk> String getCountry() {...};
}
<jc>// Create a new JSON serializer that only exposes street,city,state on Address bean.</jc>
<jc>// The 'country' field will be ignored.</jc>
WriterSerializer s = JsonSerializer
.<jsm>create</jsm>()
.beanFilters(AddressInterface.<jk>class</jk>)
.build();
</p>
</div><!-- END: 2.12.16 - juneau-marshall.Transforms.BeanFilters -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.InterfaceFilters' id='juneau-marshall.Transforms.InterfaceFilters'>2.12.17 - Interface Filters</a></h4>
<div class='topic'><!-- START: 2.12.17 - juneau-marshall.Transforms.InterfaceFilters -->
<p>
Occasionally, you may want to limit bean properties to only those defined on a parent class or interface.
This is accomplished through interface filters.
</p>
<p>
Interface filters are defined through the following:
</p>
<ul class='javatree'>
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanFilters}
<li class='ja'>{@link org.apache.juneau.annotation.Bean#interfaceClass() Bean(interfaceClass)}
<li class='jm'>{@link org.apache.juneau.transform.BeanFilterBuilder#interfaceClass(Class)}
</ul>
<p>
For example, let's define the following interface and implementation:
</p>
<p class='bpcode w800'>
<jc>// Interface</jc>
<jk>public class</jk> MyInterface {
<jk>public</jk> String getFoo();
}
<jc>// Implementation</jc>
<jk>public class</jk> MyInterfaceImpl <jk>implements</jk> MyInterface {
<jk>public</jk> String getFoo() {...}
<jk>public</jk> String getBar() {...}
}
</p>
<p>
Suppose we only want to render the properties defined on our interface, not the implementation.
To do so, we can define the following bean filter:
</p>
<p class='bpcode w800'>
<jc>// Define transform that limits properties to only those defined on MyClass</jc>
<jk>public class</jk> MyInterfaceFilter <jk>extends</jk> BeanFilter&lt;MyInterface&gt; {
<jk>public</jk> MyInterfaceFilter() {
interfaceClass(MyInterface.<jk>class</jk>);
}
}
</p>
<p>
When serialized, the serialized bean will only include properties defined on the interface.
</p>
<p class='bpcode w800'>
WriterSerializer s = JsonSerializer
.<jsm>create</jsm>()
.simple()
.beanFilters(MyInterfaceFilter.<jk>class</jk>)
.build();
MyInterface o = <jk>new</jk> MyInterfaceImpl();
<jc>// Prints "{foo:'foo'}"</jc>
<jc>// bar is ignored because it's not on the interface</jc>
String json = s.serialize(o);
</p>
<p>
The {@link org.apache.juneau.BeanContextBuilder#beanFilters(Object...)} method will automatically interpret any
non-<c>BeanFilter</c> classes passed in as meaning interface classes.
So in the previous example, the <c>BeanFilter</c> class could have been avoided altogether by just
passing in <c>MyInterface.<jk>class</jk></c> to the serializer, like so:
</p>
<p class='bpcode w800'>
WriterSerializer s = JsonSerializer
.<jsm>create</jsm>()
.beanFilters(MyInterface.<jk>class</jk>) <jc>Shortcut!</jc>
.build();
</p>
<p>
The annotation equivalent is {@link org.apache.juneau.annotation.Bean#interfaceClass() Bean#interfaceClass()}.
</p>
<p class='bpcode w800'>
<ja>@Bean</ja>(interfaceClass=MyInterface.<jk>class</jk>)
<jk>public class</jk> MyInterfaceImpl <jk>implements</jk> MyInterface {
<jk>public</jk> String getFoo() {...}
<jk>public</jk> String getBar() {...}
}
</p>
<p>
The annotation can be used in a couple of ways.
</p>
<p>
Using the annotation on an interface will be inherited by all children.
</p>
<p class='bpcode w800'>
<ja>@Bean</ja>(interfaceClass=MyInterface.<jk>class</jk>)
<jk>public class</jk> MyInterface {
<jk>public</jk> String getFoo();
}
</p>
<p>
The annotation can be used on parent classes as well.
Child beans will only serialize properties defined on the parent class.
<p class='bpcode w800'>
<ja>@Bean</ja>(interfaceClass=MyAbstractClass.<jk>class</jk>)
<jk>public abstract class</jk> MyAbstractClass {
<jk>public</jk> String getFoo() {...};
}
</p>
</div><!-- END: 2.12.17 - juneau-marshall.Transforms.InterfaceFilters -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.StopClasses' id='juneau-marshall.Transforms.StopClasses'>2.12.18 - Stop Classes</a></h4>
<div class='topic'><!-- START: 2.12.18 - juneau-marshall.Transforms.StopClasses -->
<p>
Whereas interface filters limit properties defined on child classes, stop filters
do the opposite and limit properties defined on parent classes.
</p>
<p>
Stop classes are defined through the following:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.annotation.Bean#stopClass() Bean(stopClass)}
<li class='jf'>{@link org.apache.juneau.transform.BeanFilterBuilder#stopClass(Class)}
</ul>
<p>
Stop classes are identical in purpose to the stop class specified by {@link java.beans.Introspector#getBeanInfo(Class, Class)}.
Any properties in the stop class or in its base classes will be ignored during serialization.
</p>
<p>
For example, in the following class hierarchy, instances of <c>C3</c> will include property <c>p3</c>,
but not <c>p1</c> or <c>p2</c>.
</p>
<p class='bpcode w800'>
<jk>public class</jk> C1 {
<jk>public int</jk> getP1();
}
<jk>public class</jk> C2 <jk>extends</jk> C1 {
<jk>public int</jk> getP2();
}
<ja>@Bean</ja>(stopClass=C2.<jk>class</jk>)
<jk>public class</jk> C3 <jk>extends</jk> C2 {
<jk>public int</jk> getP3();
}
<jc>// Serializes property 'p3', but NOT 'p1' or 'p2'.</jc>
String json = JsonSerializer.<jsf>DEFAULT</jsf>.serialize(<jk>new</jk> C3());
</p>
</div><!-- END: 2.12.18 - juneau-marshall.Transforms.StopClasses -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Transforms.BypassSerialization' id='juneau-marshall.Transforms.BypassSerialization'>2.12.19 - Bypass Serialization using Readers and InputStreams</a></h4>
<div class='topic'><!-- START: 2.12.19 - juneau-marshall.Transforms.BypassSerialization -->
<p>
Juneau serializers treat instances of <c>Readers</c> and <c>InputStreams</c> special by
simply serializing their contents directly to the output stream or writer.
This allows you to embed fully customized serializer output.
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
<jc>// A bean property that produces raw JSON.</jc>
<jk>public</jk> Reader f1 = <jk>new</jk> StringReader(<js>"{'foo':'bar'}"</js>);
}
<jc>// Produces "{f1:{'foo':'bar'}}"</jc>
String json = SimpleJsonSerializer.<jsf>DEFAULT</jsf>
.toString(<jk>new</jk> MyBean());
</p>
<p>
Note that if you're serializing Readers and InputStreams, it's up to you to make sure you're producing
valid output (in this case JSON).
</p>
<p>
A more typical scenario where this is useful is by using swaps to convert POJOs to Readers whose
contents are determined via the {@link org.apache.juneau.BeanSession#getMediaType()} method.
In the following example, we're customizing the JSON output for a particular bean type, but leaving
all other renditions as-is:
</p>
<p class='bpcode w800'>
<ja>@Swap</ja>(MyBeanSwapSometimes.<jk>class</jk>)
<jk>public class</jk> MyBean {...}
<jc>// A swap that produces specialized output for JSON, but default serialization for</jc>
<jc>// all other media types.</jc>
<jk>public class</jk> MyBeanSwapSometimes <jk>extends</jk> PojoSwap&lt;MyBean,Object&gt; {
<jk>public</jk> Object swap(BeanSession session, MyPojo o) <jk>throws</jk> Exception {
MediaType mt = session.getMediaType();
<jk>if</jk> (mt.hasSubType(<js>"json"</js>))
<jk>return new</jk> StringReader(<js>"{myPojo:'foobar'}"</js>); <jc>// Custom JSON output</jc>
<jk>return</jk> o; <jc>// Otherwise serialize it as a normal bean</jc>
}
}
</p>
<div class='info'>
Due to the nature of the RDF serializers, Readers and InputStreams are serialized as literals,
not as RDF text.
This is due to the fact that the RDF serializers use a DOM for serialization, so we don't have
access to the underlying stream.
</div>
</div><!-- END: 2.12.19 - juneau-marshall.Transforms.BypassSerialization -->
</div><!-- END: 2.12 - juneau-marshall.Transforms -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.BeanDictionaries' id='juneau-marshall.BeanDictionaries'>2.13 - Bean Names and Dictionaries</a></h3>
<div class='topic'><!-- START: 2.13 - juneau-marshall.BeanDictionaries -->
<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 dictionaries 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 <c>Object</c>, then the serializer will add
<js>"_type"</js> attributes so that the class can be determined during parsing.
</p>
<p class='bpcode w800'>
<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>@Beanp</ja>(dictionary={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='bpcode w800'>
{
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 <c>typeName</c> 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='bpcode w800'>
<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 registered through the following:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.annotation.Beanp#dictionary() Beanp(dictionary)}
- On individual bean properties through the annotation.
<li class='ja'>{@link org.apache.juneau.annotation.Bean#dictionary() Bean(dictionary)}
- On all properties on a bean and all subclasses.
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanDictionary}
- Configuration property on serializers and parsers.
<li class='jm'>{@link org.apache.juneau.BeanContextBuilder#dictionary(Object...)}
- Builder method on serializers and parsers.
</ul>
<p>
The bean dictionary setting can consist of any of the following types:
</p>
<ul>
<li>Any bean class that specifies a value for {@link org.apache.juneau.annotation.Bean#typeName() @Bean(typeName)}.
<li>Any subclass of {@link org.apache.juneau.BeanDictionaryList} containing a collection of bean classes with type name annotations.
<li>Any subclass of {@link org.apache.juneau.BeanDictionaryMap} containing a mapping of type names to classes without type name annotations.
<li>Any array or collection of the objects above.
</ul>
<p class='bpcode w800'>
<jc>// Create a parser and tell it which classes to try to resolve.</jc>
ReaderParser p = JsonParser
.<jsm>create</jsm>()
.dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>)
.build();
<jc>// Same, but use property.</jc>
ReaderParser p = JsonParser
.<jsm>create</jsm>()
.addTo(<jsf>BEAN_beanDictionary</jsf>, Foo.<jk>class</jk>)
.addTo(<jsf>BEAN_beanDictionary</jsf>, Bar.<jk>class</jk>)
.build();
<jc>// Use the predefined HTML5 bean dictionary which is a BeanDictionaryList.</jc>
ReaderParser p = HtmlParser
.<jsm>create</jsm>()
.dictionary(HtmlBeanDictionary.<jk>class</jk>)
.build();
</p>
<p>
The <js>"_type"</js> property name can be overridden through the following:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.annotation.Bean#typePropertyName() Bean(typePropertyName)}
- On individual beans through the annotation.
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanTypePropertyName}
- Configuration property on serializers and parsers.
<li class='jm'>{@link org.apache.juneau.BeanContextBuilder#beanTypePropertyName(String)}
- Builder method on serializers and parsers.
</ul>
<p>
When using the annotation, you'll typically want to define it on an interface class so that it can
be inherited by all subclasses.
</p>
<p class='bpcode w800'>
<ja>@Bean</ja>(typePropertyName=<js>"mytype"</js>, dictionary={MyClass1.<jk>class</jk>,MyClass2.<jk>class</jk>})
<jk>public interface</jk> MyInterface {...}
<ja>@Bean</ja>(typeName=<js>"C1"</js>)
<jk>public class</jk> MyClass1 <jk>implements</jk> MyInterface {...}
<ja>@Bean</ja>(typeName=<js>"C2"</js>)
<jk>public class</jk> MyClass2 <jk>implements</jk> MyInterface {...}
MyInterface[] x = <jk>new</jk> MyInterface[]{ <jk>new</jk> MyClass1(), <jk>new</jk> MyClass2() };
<jc>// Produces "[{mytype:'C1',...},{mytype:'C2',...}]"</jc>
String json = SimpleJsonSerializer.<jsf>DEFAULT</jsf>.serialize(x);
</p>
<div class='info'>
Type names do not need to be universally unique.
However, they must be unique within a dictionary.
</div>
<div class='info'>
The following reserved words cannot be used as type names:
<c>object, array, number, boolean, null</c>.
</div>
<div class='info'>
Serialized type names are DISABLED by default.
They must be enabled on the serializer using the
{@link org.apache.juneau.serializer.Serializer#SERIALIZER_addBeanTypes}
configuration property.
</div>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.BeanDictionaries.BeanSubTypes' id='juneau-marshall.BeanDictionaries.BeanSubTypes'>2.13.1 - Bean Subtypes</a></h4>
<div class='topic'><!-- START: 2.13.1 - juneau-marshall.BeanDictionaries.BeanSubTypes -->
<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='bpcode w800'>
<jc>// Abstract superclass</jc>
<ja>@Bean</ja>(
dictionary={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='bpcode w800'>
JsonSerializer s = SimpleJsonSerializer.<jsf>DEFAULT</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='bpcode w800'>
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><!-- END: 2.13.1 - juneau-marshall.BeanDictionaries.BeanSubTypes -->
</div><!-- END: 2.13 - juneau-marshall.BeanDictionaries -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.VirtualBeans' id='juneau-marshall.VirtualBeans'>2.14 - Virtual Beans</a></h3>
<div class='topic'><!-- START: 2.14 - juneau-marshall.VirtualBeans -->
<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='bpcode w800'>
<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 {@doc PojoCategories parsable} values, even other virtual beans.
</p>
<p>
Under-the-covers, a virtual bean is simply a proxy interface on top of an existing <c>BeanMap</c>
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 <c>BeanContext</c> class:
</p>
<p class='bpcode w800'>
Address address = BeanContext.<jsf>DEFAULT</jsf>.createSession().newBean(Address.<jk>class</jk>);
</p>
</div><!-- END: 2.14 - juneau-marshall.VirtualBeans -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.Recursion' id='juneau-marshall.Recursion'>2.15 - Non-Tree Models and Recursion Detection</a></h3>
<div class='topic'><!-- START: 2.15 - juneau-marshall.Recursion -->
<p>
The Juneau Serializer API is designed to be used against POJO tree structures.
It expects that there not be loops in the POJO model (e.g. children with references to parents, etc...).
If you try to serialize models with loops, you will usually cause a <c>StackOverflowError</c> to
be thrown (if {@link org.apache.juneau.BeanTraverseContext#BEANTRAVERSE_maxDepth} is not reached
first).
</p>
<p>
If you still want to use the Juneau serializers on such models, Juneau provides the
{@link org.apache.juneau.BeanTraverseContext#BEANTRAVERSE_detectRecursions} setting.
It tells the serializer to look for instances of an object in the current branch of the tree and skip
serialization when a duplicate is encountered.
</p>
<p>
For example, let's make a POJO model out of the following classes:
</p>
<p class='bpcode w800'>
<jk>public class</jk> A {
<jk>public</jk> B b;
}
<jk>public class</jk> B {
<jk>public</jk> C c;
}
<jk>public class</jk> C {
<jk>public</jk> A a;
}
</p>
<p>
Now we create a model with a loop and serialize the results.
</p>
<p class='bpcode w800'>
<jc>// Clone an existing serializer and set property for detecting recursions.</jc>
JsonSerializer s = SimpleJsonSerializer.<jsf>DEFAULT_READABLE</jsf>.builder().detectRecursions(<jk>true</jk>).build();
<jc>// Create a recursive loop.</jc>
A a = <jk>new</jk> A();
a.<jf>b</jf> = <jk>new</jk> B();
a.<jf>b</jf>.<jf>c</jf> = <jk>new</jk> C();
a.<jf>b</jf>.<jf>c</jf>.<jf>a</jf> = a;
<jc>// Serialize to JSON.</jc>
String json = s.serialize(a);
</p>
<p>
What we end up with is the following, which does not serialize the contents of the <c>c</c> field:
</p>
<p class='bpcode w800'>
{
<jok>b</jok>: {
<jok>c</jok>: {
}
}
}
</p>
<p>
Without recursion detection enabled, this would cause a stack-overflow error.
</p>
<p>
Recursion detection introduces a performance penalty of around 20%.
For this reason the setting is disabled by default.
</p>
</div><!-- END: 2.15 - juneau-marshall.Recursion -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.ParsingIntoGenericModels' id='juneau-marshall.ParsingIntoGenericModels'>2.16 - Parsing into Generic Models</a></h3>
<div class='topic'><!-- START: 2.16 - juneau-marshall.ParsingIntoGenericModels -->
<p>
The Juneau parsers are not limited to parsing back into the original bean classes.
If the bean classes are not available on the parsing side, the parser can also be used to
parse into a generic model consisting of <c>Maps</c>, <c>Collections</c>, and primitive
objects.
</p>
<p>
You can parse into any <c>Map</c> type (e.g. <c>HashMap</c>, <c>TreeMap</c>), but
using {@link org.apache.juneau.ObjectMap} is recommended since it has many convenience methods
for converting values to various types.
The same is true when parsing collections. You can use any Collection (e.g. <c>HashSet</c>,
<c>LinkedList</c>) or array (e.g. <c>Object[]</c>, <c>String[]</c>,
<c>String[][]</c>), but using {@link org.apache.juneau.ObjectList} is recommended.
</p>
<p>
When the map or list type is not specified, or is the abstract <c>Map</c>, <c>Collection</c>,
or <c>List</c> types, the parser will use <c>ObjectMap</c> and <c>ObjectList</c> by
default.
</p>
<p>
For example, given the following JSON:
</p>
<p class='bpcode w800'>
{
id: <jk>1</jk>,
name: <js>'John Smith'</js>,
uri: <js>'http://sample/addressBook/person/1'</js>,
addressBookUri: <js>'http://sample/addressBook'</js>,
birthDate: <js>'1946-08-12T00:00:00Z'</js>,
addresses: [
{
uri: <js>'http://sample/addressBook/address/1'</js>,
personUri: <js>'http://sample/addressBook/person/1'</js>,
id: <jk>1</jk>,
street: <js>'100 Main Street'</js>,
city: <js>'Anywhereville'</js>,
state: <js>'NY'</js>,
zip: <jk>12345</jk>,
isCurrent: <jk>true</jk>
}
]
}
</p>
<p>
We can parse this into a generic <c>ObjectMap</c>:
</p>
<p class='bpcode w800'>
<jc>// Parse JSON into a generic POJO model.</jc>
ObjectMap m = JsonParser.<jsf>DEFAULT</jsf>.parse(json, ObjectMap.<jk>class</jk>);
<jc>// Convert it back to JSON.</jc>
String json = SimpleJsonSerializer.<jsf>DEFAULT_READABLE</jsf>.serialize(m);
</p>
<p>
What we end up with is the exact same output.
Even the numbers and booleans are preserved because they are parsed into <c>Number</c> and
<c>Boolean</c> objects when parsing into generic models.
</p>
<p class='bpcode w800'>
{
id: <jk>1</jk>,
name: <js>'John Smith'</js>,
uri: <js>'http://sample/addressBook/person/1'</js>,
addressBookUri: <js>'http://sample/addressBook'</js>,
birthDate: <js>'1946-08-12T00:00:00Z'</js>,
addresses: [
{
uri: <js>'http://sample/addressBook/address/1'</js>,
personUri: <js>'http://sample/addressBook/person/1'</js>,
id: <jk>1</jk>,
street: <js>'100 Main Street'</js>,
city: <js>'Anywhereville'</js>,
state: <js>'NY'</js>,
zip: <jk>12345</jk>,
isCurrent: <jk>true</jk>
}
]
}
</p>
<p>
Once parsed into a generic model, various convenience methods are provided on the <c>ObjectMap</c>
and <c>ObjectList</c> classes to retrieve values:
</p>
<p class='bpcode w800'>
<jc>// Parse JSON into a generic POJO model.</jc>
ObjectMap m = JsonParser.<jsf>DEFAULT</jsf>.parse(json, ObjectMap.<jk>class</jk>);
<jc>// Get some simple values.</jc>
String name = m.getString(<js>"name"</js>);
<jk>int</jk> id = m.getInt(<js>"id"</js>);
<jc>// Get a value convertable from a String.</jc>
URI uri = m.get(URI.<jk>class</jk>, <js>"uri"</js>);
<jc>// Get a value using a swap.</jc>
TemporalCalendarSwap swap = <jk>new</jk> TemporalCalendarSwap.IsoInstant();
Calendar birthDate = m.get(swap, <js>"birthDate"</js>);
<jc>// Get the addresses.</jc>
ObjectList addresses = m.getObjectList(<js>"addresses"</js>);
<jc>// Get the first address and convert it to a bean.</jc>
Address address = addresses.get(Address.<jk>class</jk>, 0);
</p>
<p>
As a general rule, parsing into beans is often more efficient than parsing into generic models.
And working with beans is often less error prone than working with generic models.
</p>
</div><!-- END: 2.16 - juneau-marshall.ParsingIntoGenericModels -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.ReadingContinuousStreams' id='juneau-marshall.ReadingContinuousStreams'>2.17 - Reading Continuous Streams</a></h3>
<div class='topic'><!-- START: 2.17 - juneau-marshall.ReadingContinuousStreams -->
<p>
The following parsers can be configured to read continuous streams of objects from the same input stream:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.json.JsonParser}
<li class='jc'>{@link org.apache.juneau.uon.UonParser}
<li class='jc'>{@link org.apache.juneau.msgpack.MsgPackParser}
</ul>
<p>
The {@link org.apache.juneau.json.JsonParser} and {@link org.apache.juneau.uon.UonParser}
classes can read continuous streams by using the {@link org.apache.juneau.parser.Parser#PARSER_unbuffered PARSER_unbuffered}
setting.
This prevents the parsers from using an internal buffer that would read past the end of the currently
parsed POJO.
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// If you're calling parse on the same input multiple times, use a session instead of the parser directly.</jc>
ReaderParserSession p = JsonParser.<jsm>create</jsm>().unbuffered().build().createSession();
Object x;
Reader r;
r = new StringReader(<js>"{foo:'bar'}{baz:'qux'}"</js>);
x = p.parse(r, ObjectMap.<jk>class</jk>); <jc>// {foo:'bar'}</jc>
x = p.parse(r, ObjectMap.<jk>class</jk>); <jc>// {baz:'qux'}</jc>
r = reader(<js>"[123][456]"</js>);
x = p.parse(r, <jk>int</jk>[].<jk>class</jk>); <jc>// [123]</jc>
x = p.parse(r, <jk>int</jk>[].<jk>class</jk>); <jc>// [456]</jc>
</p>
<p>
Note that this isn't perfect in all cases since you can't combine two JSON numbers into a single
reader (e.g. <c>"123" + "456" = "123456"</c>).
</p>
<p>
For obvious reasons, do not use the following properties when reading continuous streams:
</p>
<ul class='javatree'>
<li class='jf'>{@link org.apache.juneau.json.JsonParser#JSON_validateEnd}
<li class='jf'>{@link org.apache.juneau.uon.UonParser#UON_validateEnd}
<li class='jf'>{@link org.apache.juneau.parser.Parser#PARSER_autoCloseStreams}
</ul>
<p>
The {@link org.apache.juneau.msgpack.MsgPackParser} class doesn't use any internal buffering to begin with, so it can be used with
continuous streams without any special properties.
</p>
</div><!-- END: 2.17 - juneau-marshall.ReadingContinuousStreams -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.URIs' id='juneau-marshall.URIs'>2.18 - URIs</a></h3>
<div class='topic'><!-- START: 2.18 - juneau-marshall.URIs -->
<p>
Juneau serializers have sophisticated support for transforming relative URIs to absolute form.
</p>
<p>
The classes and settings that control the behavior are:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.UriResolver}
<li class='jc'>{@link org.apache.juneau.UriContext}
<li class='jc'>{@link org.apache.juneau.UriRelativity}
<li class='jc'>{@link org.apache.juneau.UriResolution}
<li class='jac'>{@link org.apache.juneau.serializer.Serializer}
<ul>
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriContext}
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriRelativity}
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriResolution}
</ul>
</ul>
<p>
The following example shows a bean containing URIs of various forms and how they end up serialized.
</p>
<p class='bpcode w800'>
<jc>// Our bean with properties containing various kinds of URIs.</jc>
<jk>public class</jk> TestURIs {
<jk>public</jk> URI
<jf>f1a</jf> = URI.<jsm>create</jsm>(<js>"http://www.apache.org/f1a"</js>),
<jf>f1b</jf> = URI.<jsm>create</jsm>(<js>"/f1b"</js>),
<jf>f1c</jf> = URI.<jsm>create</jsm>(<js>"/f1c/x/y"</js>),
<jf>f1d</jf> = URI.<jsm>create</jsm>(<js>"f1d"</js>),
<jf>f1e</jf> = URI.<jsm>create</jsm>(<js>"f1e/x/y"</js>),
<jf>f1f</jf> = URI.<jsm>create</jsm>(<js>""</js>),
<jf>f2a</jf> = URI.<jsm>create</jsm>(<js>"context:/f2a/x"</js>),
<jf>f2b</jf> = URI.<jsm>create</jsm>(<js>"context:/f2b"</js>),
<jf>f2c</jf> = URI.<jsm>create</jsm>(<js>"context:/"</js>),
<jf>f2d</jf> = URI.<jsm>create</jsm>(<js>"context:/.."</js>),
<jf>f3a</jf> = URI.<jsm>create</jsm>(<js>"servlet:/f3a/x"</js>),
<jf>f3b</jf> = URI.<jsm>create</jsm>(<js>"servlet:/f3b"</js>),
<jf>f3c</jf> = URI.<jsm>create</jsm>(<js>"servlet:/"</js>),
<jf>f3d</jf> = URI.<jsm>create</jsm>(<js>"servlet:/.."</js>),
<jf>f4a</jf> = URI.<jsm>create</jsm>(<js>"request:/f4a/x"</js>),
<jf>f4b</jf> = URI.<jsm>create</jsm>(<js>"request:/f4b"</js>),
<jf>f4c</jf> = URI.<jsm>create</jsm>(<js>"request:/"</js>),
<jf>f4d</jf> = URI.<jsm>create</jsm>(<js>"request:/.."</js>);;
}
<jc>// Create a serializer.</jc>
WriterSerializer s = JsonSerializer
<jsm>create</jsm>()
.simple()
.uriContext(<js>"{authority:'http://foo.com:123',contextRoot:'/myContext',servletPath:'/myServlet',pathInfo:'/myPath'}"</js>)
.uriResolution(<jsf>ABSOLUTE</jsf>)
.uriRelativity(<jsf>RESOURCE</jsf>)
.build();
<jc>// Produces:</jc>
<jc>// {</jc>
<jc>// f1a:'http://www.apache.org/f1a',</jc>
<jc>// f1b:'http://foo.com:123/f1b',</jc>
<jc>// f1c:'http://foo.com:123/f1c/x/y',</jc>
<jc>// f1d:'http://foo.com:123/myContext/myServlet/f1d',</jc>
<jc>// f1e:'http://foo.com:123/myContext/myServlet/f1e/x/y',</jc>
<jc>// f1f:'http://foo.com:123/myContext/myServlet',</jc>
<jc>// f2a:'http://foo.com:123/myContext/f2a/x',</jc>
<jc>// f2b:'http://foo.com:123/myContext/f2b',</jc>
<jc>// f2c:'http://foo.com:123/myContext',</jc>
<jc>// f2d:'http://foo.com:123'</jc>
<jc>// f3a:'http://foo.com:123/myContext/myServlet/f3a/x',</jc>
<jc>// f3b:'http://foo.com:123/myContext/myServlet/f3b',</jc>
<jc>// f3c:'http://foo.com:123/myContext/myServlet',</jc>
<jc>// f3d:'http://foo.com:123/myContext',</jc>
<jc>// f4a:'http://foo.com:123/myContext/myServlet/myPath/f4a/x',</jc>
<jc>// f4b:'http://foo.com:123/myContext/myServlet/myPath/f4b',</jc>
<jc>// f4c:'http://foo.com:123/myContext/myServlet/myPath',</jc>
<jc>// f4d:'http://foo.com:123/myContext/myServlet'</jc>
<jc>// }</jc>
String json = s.serialize(<jk>new</jk> TestURIs());
</p>
<p>
URI resolution is controlled by the following settings:
</p>
<ul class='javatree'>
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriContext}
<br>Setting that defines the URI contextual information used to resolve relative URIs.
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriRelativity}
<br>Setting that defines how relative URIs should be interpreted.
<br>Possible values:
<ul>
<li class='jf'>{@link org.apache.juneau.UriRelativity#RESOURCE}
<br>Relative URIs should be considered relative to the servlet URI.
<br>(e.g. <js>"http://host:port/context-root/servlet-path"</js>).
<li class='jf'>{@link org.apache.juneau.UriRelativity#PATH_INFO}
<br>Relative URIs should be considered relative to the request URI.
<br>(e.g. <js>"http://host:port/context-root/servlet-path/path-info"</js>).
</ul>
<li class='jf'>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriResolution}
<br>Setting that defines the final format of serialized URIs.
<br>Possible values:
<ul>
<li class='jf'>{@link org.apache.juneau.UriResolution#ABSOLUTE}
<br>Resolve to an absolute URL.
<br>(e.g. <js>"http://host:port/context-root/servlet-path/path-info"</js>).
<li class='jf'>{@link org.apache.juneau.UriResolution#ROOT_RELATIVE}
<br>Resolve to a root-relative URL.
<br>(e.g. <js>"/context-root/servlet-path/path-info"</js>).
<li class='jf'>{@link org.apache.juneau.UriResolution#NONE}
<br>Don't do any URL resolution.
</ul>
</ul>
<p>
Juneau automatically interprets any {@link java.net.URL} and {@link java.net.URI} objects as URIs and will
resolve them accordingly.
The {@link org.apache.juneau.annotation.URI @URI} annotation can be used to extend that to other bean
properties and class types so that they also get interpreted as URIs.
For example:
</p>
<p class='bpcode w800'>
<jc>// Applied to a class whose toString() method returns a URI.</jc>
<ja>@URI</ja>
<jk>public class</jk> MyURI {
<ja>@Override</ja> <jc>/* Object */</jc>
<jk>public</jk> String toString() {
<jk>return</jk> <js>"http://localhost:9080/foo/bar"</js>;
}
}
<jc>// Applied to bean properties</jc>
<jk>public class</jk> MyBean {
<ja>@URI</ja>
<jk>public</jk> String <jf>beanUri</jf>;
<ja>@URI</ja>
<jk>public</jk> String getParentUri() {
...
}
}
</p>
</div><!-- END: 2.18 - juneau-marshall.URIs -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.JacksonComparison' id='juneau-marshall.JacksonComparison'>2.19 - Comparison with Jackson</a></h3>
<div class='topic'><!-- START: 2.19 - juneau-marshall.JacksonComparison -->
<p>
Juneau was developed independently from Jackson, but shares many of the same features and capabilities.
Whereas Jackson was created to work primarily 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>
<h5 class='topic'>Annotations</h5>
<table class='styled w800'>
<tr><th>Jackson</th><th>Juneau</th></tr>
<tr>
<td>
<ja>@JsonGetter</ja>
<br><ja>@JsonSetter</ja>
</td>
<td>
{@link org.apache.juneau.annotation.Beanp @Beanp}
</td>
</tr>
<tr>
<td>
<ja>@JsonAnyGetter</ja>
<br><ja>@JsonAnySetter</ja>
</td>
<td>
{@link org.apache.juneau.annotation.Beanp#name() @Beanp(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><c><ja>@JsonIgnoreProperties</ja>({...})</c></td>
<td>
{@link org.apache.juneau.annotation.Bean#bpx @Bean(bpx="...")}
</td>
</tr>
<tr>
<td><c><ja>@JsonAutoDetect</ja>(fieldVisibility=...)</c></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_beanMethodVisibility}
<br>Future annotation support planned.
</td>
</tr>
<tr>
<td>
<ja>@JsonCreator</ja>
<br><ja>@JsonProperty</ja>
</td>
<td>
{@link org.apache.juneau.annotation.Beanc @Beanc}
</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.Swap @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.Serializer}
<br>Future annotation support planned.
</td>
</tr>
<tr>
<td><ja>@JsonPropertyOrder</ja></td>
<td>
{@link org.apache.juneau.annotation.Bean#properties @Bean(bpi="...")}
<br>{@link org.apache.juneau.annotation.Bean#sort @Bean(sort=x)}
</td>
</tr>
<tr>
<td>
<ja>@JsonValue</ja>
<br><ja>@JsonRawValue</ja>
</td>
<td>
Can be replicated using swaps with <c>Reader</c> swapped values.
</td>
</tr>
</table>
</div><!-- END: 2.19 - juneau-marshall.JacksonComparison -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.PojoCategories' id='juneau-marshall.PojoCategories'>2.20 - POJO Categories</a></h3>
<div class='topic'><!-- START: 2.20 - juneau-marshall.PojoCategories -->
<p>
The following chart shows POJOs categorized into groups and whether they can be serialized or parsed:
</p>
<h5 class='figure'>General POJO serialization/parsing support</h5>
<table class='styled w800' 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 primitives and 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, Java arrays, Java Optionals</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, 6a] objects.
<br>Map, Collection, Optional, and array values are group [1, 2, 3ac, 4a, 6a] objects.
</td>
<td>
<ul class='normal'>
<li><c>HashSet&lt;String,Integer&gt;</c>
<li><c>TreeMap&lt;Integer,Bean&gt;</c>
<li><c>List&lt;<jk>int</jk>[][]&gt;</c>
<li><c>Bean[]</c>
<li><c>Optional&lt;Bean&gt;</c>
</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, 5, 6b, 7] objects.
<br>Map, Collection, and array values are group [3b, 4b, 5, 6b, 7] objects.
</td>
<td>
<ul class='normal'>
<li><c>HashSet&lt;Bean,Integer&gt;</c>
<li><c>TreeMap&lt;Integer,Reader&gt;</c>
<li><c>Optional&lt;Reader&gt;</c>
</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 one or more properties defined by public getter
or public fields.
<br>Properties can also be defined as final read-only fields and passed in as constructor args.
<br>Property values are group [1, 2, 3ac, 4a, 6a] 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 one or more properties defined by getter
and setter methods or properties, but property types include group [3b, 4b, 5, 6b, 7] 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, 6a] 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='light bb'>
<td style='text-align:center'>3d</td>
<td>
<b>Read-only beans without setters</b>
<br>The same as 3a, but without property setters or constructor args.
</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 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.TemporalDateSwap.IsoLocalDateTime} 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><c>java.util.Date</c>
<li><c>java.util.GregorianCalendar</c>
</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><c>java.util.Iterator</c>
</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>Readers and InputStreams</b>
<br>Contents are serialized directly to the output stream or writer.
<br>Typically used for low-level language-specific replacement of POJOs using per-Media-Type
POJO swaps.
</td>
<td>
<ul class='normal'>
<li>{@code FileInputStream}
<li>{@code StringReader}
</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'>6</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'>6a</td>
<td>
Classes with a method that converts it to a serializable form:
<ul>
<li><c><jk>public</jk> X swap(BeanSession);</c> where <c>X</c> is in groups
[1, 2a, 3ac].
<li><c><jk>public</jk> String toString();</c> where the string is any meaningful data.
</ul>
And a method that converts it back into the original object:
<ul>
<li><c><jk>public static</jk> T fromString(String);</c>
<li><c><jk>public static</jk> T valueOf(String);</c>
<li><c><jk>public static</jk> T parse(String);</c>
<li><c><jk>public static</jk> T parseString(String);</c>
<li><c><jk>public static</jk> T forName(String);</c>
<li><c><jk>public static</jk> T forString(String);</c>
<li><c><jk>public</jk> T(X);</c> where <c>X</c> is in groups [1, 2a, 3ac].
<li><c><jk>public static</jk> T unswap(BeanSession,X);</c> where <c>X</c> is in
groups [1, 2a, 3ac].
</ul>
</td>
<td>
<ul class='normal'>
<li><c>java.lang.Class</c>
<li><c>java.sql.Time</c>
<li><c>java.sql.Timestamp</c>
<li><c>java.text.MessageFormat</c>
<li><c>java.text.NumberFormat</c>
<li><c>java.util.Date</c>
<li><c>java.util.UUID</c>
<li><c>java.util.logging.Level</c>
<li><c>javax.xml.bind.DatatypeConverter</c>
</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'>6b</td>
<td>
Classes that only have a method to convert to a serializable form:
<ul>
<li><c><jk>public</jk> X swap(BeanSession);</c> where <c>X</c> is in groups
[1, 2, 3].
<li><c><jk>public</jk> String toString();</c> 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'>7</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>
<div 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.
</div>
<h5 class='topic' id='PojosConveribleToStrings'>POJOs convertible to/from Strings</h5>
<p>
A separate category exists for POJOs that can be converted to and from Strings.
These are used in places such as:
</p>
<ul class='spaced-list'>
<li>Serializing of POJOs to Strings in the REST client API when no serializers are registered.
<li>Parsing of POJOs from Strings in the REST server API for <js>"text/plain"</js> requests where
<js>"text/plain"</js> is not already mapped to an existing serializer.
</ul>
<p>
As a general rule, all POJOs are converted to Strings using the <c>toString()</c> method.
However, there is one exception:
</p>
<ul class='spaced-list'>
<li>{@link java.util.TimeZone} - Uses {@link java.util.TimeZone#getID()}
</ul>
<p>
POJOs are convertible from Strings using any of the following (matched in the specified order):
</p>
<ul class='spaced-list'>
<li>Any any of the following public static non-deprecated methods:
<ul>
<li><c>create(String)</c>
<li><c>fromString(String)</c>
<li><c>fromValue(String)</c>
<li><c>valueOf(String)</c>
<li><c>parse(String)</c>
<li><c>parseString(String)</c>
<li><c>forName(String)</c>
<li><c>forString(String)</c>
</ul>
<li>Has a public constructor that takes in a <c>String</c>.
</ul>
<p>
Exceptions exist for the following classes:
</p>
<ul class='spaced-list'>
<li>{@link java.util.TimeZone} - Uses {@link java.util.TimeZone#getTimeZone(String)}
<li>{@link java.util.Locale} - Uses {@link java.util.Locale#forLanguageTag(String)} after replacing <js>'_'</js> with <js>'-'</js>.
<li>{@link java.lang.Boolean} - Blank and <js>"null"</js> are interpreted as null values.
<li>Primitives (except for <c><jk>void</jk>.<jk>class</jk></c>) - Uses the primitive wrapper classes for instantiating from Strings.
</ul>
<h5 class='topic' id='PojosConveribleToOtherTypes'>POJOs convertible to/from other types</h5>
<p>
POJOs are also converted to various other types in places such as the Open-API serializers and parsers.
In this section, the type being converted to will be referred to as <c>X</c>.
</p>
<p>
POJOs are considered convertible from X if it has any of the following (matched in the specified order):
</p>
<ul class='spaced-list'>
<li>Any any of the following public static non-deprecated methods:
<ul>
<li><c>create(X)</c>
<li><c>from*(X)</c>
</ul>
<li>Has a public constructor that takes in an <c>X</c>.
<li>The X class has a public non-static no-arg non-deprecated method called <c>to*()</c>.
</ul>
<p>
POJOs are considered convertible from X if any of the reverse of above are true.
</p>
</div><!-- END: 2.20 - juneau-marshall.PojoCategories -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.JsonDetails' id='juneau-marshall.JsonDetails'>2.21 - JSON Details</a></h3>
<div class='topic'><!-- START: 2.21 - juneau-marshall.JsonDetails -->
<p>
Juneau supports converting arbitrary POJOs to and from JSON using ultra-efficient serializers and parsers.
The JSON serializer converts POJOs directly to JSON without the need for intermediate DOM objects using a
highly-efficient state machine.
Likewise, the JSON parser creates POJOs directly from JSON without the need for intermediate DOM objects.
</p>
<p>
The following example shows JSON for a typical bean:
</p>
<h5 class='figure'>Sample Beans</h5>
<p class='bpcode w800'>
<jk>public class</jk> Person {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>name</jf>;
<ja>@Swap</ja>(TemporalCalendarSwap.IsoInstant.<jk>class</jk>) <jk>public</jk> Calendar <jf>birthDate</jf>;
<jk>public</jk> List&lt;Address&gt; <jf>addresses</jf>;
<jc>// Getters/setters omitted</jc>
}
<jk>public class</jk> Address {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>street</jf>, <jf>city</jf>;
<jk>public</jk> StateEnum <jf>state</jf>;
<jk>public int</jk> <jf>zip</jf>;
<jk>public boolean</jk> <jf>isCurrent</jf>;
<jc>// Getters/setters omitted</jc>
}
</p>
<h5 class='figure'>Sample Code</h5>
<p class='bpcode w800'>
Person p = <jk>new</jk> Person()
.name(<js>"John Smith"</js>)
.birthDate(<js>"1946-08-12T00:00:00Z"</js>)
.addresses(
<jk>new</jk> Address()
.street(<js>"100 Main Street"</js>)
.city(<js>"Anywhereville"</js>)
.state(<jsf>NY</jsf>)
.zip(12345)
.isCurrent(<jk>true</jk>);
);
</p>
<h5 class='figure'>Normal JSON</h5>
<p class='bpcode w800'>
{
<js>"name"</js>: <js>"John Smith"</js>,
<js>"birthDate"</js>: <js>"1946-08-12T00:00:00Z"</js>,
<js>"addresses"</js>: [
{
<js>"street"</js>: <js>"100 Main Street"</js>,
<js>"city"</js>: <js>"Anywhereville"</js>,
<js>"state"</js>: <js>"NY"</js>,
<js>"zip"</js>: 12345,
<js>"isCurrent"</js>: <jk>true</jk>
}
]
}
</p>
<h5 class='figure'>Simplified JSON</h5>
<p class='bpcode w800'>
{
name: <js>'John Smith'</js>,
birthDate: <js>'1946-08-12T00:00:00Z'</js>,
addresses: [
{
street: <js>'100 Main Street'</js>,
city: <js>'Anywhereville'</js>,
state: <js>'NY'</js>,
zip: 12345,
isCurrent: <jk>true</jk>
}
]
}
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.JsonDetails.Methodology' id='juneau-marshall.JsonDetails.Methodology'>2.21.1 - JSON Methodology</a></h4>
<div class='topic'><!-- START: 2.21.1 - juneau-marshall.JsonDetails.Methodology -->
<p>
The JSON data type produced depends on the Java object type being serialized.
</p>
<ul class='spaced-list'>
<li>
Primitives and primitive objects are converted to JSON primitives.
<li>
Beans and Maps are converted to JSON objects.
<li>
Collections and arrays are converted to JSON arrays.
<li>
Anything else is converted to JSON strings.
</ul>
<h5 class='figure'>Data type conversions:</h5>
<table class='styled w800'>
<tr>
<th>POJO type</th>
<th>JSON type</th>
<th>Example</th>
<th>Serialized form</th>
</tr>
<tr>
<td>String</td>
<td>String</td>
<td><c>serialize(<js>"foobar"</js>);</c></td>
<td><c><js>'foobar'</js></c>
</tr>
<tr>
<td>Number</td>
<td>Number</td>
<td><c>serialize(123);</c></td>
<td><c>123</c>
</tr>
<tr>
<td>Boolean</td>
<td>Boolean</td>
<td><c>serialize(<jk>true</jk>);</c></td>
<td><c><jk>true</jk></c>
</tr>
<tr>
<td>Null</td>
<td>Null</td>
<td><c>serialize(<jk>null</jk>);</c></td>
<td><c><jk>null</jk></c>
</tr>
<tr>
<td>Beans with properties of any type on this list</td>
<td>Object</td>
<td><c>serialize(<jk>new</jk> MyBean());</c></td>
<td><c>{p1:<js>'val1'</js>,p2:<jk>true</jk>}</c>
</tr>
<tr>
<td>Maps with values of any type on this list</td>
<td>Object</td>
<td><c>serialize(<jk>new</jk> TreeMap());</c></td>
<td><c>{key1:<js>'val1'</js>,key2:<jk>true</jk>}</c>
</tr>
<tr>
<td>Collections and arrays of any type on this list</td>
<td>Array</td>
<td><c>serialize(<jk>new</jk> Object[]{1,<js>"foo"</js>,<jk>true</jk>});</c></td>
<td><c>[1,<js>'foo'</js>,<jk>true</jk>]</c>
</tr>
</table>
<p>
In addition, swaps can be used to convert non-serializable POJOs into serializable forms, such as converting
<c>Calendar</c> object to ISO8601 strings, or <c><jk>byte</jk>[]</c> arrays to Base-64
encoded strings.
</p>
</div><!-- END: 2.21.1 - juneau-marshall.JsonDetails.Methodology -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.JsonDetails.Serializers' id='juneau-marshall.JsonDetails.Serializers'>2.21.2 - JSON Serializers</a></h4>
<div class='topic'><!-- START: 2.21.2 - juneau-marshall.JsonDetails.Serializers -->
<p>
The {@link org.apache.juneau.json.JsonSerializer} class is used to serialize POJOs into JSON.
</p>
<p>
The JSON serializer provides the following settings:
</p>
<ul class='javatree'>
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.Common Common Properties}
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.CommonSerializer Common Serializer Properties}
<li class='jc'>{@link org.apache.juneau.json.JsonSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.json.JsonSerializer#JSON_addBeanTypes JSON_addBeanTypes}
<li class='jf'>{@link org.apache.juneau.json.JsonSerializer#JSON_escapeSolidus JSON_escapeSolidus}
<li class='jf'>{@link org.apache.juneau.json.JsonSerializer#JSON_simpleMode JSON_simpleMode}
</ul>
</ul>
<p>
The following pre-configured serializers are provided for convenience:
</p>
<ul class='javatree'>
<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_READABLE DEFAULT_READABLE}
</ul>
<li class='jc'>{@link org.apache.juneau.json.SimpleJsonSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.json.SimpleJsonSerializer#DEFAULT DEFAULT}
<li class='jf'>{@link org.apache.juneau.json.SimpleJsonSerializer#DEFAULT_READABLE DEFAULT_READABLE}
</ul>
</ul>
</div><!-- END: 2.21.2 - juneau-marshall.JsonDetails.Serializers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.JsonDetails.SimplifiedJson' id='juneau-marshall.JsonDetails.SimplifiedJson'>2.21.3 - Simplified JSON</a></h4>
<div class='topic'><!-- START: 2.21.3 - juneau-marshall.JsonDetails.SimplifiedJson -->
<p>
The {@link org.apache.juneau.json.SimpleJsonSerializer} class can be used to serialized POJOs into Simplified JSON notation.
</p>
<p>
Simplified JSON is identical to JSON except for the following:
</p>
<ul class='spaced-list'>
<li>JSON attributes are only quoted when necessary.
<li>Uses single-quotes for quoting.
</ul>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Some free-form JSON.</jc>
ObjectMap m = <jk>new</jk> ObjectMap()
.append(<js>"foo"</js>, <js>"x1"</js>)
.append(<js>"_bar"</js>, <js>"x2"</js>)
.append(<js>" baz "</js>, <js>"x3"</js>)
.append(<js>"123"</js>, <js>"x4"</js>)
.append(<js>"return"</js>, <js>"x5"</js>);
.append(<js>""</js>, <js>"x6"</js>);
</p>
<p class='bpcode w800'>
<joc>// Serialized to standard JSON</joc>
{
<jok>"foo"</jok>: <jov>"x1"</jov>,
<jok>"_bar"</jok>: <jov>"x2"</jov>,
<jok>" baz "</jok>: <jov>"x3"</jov>,
<jok>"123"</jok>: <jov>"x4"</jov>,
<jok>"return"</jok>: <jov>"x5"</jov>,
<jok>""</jok>: <jov>"x6"</jov>
}
</p>
<p class='bpcode w800'>
<joc>// Serialized to simplified JSON</joc>
{
<jok>foo</jok>: <jov>'x1'</jov>,
<jok>_bar</jok>: <jov>'x2'</jov>,
<jok>' baz '</jok>: <jov>'x3'</jov>, <joc>// Quoted due to embedded spaces.</joc>
<jok>'123'</jok>: <jov>'x4'</jov>, <joc>// Quoted to prevent confusion with number.</joc>
<jok>'return'</jok>: <jov>'x5'</jov>, <joc>// Quoted because it's a keyword.</joc>
<jok>''</jok>: <jov>'x6'</jov> <joc>// Quoted because it's an empty string.</joc>
}
</p>
<p>
The advantage to simplified JSON is you can represent it in a Java String in minimal form with minimal escaping.
This is particularly useful in cases such as unit testing where you can easily validate POJOs by simplifying them to Simplified JSON and do a simple string comparison.
</p>
<p class='bpcode w800'>
WriterSerializer ws = SimpleJsonSerializer.<jsf>DEFAULT</jsf>;
<jsm>assertEquals</jsm>(<js>"{foo:'bar',baz:123}"</js>, ws.toString(myPojo));
</p>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.json.JsonSerializer#JSON_simpleMode}
</ul>
</div><!-- END: 2.21.3 - juneau-marshall.JsonDetails.SimplifiedJson -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.JsonDetails.Parsers' id='juneau-marshall.JsonDetails.Parsers'>2.21.4 - JSON Parsers</a></h4>
<div class='topic'><!-- START: 2.21.4 - juneau-marshall.JsonDetails.Parsers -->
<p>
The {@link org.apache.juneau.json.JsonParser} class is used to parse JSON into POJOs.
</p>
<p>
The JSON parser provides the following settings:
</p>
<ul class='javatree'>
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.Common Common Properties}
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.CommonParser Common Parser Properties}
<li class='jc'>{@link org.apache.juneau.json.JsonParser}
<ul>
<li class='jf'>{@link org.apache.juneau.json.JsonParser#JSON_validateEnd JSON_validateEnd}
</ul>
</ul>
<p>
The following pre-configured parsers are provided for convenience:
</p>
<ul class='javatree'>
<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>
The JSON parser supports ALL valid JSON, including:
</p>
<ul class='spaced-list'>
<li>
Javascript comments.
<li>
Single or double quoted values.
<li>
Quoted (strict) or unquoted (non-strict) attributes.
<li>
JSON fragments (such as string, numeric, or boolean primitive values).
<li>
Concatenated strings.
</ul>
</div><!-- END: 2.21.4 - juneau-marshall.JsonDetails.Parsers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.JsonDetails.JsonAnnotation' id='juneau-marshall.JsonDetails.JsonAnnotation'>2.21.5 - @Json Annotation</a></h4>
<div class='topic'><!-- START: 2.21.5 - juneau-marshall.JsonDetails.JsonAnnotation -->
<p>
The {@link org.apache.juneau.json.annotation.Json @Json} annotation
is used to override the behavior of {@link org.apache.juneau.json.JsonSerializer} on individual bean classes or properties.
</p>
<p>
The annotation can be applied to beans as well as other objects serialized to other types (e.g. strings).
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.json.annotation.Json}
<ul>
<li class='jf'>{@link org.apache.juneau.json.annotation.Json#wrapperAttr() wrapperAttr}
</ul>
</ul>
<p>
The {@link org.apache.juneau.json.annotation.Json#wrapperAttr() @Json(wrapperAttr)} annotation
can be used to wrap beans inside a JSON object with a specified attribute name.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Json</ja>(wrapperAttr=<js>"personBean"</js>)
<jk>public class</jk> Person {
<jk>public</jk> String <jf>name</jf> = <js>"John Smith"</js>;
}
</p>
<p>
The following shows the JSON representation with and without the annotation present:
</p>
<table class='styled w800'>
<tr>
<th>Without annotation</th>
<th>With annotation</th>
</tr>
<tr>
<td class='code'>
{
<jok>name</jok>: <jov>'John Smith'</jov>
}
</td>
<td class='code'>
{
<jok>personBean</jok>: {
<jok>name</jok>: <jov>'John Smith'</jov>
}
}
</td>
</tr>
</table>
</div><!-- END: 2.21.5 - juneau-marshall.JsonDetails.JsonAnnotation -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.JsonDetails.JsonSchema' id='juneau-marshall.JsonDetails.JsonSchema'>2.21.6 - JSON-Schema Support</a></h4>
<div class='topic'><!-- START: 2.21.6 - juneau-marshall.JsonDetails.JsonSchema -->
<p>
Juneau provides the {@link org.apache.juneau.json.JsonSchemaSerializer} class for generating JSON-Schema
documents that describe the output generated by the {@link org.apache.juneau.json.JsonSerializer} class.
This class shares the same properties as <c>JsonSerializer</c>.
For convenience the {@link org.apache.juneau.json.JsonSerializer#getSchemaSerializer()} method has been
added for creating instances of schema serializers from the regular serializer instance.
</p>
<h5 class='figure'>Sample Beans</h5>
<p class='bpcode w800'>
<jk>public class</jk> Person {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>name</jf>;
<jk>public</jk> Calendar <jf>birthDate</jf>;
<jk>public</jk> List&lt;Address&gt; <jf>addresses</jf>;
<jc>// Getters/setters omitted</jc>
}
<jk>public class</jk> Address {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>street</jf>, <jf>city</jf>;
<jk>public</jk> StateEnum <jf>state</jf>;
<jk>public int</jk> <jf>zip</jf>;
<jk>public boolean</jk> <jf>isCurrent</jf>;
<jc>// Getters/setters omitted</jc>
}
</p>
<p>
The code for creating our POJO model and generating JSON-Schema is shown below:
</p>
<p class='bpcode w800'>
<jc>// Get the one of the default schema serializers.</jc>
JsonSchemaSerializer s = JsonSchemaSerializer.<jsf>DEFAULT_SIMPLE_READABLE</jsf>;
<jc>// Get the JSON Schema for the POJO.</jc>
String jsonSchema = s.serialize(<jk>new</jk> Person());
<jc>// This also works.</jc>
jsonSchema = s.serialize(Person.<jk>class</jk>);
</p>
<h5 class='figure'>JSON Schema</h5>
<p class='bpcode w800'>
{
<jok>type: <jov>'object'</jov>,
<jok>description</jok>: <jov>'org.apache.juneau.sample.Person'</jov>,
<jok>properties</jok>: {
<jok>name</jok>: {
<jok>type</jok>: <jov>'string'</jov>,
<jok>description</jok>: <jov>'java.lang.String'</jov>
},
<jok>birthDate</jok>: {
<jok>type</jok>: <jov>'string'</jov>,
<jok>description</jok>: <jov>'java.util.Calendar'</jov>
},
<jok>addresses</jok>: {
<jok>type</jok>: <jov>'array'</jov>,
<jok>description</jok>: <jov>'java.util.LinkedList&lt;org.apache.juneau.sample.Address&gt;'</jov>,
<jok>items</jok>: {
<jok>type</jok>: <jov>'object'</jov>,
<jok>description</jok>: <jov>'org.apache.juneau.sample.Address'</jov>,
<jok>properties</jok>: {
<jok>street</jok>: {
<jok>type</jok>: <jov>'string'</jov>,
<jok>description</jok>: <jov>'java.lang.String'</jov>
},
<jok>city</jok>: {
<jok>type</jok>: <jov>'string'</jov>,
<jok>description</jok>: <jov>'java.lang.String'</jov>
},
<jok>state</jok>: {
<jok>type</jok>: <jov>'string'</jov>,
<jok>description</jok>: <jov>'java.lang.String'</jov>
},
<jok>zip</jok>: {
<jok>type</jok>: <jov>'number'</jov>,
<jok>description</jok>: <jov>'int'</jov>
},
<jok>isCurrent</jok>: {
<jok>type</jok>: <jov>'boolean'</jov>,
<jok>description</jok>: <jov>'boolean'</jov>
}
}
}
}
}
}
</p>
</div><!-- END: 2.21.6 - juneau-marshall.JsonDetails.JsonSchema -->
</div><!-- END: 2.21 - juneau-marshall.JsonDetails -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.XmlDetails' id='juneau-marshall.XmlDetails'>2.22 - XML Details</a></h3>
<div class='topic'><!-- START: 2.22 - juneau-marshall.XmlDetails -->
<p>
Juneau supports converting arbitrary POJOs to and from XML using ultra-efficient serializers and parsers.
The XML serializer converts POJOs directly to XML without the need for intermediate DOM objects.
Likewise, the XML parser uses a STaX parser and creates POJOs directly without intermediate DOM objects.
</p>
<p>
Unlike frameworks such as JAXB, Juneau does not require POJO classes to be annotated to produce and consume
XML.
However, several XML annotations are provided for handling namespaces and fine-tuning the format of the XML produced.
</p>
<p>
The following example shows XML for a typical bean:
</p>
<h5 class='figure'>Sample Beans</h5>
<p class='bpcode w800'>
<ja>@Bean</ja>(typeName=<js>"person"</js>)
<jk>public class</jk> Person {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>name</jf>;
<ja>@Swap</ja>(TemporalCalendarSwap.IsoInstant.<jk>class</jk>) <jk>public</jk> Calendar <jf>birthDate</jf>;
<jk>public</jk> List&lt;Address&gt; <jf>addresses</jf>;
<jc>// Getters/setters omitted</jc>
}
<ja>@Bean</ja>(typeName=<js>"address"</js>)
<jk>public class</jk> Address {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>street</jf>, <jf>city</jf>;
<jk>public</jk> StateEnum <jf>state</jf>;
<jk>public int</jk> <jf>zip</jf>;
<jk>public boolean</jk> <jf>isCurrent</jf>;
<jc>// Getters/setters omitted</jc>
}
</p>
<h5 class='figure'>Sample Code</h5>
<p class='bpcode w800'>
Person p = <jk>new</jk> Person()
.name(<js>"John Smith"</js>)
.birthDate(<js>"1946-08-12T00:00:00Z"</js>)
.addresses(
<jk>new</jk> Address()
.street(<js>"100 Main Street"</js>)
.city(<js>"Anywhereville"</js>)
.state(<jsf>NY</jsf>)
.zip(12345)
.isCurrent(<jk>true</jk>);
);
</p>
<h5 class='figure'>Normal XML:</h5>
<p class='bpcode w800'>
<xt>&lt;person&gt;</xt>
<xt>&lt;name&gt;</xt>John Smith<xt>&lt;/name&gt;</xt>
<xt>&lt;birthDate&gt;</xt>1946-08-12T04:00:00Z<xt>&lt;/birthDate&gt;</xt>
<xt>&lt;addresses&gt;</xt>
<xt>&lt;address&gt;</xt>
<xt>&lt;street&gt;</xt>100 Main Street<xt>&lt;/street&gt;</xt>
<xt>&lt;city&gt;</xt>Anywhereville<xt>&lt;/city&gt;</xt>
<xt>&lt;state&gt;</xt>NY<xt>&lt;/state&gt;</xt>
<xt>&lt;zip&gt;</xt>12345<xt>&lt;/zip&gt;</xt>
<xt>&lt;isCurrent&gt;</xt>true<xt>&lt;/isCurrent&gt;</xt>
<xt>&lt;/address&gt;</xt>
<xt>&lt;/addresses&gt;</xt>
<xt>&lt;/person&gt;</xt>
</p>
<p>
Juneau produces JSON-equivalent XML, meaning any valid JSON document can be losslessly converted into an XML
equivalent.
In fact, all of the Juneau serializers and parsers are built upon this JSON-equivalence.
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.XmlDetails.Methodology' id='juneau-marshall.XmlDetails.Methodology'>2.22.1 - XML Methodology</a></h4>
<div class='topic'><!-- START: 2.22.1 - juneau-marshall.XmlDetails.Methodology -->
<p>
The following examples show how different data types are represented in XML.
They mirror how the data structures are represented in JSON.
</p>
<h5 class='topic'>Simple types</h5>
<p>
The representation of loose (not a direct bean property value) simple types are shown below:
</p>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>XML</th>
</tr>
<tr>
<td>string</td>
<td class='code'><js>'foo'</js></td>
<td class='code'><xt>&lt;string&gt;</xt>foo<xt>&lt;/string&gt;</xt></td>
</tr>
<tr>
<td>boolean</td>
<td class='code'><jk>true</jk></td>
<td class='code'><xt>&lt;boolean&gt;</xt>true<xt>&lt;/boolean&gt;</xt></td>
</tr>
<tr>
<td>integer</td>
<td class='code'>123</td>
<td class='code'><xt>&lt;number&gt;</xt>123<xt>&lt;/number&gt;</xt></td>
</tr>
<tr>
<td>float</td>
<td class='code'>1.23</td>
<td class='code'><xt>&lt;number&gt;</xt>1.23<xt>&lt;/number&gt;</xt></td>
</tr>
<tr>
<td>null</td>
<td class='code'><jk>null</jk></td>
<td class='code'><xt>&lt;null/&gt;</xt></td>
</tr>
</table>
<h5 class='topic'>Maps</h5>
<p>
Loose maps and beans use the element <xt>&lt;object&gt;</xt> for encapsulation.
</p>
<p>
<xa>_type</xa> attributes are added to bean properties or map entries if the type cannot be inferred
through reflection (e.g. an <c>Object</c> or superclass/interface value type).
</p>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>XML</th>
</tr>
<tr>
<td class='code'>
Map&lt;String,String&gt;
</td>
<td class='code'>
{
k1: <js>'v1'</js>
k2: <jk>null</jk>
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;k1&gt;<xv>v1</xv>&lt;/k1&gt;
&lt;k2 <xa>_type</xa>=<xs>'null'</xs>/&gt;
&lt;/object&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
Map&lt;String,Number&gt;
</td>
<td class='code'>
{
k1: 123,
k2: 1.23,
k3: <jk>null</jk>
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;k1&gt;<xv>123</xv>&lt;/k1&gt;
&lt;k2&gt;<xv>1.23</xv>&lt;/k2&gt;
&lt;k3 <xa>_type</xa>=<xs>'null'</xs>/&gt;
&lt;/object&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
Map&lt;String,Object&gt;
</td>
<td class='code'>
{
k1: <js>'v1'</js>
k2: 123,
k3: 1.23,
k4: <jk>true</jk>,
k5: <jk>null</jk>
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;k1&gt;<xv>v1</xv>&lt;/k1&gt;
&lt;k2 <xa>_type</xa>=<xs>'number'</xs>&gt;<xv>123</xv>&lt;/k2&gt;
&lt;k3 <xa>_type</xa>=<xs>'number'</xs>&gt;<xv>1.23</xv>&lt;/k3&gt;
&lt;k4 <xa>_type</xa>=<xs>'boolean'</xs>&gt;<xv>true</xv>&lt;/k4&gt;
&lt;k5 <xa>_type</xa>=<xs>'null'</xs>/&gt;
&lt;/object&gt;
</xt></td>
</tr>
</table>
<h5 class='topic'>Arrays</h5>
<p>
Loose collections and arrays use the element <xt>&lt;array&gt;</xt> for encapsulation.
</p>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>XML</th>
</tr>
<tr>
<td class='code'>
String[]
</td>
<td class='code'>
[
<js>'foo'</js>
<jk>null</jk>
]
</td>
<td class='code'><xt>
&lt;array&gt;
&lt;string&gt;<xv>foo</xv>&lt;/string&gt;
&lt;null/&gt;
&lt;/array&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
Number[]
</td>
<td class='code'>
[
123,
1.23,
<jk>null</jk>
]
</td>
<td class='code'><xt>
&lt;array&gt;
&lt;number&gt;<xv>123</xv>&lt;/number&gt;
&lt;number&gt;<xv>1.23</xv>&lt;/number&gt;
&lt;null/&gt;
&lt;/array&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
Object[]
</td>
<td class='code'>
[
<js>'foo'</js>,
123,
1.23,
<jk>true</jk>,
<jk>null</jk>
]
</td>
<td class='code'><xt>
&lt;array&gt;
&lt;string&gt;<xv>foo</xv>&lt;/string&gt;
&lt;number&gt;<xv>123</xv>&lt;/number&gt;
&lt;number&gt;<xv>1.23</xv>&lt;/number&gt;
&lt;boolean&gt;<xv>true</xv>&lt;/boolean&gt;
&lt;null/&gt;
&lt;/array&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
String[][]
</td>
<td class='code'>
[
[<js>'foo'</js>, <jk>null</jk>],
<jk>null</jk>,
]
</td>
<td class='code'><xt>
&lt;array&gt;
&lt;array&gt;
&lt;string&gt;<xv>foo</xv>&lt;/string&gt;
&lt;null/&gt;
&lt;/array&gt;
&lt;null/&gt;
&lt;/array&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<jk>int</jk>[]
</td>
<td class='code'>
[
123
]
</td>
<td class='code'><xt>
&lt;array&gt;
&lt;number&gt;<xv>123</xv>&lt;/number&gt;
&lt;/array&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<jk>boolean</jk>[]
</td>
<td class='code'>
[
<jk>true</jk>
]
</td>
<td class='code'><xt>
&lt;array&gt;
&lt;boolean&gt;<xv>true</xv>&lt;/boolean&gt;
&lt;/array&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
List&lt;String&gt;
</td>
<td class='code'>
[
<js>'foo'</js>
<jk>null</jk>
]
</td>
<td class='code'><xt>
&lt;array&gt;
&lt;string&gt;<xv>foo</xv>&lt;/string&gt;
&lt;null/&gt;
&lt;/array&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
List&lt;Number&gt;
</td>
<td class='code'>
[
123,
1.23,
<jk>null</jk>
]
</td>
<td class='code'><xt>
&lt;array&gt;
&lt;number&gt;<xv>123</xv>&lt;/number&gt;
&lt;number&gt;<xv>1.23</xv>&lt;/number&gt;
&lt;null/&gt;
&lt;/array&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
List&lt;Object&gt;
</td>
<td class='code'>
[
<js>'foo'</js>,
123,
1.23,
<jk>true</jk>,
<jk>null</jk>
]
</td>
<td class='code'><xt>
&lt;array&gt;
&lt;string&gt;<xv>foo</xv>&lt;/string&gt;
&lt;number&gt;<xv>123</xv>&lt;/number&gt;
&lt;number&gt;<xv>1.23</xv>&lt;/number&gt;
&lt;boolean&gt;<xv>true</xv>&lt;/boolean&gt;
&lt;null/&gt;
&lt;/array&gt;
</xt></td>
</tr>
</table>
<h5 class='topic'>Beans</h5>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>XML</th>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<jk>public</jk> String a;
<jk>public</jk> <jk>int</jk> b;
<jk>public</jk> Object c; <jc>// String value</jc>
<jk>public</jk> Object d; <jc>// Integer value</jc>
<jk>public</jk> MyBean2 e;
<jk>public</jk> String[] f;
<jk>public</jk> <jk>int</jk>[] g;
}
<jk>class</jk> MyBean2 {
String h;
}
</td>
<td class='code'>
{
<jok>a</jok>: <jov>'foo'</jov>,
<jok>b</jok>: <jov>123</jov>,
<jok>c</jok>: <jov>'bar'</jov>,
<jok>d</jok>: <jov>456</jov>,
<jok>e</jok>: {
<jok>h</jok>: <jov>'baz'</jov>
}
<jok>f</jok>: [<jov>'qux'</jov>]
<jok>g</jok>: [<jov>789</jov>]
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;<xv>foo</xv>&lt;/a&gt;
&lt;b&gt;<xv>123</xv>&lt;/b&gt;
&lt;c&gt;<xv>bar</xv>&lt;/c&gt;
&lt;d <xa>_type</xa>=<xs>'number'</xs>&gt;<xv>456</xv>&lt;/d&gt;
&lt;e&gt;
&lt;h&gt;<xv>baz</xv>&lt;/h&gt;
&lt;/e&gt;
&lt;f&gt;
&lt;string&gt;<xv>qux</xv>&lt;/string&gt;
&lt;/f&gt;
&lt;g&gt;
&lt;number&gt;<xv>789</xv>&lt;/number&gt;
&lt;/g&gt;
&lt;/object&gt;
</xt></td>
</tr>
</table>
<h5 class='topic'>Beans with Map properties</h5>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>XML</th>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<jk>public</jk> Map&lt;String,String&gt; a;
<jk>public</jk> Map&lt;String,Number&gt; b;
<jk>public</jk> Map&lt;String,Object&gt; c;
}
</td>
<td class='code'>
{
<jok>a</jok>: {
<jok>k1</jok>: <jov>'foo'</jov>
},
<jok>b</jok>: {
<jok>k2</jok>: <jov>123</jov>
},
<jok>c</jok>: {
<jok>k3</jok>: <jov>'bar'</jov>,
<jok>k4</jok>: <jov>456</jov>,
<jok>k5</jok>: <jov>true</jov>,
<jok>k6</jok>: <jov>null</jov>
}
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;
&lt;k1&gt;<xv>foo</xv>&lt;/k1&gt;
&lt;/a&gt;
&lt;b&gt;
&lt;k2&gt;<xv>123</xv>&lt;/k2&gt;
&lt;/b&gt;
&lt;c&gt;
&lt;k3&gt;<xv>bar</xv>&lt;/k3&gt;
&lt;k4 <xa>_type</xa>=<xs>'number'</xs>&gt;<xv>456</xv>&lt;/k4&gt;
&lt;k5 <xa>_type</xa>=<xs>'boolean'</xs>&gt;<xv>true</xv>&lt;/k5&gt;
&lt;k6 <xa>_type</xa>=<xs>'null'</xs>/&gt;
&lt;/c&gt;
&lt;/object&gt;
</xt></td>
</tr>
</table>
</div><!-- END: 2.22.1 - juneau-marshall.XmlDetails.Methodology -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.XmlDetails.Serializers' id='juneau-marshall.XmlDetails.Serializers'>2.22.2 - XML Serializers</a></h4>
<div class='topic'><!-- START: 2.22.2 - juneau-marshall.XmlDetails.Serializers -->
<p>
The {@link org.apache.juneau.xml.XmlSerializer} class is used to serialize POJOs into XML.
</p>
<p>
The {@link org.apache.juneau.xml.XmlDocSerializer} class is the same, but serializes a <xt>&lt;?xml?&gt;</xt> header
at the top of the file.
</p>
<p>
The XML serializers provide the following settings:
</p>
<ul class='javatree'>
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.Common Common Properties}
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.CommonSerializer Common Serializer Properties}
<li class='jc'>{@link org.apache.juneau.xml.XmlSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#XML_addBeanTypes XML_addBeanTypes}
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#XML_addNamespaceUrisToRoot XML_addNamespaceUrisToRoot}
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#XML_autoDetectNamespaces XML_autoDetectNamespaces}
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#XML_defaultNamespace XML_defaultNamespace}
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#XML_enableNamespaces XML_enableNamespaces}
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#XML_namespaces XML_namespaces}
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#XML_xsNamespace XML_xsNamespace}
</ul>
</ul>
<p>
The following pre-configured serializers are provided for convenience:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.xml.XmlSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#DEFAULT DEFAULT}
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#DEFAULT_JUNEAU_NAMESPACE DEFAULT_JUNEAU_NAMESPACE}
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#DEFAULT_NS DEFAULT_NS}
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#DEFAULT_NS_SQ DEFAULT_NS_SQ}
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#DEFAULT_NS_SQ_READABLE DEFAULT_NS_SQ_READABLE}
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#DEFAULT_SQ DEFAULT_SQ}
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#DEFAULT_SQ_READABLE DEFAULT_SQ_READABLE}
<li class='jf'>{@link org.apache.juneau.xml.XmlSerializer#DEFAULT_XS_NAMESPACE DEFAULT_XS_NAMESPACE}
</ul>
</ul>
</div><!-- END: 2.22.2 - juneau-marshall.XmlDetails.Serializers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.XmlDetails.Parsers' id='juneau-marshall.XmlDetails.Parsers'>2.22.3 - XML Parsers</a></h4>
<div class='topic'><!-- START: 2.22.3 - juneau-marshall.XmlDetails.Parsers -->
<p>
The {@link org.apache.juneau.xml.XmlParser} class is used to parse XML into POJOs.
</p>
<p>
The XML parser provides the following settings:
</p>
<ul class='javatree'>
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.Common Common Properties}
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.CommonParser Common Parser Properties}
<li class='jc'>{@link org.apache.juneau.xml.XmlParser}
<ul>
<li class='jf'>{@link org.apache.juneau.xml.XmlParser#XML_eventAllocator XML_eventAllocator}
<li class='jf'>{@link org.apache.juneau.xml.XmlParser#XML_preserveRootElement XML_preserveRootElement}
<li class='jf'>{@link org.apache.juneau.xml.XmlParser#XML_reporter XML_reporter}
<li class='jf'>{@link org.apache.juneau.xml.XmlParser#XML_resolver XML_resolver}
<li class='jf'>{@link org.apache.juneau.xml.XmlParser#XML_validating XML_validating}
</ul>
</ul>
<p>
The following pre-configured parsers are provided for convenience:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.xml.XmlParser}
<ul>
<li class='jf'>{@link org.apache.juneau.xml.XmlParser#DEFAULT DEFAULT}
</ul>
</ul>
</div><!-- END: 2.22.3 - juneau-marshall.XmlDetails.Parsers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.XmlDetails.BeanTypeNameAnnotation' id='juneau-marshall.XmlDetails.BeanTypeNameAnnotation'>2.22.4 - @Bean(typeName) Annotation</a></h4>
<div class='topic'><!-- START: 2.22.4 - juneau-marshall.XmlDetails.BeanTypeNameAnnotation -->
<p>
The {@link org.apache.juneau.annotation.Bean#typeName() @Bean(typeName)} annotation can be used to
override the Juneau default name on bean elements.
Types names serve two distinct purposes:
</p>
<ol>
<li>To override the element name.
<li>To serve as a class identifier so that the bean class can be inferred during parsing if it
cannot automatically be inferred through reflection.
</ol>
<h5 class='figure'>Example</h5>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>Without annotation</th>
<th>With annotation</th>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<jk>public</jk> String a;
<jk>public int</jk> b;
}
</td>
<td class='code'>
{
a: <js>'foo'</js>,
b: 123
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;<xv>foo</xv>&lt;/id&gt;
&lt;b&gt;<xv>123</xv>&lt;/name&gt;
&lt;/object&gt;
</xt></td>
<td class='code'><xt>
&lt;X&gt;
&lt;a&gt;<xv>foo</xv>&lt;/id&gt;
&lt;b&gt;<xv>123</xv>&lt;/name&gt;
&lt;/X&gt;
</xt></td>
</tr>
</table>
<p>
On bean properties, a <xa>_type</xa> attribute will be added if a type name is present and the bean
class cannot be inferred through reflection.
</p>
<p>
In the following example, a type attribute is used on property 'b' but not property 'a' since
'b' is of type <c>Object</c> and therefore the bean class cannot be inferred.
</p>
<h5 class='figure'>Example</h5>
<table class='styled w800'>
<tr>
<th>Java</th>
<th>Without annotation</th>
<th>With annotation</th>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<jk>public</jk> BeanX a = <jk>new</jk> BeanX();
<jk>public</jk> Object b = <jk>new</jk> BeanX();
}
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> BeanX {
<jk>public</jk> String fx = <js>"foo"</js>;
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;
&lt;fx&gt;<xv>foo</xv>&lt;/fx&gt;
&lt;/a&gt;
&lt;b&gt;
&lt;fx&gt;<xv>foo</xv>&lt;/fx&gt;
&lt;/b&gt;
&lt;/object&gt;
</xt></td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;
&lt;fx&gt;<xv>foo</xv>&lt;/fx&gt;
&lt;/a&gt;
&lt;b <xa>_type</xa>=<xs>'X'</xs>&gt;
&lt;fx&gt;<xv>foo</xv>&lt;/fx&gt;
&lt;/b&gt;
&lt;/object&gt;
</xt></td>
</tr>
</table>
<div class='info'>
<c>string</c>, <c>number</c>, <c>boolean</c>, <c>object</c>,
<c>array</c>, and <c>null</c> are reserved keywords that cannot be used as type names.
</div>
<p>
Beans with type names are often used in conjunction with the
{@link org.apache.juneau.annotation.Bean#dictionary() @Bean(dictionary)} and
{@link org.apache.juneau.annotation.Beanp#dictionary() @Beanp(dictionary)}
annotations so that the beans can be resolved at parse time.
These annotations are not necessary during serialization, but are needed during parsing in order to
resolve the bean types.
</p>
<p>
The following examples show how type names are used under various circumstances.
</p>
<p>
Pay special attention to when <xa>_type</xa> attributes are and are not used.
</p>
<h5 class='figure'>Examples</h5>
<table class='styled w800'>
<tr>
<th>Java</th>
<th>XML</th>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(dictionary={BeanX.<jk>class</jk>})
<jk>class</jk> BeanWithArrayPropertiesWithTypeNames {
<jk>public</jk> BeanX[] b1 = <jk>new</jk> BeanX[]{
<jk>new</jk> BeanX()
};
<jk>public</jk> Object[] b2 = <jk>new</jk> BeanX[]{
<jk>new</jk> BeanX()
};
<jk>public</jk> Object[] b3 = <jk>new</jk> Object[]{
<jk>new</jk> BeanX()
};
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;b1&gt;
&lt;X&gt;
&lt;fx&gt;<xv>foo</xv>&lt;/fx&gt;
&lt;/X&gt;
&lt;/b1&gt;
&lt;b2&gt;
&lt;X&gt;
&lt;fx&gt;<xv>foo</xv>&lt;/fx&gt;
&lt;/X&gt;
&lt;/b2&gt;
&lt;b3&gt;
&lt;X&gt;
&lt;fx&gt;<xv>foo</xv>&lt;/fx&gt;
&lt;/X&gt;
&lt;/b3&gt;
&lt;/object&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(dictionary={BeanX.<jk>class</jk>})
<jk>class</jk> BeanWith2dArrayPropertiesWithTypeNames {
<jk>public</jk> BeanX[][] b1 = <jk>new</jk> BeanX[][]{{
<jk>new</jk> BeanX()
}};
<jk>public</jk> Object[][] b2 = <jk>new</jk> BeanX[][]{{
<jk>new</jk> BeanX()
}};
<jk>public</jk> Object[][] b3 = <jk>new</jk> Object[][]{{
<jk>new</jk> BeanX()
}};
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;b1&gt;
&lt;array&gt;
&lt;X&gt;
&lt;fx&gt;<xv>foo</xv>&lt;/fx&gt;
&lt;/X&gt;
&lt;/array&gt;
&lt;/b1&gt;
&lt;b2&gt;
&lt;array&gt;
&lt;X&gt;
&lt;fx&gt;<xv>foo</xv>&lt;/fx&gt;
&lt;/X&gt;
&lt;/array&gt;
&lt;/b2&gt;
&lt;b3&gt;
&lt;array&gt;
&lt;X&gt;
&lt;fx&gt;<xv>foo</xv>&lt;/fx&gt;
&lt;/X&gt;
&lt;/array&gt;
&lt;/b3&gt;
&lt;/object&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(dictionary={BeanX.<jk>class</jk>})
<jk>class</jk> BeanWithMapPropertiesWithTypeNames {
<jk>public</jk> Map&lt;String,BeanX&gt; b1 = <jk>new</jk> HashMap&lt;&gt;() {{
put(<js>"k1"</js>, <jk>new</jk> BeanX());
}};
<jk>public</jk> Map&lt;String,Object&gt; b2 = <jk>new</jk> HashMap&lt;&gt;() {{
put(<js>"k2"</js>, <jk>new</jk> BeanX());
}}
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;b1&gt;
&lt;k1&gt;
&lt;fx&gt;<xv>foo</xv>&lt;/fx&gt;
&lt;/k1&gt;
&lt;/b1&gt;
&lt;b2&gt;
&lt;k2 <xa>_type</xa>=<xs>'X'</xs>&gt;
&lt;fx&gt;<xv>foo</xv>&lt;/fx&gt;
&lt;/k2&gt;
&lt;/b2&gt;
&lt;/object&gt;
</xt></td>
</tr>
</table>
<p>
Bean type names are also used for resolution when abstract fields are used.
The following examples show how they are used in a variety of circumstances.
</p>
<table class='styled w800'>
<tr>
<th>Java</th>
<th>XML</th>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(dictionary={A.<jk>class</jk>})
<jk>class</jk> BeanWithAbstractFields {
<jk>public</jk> A a = <jk>new</jk> A();
<jk>public</jk> IA ia = <jk>new</jk> A();
<jk>public</jk> AA aa = <jk>new</jk> A();
<jk>public</jk> Object o = <jk>new</jk> A();
}
<jk>interface</jk> IA {}
<jk>abstract class</jk> AA <jk>implements</jk> IA {}
<ja>@Bean</ja>(typeName=<js>"A"</js>)
<jk>class</jk> A <jk>extends</jk> AA {
<jk>public</jk> String fa = <js>"foo"</js>;
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/a&gt;
&lt;ia <xa>_type</xa>=<xs>'A'</xs>&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/ia&gt;
&lt;aa <xa>_type</xa>=<xs>'A'</xs>&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/aa&gt;
&lt;o <xa>_type</xa>=<xs>'A'</xs>&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/o&gt;
&lt;/object&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(dictionary={A.<jk>class</jk>})
<jk>class</jk> BeanWithAbstractArrayFields {
<jk>public</jk> A[] a = <jk>new</jk> A[]{<jk>new</jk> A()};
<jk>public</jk> IA[] ia1 = <jk>new</jk> A[]{<jk>new</jk> A()};
<jk>public</jk> IA[] ia2 = <jk>new</jk> IA[]{<jk>new</jk> A()};
<jk>public</jk> AA[] aa1 = <jk>new</jk> A[]{<jk>new</jk> A()};
<jk>public</jk> AA[] aa2 = <jk>new</jk> AA[]{<jk>new</jk> A()};
<jk>public</jk> Object[] o1 = <jk>new</jk> A[]{<jk>new</jk> A()};
<jk>public</jk> Object[] o2 = <jk>new</jk> Object[]{<jk>new</jk> A()};
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;
&lt;A&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/A&gt;
&lt;/a&gt;
&lt;ia1&gt;
&lt;A&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/A&gt;
&lt;/ia1&gt;
&lt;ia2&gt;
&lt;A&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/A&gt;
&lt;/ia2&gt;
&lt;aa1&gt;
&lt;A&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/A&gt;
&lt;/aa1&gt;
&lt;aa2&gt;
&lt;A&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/A&gt;
&lt;/aa2&gt;
&lt;o1&gt;
&lt;A&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/A&gt;
&lt;/o1&gt;
&lt;o2&gt;
&lt;A&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/A&gt;
&lt;/o2&gt;
&lt;/object&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(dictionary={A.<jk>class</jk>})
<jk>class</jk> BeanWithAbstractMapFields {
<jk>public</jk> Map&lt;String,A&gt; a = <jk>new</jk> HashMap&lt;&gt;() {{
put(<js>"k1"</js>, <jk>new</jk> A());
}};
<jk>public</jk> Map&lt;String,AA&gt; b = <jk>new</jk> HashMap&lt;&gt;() {{
put(<js>"k2"</js>, <jk>new</jk> A());
}};
<jk>public</jk> Map&lt;String,Object&gt; c = <jk>new</jk> HashMap&lt;&gt;() {{
put(<js>"k3"</js>, <jk>new</jk> A());
}};
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;
&lt;k1&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/k1&gt;
&lt;/a&gt;
&lt;b&gt;
&lt;k2 <xa>_type</xa>=<xs>'A'</xs>&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/k2&gt;
&lt;/b&gt;
&lt;c&gt;
&lt;k3 <xa>_type</xa>=<xs>'A'</xs>&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/k3&gt;
&lt;/c&gt;
&lt;/object&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(dictionary={A.<jk>class</jk>})
<jk>class</jk> BeanWithAbstractMapArrayFields {
<jk>public</jk> Map&lt;String,A[]&gt; a = <jk>new</jk> LinkedHashMap&lt;&gt;() {{
put(<js>"a1"</js>, <jk>new</jk> A[]{<jk>new</jk> A()});
}};
<jk>public</jk> Map&lt;String,IA[]&gt; ia = <jk>new</jk> LinkedHashMap&lt;&gt;() {{
put(<js>"ia1"</js>, <jk>new</jk> A[]{<jk>new</jk> A()});
put(<js>"ia2"</js>, <jk>new</jk> IA[]{<jk>new</jk> A()});
}};
<jk>public</jk> Map&lt;String,AA[]&gt; aa = <jk>new</jk> LinkedHashMap&lt;&gt;() {{
put(<js>"aa1"</js>, <jk>new</jk> A[]{<jk>new</jk> A()});
put(<js>"aa2"</js>, <jk>new</jk> AA[]{<jk>new</jk> A()});
}};
<jk>public</jk> Map&lt;String,Object[]&gt; o = <jk>new</jk>LinkedHashMap&lt;&gt;() {{
put(<js>"o1"</js>, <jk>new</jk> A[]{<jk>new</jk> A()});
put(<js>"o2"</js>, <jk>new</jk> AA[]{<jk>new</jk> A()});
}};
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;
&lt;a1&gt;
&lt;A&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/A&gt;
&lt;/a1&gt;
&lt;/a&gt;
&lt;ia&gt;
&lt;ia1&gt;
&lt;A&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/A&gt;
&lt;/ia1&gt;
&lt;ia2&gt;
&lt;A&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/A&gt;
&lt;/ia2&gt;
&lt;/ia&gt;
&lt;aa&gt;
&lt;aa1&gt;
&lt;A&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/A&gt;
&lt;/aa1&gt;
&lt;aa2&gt;
&lt;A&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/A&gt;
&lt;/aa2&gt;
&lt;/aa&gt;
&lt;o&gt;
&lt;o1&gt;
&lt;A&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/A&gt;
&lt;/o1&gt;
&lt;o2&gt;
&lt;A&gt;
&lt;fa&gt;<xv>foo</xv>&lt;/fa&gt;
&lt;/A&gt;
&lt;/o2&gt;
&lt;/o&gt;
&lt;/object&gt;
</xt></td>
</tr>
</table>
<p>
On a side note, characters that cannot be represented in XML 1.0 are encoded using a simple encoding.
Note in the examples below, some characters such as <js>'\n'</js>, <js>'\t</js>', and <js>'\r'</js>
can be represented as XML entities when used in text but not in element names. Other characters such as
<js>'\b'</js> and <js>'\f'</js> cannot be encoded in XML 1.0 at all without inventing our own notation.
Whitespace characters in element names are encoded as well as whitespace end characters in text.
</p>
<table class='styled w800'>
<tr>
<th>Java</th>
<th>XML</th>
</tr>
<tr>
<td class='code'>
<jk>class</jk> BeanWithSpecialCharacters {
<jk>public</jk> String a = <js>" \b\f\n\t\r "</js>;
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;<xv>_x0020_ _x0008__x000C_&amp;#x000a;&amp;#x0009;&amp;#x000d; _x0020_</xv>&lt;/a&gt;
&lt;/object&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>" \b\f\n\t\r "</js>)
<jk>class</jk> BeanWithNamesWithSpecialCharacters {
<ja>@Beanp</ja>(name=<js>" \b\f\n\t\r "</js>)
<jk>public</jk> String a = <js>" \b\f\n\t\r "</js>;
}
</td>
<td class='code'><xt>
&lt;_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_&gt;
&lt;_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_&gt;
<xv>_x0020_ _x0008__x000C_&amp;#x000a;&amp;#x0009;&amp;#x000d; _x0020_</xv>
&lt;/_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_&gt;
&lt;/_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_&gt;
</xt></td>
</tr>
</table>
<p>
While it's true that these characters CAN be represented in XML 1.1, it's impossible to parse XML 1.1
text in Java without the XML containing an XML declaration.
Unfortunately, this, and the uselessness of the
{@link javax.xml.stream.XMLInputFactory#IS_REPLACING_ENTITY_REFERENCES} setting in Java
forced us to make some hard design decisions that may not be the most elegant.
</p>
</div><!-- END: 2.22.4 - juneau-marshall.XmlDetails.BeanTypeNameAnnotation -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.XmlDetails.XmlChildNameAnnotation' id='juneau-marshall.XmlDetails.XmlChildNameAnnotation'>2.22.5 - @Xml(childName) Annotation</a></h4>
<div class='topic'><!-- START: 2.22.5 - juneau-marshall.XmlDetails.XmlChildNameAnnotation -->
<p>
The {@link org.apache.juneau.xml.annotation.Xml#childName() @Xml(childName)} annotation can be used to
specify the name of XML child elements for bean properties of type collection or array.
</p>
<h5 class='figure'>Example</h5>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>Without annotation</th>
<th>With annotation</th>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<ja>@Xml</ja>(childName=<js>"X"</js>)
<jk>public</jk> String[] a;
<ja>@Xml</ja>(childName=<js>"Y"</js>)
<jk>public</jk> int[] b;
}
</td>
<td class='code'>
{
a: [<js>'foo'</js>,<js>'bar'</js>],
b: [123,456]
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;
&lt;string&gt;<xv>foo</xv>&lt;/string&gt;
&lt;string&gt;<xv>bar</xv>&lt;/string&gt;
&lt;/a&gt;
&lt;b&gt;
&lt;number&gt;<xv>123</xv>&lt;/number&gt;
&lt;number&gt;<xv>456</xv>&lt;/number&gt;
&lt;/b&gt;
&lt;/object&gt;
</xt></td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;
&lt;X&gt;<xv>foo</xv>&lt;/X&gt;
&lt;X&gt;<xv>bar</xv>&lt;/X&gt;
&lt;/a&gt;
&lt;b&gt;
&lt;Y&gt;<xv>123</xv>&lt;/Y&gt;
&lt;Y&gt;<xv>456</xv>&lt;/Y&gt;
&lt;/b&gt;
&lt;/object&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<ja>@Xml</ja>(childName=<js>"child"</js>)
<jk>public</jk> int[] a;
}
</td>
<td class='code'>
{
a: [123,456]
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;
&lt;string&gt;<xv>foo</xv>&lt;/string&gt;
&lt;string&gt;<xv>bar</xv>&lt;/string&gt;
&lt;/a&gt;
&lt;/object&gt;
</xt></td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;
&lt;child&gt;<xv>foo</xv>&lt;/child&gt;
&lt;child&gt;<xv>bar</xv>&lt;/child&gt;
&lt;/a&gt;
&lt;/object&gt;
</xt></td>
</tr>
</table>
</div><!-- END: 2.22.5 - juneau-marshall.XmlDetails.XmlChildNameAnnotation -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.XmlDetails.XmlFormatAnnotation' id='juneau-marshall.XmlDetails.XmlFormatAnnotation'>2.22.6 - @Xml(format) Annotation</a></h4>
<div class='topic'><!-- START: 2.22.6 - juneau-marshall.XmlDetails.XmlFormatAnnotation -->
<p>
The {@link org.apache.juneau.xml.annotation.Xml#format() @Xml(format)} annotation can be used to tweak
the XML format of a POJO.
The value is set to an enum value of type {@link org.apache.juneau.xml.annotation.XmlFormat}.
This annotation can be applied to both classes and bean properties.
</p>
<p>
The {@link org.apache.juneau.xml.annotation.XmlFormat#ATTR} format can be applied to bean properties to
serialize them as XML attributes instead of elements.
Note that this only supports properties of simple types (e.g. strings, numbers, booleans).
</p>
<h5 class='figure'>Example</h5>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>Without annotation</th>
<th>With annotation</th>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>ATTR</jsf>)
<jk>public</jk> String a;
}
</td>
<td class='code'>
{
a: <js>'foo'</js>
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;<xv>foo</xv>&lt;/a&gt;
&lt;/object&gt;
</xt></td>
<td class='code'><xt>
&lt;object <xa>a</xa>=<xs>'foo'</xs>/&gt;
</xt></td>
</tr>
</table>
<p>
The {@link org.apache.juneau.xml.annotation.XmlFormat#ATTRS} format can be applied to bean classes to
force all bean properties to be serialized as XML attributes instead of child elements.
</p>
<h5 class='figure'>Example</h5>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>Without annotation</th>
<th>With annotation</th>
</tr>
<tr>
<td class='code'>
<ja>@Xml</ja>(format=XmlFormat.<jsf>ATTRS</jsf>)
<jk>class</jk> MyBean {
<jk>public</jk> String a;
<jk>public int</jk> b;
}
</td>
<td class='code'>
{
a: <js>'foo'</js>,
b: 123
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;<xv>foo</xv>&lt;/a&gt;
&lt;b&gt;<xv>123</xv>&lt;/b&gt;
&lt;/object&gt;
</xt></td>
<td class='code'><xt>
&lt;object <xa>a</xa>=<xs>'foo'</xs> <xa>b</xa>=<xs>'123'</xs>/&gt;
</xt></td>
</tr>
</table>
<p>
The {@link org.apache.juneau.xml.annotation.XmlFormat#ELEMENT} format can be applied to bean properties
to override the {@link org.apache.juneau.xml.annotation.XmlFormat#ATTRS} format applied on the bean
class.
</p>
<h5 class='figure'>Example</h5>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>Without annotation</th>
<th>With annotation</th>
</tr>
<tr>
<td class='code'>
<ja>@Xml</ja>(format=XmlFormat.<jsf>ATTRS</jsf>)
<jk>class</jk> MyBean {
<jk>public</jk> String a;
<ja>@Xml</ja>(format=XmlFormat.<jsf>ELEMENT</jsf>)
<jk>public int</jk> b;
}
</td>
<td class='code'>
{
a: <js>'foo'</js>,
b: 123
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;<xv>foo</xv>&lt;/a&gt;
&lt;b&gt;<xv>123</xv>&lt;/b&gt;
&lt;/object&gt;
</xt></td>
<td class='code'><xt>
&lt;object <xa>a</xa>=<xs>'foo'</xs></xs>&gt;
&lt;b&gt;<xv>123</xv>&lt;/b&gt;
&lt;/object&gt;
</xt></td>
</tr>
</table>
<p>
The {@link org.apache.juneau.xml.annotation.XmlFormat#ATTRS} format can be applied to a single bean
property of type <c>Map&lt;String,Object&gt;</c> to denote arbitrary XML attribute values on the
element.
These can be mixed with other {@link org.apache.juneau.xml.annotation.XmlFormat#ATTR} annotated
properties, but there must not be an overlap in bean property names and map keys.
</p>
<h5 class='figure'>Example</h5>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>Without annotation</th>
<th>With annotation</th>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>ATTRS</jsf>)
<jk>public</jk> Map&lt;String,Object&gt; a;
<ja>@Xml</ja>(format=XmlFormat.<jsf>ATTR</jsf>)
<jk>public int</jk> b;
}
</td>
<td class='code'>
{
<jok>a</jok>: {
<jok>k1</jok>: <jov>'foo'</jov>,
<jok>k2</jok>: <jov>123</jov>,
},
<jok>b</jok>: <jov>456</jov>
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;
&lt;k1&gt;<xv>foo</xv>&lt;/k1&gt;
&lt;k2 <xa>_type</xa>=<xs>'number'</xs>&gt;<xv>123</xv>&lt;/k2&gt;
&lt;/a&gt;
&lt;b&gt;<xv>456</xv>&lt;/b&gt;
&lt;/object&gt;
</xt></td>
<td class='code'><xt>
&lt;object <xa>k1</xa>=<xs>'foo'</xs> <xa>k2</xa>=<xs>'123'</xs> <xa>b</xa>=<xs>'456'</xs>/&gt;
</xt></td>
</tr>
</table>
<p>
The {@link org.apache.juneau.xml.annotation.XmlFormat#COLLAPSED} format can be applied to bean properties
of type array/Collection.
This causes the child objects to be serialized directly inside the bean element.
This format must be used in conjunction with {@link org.apache.juneau.xml.annotation.Xml#childName() @Xml(childName)}
to differentiate which collection the values came from if you plan on parsing the output back into beans.
Note that child names must not conflict with other property names.
</p>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>Without annotation</th>
<th>With annotation</th>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<ja>@Xml</ja>(childName=<js>"A"</js>,format=XmlFormat.<jsf>COLLAPSED</jsf>)
<jk>public</jk> String[] a;
<ja>@Xml</ja>(childName=<js>"B"</js>,format=XmlFormat.<jsf>COLLAPSED</jsf>)
<jk>public int</jk>[] b;
}
</td>
<td class='code'>
{
a: [<js>'foo'</js>,<js>'bar'</js>],
b: [123,456]
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;
&lt;string&gt;<xv>foo</xv>&lt;/string&gt;
&lt;string&gt;<xv>bar</xv>&lt;/string&gt;
&lt;/a&gt;
&lt;b&gt;
&lt;number&gt;<xv>123</xv>&lt;/number&gt;
&lt;number&gt;<xv>456</xv>&lt;/number&gt;
&lt;/b&gt;
&lt;/object&gt;
</xt></td>
<td class='code'><xt>
&lt;object&gt;
&lt;A&gt;<xv>foo</xv>&lt;/A&gt;
&lt;A&gt;<xv>bar</xv>&lt;/A&gt;
&lt;B&gt;<xv>123</xv>&lt;/B&gt;
&lt;B&gt;<xv>456</xv>&lt;/B&gt;
&lt;/object&gt;
</xt></td>
</tr>
</table>
<p>
The {@link org.apache.juneau.xml.annotation.XmlFormat#ELEMENTS} format can be applied to a single bean
property of either a simple type or array/Collection.
It allows free-form child elements to be formed.
All other properties on the bean MUST be serialized as attributes.
</p>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>With annotation</th>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>ATTR</jsf>)
<jk>public</jk> String a;
<ja>@Xml</ja>(format=XmlFormat.<jsf>ELEMENTS</jsf>)
<jk>public</jk> String b;
}
</td>
<td class='code'>
{
a: <js>'foo'</js>,
b: <js>'bar'</js>
}
</td>
<td class='code'><xt>
&lt;object <xa>a</xa>=<xs>'foo'</xs>&gt;
&lt;string&gt;<xv>bar</xv>&lt;/string&gt;
&lt;/object&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>ATTR</jsf>)
<jk>public</jk> String a;
<ja>@Xml</ja>(format=XmlFormat.<jsf>ELEMENTS</jsf>)
<jk>public</jk> Object[] b;
}
</td>
<td class='code'>
{
a: <js>'foo'</js>,
b: [
<js>'bar'</js>,
<js>'baz'</js>,
123,
<jk>true</jk>,
<jk>null</jk>
]
}
</td>
<td class='code'><xt>
&lt;object <xa>a</xa>=<xs>'foo'</xs>&gt;
&lt;string&gt;<xv>bar</xv>&lt;/string&gt;
&lt;string&gt;<xv>baz</xv>&lt;/string&gt;
&lt;number&gt;<xv>123</xv>&lt;/number&gt;
&lt;boolean&gt;<xv>true</xv>&lt;/boolean&gt;
&lt;null/&gt;
&lt;/object&gt;
</xt></td>
</tr>
</table>
<p>
The {@link org.apache.juneau.xml.annotation.XmlFormat#MIXED} format is similar to
{@link org.apache.juneau.xml.annotation.XmlFormat#ELEMENTS} except elements names on primitive types
(string/number/boolean/null) are stripped from the output.
This format particularly useful when combined with bean dictionaries to produce mixed content.
The bean dictionary isn't used during serialization, but it is needed during parsing to resolve bean
types.
</p>
<p>
The {@link org.apache.juneau.xml.annotation.XmlFormat#MIXED_PWS} format identical to
{@link org.apache.juneau.xml.annotation.XmlFormat#MIXED} except whitespace characters are preserved in
the output.
</p>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>Without annotations</th>
<th>With annotations</th>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>MIXED</jsf>)
<ja>@Beanp</ja>(dictionary={MyBeanX.<jk>class</jk>, MyBeanY.<jk>class</jk>})
<jk>public</jk> Object[] a;
}
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBeanX {
<ja>@Xml</ja>(format=XmlFormat.<jsf>ATTR</jsf>)
<jk>public</jk> String b;
}
<ja>@Bean</ja>(typeName=<js>"Y"</js>)
<jk>class</jk> MyBeanY {
<ja>@Xml</ja>(format=XmlFormat.<jsf>ATTR</jsf>)
<jk>public</jk> String c;
}
</td>
<td class='code'>
{
a: [
<js>'foo'</js>,
{ _type:<js>'X'</js>, b:<js>'bar'</js> }
<js>'baz'</js>,
{ _type:<js>'Y'</js>, b:<js>'qux'</js> },
<js>'quux'</js>
]
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;
&lt;string&gt;<xv>foo</xv>&lt;/string&gt;
&lt;object&gt;
&lt;b&gt;<xv>bar</xv>&lt;/b&gt;
&lt;/object&gt;
&lt;string&gt;<xv>baz</xv>&lt;/string&gt;
&lt;object&gt;
&lt;b&gt;<xv>qux</xv>&lt;/b&gt;
&lt;/object&gt;
&lt;string&gt;<xv>quux</xv>&lt;/string&gt;
&lt;/a&gt;
&lt;/object&gt;
</xt></td>
<td class='code'><xt>
&lt;object&gt;<xv>foo</xv>&lt;X <xa>b</xa>=<xs>'bar'</xs>/&gt;<xv>baz</xv>&lt;Y <xa>c</xa>=<xs>'qux'</xs>/&gt;<xv>quux</xv>&lt;/object&gt;
</xt></td>
</tr>
</table>
<p>
Whitespace (tabs and newlines) are not added to MIXED child nodes in readable-output mode.
This helps ensures strings in the serialized output can be losslessly parsed back into their original
forms when they contain whitespace characters.
If the {@link javax.xml.stream.XMLInputFactory#IS_REPLACING_ENTITY_REFERENCES} setting was not useless
in Java, we could support lossless readable XML for MIXED content.
But as of Java 8, it still does not work.
</p>
<p>
XML suffers from other deficiencies as well that affect MIXED content.
For example, <xt>&lt;X&gt;&lt;/X&gt;</xt> and <xt>&lt;X/&gt;</xt> are equivalent in XML and
indistinguishable by the Java XML parsers.
This makes it impossible to differentiate between an empty element and an element containing an empty
string.
This causes empty strings to get lost in translation.
To alleviate this, we use the constructs <js>"_xE000_"</js> to represent an empty string, and
<js>"_x0020_"</js> to represent leading and trailing spaces.
</p>
<p>
The examples below show how whitespace is handled under various circumstances:
</p>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>XML</th>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>TEXT</jsf>)
<jk>public</jk> String a = <jk>null</jk>;
}
</td>
<td class='code'><xt>
&lt;X/&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>TEXT</jsf>)
<jk>public</jk> String a = <js>""</js>;
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv>_xE000_</xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>TEXT</jsf>)
<jk>public</jk> String a = <js>" "</js>;
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv>_x0020_</xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>TEXT</jsf>)
<jk>public</jk> String a = <js>" "</js>;
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv>_x0020__x0020_</xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>TEXT</jsf>)
<jk>public</jk> String a = <js>" foobar "</js>;
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv>_x0020_ foobar _x0020_</xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>TEXT_PWS</jsf>)
<jk>public</jk> String a = <jk>null</jk>;
}
</td>
<td class='code'><xt>
&lt;X/&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>TEXT_PWS</jsf>)
<jk>public</jk> String a = <js>""</js>;
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv>_xE000_</xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>TEXT_PWS</jsf>)
<jk>public</jk> String a = <js>" "</js>;
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv> </xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>TEXT_PWS</jsf>)
<jk>public</jk> String a = <js>" "</js>;
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv> </xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>TEXT_PWS</jsf>)
<jk>public</jk> String a = <js>" foobar "</js>;
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv> foobar </xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>MIXED</jsf>)
<jk>public</jk> String[] a = <jk>null</jk>;
}
</td>
<td class='code'><xt>
&lt;X/&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>MIXED</jsf>)
<jk>public</jk> String a[] = <jk>new</jk> String[]{<js>""</js>};
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv>_xE000_</xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>MIXED</jsf>)
<jk>public</jk> String a[] = <jk>new</jk> String[]{<js>" "</js>};
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv>_x0020_</xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>MIXED</jsf>)
<jk>public</jk> String a[] = <jk>new</jk> String[]{<js>" "</js>};
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv>_x0020__x0020_</xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>MIXED</jsf>)
<jk>public</jk> String a[] = <jk>new</jk> String[]{
<js>" foobar "</js>
};
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv>_x0020_ foobar _x0020_</xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>MIXED_PWS</jsf>)
<jk>public</jk> String[] a = <jk>null</jk>;
}
</td>
<td class='code'><xt>
&lt;X/&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>MIXED_PWS</jsf>)
<jk>public</jk> String a[] = <jk>new</jk> String[]{<js>""</js>};
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv>_xE000_</xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>MIXED_PWS</jsf>)
<jk>public</jk> String a[] = <jk>new</jk> String[]{<js>" "</js>};
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv> </xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>MIXED_PWS</jsf>)
<jk>public</jk> String a[] = <jk>new</jk> String[]{<js>" "</js>};
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv> </xv>&lt;/X&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<ja>@Bean</ja>(typeName=<js>"X"</js>)
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>MIXED_PWS</jsf>)
<jk>public</jk> String a[] = <jk>new</jk> String[]{
<js>" foobar "</js>
};
}
</td>
<td class='code'><xt>
&lt;X&gt;<xv> foobar </xv>&lt;/X&gt;
</xt></td>
</tr>
</table>
<p>
It should be noted that when using <jsf>MIXED</jsf>, you are not guaranteed to parse back the exact
same content since side-by-side strings in the content will end up concatenated when parsed.
</p>
<p>
The {@link org.apache.juneau.xml.annotation.XmlFormat#TEXT} format is similar to
{@link org.apache.juneau.xml.annotation.XmlFormat#MIXED} except it's meant for solitary objects that
get serialized as simple child text nodes.
Any object that can be serialize to a <c>String</c> can be used.
The {@link org.apache.juneau.xml.annotation.XmlFormat#TEXT_PWS} is the same except whitespace is
preserved in the output.
</p>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>Without annotations</th>
<th>With annotations</th>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>TEXT</jsf>)
<jk>public</jk> String a;
}
</td>
<td class='code'>
{
a: <js>'foo'</js>
}
</td>
<td class='code'><xt>
&lt;object&gt;
&lt;a&gt;<xv>foo</xv>&lt;/a&gt;
&lt;/object&gt;
</xt></td>
<td class='code'><xt>
&lt;object&gt;<xv>foo</xv>&lt;/object&gt;
</xt></td>
</tr>
</table>
<p>
The {@link org.apache.juneau.xml.annotation.XmlFormat#XMLTEXT} format is similar to
{@link org.apache.juneau.xml.annotation.XmlFormat#TEXT} except it's meant for strings containing XML
that should be serialized as-is to the document.
Any object that can be serialize to a <c>String</c> can be used.
During parsing, the element content gets parsed with the rest of the document and then re-serialized to
XML before being set as the property value.
This process may not be perfect (e.g. double quotes may be replaced by single quotes, etc...).
</p>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>With TEXT annotation</th>
<th>With XMLTEXT annotation</th>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<ja>@Xml</ja>(format=XmlFormat.<jsf>XMLTEXT</jsf>)
<jk>public</jk> String a;
}
</td>
<td class='code'>
{
a: <js>'Some &lt;b&gt;XML&lt;/b&gt; text'</js>
}
</td>
<td class='code'><xt>
&lt;object&gt;<xv>Some &amp;lt;b&amp;gt;XML&amp;lt;/b&amp;gt; text</xv>&lt;/object&gt;
</xt></td>
<td class='code'><xt>
&lt;object&gt;<xv>Some <xt>&lt;b&gt;</xt>XML<xt>&lt;/b&gt;</xt> text</xv>&lt;/object&gt;
</xt></td>
</tr>
</table>
</div><!-- END: 2.22.6 - juneau-marshall.XmlDetails.XmlFormatAnnotation -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.XmlDetails.Namespaces' id='juneau-marshall.XmlDetails.Namespaces'>2.22.7 - Namespaces</a></h4>
<div class='topic'><!-- START: 2.22.7 - juneau-marshall.XmlDetails.Namespaces -->
<p>
Let's go back to the example of our original <c>Person</c> bean class, but add some namespace annotations:
</p>
<h5 class='figure'>Sample Beans</h5>
<p class='bpcode w800'>
<ja>@Xml</ja>(prefix=<js>"per"</js>)
<ja>@Bean</ja>(typeName=<js>"person"</js>)
<jk>public class</jk> Person {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>name</jf>;
<ja>@Swap</ja>(TemporalCalendarSwap.IsoInstant.<jk>class</jk>) <jk>public</jk> Calendar <jf>birthDate</jf>;
<jk>public</jk> List&lt;Address&gt; <jf>addresses</jf>;
<jc>// Getters/setters omitted</jc>
}
<ja>@Xml</ja>(prefix=<js>"addr"</js>)
<ja>@Bean</ja>(typeName=<js>"address"</js>)
<jk>public class</jk> Address {
<jc>// Bean properties</jc>
<ja>@Xml</ja>(prefix=<js>"mail"</js>) <jk>public</jk> String <jf>street</jf>, <jf>city</jf>;
<ja>@Xml</ja>(prefix=<js>"mail"</js>) <jk>public</jk> StateEnum <jf>state</jf>;
<ja>@Xml</ja>(prefix=<js>"mail"</js>) <jk>public int</jk> <jf>zip</jf>;
<jk>public boolean</jk> <jf>isCurrent</jf>;
<jc>// Getters/setters omitted</jc>
}
</p>
<p>
The namespace URLs can either be defined as part of the {@link org.apache.juneau.xml.annotation.Xml @Xml}
annotation, or can be defined at the package level with the {@link org.apache.juneau.xml.annotation.XmlSchema @XmlSchema}
annotation.
Below shows it defined at the package level:
</p>
<h5 class='figure'>package-info.java</h5>
<p class='bpcode w800'>
<ja>@XmlSchema</ja>(
prefix=<js>"ab"</js>, <jc>// Default namespace</jc>
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;
</p>
<h5 class='figure'>Sample Code</h5>
<p class='bpcode w800'>
Person p = <jk>new</jk> Person()
.name(<js>"John Smith"</js>)
.birthDate(<js>"1946-08-12T00:00:00Z"</js>)
.addresses(
<jk>new</jk> Address()
.street(<js>"100 Main Street"</js>)
.city(<js>"Anywhereville"</js>)
.state(<jsf>NY</jsf>)
.zip(12345)
.isCurrent(<jk>true</jk>);
);
<jc>// Create a new serializer with readable output, this time with namespaces enabled.</jc>
<jc>// Note that this is identical to XmlSerializer.DEFAULT_NS_SQ_READABLE.</jc>
XmlSerializer s = XmlSerializer.<jsm>create</jsm>().ns().ws().sq().build();
String xml = s.serialize(p);
</p>
<p>
Now when we run this code, we'll see namespaces added to our output:
</p>
<p class='bpcode w800'>
<xt>&lt;per:person&gt;</xt>
<xt>&lt;per:name&gt;</xt>John Smith<xt>&lt;/per:name&gt;</xt>
<xt>&lt;per:birthDate&gt;</xt>1946-08-12T04:00:00Z<xt>&lt;/per:birthDate&gt;</xt>
<xt>&lt;per:addresses&gt;</xt>
<xt>&lt;addr:address&gt;</xt>
<xt>&lt;mail:street&gt;</xt>100 Main Street<xt>&lt;/mail:street&gt;</xt>
<xt>&lt;mail:city&gt;</xt>Anywhereville<xt>&lt;/mail:city&gt;</xt>
<xt>&lt;mail:state&gt;</xt>NY<xt>&lt;/mail:state&gt;</xt>
<xt>&lt;mail:zip&gt;</xt>12345<xt>&lt;/mail:zip&gt;</xt>
<xt>&lt;addr:isCurrent&gt;</xt>true<xt>&lt;/addr:isCurrent&gt;</xt>
<xt>&lt;/addr:address&gt;</xt>
<xt>&lt;/per:addresses&gt;</xt>
<xt>&lt;/per:person&gt;</xt>
</p>
<p>
Enabling the {@link org.apache.juneau.xml.XmlSerializer#XML_addNamespaceUrisToRoot} setting results
in the namespace URLs being added to the root node:
</p>
<p class='bpcode w800'>
<xt>&lt;per:person</xt>
<xa>xmlns</xa>=<xs>'http://www.apache.org/2013/Juneau'</xs>
<xa>xmlns:per</xa>=<xs>'http://www.apache.org/person/'</xs>
<xa>xmlns:addr</xa>=<xs>'http://www.apache.org/address/'</xs>
<xa>xmlns:mail</xa>=<xs>'http://www.apache.org/mail/'</xs>
<xt>&gt;</xt>
<xt>&lt;per:name&gt;</xt>John Smith<xt>&lt;/per:name&gt;</xt>
<xt>&lt;per:birthDate&gt;</xt>1946-08-12T04:00:00Z<xt>&lt;/per:birthDate&gt;</xt>
<xt>&lt;per:addresses&gt;</xt>
<xt>&lt;addr:address&gt;</xt>
<xt>&lt;mail:street&gt;</xt>100 Main Street<xt>&lt;/mail:street&gt;</xt>
<xt>&lt;mail:city&gt;</xt>Anywhereville<xt>&lt;/mail:city&gt;</xt>
<xt>&lt;mail:state&gt;</xt>NY<xt>&lt;/mail:state&gt;</xt>
<xt>&lt;mail:zip&gt;</xt>12345<xt>&lt;/mail:zip&gt;</xt>
<xt>&lt;addr:isCurrent&gt;</xt>true<xt>&lt;/addr:isCurrent&gt;</xt>
<xt>&lt;/addr:address&gt;</xt>
<xt>&lt;/per:addresses&gt;</xt>
<xt>&lt;/per:person&gt;</xt>
</p>
<p>
We can simplify the output by setting the default namespace on the serializer so that all the elements do
not need to be prefixed:
<p class='bpcode w800'>
<jc>// Create a new serializer with readable output, this time with namespaces enabled.</jc>
XmlSerializer s = XmlSerializer.<jsm>create</jsm>().ws().sq().ns()
.defaultNamespaceUri(<js>"http://www.apache.org/person/"</js>)
.build();
</p>
<p>
This produces the following equivalent where the elements don't need prefixes since they're already in the
default document namespace:
</p>
<p class='bpcode w800'>
<xt>&lt;person</xt>
<xa>xmlns:juneau</xa>=<xs>'http://www.apache.org/2013/Juneau'</xs>
<xa>xmlns</xa>=<xs>'http://www.apache.org/person/'</xs>
<xa>xmlns:addr</xa>=<xs>'http://www.apache.org/address/'</xs>
<xa>xmlns:mail</xa>=<xs>'http://www.apache.org/mail/'</xs>
<xt>&gt;</xt>
<xt>&lt;name&gt;</xt>John Smith<xt>&lt;/name&gt;</xt>
<xt>&lt;birthDate&gt;</xt>1946-08-12T04:00:00Z<xt>&lt;/birthDate&gt;</xt>
<xt>&lt;addresses&gt;</xt>
<xt>&lt;addr:address&gt;</xt>
<xt>&lt;mail:street&gt;</xt>100 Main Street<xt>&lt;/mail:street&gt;</xt>
<xt>&lt;mail:city&gt;</xt>Anywhereville<xt>&lt;/mail:city&gt;</xt>
<xt>&lt;mail:state&gt;</xt>NY<xt>&lt;/mail:state&gt;</xt>
<xt>&lt;mail:zip&gt;</xt>12345<xt>&lt;/mail:zip&gt;</xt>
<xt>&lt;addr:isCurrent&gt;</xt>true<xt>&lt;/addr:isCurrent&gt;</xt>
<xt>&lt;/addr:address&gt;</xt>
<xt>&lt;/addresses&gt;</xt>
<xt>&lt;/person&gt;</xt>
</p>
<p>
One important property on the XML serializer class is
{@link org.apache.juneau.xml.XmlSerializer#XML_autoDetectNamespaces XML_autoDetectNamespaces}.
This property tells the serializer to make a first-pass over the data structure to look for namespaces
defined on classes and bean properties.
In high-performance environments, you may want to consider disabling auto-detection and providing your
own explicit list of namespaces to the serializer to avoid this scanning step.
</p>
<p>
The following code will produce the same output as before, but will perform slightly better since it
avoids this pre-scan step.
</p>
<p class='bpcode w800'>
<jc>// Create a new serializer with readable output, this time with namespaces enabled.</jc>
XmlSerializer s = XmlSerializer.<jsm>create</jsm>()
.ws()
.sq()
.autoDetectNamespaces(<jk>false</jk>)
.namespaces(<js>"{per:'http://www.apache.org/person/'}"</js>)
.build();
</p>
</div><!-- END: 2.22.7 - juneau-marshall.XmlDetails.Namespaces -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.XmlDetails.XmlSchema' id='juneau-marshall.XmlDetails.XmlSchema'>2.22.8 - XML-Schema Support</a></h4>
<div class='topic'><!-- START: 2.22.8 - juneau-marshall.XmlDetails.XmlSchema -->
<p>
Juneau provides the {@link org.apache.juneau.xmlschema.XmlSchemaSerializer} class for generating XML-Schema
documents that describe the output generated by the {@link org.apache.juneau.xml.XmlSerializer} class.
This class shares the same properties as <c>XmlSerializer</c>.
Since the XML output differs based on settings on the XML serializer class, the XML-Schema serializer
class must have the same property values as the XML serializer class it's describes.
To help facilitate creating an XML Schema serializer with the same properties as the corresponding
XML serializer, the {@link org.apache.juneau.xml.XmlSerializer#getSchemaSerializer()} method
has been added.
</p>
<p>
XML-Schema requires a separate file for each namespace.
Unfortunately, does not mesh well with the Juneau serializer architecture which serializes to single writers.
To get around this limitation, the schema serializer will produce a single output, but with multiple
schema documents separated by the null character (<js>'\u0000'</js>) to make it simple to split apart.
</p>
<p>
Lets start with an example where everything is in the same namespace.
We'll use the classes from before, but remove the references to namespaces.
Since we have not defined a default namespace, everything is defined under the default Juneau namespace.
</p>
<h5 class='figure'>Sample Beans</h5>
<p class='bpcode w800'>
<ja>@Bean</ja>(typeName=<js>"person"</js>)
<jk>public class</jk> Person {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>name</jf>;
<ja>@Swap</ja>(TemporalCalendarSwap.IsoInstant.<jk>class</jk>) <jk>public</jk> Calendar <jf>birthDate</jf>;
<jk>public</jk> List&lt;Address&gt; <jf>addresses</jf>;
<jc>// Getters/setters omitted</jc>
}
<ja>@Bean</ja>(typeName=<js>"address"</js>)
<jk>public class</jk> Address {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>street</jf>, <jf>city</jf>;
<jk>public</jk> StateEnum <jf>state</jf>;
<jk>public int</jk> <jf>zip</jf>;
<jk>public boolean</jk> <jf>isCurrent</jf>;
<jc>// Getters/setters omitted</jc>
}
</p>
<p>
The code for creating our POJO model and generating XML Schema is shown below:
</p>
<p class='bpcode w800'>
<jc>// Create a new serializer with readable output.</jc>
XmlSerializer s = XmlSerializer.<jsm>create</jsm>()
.ws()
.ns()
.sq()
.addNamespaceUrisToRoot(<jk>true</jk>)
.build();
<jc>// Create the equivalent schema serializer.</jc>
XmlSchemaSerializer ss = s.getSchemaSerializer();
<jc>// Get the XML Schema corresponding to the XML generated above.</jc>
String xmlSchema = ss.serialize(<jk>new</jk> Person());
</p>
<h5 class='figure'>XML-Schema results</h5>
<p class='bpcode w800'>
<xt>&lt;schema</xt>
<xa>xmlns</xa>=<xs>'http://www.w3.org/2001/XMLSchema'</xs>
<xa>targetNamespace</xa>=<xs>'http://www.apache.org/2013/Juneau'</xs>
<xa>elementFormDefault</xa>=<xs>'qualified'</xs>
<xa>xmlns:juneau</xa>=<xs>'http://www.apache.org/2013/Juneau'</xs><xt>&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'person'</xs> <xa>_type</xa>=<xs>'juneau:org.apache.juneau.examples.addressbook.Person'</xs><xt>/&gt;</xt>
<xt>&lt;complexType</xt> <xa>name</xa>=<xs>'org.apache.juneau.examples.addressbook.Person'</xs><xt>&gt;</xt>
<xt>&lt;sequence&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'name'</xs> <xa>_type</xa>=<xs>'string'</xs> <xa>minOccurs</xa>=<xs>'0'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'birthDate'</xs> <xa>_type</xa>=<xs>'juneau:java.util.Calendar'</xs> <xa>minOccurs</xa>=<xs>'0'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'addresses'</xs> <xa>_type</xa>=<xs>'juneau:java.util.LinkedList_x003C_org.apache.juneau.examples.addressbook.Address_x003E_'</xs> <xa>minOccurs</xa>=<xs>'0'</xs><xt>/&gt;</xt>
<xt>&lt;/sequence&gt;</xt>
<xt>&lt;/complexType&gt;</xt>
<xt>&lt;complexType</xt> <xa>name</xa>=<xs>'java.util.Calendar'</xs><xt>&gt;</xt>
<xt>&lt;sequence&gt;</xt>
<xt>&lt;any</xt> <xa>processContents</xa>=<xs>'skip'</xs> <xa>maxOccurs</xa>=<xs>'unbounded'</xs> <xa>minOccurs</xa>=<xs>'0'</xs><xt>/&gt;</xt>
<xt>&lt;/sequence&gt;</xt>
<xt>&lt;/complexType&gt;</xt>
<xt>&lt;complexType</xt> <xa>name</xa>=<xs>'java.util.LinkedList_x003C_org.apache.juneau.examples.addressbook.Address_x003E_'</xs><xt>&gt;</xt>
<xt>&lt;sequence&gt;</xt>
<xt>&lt;choice</xt> <xa>minOccurs</xa>=<xs>'0'</xs> <xa>maxOccurs</xa>=<xs>'unbounded'</xs><xt>&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'address'</xs> <xa>_type</xa>=<xs>'juneau:org.apache.juneau.examples.addressbook.Address'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'null'</xs> <xa>_type</xa>=<xs>'string'</xs><xt>/&gt;</xt>
<xt>&lt;/choice&gt;</xt>
<xt>&lt;/sequence&gt;</xt>
<xt>&lt;/complexType&gt;</xt>
<xt>&lt;complexType</xt> <xa>name</xa>=<xs>'org.apache.juneau.examples.addressbook.Address'</xs><xt>&gt;</xt>
<xt>&lt;sequence&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'street'</xs> <xa>_type</xa>=<xs>'string'</xs> <xa>minOccurs</xa>=<xs>'0'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'city'</xs> <xa>_type</xa>=<xs>'string'</xs> <xa>minOccurs</xa>=<xs>'0'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'state'</xs> <xa>_type</xa>=<xs>'string'</xs> <xa>minOccurs</xa>=<xs>'0'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'zip'</xs> <xa>_type</xa>=<xs>'integer'</xs> <xa>minOccurs</xa>=<xs>'0'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'isCurrent'</xs> <xa>_type</xa>=<xs>'boolean'</xs> <xa>minOccurs</xa>=<xs>'0'</xs><xt>/&gt;</xt>
<xt>&lt;/sequence&gt;</xt>
<xt>&lt;/complexType&gt;</xt>
<xt>&lt;/schema&gt;</xt>
</p>
<p>
Now if we add in some namespaces, we'll see how multiple namespaces are handled.
</p>
<h5 class='figure'>Sample Beans with multiple namespaces</h5>
<p class='bpcode w800'>
<ja>@Xml</ja>(prefix=<js>"per"</js>)
<ja>@Bean</ja>(typeName=<js>"person"</js>)
<jk>public class</jk> Person {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>name</jf>;
<ja>@Swap</ja>(TemporalCalendarSwap.IsoInstant.<jk>class</jk>) <jk>public</jk> Calendar <jf>birthDate</jf>;
<jk>public</jk> List&lt;Address&gt; <jf>addresses</jf>;
<jc>// Getters/setters omitted</jc>
}
<ja>@Xml</ja>(prefix=<js>"addr"</js>)
<ja>@Bean</ja>(typeName=<js>"address"</js>)
<jk>public class</jk> Address {
<jc>// Bean properties</jc>
<ja>@Xml</ja>(prefix=<js>"mail"</js>) <jk>public</jk> String <jf>street</jf>, <jf>city</jf>;
<ja>@Xml</ja>(prefix=<js>"mail"</js>) <jk>public</jk> StateEnum <jf>state</jf>;
<ja>@Xml</ja>(prefix=<js>"mail"</js>) <jk>public int</jk> <jf>zip</jf>;
<jk>public boolean</jk> <jf>isCurrent</jf>;
<jc>// Getters/setters omitted</jc>
}
</p>
<p>
The schema consists of 4 documents separated by a <js>'\u0000'</js> character.
</p>
<h5 class='figure'>XML-Schema results</h5>
<p class='bpcode w800'>
<xt>&lt;schema</xt>
<xa>xmlns</xa>=<xs>'http://www.w3.org/2001/XMLSchema'</xs>
<xa>targetNamespace</xa>=<xs>'http://www.apache.org/2013/Juneau'</xs>
<xa>elementFormDefault</xa>=<xs>'qualified'</xs>
<xa>xmlns:juneau</xa>=<xs>'http://www.apache.org/2013/Juneau'</xs>
<xa>xmlns:per</xa>=<xs>'http://www.apache.org/person/'</xs>
<xa>xmlns:addr</xa>=<xs>'http://www.apache.org/address/'</xs>
<xa>xmlns:mail</xa>=<xs>'http://www.apache.org/mail/'</xs><xt>&gt;</xt>
<xt>&lt;import</xt> <xa>namespace</xa>=<xs>'http://www.apache.org/person/'</xs> <xa>schemaLocation</xa>=<xs>'per.xsd'</xs><xt>/&gt;</xt>
<xt>&lt;import</xt> <xa>namespace</xa>=<xs>'http://www.apache.org/address/'</xs> <xa>schemaLocation</xa>=<xs>'addr.xsd'</xs><xt>/&gt;</xt>
<xt>&lt;import</xt> <xa>namespace</xa>=<xs>'http://www.apache.org/mail/'</xs> <xa>schemaLocation</xa>=<xs>'mail.xsd'</xs><xt>/&gt;</xt>
<xt>&lt;complexType</xt> <xa>name</xa>=<xs>'int'</xs><xt>&gt;</xt>
<xt>&lt;simpleContent&gt;</xt>
<xt>&lt;extension</xt> <xa>base</xa>=<xs>'integer'</xs><xt>/&gt;</xt>
<xt>&lt;/simpleContent&gt;</xt>
<xt>&lt;/complexType&gt;</xt>
<xt>&lt;complexType</xt> <xa>name</xa>=<xs>'java.lang.String'</xs><xt>&gt;</xt>
<xt>&lt;simpleContent&gt;</xt>
<xt>&lt;extension</xt> <xa>base</xa>=<xs>'string'</xs><xt>/&gt;</xt>
<xt>&lt;/simpleContent&gt;</xt>
<xt>&lt;/complexType&gt;</xt>
<xt>&lt;complexType</xt> <xa>name</xa>=<xs>'java.net.URI'</xs><xt>&gt;</xt>
<xt>&lt;simpleContent&gt;</xt>
<xt>&lt;extension</xt> <xa>base</xa>=<xs>'string'</xs><xt>/&gt;</xt>
<xt>&lt;/simpleContent&gt;</xt>
<xt>&lt;/complexType&gt;</xt>
<xt>&lt;complexType</xt> <xa>name</xa>=<xs>'java.util.Calendar'</xs><xt>&gt;</xt>
<xt>&lt;sequence&gt;</xt>
<xt>&lt;any</xt> <xa>processContents</xa>=<xs>'skip'</xs> <xa>maxOccurs</xa>=<xs>'unbounded'</xs> <xa>minOccurs</xa>=<xs>'0'</xs><xt>/&gt;</xt>
<xt>&lt;/sequence&gt;</xt>
<xt>&lt;/complexType&gt;</xt>
<xt>&lt;complexType</xt> <xa>name</xa>=<xs>'java.util.LinkedList_x003C_org.apache.juneau.examples.addressbook.Address_x003E_'</xs><xt>&gt;</xt>
<xt>&lt;sequence&gt;</xt>
<xt>&lt;choice</xt> <xa>minOccurs</xa>=<xs>'0'</xs> <xa>maxOccurs</xa>=<xs>'unbounded'</xs><xt>&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'address'</xs> <xa>_type</xa>=<xs>'addr:org.apache.juneau.examples.addressbook.Address'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'null'</xs> <xa>_type</xa>=<xs>'string'</xs><xt>/&gt;</xt>
<xt>&lt;/choice&gt;</xt>
<xt>&lt;/sequence&gt;</xt>
<xt>&lt;/complexType&gt;</xt>
<xt>&lt;complexType</xt> <xa>name</xa>=<xs>'boolean'</xs><xt>&gt;</xt>
<xt>&lt;simpleContent&gt;</xt>
<xt>&lt;extension</xt> <xa>base</xa>=<xs>'boolean'</xs><xt>/&gt;</xt>
<xt>&lt;/simpleContent&gt;</xt>
<xt>&lt;/complexType&gt;</xt>
<xt>&lt;/schema&gt;</xt>
[\u0000]
<xt>&lt;schema</xt>
<xa>xmlns</xa>=<xs>'http://www.w3.org/2001/XMLSchema'</xs>
<xa>targetNamespace</xa>=<xs>'http://www.apache.org/person/'</xs>
<xa>elementFormDefault</xa>=<xs>'qualified'</xs>
<xa>attributeFormDefault</xa>=<xs>'qualified'</xs>
<xa>xmlns:juneau</xa>=<xs>'http://www.apache.org/2013/Juneau'</xs>
<xa>xmlns:per</xa>=<xs>'http://www.apache.org/person/'</xs>
<xa>xmlns:addr</xa>=<xs>'http://www.apache.org/address/'</xs>
<xa>xmlns:mail</xa>=<xs>'http://www.apache.org/mail/'</xs><xt>&gt;</xt>
<xt>&lt;import</xt> <xa>namespace</xa>=<xs>'http://www.apache.org/2013/Juneau'</xs> <xa>schemaLocation</xa>=<xs>'juneau.xsd'</xs><xt>/&gt;</xt>
<xt>&lt;import</xt> <xa>namespace</xa>=<xs>'http://www.apache.org/address/'</xs> <xa>schemaLocation</xa>=<xs>'addr.xsd'</xs><xt>/&gt;</xt>
<xt>&lt;import</xt> <xa>namespace</xa>=<xs>'http://www.apache.org/mail/'</xs> <xa>schemaLocation</xa>=<xs>'mail.xsd'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'person'</xs> <xa>_type</xa>=<xs>'per:org.apache.juneau.examples.addressbook.Person'</xs><xt>/&gt;</xt>
<xt>&lt;complexType</xt> <xa>name</xa>=<xs>'org.apache.juneau.examples.addressbook.Person'</xs><xt>&gt;</xt>
<xt>&lt;sequence&gt;</xt>
<xt>&lt;any</xt> <xa>minOccurs</xa>=<xs>'0'</xs> <xa>maxOccurs</xa>=<xs>'unbounded'</xs><xt>/&gt;</xt>
<xt>&lt;/sequence&gt;</xt>
<xt>&lt;attribute</xt> <xa>name</xa>=<xs>'uri'</xs> <xa>_type</xa>=<xs>'string'</xs><xt>/&gt;</xt>
<xt>&lt;/complexType&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'name'</xs> <xa>_type</xa>=<xs>'juneau:java.lang.String'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'birthDate'</xs> <xa>_type</xa>=<xs>'juneau:java.util.Calendar'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'addresses'</xs> <xa>_type</xa>=<xs>'juneau:java.util.LinkedList_x003C_org.apache.juneau.examples.addressbook.Address_x003E_'</xs><xt>/&gt;</xt>
<xt>&lt;/schema&gt;</xt>
[\u0000]
<xt>&lt;schema</xt>
<xa>xmlns</xa>=<xs>'http://www.w3.org/2001/XMLSchema'</xs>
<xa>targetNamespace</xa>=<xs>'http://www.apache.org/address/'</xs>
<xa>elementFormDefault</xa>=<xs>'qualified'</xs>
<xa>attributeFormDefault</xa>=<xs>'qualified'</xs>
<xa>xmlns:juneau</xa>=<xs>'http://www.apache.org/2013/Juneau'</xs>
<xa>xmlns:per</xa>=<xs>'http://www.apache.org/person/'</xs>
<xa>xmlns:addr</xa>=<xs>'http://www.apache.org/address/'</xs>
<xa>xmlns:mail</xa>=<xs>'http://www.apache.org/mail/'</xs><xt>&gt;</xt>
<xt>&lt;import</xt> <xa>namespace</xa>=<xs>'http://www.apache.org/2013/Juneau'</xs> <xa>schemaLocation</xa>=<xs>'juneau.xsd'</xs><xt>/&gt;</xt>
<xt>&lt;import</xt> <xa>namespace</xa>=<xs>'http://www.apache.org/person/'</xs> <xa>schemaLocation</xa>=<xs>'per.xsd'</xs><xt>/&gt;</xt>
<xt>&lt;import</xt> <xa>namespace</xa>=<xs>'http://www.apache.org/mail/'</xs> <xa>schemaLocation</xa>=<xs>'mail.xsd'</xs><xt>/&gt;</xt>
<xt>&lt;complexType</xt> <xa>name</xa>=<xs>'org.apache.juneau.examples.addressbook.Address'</xs><xt>&gt;</xt>
<xt>&lt;sequence&gt;</xt>
<xt>&lt;any</xt> <xa>minOccurs</xa>=<xs>'0'</xs> <xa>maxOccurs</xa>=<xs>'unbounded'</xs><xt>/&gt;</xt>
<xt>&lt;/sequence&gt;</xt>
<xt>&lt;/complexType&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'isCurrent'</xs> <xa>_type</xa>=<xs>'juneau:boolean'</xs><xt>/&gt;</xt>
<xt>&lt;/schema&gt;</xt>
[\u0000]
<xt>&lt;schema</xt>
<xa>xmlns</xa>=<xs>'http://www.w3.org/2001/XMLSchema'</xs>
<xa>targetNamespace</xa>=<xs>'http://www.apache.org/mail/'</xs>
<xa>elementFormDefault</xa>=<xs>'qualified'</xs>
<xa>attributeFormDefault</xa>=<xs>'qualified'</xs>
<xa>xmlns:juneau</xa>=<xs>'http://www.apache.org/2013/Juneau'</xs>
<xa>xmlns:per</xa>=<xs>'http://www.apache.org/person/'</xs>
<xa>xmlns:addr</xa>=<xs>'http://www.apache.org/address/'</xs>
<xa>xmlns:mail</xa>=<xs>'http://www.apache.org/mail/'</xs><xt>&gt;</xt>
<xt>&lt;import</xt> <xa>namespace</xa>=<xs>'http://www.apache.org/2013/Juneau'</xs> <xa>schemaLocation</xa>=<xs>'juneau.xsd'</xs><xt>/&gt;</xt>
<xt>&lt;import</xt> <xa>namespace</xa>=<xs>'http://www.apache.org/person/'</xs> <xa>schemaLocation</xa>=<xs>'per.xsd'</xs><xt>/&gt;</xt>
<xt>&lt;import</xt> <xa>namespace</xa>=<xs>'http://www.apache.org/address/'</xs> <xa>schemaLocation</xa>=<xs>'addr.xsd'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'street'</xs> <xa>_type</xa>=<xs>'juneau:java.lang.String'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'city'</xs> <xa>_type</xa>=<xs>'juneau:java.lang.String'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'state'</xs> <xa>_type</xa>=<xs>'juneau:java.lang.String'</xs><xt>/&gt;</xt>
<xt>&lt;element</xt> <xa>name</xa>=<xs>'zip'</xs> <xa>_type</xa>=<xs>'juneau:int'</xs><xt>/&gt;</xt>
<xt>&lt;/schema&gt;</xt>
</p>
<p>
For convenience, the {@link org.apache.juneau.xmlschema.XmlSchemaSerializer
#getValidator(SerializerSession,Object)} method is provided to create a
{@link javax.xml.validation.Validator} using the input from the serialize method.
</p>
</div><!-- END: 2.22.8 - juneau-marshall.XmlDetails.XmlSchema -->
</div><!-- END: 2.22 - juneau-marshall.XmlDetails -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.HtmlDetails' id='juneau-marshall.HtmlDetails'>2.23 - HTML Details</a></h3>
<div class='topic'><!-- START: 2.23 - juneau-marshall.HtmlDetails -->
<p>
Juneau supports converting arbitrary POJOs to and from HTML.
Built on top of the existing XML parser, it also uses a STaX parser and creates POJOs directly without intermediate DOM objects.
</p>
<p>
The primary use case for HTML serialization is rendering POJOs in easy-to-read format in REST interfaces.
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.HtmlDetails.Methodology' id='juneau-marshall.HtmlDetails.Methodology'>2.23.1 - HTML Methodology</a></h4>
<div class='topic'><!-- START: 2.23.1 - juneau-marshall.HtmlDetails.Methodology -->
<p>
The following examples show how different data types are represented in HTML.
They mirror how the data structures are represented in JSON.
</p>
<h5 class='topic'>Simple types</h5>
<p>
The representation for simple types mirror those produced by the XML serializer.
Tags are added to help differentiate data types when they cannot be inferred through reflection.
These tags are ignored by browsers and treated as plain text.
</p>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>HTML</th>
</tr>
<tr>
<td>string</td>
<td class='code'><js>'foo'</js></td>
<td class='code'><xt>&lt;string&gt;</xt>foo<xt>&lt;/string&gt;</xt></td>
</tr>
<tr>
<td>boolean</td>
<td class='code'><jk>true</jk></td>
<td class='code'><xt>&lt;boolean&gt;</xt>true<xt>&lt;/boolean&gt;</xt></td>
</tr>
<tr>
<td>integer</td>
<td class='code'>123</td>
<td class='code'><xt>&lt;number&gt;</xt>123<xt>&lt;/number&gt;</xt></td>
</tr>
<tr>
<td>float</td>
<td class='code'>1.23</td>
<td class='code'><xt>&lt;number&gt;</xt>1.23<xt>&lt;/number&gt;</xt></td>
</tr>
<tr>
<td>null</td>
<td class='code'><jk>null</jk></td>
<td class='code'><xt>&lt;null/&gt;</xt></td>
</tr>
</table>
<h5 class='topic'>Maps</h5>
<p>
Maps and beans are represented as tables.
</p>
<p>
The <xa>_type</xa> attribute is added to differentiate between objects (maps/beans) and arrays
(arrays/collections).
</p>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>HTML</th>
</tr>
<tr>
<td class='code'>
Map&lt;String,String&gt;
</td>
<td class='code'>
{
k1: <js>'v1'</js>
k2: <jk>null</jk>
}
</td>
<td class='code'><xt>
&lt;table <xa>_type</xa>=<xs>'object'</xs>&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k1</xv>&lt;/td&gt;
&lt;td&gt;<xv>v1</xv>&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k2</xv>&lt;/td&gt;
&lt;td&gt;&lt;null/&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
Map&lt;String,Number&gt;
</td>
<td class='code'>
{
k1: 123,
k2: 1.23,
k3: <jk>null</jk>
}
</td>
<td class='code'><xt>
&lt;table <xa>_type</xa>=<xs>'object'</xs>&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k1</xv>&lt;/td&gt;
&lt;td&gt;<xv>123</xv>&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k2</xv>&lt;/td&gt;
&lt;td&gt;<xv>1.23</xv>&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k3</xv>&lt;/td&gt;
&lt;td&gt;&lt;null/&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
Map&lt;String,Object&gt;
</td>
<td class='code'>
{
k1: <js>'v1'</js>
k2: 123,
k3: 1.23,
k4: <jk>true</jk>,
k5: <jk>null</jk>
}
</td>
<td class='code'><xt>
&lt;table <xa>_type</xa>=<xs>'object'</xs>&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k1</xv>&lt;/td&gt;
&lt;td&gt;<xv>v1</xv>&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k2</xv>&lt;/td&gt;
&lt;td&gt;&lt;number&gt;<xv>123</xv>&lt;/number&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k3</xv>&lt;/td&gt;
&lt;td&gt;&lt;number&gt;<xv>1.23</xv>&lt;/number&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k4</xv>&lt;/td&gt;
&lt;td&gt;&lt;boolean&gt;<xv>true</xv>&lt;/boolean&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k5</xv>&lt;/td&gt;
&lt;td&gt;&lt;null/&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
</xt></td>
</tr>
</table>
<h5 class='topic'>Arrays</h5>
<p>
Collections and arrays are represented as ordered lists.
</p>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>HTML</th>
</tr>
<tr>
<td class='code'>
String[]
</td>
<td class='code'>
[
<js>'foo'</js>
<jk>null</jk>
]
</td>
<td class='code'><xt>
&lt;ul&gt;
&lt;li&gt;<xv>foo</xv>&lt;/li&gt;
&lt;li&gt;&lt;null/&gt;&lt;/li&gt;
&lt;/ul&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
Number[]
</td>
<td class='code'>
[
123,
1.23,
<jk>null</jk>
]
</td>
<td class='code'><xt>
&lt;ul&gt;
&lt;li&gt;<xv>123</xv>&lt;/li&gt;
&lt;li&gt;<xv>1.23</xv>&lt;/li&gt;
&lt;li&gt;&lt;null/&gt;&lt;/li&gt;
&lt;/ul&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
Object[]
</td>
<td class='code'>
[
<js>'foo'</js>,
123,
1.23,
<jk>true</jk>,
<jk>null</jk>
]
</td>
<td class='code'><xt>
&lt;ul&gt;
&lt;li&gt;<xv>foo</xv>&lt;/li&gt;
&lt;li&gt;&lt;number&gt;<xv>123</xv>&lt;/number&gt;&lt;/li&gt;
&lt;li&gt;&lt;number&gt;<xv>1.23</xv>&lt;/number&gt;&lt;/li&gt;
&lt;li&gt;&lt;boolean&gt;<xv>true</xv>&lt;/boolean&gt;&lt;/li&gt;
&lt;li&gt;&lt;null/&gt;&lt;/li&gt;
&lt;/ul&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
String[][]
</td>
<td class='code'>
[
[<js>'foo'</js>, <jk>null</jk>],
<jk>null</jk>,
]
</td>
<td class='code'><xt>
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;<xv>foo</xv>&lt;/li&gt;
&lt;li&gt;&lt;null/&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;null/&gt;&lt;/li&gt;
&lt;/ul&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<jk>int</jk>[]
</td>
<td class='code'>
[
123
]
</td>
<td class='code'><xt>
&lt;ul&gt;
&lt;li&gt;<xv>123</xv>&lt;/li&gt;
&lt;/ul&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
<jk>boolean</jk>[]
</td>
<td class='code'>
[
<jk>true</jk>
]
</td>
<td class='code'><xt>
&lt;ul&gt;
&lt;li&gt;<xv>true</xv>&lt;/li&gt;
&lt;/ul&gt;
</xt></td>
</tr>
</table>
<h5 class='topic'>Collections</h5>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>HTML</th>
</tr>
<tr>
<td class='code'>
List&lt;String&gt;
</td>
<td class='code'>
[
<js>'foo'</js>
<jk>null</jk>
]
</td>
<td class='code'><xt>
&lt;ul&gt;
&lt;li&gt;<xv>foo</xv>&lt;/li&gt;
&lt;li&gt;&lt;null/&gt;&lt;/li&gt;
&lt;/ul&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
List&lt;Number&gt;
</td>
<td class='code'>
[
123,
1.23,
<jk>null</jk>
]
</td>
<td class='code'><xt>
&lt;ul&gt;
&lt;li&gt;<xv>123</xv>&lt;/li&gt;
&lt;li&gt;<xv>1.23</xv>&lt;/li&gt;
&lt;li&gt;&lt;null/&gt;&lt;/li&gt;
&lt;/ul&gt;
</xt></td>
</tr>
<tr>
<td class='code'>
List&lt;Object&gt;
</td>
<td class='code'>
[
<js>'foo'</js>,
123,
1.23,
<jk>true</jk>,
<jk>null</jk>
]
</td>
<td class='code'><xt>
&lt;ul&gt;
&lt;li&gt;<xv>foo</xv>&lt;/li&gt;
&lt;li&gt;&lt;number&gt;<xv>123</xv>&lt;/number&gt;&lt;/li&gt;
&lt;li&gt;&lt;number&gt;<xv>1.23</xv>&lt;/number&gt;&lt;/li&gt;
&lt;li&gt;&lt;boolean&gt;<xv>true</xv>&lt;/boolean&gt;&lt;/li&gt;
&lt;li&gt;&lt;null/&gt;&lt;/li&gt;
&lt;/ul&gt;
</xt></td>
</tr>
</table>
<h5 class='topic'>Beans</h5>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>HTML</th>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<jk>public</jk> String a;
<jk>public</jk> <jk>int</jk> b;
<jk>public</jk> Object c; <jc>// String value</jc>
<jk>public</jk> Object d; <jc>// Integer value</jc>
<jk>public</jk> MyBean2 e;
<jk>public</jk> String[] f;
<jk>public</jk> <jk>int</jk>[] g;
}
<jk>class</jk> MyBean2 {
String h;
}
</td>
<td class='code'>
{
<jok>a</jok>: <jov>'foo'</jov>,
<jok>b</jok>: <jov>123</jov>,
<jok>c</jok>: <jov>'bar'</jov>,
<jok>d</jok>: <jov>456</jov>,
<jok>e</jok>: {
<jok>h</jok>: <jov>'baz'</jov>
}
<jok>f</jok>: [<jov>'qux'</jov>]
<jok>g</jok>: [<jov>789</jov>]
}
</td>
<td class='code'><xt>
&lt;table <xa>_type</xa>=<xs>'object'</xs>&gt;
&lt;tr&gt;
&lt;td&gt;<xv>a</xv>&lt;/td&gt;
&lt;td&gt;<xv>foo</xv>&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>b</xv>&lt;/td&gt;
&lt;td&gt;<xv>123</xv>&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>c</xv>&lt;/td&gt;
&lt;td&gt;<xv>bar</xv>&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>d</xv>&lt;/td&gt;
&lt;td&gt;&lt;number&gt;<xv>456</xv>&lt;/number&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>e</xv>&lt;/td&gt;
&lt;td&gt;
&lt;table <xa>_type</xa>=<xs>'object'</xs>&gt;
&lt;tr&gt;
&lt;td&gt;<xv>h</xv>&lt;/td&gt;
&lt;td&gt;<xv>qux</xv>&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>f</xv>&lt;/td&gt;
&lt;td&gt;
&lt;ul&gt;
&lt;li&gt;<xv>baz</xv>&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>g</xv>&lt;/td&gt;
&lt;td&gt;
&lt;ul&gt;
&lt;li&gt;<xv>789</xv>&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
</xt></td>
</tr>
</table>
<h5 class='topic'>Beans with Map properties</h5>
<table class='styled w800'>
<tr>
<th>Data type</th>
<th>JSON example</th>
<th>HTML</th>
</tr>
<tr>
<td class='code'>
<jk>class</jk> MyBean {
<jk>public</jk> Map&lt;String,String&gt; a;
<jk>public</jk> Map&lt;String,Number&gt; b;
<jk>public</jk> Map&lt;String,Object&gt; c;
}
</td>
<td class='code'>
{
<jok>a</jok>: {
<jok>k1</jok>: <jov>'foo'</jov>
},
<jok>b</jok>: {
<jok>k2</jok>: <jov>123</jov>
},
<jok>c</jok>: {
<jok>k3</jok>: <jov>'bar'</jov>,
<jok>k4</jok>: <jov>456</jov>,
<jok>k5</jok>: <jov>true</jov>,
<jok>k6</jok>: <jov>null</jov>
}
}
</td>
<td class='code'><xt>
&lt;table <xa>_type</xa>=<xs>'object'</xs>&gt;
&lt;tr&gt;
&lt;td&gt;<xv>a</xv>&lt;/td&gt;
&lt;td&gt;
&lt;table _type='object'&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k1</xv>&lt;/td&gt;
&lt;td&gt;<xv>foo</xv>&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>b</xv>&lt;/td&gt;
&lt;td&gt;
&lt;table _type='object'&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k2</xv>&lt;/td&gt;
&lt;td&gt;<xv>123</xv>&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>c</xv>&lt;/td&gt;
&lt;td&gt;
&lt;table <xa>_type</xa>=<xs>'object'</xs>&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k3</xv>&lt;/td&gt;
&lt;td&gt;<xv>bar</xv>&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k4</xv>&lt;/td&gt;
&lt;td&gt;&lt;number&gt;<xv>456</xv>&lt;/number&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k5</xv>&lt;/td&gt;
&lt;td&gt;&lt;boolean&gt;<xv>true</xv>&lt;/boolean&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;<xv>k6</xv>&lt;/td&gt;
&lt;td&gt;&lt;null/&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
</xt></td>
</tr>
</table>
</div><!-- END: 2.23.1 - juneau-marshall.HtmlDetails.Methodology -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.HtmlDetails.Serializers' id='juneau-marshall.HtmlDetails.Serializers'>2.23.2 - HTML Serializers</a></h4>
<div class='topic'><!-- START: 2.23.2 - juneau-marshall.HtmlDetails.Serializers -->
<p>
The {@link org.apache.juneau.html.HtmlSerializer} class is used to serialize POJOs into HTML.
</p>
<p>
The {@link org.apache.juneau.html.HtmlDocSerializer} class is the same, but wraps the serialized POJO
inside a document template consisting of header, nav, aside, and footer sections.
</p>
<p>
The HTML serializers provides the following settings:
</p>
<ul class='javatree'>
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.Common Common Properties}
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.CommonSerializer Common Serializer Properties}
<li class='jc'>{@link org.apache.juneau.html.HtmlSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.html.HtmlSerializer#HTML_addBeanTypes HTML_addBeanTypes}
<li class='jf'>{@link org.apache.juneau.html.HtmlSerializer#HTML_addKeyValueTableHeaders HTML_addKeyValueTableHeaders}
<li class='jf'>{@link org.apache.juneau.html.HtmlSerializer#HTML_detectLabelParameters HTML_detectLabelParameters}
<li class='jf'>{@link org.apache.juneau.html.HtmlSerializer#HTML_detectLinksInStrings HTML_detectLinksInStrings}
<li class='jf'>{@link org.apache.juneau.html.HtmlSerializer#HTML_labelParameter HTML_labelParameter}
<li class='jf'>{@link org.apache.juneau.html.HtmlSerializer#HTML_uriAnchorText HTML_uriAnchorText}
</ul>
<li class='jc'>{@link org.apache.juneau.html.HtmlDocSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_aside HTMLDOC_aside}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_footer HTMLDOC_footer}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_head HTMLDOC_head}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_header HTMLDOC_header}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_nav HTMLDOC_nav}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_navlinks HTMLDOC_navlinks}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_noResultsMessage HTMLDOC_noResultsMessage}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_nowrap HTMLDOC_nowrap}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_script HTMLDOC_script}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_style HTMLDOC_style}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_stylesheet HTMLDOC_stylesheet}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_template HTMLDOC_template}
</ul>
</ul>
<p>
The following pre-configured serializers are provided for convenience:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.html.HtmlSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.html.HtmlSerializer#DEFAULT }
<li class='jf'>{@link org.apache.juneau.html.HtmlSerializer#DEFAULT_SQ }
<li class='jf'>{@link org.apache.juneau.html.HtmlSerializer#DEFAULT_SQ_READABLE }
</ul>
<li class='jc'>{@link org.apache.juneau.html.HtmlDocSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#DEFAULT }
</ul>
</ul>
</div><!-- END: 2.23.2 - juneau-marshall.HtmlDetails.Serializers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.HtmlDetails.Parsers' id='juneau-marshall.HtmlDetails.Parsers'>2.23.3 - HTML Parsers</a></h4>
<div class='topic'><!-- START: 2.23.3 - juneau-marshall.HtmlDetails.Parsers -->
<p>
The {@link org.apache.juneau.html.HtmlParser} class is used to parse HTML into POJOs.
They can also parse the contents produced by {@link org.apache.juneau.html.HtmlDocSerializer}.
</p>
<p>
The HTML parser provides the following settings:
</p>
<ul class='javatree'>
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.Common Common Properties}
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.CommonParser Common Parser}
</ul>
<p>
The following pre-configured parsers are provided for convenience:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.html.HtmlParser}
<ul>
<li class='jf'>{@link org.apache.juneau.html.HtmlParser#DEFAULT DEFAULT}
</ul>
</ul>
</div><!-- END: 2.23.3 - juneau-marshall.HtmlDetails.Parsers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.HtmlDetails.HtmlAnnotation' id='juneau-marshall.HtmlDetails.HtmlAnnotation'>2.23.4 - @Html Annotation</a></h4>
<div class='topic'><!-- START: 2.23.4 - juneau-marshall.HtmlDetails.HtmlAnnotation -->
<p>
The {@link org.apache.juneau.html.annotation.Html @Html} annotation can be used to customize how POJOs are serialized to HTML on a per-class/field/method basis.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.html.annotation.Html}
<ul>
<li class='jf'>{@link org.apache.juneau.html.annotation.Html#anchorText() anchorText}
<li class='jf'>{@link org.apache.juneau.html.annotation.Html#format() format}
<li class='jf'>{@link org.apache.juneau.html.annotation.Html#link() link}
<li class='jf'>{@link org.apache.juneau.html.annotation.Html#noTableHeaders() noTableHeaders}
<li class='jf'>{@link org.apache.juneau.html.annotation.Html#noTables() noTables}
<li class='jf'>{@link org.apache.juneau.html.annotation.Html#render() render}
</ul>
</ul>
<p>
The {@link org.apache.juneau.html.annotation.Html#link @Html(link)} annotation adds a hyperlink to a bean property when rendered as HTML.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jk>public class</jk> FileSpace {
<jc>// Add a hyperlink to this bean property.</jc>
<ja>@Html</ja>(link&#61;<js>"servlet:/drive/{drive}"</js>)
public String getDrive() {...}
}
</p>
<p>
The {@link org.apache.juneau.html.annotation.Html#anchorText @Html(anchorText)} annotation is used to specify the anchor text of a hyperlink.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Produces &lt;a href&#61;'...'&gt;CLICK ME!&lt;/a&gt; when serialized to HTML.</jc>
<jk>public class</jk> FileSpace {
<jc>// Add a hyperlink to this bean property.</jc>
<ja>@Html</ja>(link=<js>"servlet:/drive/{drive}"</js>, anchorText=<js>"CLICK ME!"</js>)
public String getDrive() {...}
}
</p>
<p>
The {@link org.apache.juneau.html.annotation.Html#format @Html(format)} annotation is used to specify what format to use for HTML elements.
For example, the HTML beans defined in the {@link org.apache.juneau.dto.html5} package use <c>format=<jsf>XML</jsf></c> so that
the beans get serialized as standard XML:
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Parent class of all HTML DTO beans.</jc>
<ja>@Html</ja>(format=<jsf>XML</jsf>)
<jk>public abstract class</jk> HtmlElement {...}
</p>
<p>
The {@link org.apache.juneau.html.annotation.Html#noTableHeaders @Html(noTableHeaders)} annotation is used to prevent beans from being serialized with table headers.
</p>
<p>
The {@link org.apache.juneau.html.annotation.Html#noTables @Html(noTables)} annotation is used to force beans to be serialized as trees instead of tables
</p>
</div><!-- END: 2.23.4 - juneau-marshall.HtmlDetails.HtmlAnnotation -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.HtmlDetails.HtmlRenderAnnotation' id='juneau-marshall.HtmlDetails.HtmlRenderAnnotation'>2.23.5 - @Html(render) Annotation</a></h4>
<div class='topic'><!-- START: 2.23.5 - juneau-marshall.HtmlDetails.HtmlRenderAnnotation -->
<p>
The {@link org.apache.juneau.html.annotation.Html#render @Html(render)} annotation allows for custom rendering of bean property values when serialized as HTML.
Using this class, you can alter the CSS style and HTML content of the bean property.
</p>
<p>
The following example shows two render classes that customize the appearance of the <c>pctFull</c> and
<c>status</c> columns in the code below:
</p>
<p class='bpcode w800'>
<jk>import static</jk> org.apache.juneau.dto.html5.HtmlBuilder.*;
<jc>// Our bean class</jc>
<jk>public class</jk> FileSpace {
<jk>private final</jk> String <jf>drive</jf>;
<jk>private final long</jk> <jf>total</jf>, <jf>available</jf>;
<jk>public</jk> FileSpace(String drive, <jk>long</jk> total, <jk>long</jk> available) {
<jk>this</jk>.<jf>drive</jf> = drive;
<jk>this</jk>.<jf>total</jf> = total;
<jk>this</jk>.<jf>available</jf> = available;
}
<ja>@Html</ja>(link=<js>"drive/{drive}"</js>)
<jk>public</jk> String getDrive() {
<jk>return</jk> <jf>drive</jf>;
}
<jk>public long</jk> getTotal() {
<jk>return</jk> <jf>total</jf>;
}
<jk>public long</jk> getAvailable() {
<jk>return</jk> <jf>available</jf>;
}
<ja>@Html</ja>(render=FileSpacePctRender.<jk>class</jk>)
<jk>public float</jk> getPctFull() {
<jk>return</jk> ((100 * <jf>available</jf>) / <jf>total</jf>);
}
<ja>@Html</ja>(render=FileSpaceStatusRender.<jk>class</jk>)
<jk>public</jk> FileSpaceStatus getStatus() {
<jk>float</jk> pf = getPctFull();
<jk>if</jk> (pf &lt; 80)
<jk>return</jk> FileSpaceStatus.<jsf>OK</jsf>;
<jk>if</jk> (pf &lt; 90)
<jk>return</jk> FileSpaceStatus.<jsf>WARNING</jsf>;
<jk>return</jk> FileSpaceStatus.<jsf>SEVERE</jsf>;
}
}
</p>
<p class='bpcode w800'>
<jc>// Possible values for the getStatus() method</jc>
<jk>public enum</jk> FileSpaceStatus {
<jsf>OK</jsf>, <jsf>WARNING</jsf>, <jsf>SEVERE</jsf>;
}
</p>
<p class='bpcode w800'>
<jc>// Custom render for getPctFull() method</jc>
<jk>public class</jk> FileSpacePctRender <jk>extends</jk> HtmlRender&lt;Float&gt; {
<ja>@Override</ja>
<jk>public</jk> String getStyle(SerializerSession session, Float value) {
<jk>if</jk> (value &lt; 80)
<jk>return</jk> <js>"background-color:lightgreen;text-align:center"</js>;
<jk>if</jk> (value &lt; 90)
<jk>return</jk> <js>"background-color:yellow;text-align:center"</js>;
<jk>return</jk> <js>"background-color:red;text-align:center;border:;animation:color_change 0.5s infinite alternate"</js>;
}
<ja>@Override</ja>
<jk>public</jk> Object getContent(SerializerSession session, Float value) {
<jk>if</jk> (value >= 90)
<jk>return</jk> <jsm>div</jsm>(
String.<jsm>format</jsm>(<js>"%.0f%%"</js>, value),
<jsm>style</jsm>(<js>"@keyframes color_change { from { background-color: red; } to { background-color: yellow; }"</js>)
);
<jk>return</jk> String.<jsm>format</jsm>(<js>"%.0f%%"</js>, value);
}
}
</p>
<p class='bpcode w800'>
<jc>// Custom render for getStatus() method</jc>
<jk>public class</jk> FileSpaceStatusRender <jk>extends</jk> HtmlRender&lt;FileSpaceStatus&gt; {
<ja>@Override</ja>
<jk>public</jk> String getStyle(SerializerSession session, FileSpaceStatus value) {
<jk>return</jk> <js>"text-align:center"</js>;
}
<ja>@Override</ja>
<jk>public</jk> Object getContent(SerializerSession session, FileSpaceStatus value) {
<jk>switch</jk> (value) {
<jk>case</jk> <jsf>OK</jsf>: <jk>return</jk> <jsm>img</jsm>().src(URI.<jsm>create</jsm>(<js>"servlet:/htdocs/ok.png"</js>));
<jk>case</jk> <jsf>WARNING</jsf>: <jk>return</jk> <jsm>img</jsm>().src(URI.<jsm>create</jsm>(<js>"servlet:/htdocs/warning.png"</js>));
<jk>default</jk>: <jk>return</jk> <jsm>img</jsm>().src(URI.<jsm>create</jsm>(<js>"servlet:/htdocs/severe.png"</js>));
}
}
}
</p>
</div><!-- END: 2.23.5 - juneau-marshall.HtmlDetails.HtmlRenderAnnotation -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.HtmlDetails.HtmlDocSerializer' id='juneau-marshall.HtmlDetails.HtmlDocSerializer'>2.23.6 - HtmlDocSerializer</a></h4>
<div class='topic'><!-- START: 2.23.6 - juneau-marshall.HtmlDetails.HtmlDocSerializer -->
<p>
{@link org.apache.juneau.html.HtmlDocSerializer} is an extension of {@link org.apache.juneau.html.HtmlSerializer}
that wraps serialized POJOs in a complete HTML document.
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.html.HtmlDocSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_aside HTMLDOC_aside}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_footer HTMLDOC_footer}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_head HTMLDOC_head}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_header HTMLDOC_header}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_nav HTMLDOC_nav}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_navlinks HTMLDOC_navlinks}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_noResultsMessage HTMLDOC_noResultsMessage}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_nowrap HTMLDOC_nowrap}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_script HTMLDOC_script}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_style HTMLDOC_style}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_stylesheet HTMLDOC_stylesheet}
<li class='jf'>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_template HTMLDOC_template}
</ul>
</ul>
<p>
This class is used extensively in the creation of POJO-based user interfaces in the REST API.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jd>/**
* Sample REST resource that prints out a simple "Hello world!" message.
*/</jd>
<ja>@Rest</ja>(
path=<js>"/helloWorld"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
navlinks={
<js>"up: request:/.."</js>,
<js>"options: servlet:/?method=OPTIONS"</js>
},
aside={
<js>"&lt;div style='max-width:400px' class='text'&gt;"</js>,
<js>" &lt;p&gt;This page shows a resource that simply response with a 'Hello world!' message&lt;/p&gt;"</js>,
<js>" &lt;p&gt;The POJO serialized is a simple String.&lt;/p&gt;"</js>,
<js>"&lt;/div&gt;"</js>
}
)
)
<jk>public class</jk> HelloWorldResource <jk>extends</jk> BasicRestServlet {...}
</p>
<p>
The {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_template HTMLDOC_template} setting defines
a template for the HTML page being generated.
The default template is described next.
</p>
</div><!-- END: 2.23.6 - juneau-marshall.HtmlDetails.HtmlDocSerializer -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.HtmlDetails.BasicHtmlDocTemplate' id='juneau-marshall.HtmlDetails.BasicHtmlDocTemplate'>2.23.7 - BasicHtmlDocTemplate</a></h4>
<div class='topic'><!-- START: 2.23.7 - juneau-marshall.HtmlDetails.BasicHtmlDocTemplate -->
<p>
The {@link org.apache.juneau.html.BasicHtmlDocTemplate} class defines a default template for HTML documents
created by {@link org.apache.juneau.html.HtmlDocSerializer}.
</p>
<p>
The HTML document created by this template consists of the following structure:
</p>
<p class='bpcode w800'>
<xt>&lt;html&gt;
&lt;head&gt;
&lt;style <xa>type</xa>=<xs>'text/css'</xs>&gt;
<xv>CSS styles and links to stylesheets</xv>
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;header&gt;
<xv>Page header</xv>
&lt;/header&gt;
&lt;nav&gt;
<xv>Navigation links</xv>
&lt;/nav&gt;
&lt;aside&gt;
<xv>Side-bar text</xv>
&lt;/aside&gt;
&lt;article&gt;
<xv>Contents of serialized object</xv>
&lt;/article&gt;
&lt;footer&gt;
<xv>Footer message</xv>
&lt;/footer&gt;
&lt;/body&gt;
&lt;/html&gt;</xt>
</p>
</div><!-- END: 2.23.7 - juneau-marshall.HtmlDetails.BasicHtmlDocTemplate -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.HtmlDetails.CustomTemplates' id='juneau-marshall.HtmlDetails.CustomTemplates'>2.23.8 - Custom Templates</a></h4>
<div class='topic'><!-- START: 2.23.8 - juneau-marshall.HtmlDetails.CustomTemplates -->
<p>
Custom page templates can be created by implementing the {@link org.apache.juneau.html.HtmlDocTemplate}
interface and associating it with your {@link org.apache.juneau.html.HtmlDocSerializer} using the {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_template HTMLDOC_template}
setting.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.html.HtmlDocTemplate}
<ul>
<li class='jm'>{@link org.apache.juneau.html.HtmlDocTemplate#writeTo(HtmlDocSerializerSession,HtmlWriter,Object) writeTo(HtmlDocSerializerSession,HtmlWriter,Object)}
</ul>
</ul>
<p>
The interface implementation is open-ended allowing you to define the contents of the page any way you wish.
</p>
</div><!-- END: 2.23.8 - juneau-marshall.HtmlDetails.CustomTemplates -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.HtmlDetails.HtmlSchema' id='juneau-marshall.HtmlDetails.HtmlSchema'>2.23.9 - HTML-Schema Support</a></h4>
<div class='topic'><!-- START: 2.23.9 - juneau-marshall.HtmlDetails.HtmlSchema -->
<p>
The {@link org.apache.juneau.html.HtmlSchemaSerializer} class is the HTML-equivalent to the
{@link org.apache.juneau.json.JsonSchemaSerializer} class.
It's used to generate HTML versions of JSON-Schema documents that describe the output generated by the
{@link org.apache.juneau.json.JsonSerializer} class.
</p>
<h5 class='figure'>Sample Beans</h5>
<p class='bpcode w800'>
<jk>public class</jk> Person {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>name</jf>;
<jk>public</jk> Calendar <jf>birthDate</jf>;
<jk>public</jk> List&lt;Address&gt; <jf>addresses</jf>;
<jc>// Getters/setters omitted</jc>
}
<jk>public class</jk> Address {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>street</jf>, <jf>city</jf>;
<jk>public</jk> StateEnum <jf>state</jf>;
<jk>public int</jk> <jf>zip</jf>;
<jk>public boolean</jk> <jf>isCurrent</jf>;
<jc>// Getters/setters omitted</jc>
}
</p>
<p>
The code for creating our POJO model and generating HTML-Schema is shown below:
</p>
<p class='bpcode w800'>
<jc>// Get the one of the default schema serializers.</jc>
HtmlSchemaSerializer s = HtmlSchemaSerializer.<jsf>DEFAULT_SIMPLE_READABLE</jsf>;
<jc>// Get the HTML Schema for the POJO.</jc>
String htmlSchema = s.serialize(<jk>new</jk> Person());
<jc>// This also works.</jc>
htmlSchema = s.serialize(Person.<jk>class</jk>);
</p>
<p>
The result is the HTML table shown below:
</p>
<table class='bordered unstyled w800'>
<tr>
<td>type</td>
<td>object</td>
</tr>
<tr>
<td>properties</td>
<td>
<table>
<tr>
<td>name</td>
<td>
<table>
<tr>
<td>type</td>
<td>string</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>birthDate</td>
<td>
<table>
<tr>
<td>type</td>
<td>string</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>addresses</td>
<td>
<table>
<tr>
<td>type</td>
<td>array</td>
</tr>
<tr>
<td>items</td>
<td>
<table>
<tr>
<td>type</td>
<td>object</td>
</tr>
<tr>
<td>properties</td>
<td>
<table>
<tr>
<td>street</td>
<td>
<table>
<tr>
<td>type</td>
<td>string</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>city</td>
<td>
<table>
<tr>
<td>type</td>
<td>string</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>state</td>
<td>
<table>
<tr>
<td>type</td>
<td>string</td>
</tr>
<tr>
<td>enum</td>
<td>
<ul>
<li>AL</li>
<li>PA</li>
<li>NC</li>
</ul>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>zip</td>
<td>
<table>
<tr>
<td>type</td>
<td>integer</td>
</tr>
<tr>
<td>format</td>
<td>int32</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>isCurrent</td>
<td>
<table>
<tr>
<td>type</td>
<td>boolean</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div><!-- END: 2.23.9 - juneau-marshall.HtmlDetails.HtmlSchema -->
</div><!-- END: 2.23 - juneau-marshall.HtmlDetails -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.UonDetails' id='juneau-marshall.UonDetails'>2.24 - UON Details</a></h3>
<div class='topic'><!-- START: 2.24 - juneau-marshall.UonDetails -->
<p>
Juneau supports converting arbitrary POJOs to and from UON strings using ultra-efficient serializers
and parsers.
The serializer converts POJOs directly to UON strings without the need for intermediate DOM objects
using a highly-efficient state machine.
Likewise, the parser creates POJOs directly from UON strings without the need for intermediate DOM
objects.
</p>
<p>
Juneau uses UON (URL-Encoded Object Notation) for representing POJOs.
The UON specification can be found <a href='doc-files/rfc_uon.txt'>here</a>.
</p>
<p>
The following example shows JSON for a typical bean:
</p>
<h5 class='figure'>Sample Beans</h5>
<p class='bpcode w800'>
<jk>public class</jk> Person {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>name</jf>;
<ja>@Swap</ja>(TemporalCalendarSwap.IsoInstant.<jk>class</jk>) <jk>public</jk> Calendar <jf>birthDate</jf>;
<jk>public</jk> List&lt;Address&gt; <jf>addresses</jf>;
<jc>// Getters/setters omitted</jc>
}
<jk>public class</jk> Address {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>street</jf>, <jf>city</jf>;
<jk>public</jk> StateEnum <jf>state</jf>;
<jk>public int</jk> <jf>zip</jf>;
<jk>public boolean</jk> <jf>isCurrent</jf>;
<jc>// Getters/setters omitted</jc>
}
</p>
<h5 class='figure'>Sample Code</h5>
<p class='bpcode w800'>
Person p = <jk>new</jk> Person()
.name(<js>"John Smith"</js>)
.birthDate(<js>"1946-08-12T00:00:00Z"</js>)
.addresses(
<jk>new</jk> Address()
.street(<js>"100 Main Street"</js>)
.city(<js>"Anywhereville"</js>)
.state(<jsf>NY</jsf>)
.zip(12345)
.isCurrent(<jk>true</jk>);
);
</p>
<h5 class='figure'>UON</h5>
<p class='bpcode w800'>
(
<ua>name</ua>=<us>'John+Smith'</us>,
<ua>birthDate</ua>=<us>'1946-08-12T00:00:00Z'</us>,
<ua>addresses</ua>=@(
(
<ua>street</ua>=<us>'100 Main Street'</us>,
<ua>city</ua>=<us>Anywhereville</us>,
<ua>state</ua>=<us>NY</us>,
<ua>zip</ua>=<un>12345</un>,
<ua>isCurrent</ua>=<uk>true</uk>
)
)
)
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.UonDetails.Methodology' id='juneau-marshall.UonDetails.Methodology'>2.24.1 - UON Methodology</a></h4>
<div class='topic'><!-- START: 2.24.1 - juneau-marshall.UonDetails.Methodology -->
<h5 class='figure'>General methodology:</h5>
<table class='styled w800' style='border-collapse:collapse'>
<tr><th>Java type</th><th>JSON equivalent</th><th>UON</th></tr>
<tr>
<td>Maps/beans</td>
<td>OBJECT</td>
<td class='code'>
<ua>a1</ua>=(<ua>b1</ua>=<us>x1</us>,<ua>b2</ua>=<us>x2</us>)
<ua>a1</ua>=(<ua>b1</ua>=(<ua>c1</ua>=<us>x1</us>,<ua>c2</ua>=<us>x2</us>))
</td>
</tr>
<tr>
<td>Collections/arrays</td>
<td>ARRAY</td>
<td class='code'>
<ua>a1</ua>=@(<us>x1</us>,<us>x2</us>)
<ua>a1</ua>=@(@(<us>x1</us>,<us>x2</us>),@(<us>x3</us>,<us>x4</us>))
<ua>a1</ua>=@((<ua>b1</ua>=<us>x1</us>,<ua>b2</ua>=<us>x2</us>),(<ua>c1</ua>=<us>x1</us>,<ua>c2</ua>=<us>x2</us>))
</td>
</tr>
<tr>
<td>Booleans</td>
<td>BOOLEAN</td>
<td class='code'>
<ua>a1</ua>=<uk>true</uk>&amp;<ua>a2</ua>=<uk>false</uk>
</td>
</tr>
<tr>
<td>int/float/double/...</td>
<td>NUMBER</td>
<td class='code'>
<ua>a1</ua>=<un>123</un>&amp;<ua>a2</ua>=<un>1.23e1</un>
</td>
</tr>
<tr>
<td>null</td>
<td>NULL</td>
<td class='code'>
<ua>a1</ua>=<uk>null</uk>
</td>
</tr>
<tr>
<td>String</td>
<td>STRING</td>
<td class='code'>
<ua>a1</ua>=<us>foobar</us>
<ua>a1</ua>=<us>'true'</us>
<ua>a1</ua>=<us>'null'</us>
<ua>a1</ua>=<us>'123'</us>
<ua>a1</ua>=<us>' string with whitespace '</us>
<ua>a1</ua>=<us>'string with ~'escaped~' quotes'</us>
</td>
</tr>
</table>
<p>
Refer to the <a href='doc-files/rfc_uon.txt'>UON specification</a> for a complete set of syntax rules.
</p>
</div><!-- END: 2.24.1 - juneau-marshall.UonDetails.Methodology -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.UonDetails.Serializers' id='juneau-marshall.UonDetails.Serializers'>2.24.2 - UON Serializers</a></h4>
<div class='topic'><!-- START: 2.24.2 - juneau-marshall.UonDetails.Serializers -->
<p>
The {@link org.apache.juneau.uon.UonSerializer} class is used to serialize POJOs into UON.
</p>
<p>
The UON serializers provides the following settings:
</p>
<ul class='javatree'>
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.Common Common Properties}
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.CommonSerializer Common Serializer Properties}
<li class='jc'>{@link org.apache.juneau.uon.UonSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.uon.UonSerializer#UON_addBeanTypes UON_addBeanTypes}
<li class='jf'>{@link org.apache.juneau.uon.UonSerializer#UON_encoding UON_encoding}
<li class='jf'>{@link org.apache.juneau.uon.UonSerializer#UON_paramFormat UON_paramFormat}
</ul>
</ul>
<p>
The following pre-configured serializers are provided for convenience:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.uon.UonSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.uon.UonSerializer#DEFAULT DEFAULT}
<li class='jf'>{@link org.apache.juneau.uon.UonSerializer#DEFAULT_ENCODING DEFAULT_ENCODING}
<li class='jf'>{@link org.apache.juneau.uon.UonSerializer#DEFAULT_READABLE DEFAULT_READABLE}
</ul>
</ul>
</div><!-- END: 2.24.2 - juneau-marshall.UonDetails.Serializers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.UonDetails.Parsers' id='juneau-marshall.UonDetails.Parsers'>2.24.3 - UON Parsers</a></h4>
<div class='topic'><!-- START: 2.24.3 - juneau-marshall.UonDetails.Parsers -->
<p>
The {@link org.apache.juneau.uon.UonParser} class is used to parse UON into POJOs.
</p>
<p>
The UON parser provides the following settings:
</p>
<ul class='javatree'>
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.Common Common Properties}
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.CommonParser Common Parser Properties}
<li class='jc'>{@link org.apache.juneau.uon.UonParser}
<ul>
<li class='jf'>{@link org.apache.juneau.uon.UonParser#UON_decoding UON_decoding}
<li class='jf'>{@link org.apache.juneau.uon.UonParser#UON_validateEnd UON_validateEnd}
</ul>
</ul>
<p>
The following pre-configured parsers are provided for convenience:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.uon.UonParser}
<ul>
<li class='jf'>{@link org.apache.juneau.uon.UonParser#DEFAULT DEFAULT}
<li class='jf'>{@link org.apache.juneau.uon.UonParser#DEFAULT_DECODING DEFAULT_DECODING}
</ul>
</ul>
</div><!-- END: 2.24.3 - juneau-marshall.UonDetails.Parsers -->
</div><!-- END: 2.24 - juneau-marshall.UonDetails -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.UrlEncodingDetails' id='juneau-marshall.UrlEncodingDetails'>2.25 - URL-Encoding Details</a></h3>
<div class='topic'><!-- START: 2.25 - juneau-marshall.UrlEncodingDetails -->
<p>
Juneau supports converting arbitrary POJOs to and from URL-encoded strings using ultra-efficient serializers
and parsers.
The serializer converts POJOs directly to URL-encoded strings without the need for intermediate DOM objects
using a highly-efficient state machine.
Likewise, the parser creates POJOs directly from URL-encoded strings without the need for intermediate DOM
objects.
</p>
<p>
Juneau uses UON (URL-Encoded Object Notation) for representing POJOs as URL-Encoded values in key-value pairs.
The UON specification can be found <a href='doc-files/rfc_uon.txt'>here</a>.
</p>
<p>
The following example shows JSON for a typical bean:
</p>
<h5 class='figure'>Sample Beans</h5>
<p class='bpcode w800'>
<jk>public class</jk> Person {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>name</jf>;
<ja>@Swap</ja>(TemporalCalendarSwap.IsoInstant.<jk>class</jk>) <jk>public</jk> Calendar <jf>birthDate</jf>;
<jk>public</jk> List&lt;Address&gt; <jf>addresses</jf>;
<jc>// Getters/setters omitted</jc>
}
<jk>public class</jk> Address {
<jc>// Bean properties</jc>
<jk>public</jk> String <jf>street</jf>, <jf>city</jf>;
<jk>public</jk> StateEnum <jf>state</jf>;
<jk>public int</jk> <jf>zip</jf>;
<jk>public boolean</jk> <jf>isCurrent</jf>;
<jc>// Getters/setters omitted</jc>
}
</p>
<h5 class='figure'>Sample Code</h5>
<p class='bpcode w800'>
Person p = <jk>new</jk> Person()
.name(<js>"John Smith"</js>)
.birthDate(<js>"1946-08-12T00:00:00Z"</js>)
.addresses(
<jk>new</jk> Address()
.street(<js>"100 Main Street"</js>)
.city(<js>"Anywhereville"</js>)
.state(<jsf>NY</jsf>)
.zip(12345)
.isCurrent(<jk>true</jk>);
);
</p>
<h5 class='figure'>URL-Encoding</h5>
<p class='bpcode w800'>
<ua>name</ua>=<us>'John+Smith'</us>
&amp;<ua>birthDate</ua>=<us>'1946-08-12T00:00:00Z'</us>
&amp;<ua>addresses</ua>=@(
(
<ua>street</ua>=<us>'100 Main Street'</us>,
<ua>city</ua>=<us>Anywhereville</us>,
<ua>state</ua>=<us>NY</us>,
<ua>zip</ua>=<un>12345</un>,
<ua>isCurrent</ua>=<uk>true</uk>
)
)
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.UrlEncodingDetails.Methodology' id='juneau-marshall.UrlEncodingDetails.Methodology'>2.25.1 - URL-Encoding Methodology</a></h4>
<div class='topic'><!-- START: 2.25.1 - juneau-marshall.UrlEncodingDetails.Methodology -->
<h5 class='figure'>General methodology:</h5>
<table class='styled w800' style='border-collapse:collapse'>
<tr><th>Java type</th><th>JSON equivalent</th><th>UON</th></tr>
<tr>
<td>Maps/beans</td>
<td>OBJECT</td>
<td class='code'>
<ua>a1</ua>=(<ua>b1</ua>=<us>x1</us>,<ua>b2</ua>=<us>x2</us>)
<ua>a1</ua>=(<ua>b1</ua>=(<ua>c1</ua>=<us>x1</us>,<ua>c2</ua>=<us>x2</us>))
</td>
</tr>
<tr>
<td>Collections/arrays</td>
<td>ARRAY</td>
<td class='code'>
<ua>a1</ua>=@(<us>x1</us>,<us>x2</us>)
<ua>a1</ua>=@(@(<us>x1</us>,<us>x2</us>),@(<us>x3</us>,<us>x4</us>))
<ua>a1</ua>=@((<ua>b1</ua>=<us>x1</us>,<ua>b2</ua>=<us>x2</us>),(<ua>c1</ua>=<us>x1</us>,<ua>c2</ua>=<us>x2</us>))
</td>
</tr>
<tr>
<td>Booleans</td>
<td>BOOLEAN</td>
<td class='code'>
<ua>a1</ua>=<uk>true</uk>&amp;<ua>a2</ua>=<uk>false</uk>
</td>
</tr>
<tr>
<td>int/float/double/...</td>
<td>NUMBER</td>
<td class='code'>
<ua>a1</ua>=<un>123</un>&amp;<ua>a2</ua>=<un>1.23e1</un>
</td>
</tr>
<tr>
<td>null</td>
<td>NULL</td>
<td class='code'>
<ua>a1</ua>=<uk>null</uk>
</td>
</tr>
<tr>
<td>String</td>
<td>STRING</td>
<td class='code'>
<ua>a1</ua>=<us>foobar</us>
<ua>a1</ua>=<us>'true'</us>
<ua>a1</ua>=<us>'null'</us>
<ua>a1</ua>=<us>'123'</us>
<ua>a1</ua>=<us>' string with whitespace '</us>
<ua>a1</ua>=<us>'string with ~'escaped~' quotes'</us>
</td>
</tr>
</table>
<p>
Refer to the <a href='doc-files/rfc_uon.txt'>UON specification</a> for a complete set of syntax rules.
</p>
</div><!-- END: 2.25.1 - juneau-marshall.UrlEncodingDetails.Methodology -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.UrlEncodingDetails.Serializers' id='juneau-marshall.UrlEncodingDetails.Serializers'>2.25.2 - URL-Encoding Serializers</a></h4>
<div class='topic'><!-- START: 2.25.2 - juneau-marshall.UrlEncodingDetails.Serializers -->
<p>
The {@link org.apache.juneau.urlencoding.UrlEncodingSerializer} class is used to serialize POJOs into URL-Encoding.
</p>
<p>
The URL-Encoding serializers provides the following settings:
</p>
<ul class='javatree'>
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.Common Common Properties}
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.CommonSerializer Common Serializer Properties}
<li class='jc'>{@link org.apache.juneau.urlencoding.UrlEncodingSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.urlencoding.UrlEncodingSerializer#URLENC_expandedParams URLENC_expandedParams}
</ul>
</ul>
<p>
The following pre-configured serializers are provided for convenience:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.urlencoding.UrlEncodingSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.urlencoding.UrlEncodingSerializer#DEFAULT DEFAULT}
<li class='jf'>{@link org.apache.juneau.urlencoding.UrlEncodingSerializer#DEFAULT_EXPANDED DEFAULT_EXPANDED}
<li class='jf'>{@link org.apache.juneau.urlencoding.UrlEncodingSerializer#DEFAULT_PLAINTEXT DEFAULT_PLAINTEXT}
<li class='jf'>{@link org.apache.juneau.urlencoding.UrlEncodingSerializer#DEFAULT_READABLE DEFAULT_READABLE}
</ul>
</ul>
</div><!-- END: 2.25.2 - juneau-marshall.UrlEncodingDetails.Serializers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.UrlEncodingDetails.Parsers' id='juneau-marshall.UrlEncodingDetails.Parsers'>2.25.3 - URL-Encoding Parsers</a></h4>
<div class='topic'><!-- START: 2.25.3 - juneau-marshall.UrlEncodingDetails.Parsers -->
<p>
The {@link org.apache.juneau.urlencoding.UrlEncodingParser} class is used to parse URL-Encoding into POJOs.
</p>
<p>
The URL-Encoding parser provides the following settings:
</p>
<ul class='javatree'>
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.Common Common Properties}
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.CommonParser Common Parser Properties}
<li class='jc'>{@link org.apache.juneau.urlencoding.UrlEncodingParser}
<ul>
<li class='jf'>{@link org.apache.juneau.urlencoding.UrlEncodingParser#URLENC_expandedParams URLENC_expandedParams}
</ul>
</ul>
<p>
The following pre-configured parsers are provided for convenience:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.urlencoding.UrlEncodingParser}
<ul>
<li class='jf'>{@link org.apache.juneau.urlencoding.UrlEncodingParser#DEFAULT DEFAULT}
</ul>
</ul>
</div><!-- END: 2.25.3 - juneau-marshall.UrlEncodingDetails.Parsers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.UrlEncodingDetails.UrlEncodingAnnotation' id='juneau-marshall.UrlEncodingDetails.UrlEncodingAnnotation'>2.25.4 - @UrlEncoding Annotation</a></h4>
<div class='topic'><!-- START: 2.25.4 - juneau-marshall.UrlEncodingDetails.UrlEncodingAnnotation -->
<p>
The {@link org.apache.juneau.urlencoding.annotation.UrlEncoding @UrlEncoding} annotation
is used to override the behavior of {@link org.apache.juneau.urlencoding.UrlEncodingSerializer} on individual bean classes or properties.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.urlencoding.annotation.UrlEncoding}
<ul>
<li class='jf'>{@link org.apache.juneau.urlencoding.annotation.UrlEncoding#expandedParams() expandedParams}
</ul>
</ul>
<p>
The {@link org.apache.juneau.urlencoding.annotation.UrlEncoding#expandedParams() expandedParams} setting is
used to force bean properties of type array or Collection to be expanded into multiple key/value pairings.
It's identical in behavior to using the {@link org.apache.juneau.urlencoding.UrlEncodingSerializer#URLENC_expandedParams}
and {@link org.apache.juneau.urlencoding.UrlEncodingParser#URLENC_expandedParams} properties, but applies to only individual bean properties.
</p>
</div><!-- END: 2.25.4 - juneau-marshall.UrlEncodingDetails.UrlEncodingAnnotation -->
</div><!-- END: 2.25 - juneau-marshall.UrlEncodingDetails -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.MsgPackDetails' id='juneau-marshall.MsgPackDetails'>2.26 - MessagePack Details</a></h3>
<div class='topic'><!-- START: 2.26 - juneau-marshall.MsgPackDetails -->
<p>
Juneau supports converting arbitrary POJOs to and from MessagePack using ultra-efficient serializers
and parsers.
</p>
<p>
MessagePack is a compact binary form of JSON.
The serialization support for MessagePack mirrors that of JSON.
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.MsgPackDetails.Serializers' id='juneau-marshall.MsgPackDetails.Serializers'>2.26.1 - MessagePack Serializers</a></h4>
<div class='topic'><!-- START: 2.26.1 - juneau-marshall.MsgPackDetails.Serializers -->
<p>
The {@link org.apache.juneau.msgpack.MsgPackSerializer} class is used to serialize POJOs into MessagePack.
</p>
<p>
The MessagePack serializer provides the following settings:
</p>
<ul class='javatree'>
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.Common Common Properties}
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.CommonSerializer Common Serializer Properties}
<li class='jc'>{@link org.apache.juneau.msgpack.MsgPackSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.msgpack.MsgPackSerializer#MSGPACK_addBeanTypes MSGPACK_addBeanTypes}
</ul>
</ul>
<p>
The following pre-configured serializers are provided for convenience:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.msgpack.MsgPackSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.msgpack.MsgPackSerializer#DEFAULT DEFAULT}
</ul>
</ul>
</div><!-- END: 2.26.1 - juneau-marshall.MsgPackDetails.Serializers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.MsgPackDetails.Parsers' id='juneau-marshall.MsgPackDetails.Parsers'>2.26.2 - MessagePack Parsers</a></h4>
<div class='topic'><!-- START: 2.26.2 - juneau-marshall.MsgPackDetails.Parsers -->
<p>
The {@link org.apache.juneau.msgpack.MsgPackParser} class is used to parse MessagePack into POJOs.
</p>
<p>
The MessagePack parser provides the following settings:
</p>
<ul class='javatree'>
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.Common Common Properties}
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.CommonParser Common Parser Properties}
</ul>
<p>
The following pre-configured parsers are provided for convenience:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.msgpack.MsgPackParser}
<ul>
<li class='jf'>{@link org.apache.juneau.msgpack.MsgPackParser#DEFAULT DEFAULT}
</ul>
</ul>
</div><!-- END: 2.26.2 - juneau-marshall.MsgPackDetails.Parsers -->
</div><!-- END: 2.26 - juneau-marshall.MsgPackDetails -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.OpenApiDetails' id='juneau-marshall.OpenApiDetails'>2.27 - OpenAPI Details</a></h3>
<div class='topic'><!-- START: 2.27 - juneau-marshall.OpenApiDetails -->
<p>
Juneau supports converting arbitrary POJOs to and from strings using OpenAPI-based schema rules.
</p>
<p>
The relevant classes for using OpenAPI-based serialization are:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.oapi.OpenApiSerializer} - Converts POJOs to strings.
<li class='jc'>{@link org.apache.juneau.oapi.OpenApiParser} - Converts strings to POJOs.
<li class='jc'>{@link org.apache.juneau.httppart.HttpPartSchema} - Defines the schema for your POJO.
</ul>
<p>
The {@link org.apache.juneau.httppart.HttpPartSchema} class is used to define the formatting and
validations for a POJO.
It's used in conjunction with the serializer and parser to produce and consume HTTP parts based on
OpenAPI rules.
</p>
<p>
Later in the rest-server and rest-client sections, we also describe how the following annotations
can be applied to method parameters and class types to define the schema for various HTTP parts:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Body}
<li class='ja'>{@link org.apache.juneau.http.annotation.Header}
<li class='ja'>{@link org.apache.juneau.http.annotation.Query}
<li class='ja'>{@link org.apache.juneau.http.annotation.FormData}
<li class='ja'>{@link org.apache.juneau.http.annotation.Path}
<li class='ja'>{@link org.apache.juneau.http.annotation.Response}
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseHeader}
</ul>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.OpenApiDetails.Methodology' id='juneau-marshall.OpenApiDetails.Methodology'>2.27.1 - OpenAPI Methodology</a></h4>
<div class='topic'><!-- START: 2.27.1 - juneau-marshall.OpenApiDetails.Methodology -->
<p>
Unlike the other Juneau serializers and parsers that convert input and output directly to-and-from POJOs,
the OpenAPI serializers and parsers use intermediate objects based on the <c>type</c> and <c>format</c>
of the schema.
</p>
<p>
The following table shows the "natural" intermediate type of the object based on the <c>type/format</c>:
</p>
<table class='styled w800'>
<tr><th>Type</th><th>Format</th><th>Intermediate Java Type</th></tr>
<tr class='dark bb'>
<td rowspan='4'><c>string</c> or empty</td>
<td><c>byte<br>binary<br>binary-spaced</c></td>
<td><c><jk>byte</jk>[]</c></td>
</tr>
<tr class='dark bb'>
<td><c>date<br>date-time</c></td>
<td>{@link java.util.Calendar}</td>
</tr>
<tr class='dark bb'>
<td><c>uon</c></td>
<td>No intermediate type.<br>(serialized directly to/from POJO)</td>
</tr>
<tr class='dark bb'>
<td>empty</td>
<td>{@link java.lang.String}</td>
</tr>
<tr class='light bb'>
<td rowspan='1'><c>boolean</c></td>
<td>empty</td>
<td>{@link java.lang.Boolean}</td>
</tr>
<tr class='dark bb'>
<td rowspan='2'><c>integer</c></td>
<td><c>int32</c></td>
<td>{@link java.lang.Integer}</td>
</tr>
<tr class='dark bb'>
<td><c>int64</c></td>
<td>{@link java.lang.Long}</td>
</tr>
<tr class='light bb'>
<td rowspan='2'><c>number</c></td>
<td><c>float</c></td>
<td>{@link java.lang.Float}</td>
</tr>
<tr class='light bb'>
<td><c>double</c></td>
<td>{@link java.lang.Double}</td>
</tr>
<tr class='dark bb'>
<td rowspan='2'><c>array</c></td>
<td>empty</td>
<td>Arrays of intermediate types on this list.</td>
</tr>
<tr class='dark bb'>
<td><c>uon</c></td>
<td>No intermediate type.<br>(serialized directly to/from POJO)</td>
</tr>
<tr class='light bb'>
<td rowspan='2'><c>object</c></td>
<td>empty</td>
<td><c>Map&lt;String,Object&gt;</c></td>
</tr>
<tr class='light bb'>
<td><c>uon</c></td>
<td>No intermediate type.<br>(serialized directly to/from POJO)</td>
</tr>
</table>
<p>
The valid POJO types for serializing/parsing are based on the intermediate types above.
As a general rule, any POJOs that are the intermediate type or transformable to or from
the intermediate type are valid POJO types.
</p>
<p>
For example, the following POJO type can be transformed to and from a byte array.
</p>
<p class='bpcode w800'>
<jc>// Sample POJO class convertable to and from a byte[].</jc>
<jk>public class</jk> MyPojo {
<jc>// Constructor used by parser.</jc>
<jk>public</jk> MyPojo(<jk>byte</jk>[] fromBytes) {...}
<jc>// toX method used by serializer.</jc>
<jk>public byte</jk>[] toBytes() {...}
}
</p>
<p>
This example shows how that POJO can be converted to a BASE64-encoded string.
</p>
<p class='bpcode w800'>
<jc>// Construct a POJO.</jc>
MyPojo myPojo = ...;
<jc>// Define a schema.</jc>
HttpPartSchema schema = HttpPartSchema.<jsm>create</jsm>().type(<js>"string"</js>).format(<js>"byte"</js>).build();
<jc>// Convert POJO to BASE64-encoded string.</jc>
HttpPartSerializer s = OpenApiSerializer.<jsf>DEFAULT</jsf>;
String httpPart = s.serialize(schema, myPojo);
<jc>// Convert BASE64-encoded string back into a POJO.</jc>
HttpPartParser p = OpenApiParser.<jsf>DEFAULT</jsf>;
myPojo = p.parse(schema, httpPart, MyPojo.<jk>class</jk>);
</p>
<p>
In addition to defining format, the schema also allows for validations of the serialized form.
</p>
<p class='bpcode w800'>
<jc>// Construct a POJO.</jc>
MyPojo myPojo = ...;
<jc>// Define a schema.</jc>
<jc>// Serialized string must be no smaller than 100 characters.</jc>
HttpPartSchema schema = HttpPartSchema.<jsm>create</jsm>().type(<js>"string"</js>).format(<js>"byte"</js>).minLength(100).build();
<jc>// Convert POJO to BASE64-encoded string.</jc>
HttpPartSerializer s = OpenApiSerializer.<jsf>DEFAULT</jsf>;
String httpPart;
<jk>try</jk> {
httpPart = s.serialize(schema, myPojo);
} <jk>catch</jk> (SchemaValidationException e) {
<jc>// Oops, output too small.</jc>
}
<jc>// Convert BASE64-encoded string back into a POJO.</jc>
HttpPartParser p = OpenApiParser.<jsf>DEFAULT</jsf>;
<jk>try</jk> {
myPojo = p.parse(schema, httpPart, MyPojo.<jk>class</jk>);
} <jk>catch</jk> (SchemaValidationException e) {
<jc>// Oops, input too small.</jc>
}
</p>
<p>
It looks simple, but the implementation is highly sophisticated being able to serialize and parse and validate using complex schemas.
</p>
<p>
The next sections go more into depth on serializing and parsing various POJO types.
</p>
</div><!-- END: 2.27.1 - juneau-marshall.OpenApiDetails.Methodology -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.OpenApiDetails.Serializers' id='juneau-marshall.OpenApiDetails.Serializers'>2.27.2 - OpenAPI Serializers</a></h4>
<div class='topic'><!-- START: 2.27.2 - juneau-marshall.OpenApiDetails.Serializers -->
<p>
The {@link org.apache.juneau.oapi.OpenApiSerializer} class is used to convert POJOs to HTTP parts.
</p>
<p>
Later we'll describe how to use HTTP-Part annotations to define OpenAPI schemas for serialization and parsing
of HTTP parts.
The following example is a preview showing an HTTP body defined as pipe-delimited list of comma-delimited numbers (e.g. <js>"1,2,3|4,5,6|7,8,9"</js>):
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(method=<js>"POST"</js>, path=<js>"/2dLongArray"</js>)
<jk>public void</jk> post2dLongArray(
<ja>@Body</ja>(
schema=<ja>@Schema</ja>(
items=<ja>@Items</ja>(
collectionFormat=<js>"pipes"</js>,
items=<ja>@SubItems</ja>(
collectionFormat=<js>"csv"</js>,
type=<js>"integer"</js>,
format=<js>"int64"</js>,
minimum=<js>"0"</js>,
maximum=<js>"100"</js>
minLength=1,
maxLength=10
)
)
minLength=1,
maxLength=10
)
)
Long[][] body
) {...}
</p>
<p>
Under-the-covers, this gets converted to the following schema object:
</p>
<p class='bpcode w800'>
<jk>import static</jk> org.apache.juneau.httppart.HttpPartSchema.*;
HttpPartSchema schema = <jsm>create</jsm>()
.items(
<jsm>create</jsm>()
.collectionFormat(<js>"pipes"</js>)
.items(
<jsm>create</jsm>()
.collectionFormat(<js>"csv"</js>)
.type(<js>"integer"</js>)
.format(<js>"int64"</js>)
.minimum(<js>"0"</js>)
.maximum(<js>"100"</js>)
.minLength(1)
.maxLength=(10)
)
)
.build();
</p>
<p>
The following code shows how the schema above can be used to create our pipe+csv list of numbers:
</p>
<p class='bpcode w800'>
<jc>// Our POJO being serialized.</jc>
Long[][] input = ....
<jc>// The serializer to use.</jc>
HttpPartSerializer s = OpenApiSerializer.<jsf>DEFAULT</jsf>;
<jc>// Convert POJO to a string.</jc>
<jk>try</jk> {
String httpPart = s.serialize(schema, input);
} <jk>catch</jk> (SchemaValidationException e) {
<jc>// Oops, one of the restrictions were not met.</jc>
}
</p>
<p>
As a general rule, any POJO convertible to the intermediate type for the <c>type/format</c> of the schema can
be serialized using the OpenAPI serializer.
Here are the rules of POJO types allowed for various type/format combinations:
</p>
<table class='styled w800'>
<tr><th>Type</th><th>Format</th><th>Valid parameter types</th></tr>
<tr class='dark bb'>
<td rowspan='4'><c>string</c> or empty</td>
<td><c>byte<br>binary<br>binary-spaced</c></td>
<td>
<ul>
<li><c><jk>byte</jk>[]</c> (default)
<li>{@link java.io.InputStream}
<li>{@link java.io.Reader} - Read into String and then converted using {@link java.lang.String#getBytes()}.
<li>{@link java.lang.Object} - Converted to String and then converted using {@link java.lang.String#getBytes()}.
<li>Any POJO transformable to a <c><jk>byte</jk>[]</c> via the following methods:
<ul>
<li><c><jk>public byte</jk>[] toBytes() {...}</c>
<li><c><jk>public byte</jk>[]</jk> toFoo() {...}</c> (any method name starting with "to")
</ul>
<li>Any POJO transformable to a <c><jk>byte</jk>[]</c> via a {@link org.apache.juneau.transform.PojoSwap}.
</ul>
</td>
</tr>
<tr class='dark bb'>
<td><c>date<br>date-time</c></td>
<td>
<ul>
<li>{@link java.util.Calendar} (default)
<li>{@link java.util.Date}
<li>Any POJO transformable to a {@link java.util.Calendar} via the following methods:
<ul>
<li><c><jk>public</jk> Calendar toCalendar() {...}</c>
<li><c><jk>public</jk> Calendar toFoo() {...}</c> (any method name starting with "to")
</ul>
<li>Any POJO transformable to a {@link java.util.Calendar} via a {@link org.apache.juneau.transform.PojoSwap}.
</ul>
</td>
</tr>
<tr class='dark bb'>
<td><c>uon</c></td>
<td>
<ul>
<li>Any {@doc PojoCategories Serializable POJO} type.
</ul>
</td>
</tr>
<tr class='dark bb'>
<td>empty</td>
<td>
<ul>
<li>{@link java.lang.String} (default)
<li>Any POJO transformable to a {@link java.lang.String} via the following methods:
<ul>
<li><c><jk>public</jk> String toString() {...}</c>
</ul>
<li>Any POJO transformable to a {@link java.lang.String} via a {@link org.apache.juneau.transform.PojoSwap}.
</ul>
</td>
</tr>
<tr class='light bb'>
<td rowspan='1'><c>boolean</c></td>
<td>empty</td>
<td>
<ul>
<li>{@link java.lang.Boolean} (default)
<li><jk>boolean</jk>
<li>{@link java.lang.String} - Converted to a {@link java.lang.Boolean}.
<li>Any POJO transformable to a {@link java.lang.Boolean} via the following methods:
<ul>
<li><c><jk>public</jk> Boolean toBoolean() {...}</c>
<li><c><jk>public</jk> Boolean toFoo() {...}</c> (any method name starting with "to")
</ul>
<li>Any POJO transformable to a {@link java.lang.Boolean} via a {@link org.apache.juneau.transform.PojoSwap}.
</ul>
</td>
</tr>
<tr class='dark bb'>
<td rowspan='2'><c>integer</c></td>
<td><c>int32</c></td>
<td>
<ul>
<li>{@link java.lang.Integer} (default)
<li><jk>int</jk>
<li>{@link java.lang.String} - Converted to an {@link java.lang.String}.
<li>Any POJO transformable to an {@link java.lang.Integer} via the following methods:
<ul>
<li><c><jk>public</jk> Integer toInteger() {...}</c>
<li><c><jk>public</jk> Integer toFoo() {...}</c> (any method name starting with "to")
</ul>
<li>Any POJO transformable to an {@link java.lang.Integer} via a {@link org.apache.juneau.transform.PojoSwap}.
</ul>
</td>
</tr>
<tr class='dark bb'>
<td><c>int64</c></td>
<td>
<ul>
<li>{@link java.lang.Long} (default)
<li><jk>long</jk>
<li>{@link java.lang.String} - Converted to a {@link java.lang.Long}.
<li>Any POJO transformable to a {@link java.lang.Long} via the following methods:
<ul>
<li><c><jk>public</jk> Long toLong() {...}</c>
<li><c><jk>public</jk> Long toFoo() {...}</c> (any method name starting with "to")
</ul>
<li>Any POJO transformable to a {@link java.lang.Long} via a {@link org.apache.juneau.transform.PojoSwap}.
</ul>
</td>
</tr>
<tr class='light bb'>
<td rowspan='2'><c>number</c></td>
<td><c>float</c></td>
<td>
<ul>
<li>{@link java.lang.Float} (default)
<li><jk>float</jk>
<li>{@link java.lang.String} - Converted to a {@link java.lang.Float}.
<li>Any POJO transformable to a {@link java.lang.Float} via the following methods:
<ul>
<li><c><jk>public</jk> Float toFloat() {...}</c>
<li><c><jk>public</jk> Float toFoo() {...}</c> (any method name starting with "to")
</ul>
<li>Any POJO transformable to a {@link java.lang.Float} via a {@link org.apache.juneau.transform.PojoSwap}.
</ul>
</td>
</tr>
<tr class='light bb'>
<td><c>double</c></td>
<td>
<ul>
<li>{@link java.lang.Double} (default)
<li><jk>double</jk>
<li>{@link java.lang.String} - Converted to a {@link java.lang.Double}.
<li>Any POJO transformable to a {@link java.lang.Double} via the following methods:
<ul>
<li><c><jk>public</jk> Double toDouble() {...}</c>
<li><c><jk>public</jk> Double toFoo() {...}</c> (any method name starting with "to")
</ul>
<li>Any POJO transformable to a {@link java.lang.Double} via a {@link org.apache.juneau.transform.PojoSwap}.
</ul>
</td>
</tr>
<tr class='dark bb'>
<td rowspan='2'><c>array</c></td>
<td>empty</td>
<td>
<ul>
<li>Arrays or Collections of any defaults on this list.
<li>Any POJO transformable to arrays of the default types (e.g. <c>Integer[]</c>, <c>Boolean[][]</c>, etc...).
<br>For example:
<ul>
<li><c><jk>public</jk> Boolean[][] toFoo() {...}</c> (any method name starting with "to")
</ul>
<li>Any POJO transformable to arrays of the default types via a {@link org.apache.juneau.transform.PojoSwap}
</ul>
</td>
</tr>
<tr class='dark bb'>
<td><c>uon</c></td>
<td>
<ul>
<li>Any {@doc PojoCategories Serializable POJO} type.
</ul>
</td>
</tr>
<tr class='light bb'>
<td rowspan='2'><c>object</c></td>
<td>empty</td>
<td>
<ul>
<li><c>Map&lt;String,Object&gt;</c> (default)
<li>Beans with properties of anything on this list.
<li>Any POJO transformable to a map via a {@link org.apache.juneau.transform.PojoSwap}
</ul>
</td>
</tr>
<tr class='light bb'>
<td><c>uon</c></td>
<td>
<ul>
<li>Any {@doc PojoCategories Serializable POJO} type.
</ul>
</td>
</tr>
</table>
<p>
For arrays, an example of "Any POJO transformable to arrays of the default types" is:
</p>
<p class='bpcode w800'>
<jc>// Sample POJO class convertable to a Long[][].</jc>
<jk>public class</jk> MyPojo {
<jc>// toX method used by serializer.</jc>
<jk>public</jk> Long[][] to2dLongs() {...}
}
</p>
<p>
In the example above, our POJO class can be used to create our pipe-delimited list of comma-delimited numbers:
</p>
<p class='bpcode w800'>
<jc>// Our POJO being serialized.</jc>
MyPojo input = ....
<jc>// The serializer to use.</jc>
HttpPartSerializer s = OpenApiSerializer.<jsf>DEFAULT</jsf>;
<jc>// Convert POJO to a string.</jc>
<jk>try</jk> {
String httpPart = s.serialize(schema, input);
} <jk>catch</jk> (SchemaValidationException e) {
<jc>// Oops, one of the restrictions were not met.</jc>
}
</p>
<p>
The <c>object</c> type is not officially part of the OpenAPI standard.
However, Juneau supports serializing Maps and beans to HTTP parts using UON notation.
</p>
<p>
The following shows an example of a bean with several properties of various types.
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
<jk>private static byte</jk>[] <jsf>FOOB</jsf> = <js>"foo"</js>.getBytes();
<jk>public</jk> String <jf>f1</jf> = <js>"foo"</js>;
<jk>public byte</jk>[] <jf>f2</jf> = <jsf>FOOB</jsf>;
<jk>public byte</jk>[] <jf>f3</jf> = <jsf>FOOB</jsf>;
<jk>public byte</jk>[] <jf>f4</jf> = <jsf>FOOB</jsf>;
<jk>public</jk> Calendar <jf>f5</jf> = <jsm>parseIsoCalendar</jsm>(<js>"2012-12-21T12:34:56Z"</js>);
<jk>public</jk> String <jf>f6</jf> = <js>"foo"</js>;
<jk>public int</jk> <jf>f7</jf> = 1;
<jk>public</jk> Long <jf>f8</jf> = 2l;
<jk>public float</jk> <jf>f9</jf> = 1.0;
<jk>public</jk> Double <jf>f10</jf> = 1.0;
<jk>public</jk> Boolean <jf>f11</jf> = <jk>true</jk>;
<jk>public</jk> Object <jf>fExtra</jf> = "1";
}
</p>
<p>
We define the following schema:
</p>
<p class='bpcode w800'>
<jk>import static</jk> org.apache.juneau.httppart.HttpPartSchema.*;
HttpPartSchema ps = <jsm>schema</jsm>(<js>"object"</js>)
.property(<js>"f1"</js>, <jsm>schema</jsm>(<js>"string"</js>))
.property(<js>"f2"</js>, <jsm>schema</jsm>(<js>"string"</js>, <js>"byte"</js>))
.property(<js>"f3"</js>, <jsm>schema</jsm>(<js>"string"</js>, <js>"binary"</js>))
.property(<js>"f4"</js>, <jsm>schema</jsm>(<js>"string"</js>, <js>"binary-spaced"</js>))
.property(<js>"f5"</js>, <jsm>schema</jsm>(<js>"string"</js>, <js>"date-time"</js>))
.property(<js>"f6"</js>, <jsm>schema</jsm>(<js>"string"</js>, "<js>uon"</js>))
.property(<js>"f7"</js>, <jsm>schema</jsm>(<js>"integer"</js>))
.property(<js>"f8"</js>, <jsm>schema</jsm>(<js>"integer"</js>, <js>"int64"</js>))
.property(<js>"f9"</js>, <jsm>schema</jsm>(<js>"number"</js>))
.property(<js>"f10"</js>, <jsm>schema</jsm>(<js>"number"</js>, <js>"double"</js>))
.property(<js>"f11"</js>, <jsm>schema</jsm>(<js>"boolean"</js>))
.additionalProperties(<jsm>schema</jsm>(<js>"integer"</js>))
.build();
</p>
<p>
Then we serialize our bean:
</p>
<p class='bpcode w800'>
HttpPartSerializer s = OpenApiSerializer.<jsf>DEFAULT</jsf>;
String httpPart = s.serialize(schema, <jk>new</jk> MyBean());
</p>
<p>
The results of this serialization is shown below:
</p>
<p class='bpcode w800'>
(
f1=foo,
f2=Zm9v,
f3=666F6F,
f4='66 6F 6F',
f5=2012-12-21T12:34:56Z,
f6=foo,
f7=1,
f8=2,
f9=1.0,
f10=1.0,
f11=true,
fExtra=1
)
</p>
<p>
The following is an example of a bean with various array property types:
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
<jk>private static byte</jk>[] <jsf>FOOB</jsf> = <js>"foo"</js>.getBytes();
<jk>public</jk> String[] <jf>f1</jf> = <jk>new</jk> String[]{<js>"a,b"</js>,<jk>null</jk>},
<jk>public byte</jk>[][] <jf>f2</jf> = <jk>new byte</jk>[][]{<jsf>FOOB</jsf>,<jk>null</jk>},
<jk>public byte</jk>[][] <jf>f3</jf> = <jk>new byte</jk>[][]{<jsf>FOOB</jsf>,<jk>null</jk>},
<jk>public byte</jk>[][] <jf>f4</jf> = <jk>new byte</jk>[][]{<jsf>FOOB</jsf>,<jk>null</jk>},
<jk>public</jk> Calendar[] <jf>f5</jf> = <jk>new</jk> Calendar[]{<jsm>parseIsoCalendar</jsm>(<js>"2012-12-21T12:34:56Z"</js>),<jk>null</jk>},
<jk>public</jk> String[] <jf>f6</jf> = <jk>new</jk> String[]{<js>"a"</js>,<js>"b"</js>,<jk>null</jk>},
<jk>public int</jk>[] <jf>f7</jf> = <jk>new int</jk>[]{1,2,<jk>null</jk>},
<jk>public</jk> Integer[] <jf>f8</jf> = <jk>new</jk> Integer[]{3,4,<jk>null</jk>},
<jk>public float</jk>[] <jf>f9</jf> = <jk>new float</jk>[]{1f,2f,<jk>null</jk>},
<jk>public</jk> Float[] <jf>f10</jf> = <jk>new</jk> Float[]{3f,4f,<jk>null</jk>},
<jk>public</jk> Boolean[] <jf>f11</jf> = <jk>new</jk> Boolean[]{<jk>true</jk>,<jk>false</jk>,<jk>null</jk>},
<jk>public</jk> Object[] <jf>fExtra</jf> = <jk>new</jk> Object[]{1,<js>"2"</js>,<jk>null</jk>};
}
</p>
<p>
For this bean, we define the following schema:
</p>
<p class='bpcode w800'>
HttpPartSchema ps = <jsm>schema</jsm>("object")
.property(<js>"f1"</js>, <jsm>schema</jsm>(<js>"array"</js>).items(<jsm>schema</jsm>(<js>"string"</js>)))
.property(<js>"f2"</js>, <jsm>schema</jsm>(<js>"array"</js>).items(<jsm>schema</jsm>(<js>"string"</js>, <js>"byte"</js>)))
.property(<js>"f3"</js>, <jsm>schema</jsm>(<js>"array"</js>).items(<jsm>schema</jsm>(<js>"string"</js>, <js>"binary"</js>)))
.property(<js>"f4"</js>, <jsm>schema</jsm>(<js>"array"</js>).items(<jsm>schema</jsm>(<js>"string"</js>, <js>"binary-spaced"</js>)))
.property(<js>"f5"</js>, <jsm>schema</jsm>(<js>"array"</js>).items(<jsm>schema</jsm>(<js>"string"</js>, <js>"date-time"</js>)))
.property(<js>"f6"</js>, <jsm>schema</jsm>(<js>"array"</js>).items(<jsm>schema</jsm>(<js>"string"</js>, <js>"uon"</js>)))
.property(<js>"f7"</js>, <jsm>schema</jsm>(<js>"array"</js>).items(<jsm>schema</jsm>(<js>"integer"</js>)))
.property(<js>"f8"</js>, <jsm>schema</jsm>(<js>"array"</js>).items(<jsm>schema</jsm>(<js>"integer"</js>, <js>"int64"</js>)))
.property(<js>"f9"</js>, <jsm>schema</jsm>(<js>"array"</js>).items(<jsm>schema</jsm>(<js>"number"</js>)))
.property(<js>"f10"</js>, <jsm>schema</jsm>(<js>"array"</js>).items(<jsm>schema</jsm>(<js>"number"</js>, <js>"double"</js>)))
.property(<js>"f11"</js>, <jsm>schema</jsm>(<js>"array"</js>).items(<jsm>schema</jsm>(<js>"boolean"</js>)))
.additionalProperties(<jsm>schema</jsm>(<js>"array"</js>).items(<jsm>schema</jsm>(<js>"integer"</js>)))
.build();
</p>
<p>
Serializing this bean produces the following output:
</p>
<p class='bpcode w800'>
(
f1=@('a,b',null),
f2=@(Zm9v,null),
f4=@(2012-12-21T12:34:56Z,null),
f5=@(666F6F,null),
f6=@('66 6F 6F',null),
f7=@(a,b,null),
f8=@(1,2,null),
f9=@(3,4,null),
f10=@(1.0,2.0,null),
f11=@(3.0,4.0,null),
f12=@(true,false,null),
fExtra=@(1,2,null)
)
</p>
<ul class='notes'>
<li>
Array properties can also use CSV/SSV/PIPES for array notation.
<br>Various notations can be mixed throughout.
<li>
Schemas and POJOs can be defined arbitrarily deep.
<li>
Schemas are optional.
They can be skipped or partially defined.
<li>
We make our best attempt to convert the input to the matching type.
However, you will get <c>SerializeExceptions</c> if you attempt an impossible conversion.
(e.g. trying to serialize the string "foo" as a boolean).
</ul>
</div><!-- END: 2.27.2 - juneau-marshall.OpenApiDetails.Serializers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.OpenApiDetails.Parsers' id='juneau-marshall.OpenApiDetails.Parsers'>2.27.3 - OpenAPI Parsers</a></h4>
<div class='topic'><!-- START: 2.27.3 - juneau-marshall.OpenApiDetails.Parsers -->
<p>
The {@link org.apache.juneau.oapi.OpenApiParser} class is used to convert HTTP parts back into POJOs.
</p>
<p>
The following is the previous example of a schema that defines the format of a pipe-delimited list of comma-delimited numbers (e.g. <js>"1,2,3|4,5,6|7,8,9"</js>):
</p>
<p class='bpcode w800'>
<jk>import static</jk> org.apache.juneau.httppart.HttpPartSchema.*;
HttpPartSchema schema = <jsm>create</jsm>()
.items(
<jsm>create</jsm>()
.collectionFormat(<js>"pipes"</js>)
.items(
<jsm>create</jsm>()
.collectionFormat(<js>"csv"</js>)
.type(<js>"integer"</js>)
.format(<js>"int64"</js>)
.minimum(<js>"0"</js>)
.maximum(<js>"100"</js>)
.minLength(1)
.maxLength=(10)
)
)
.build();
</p>
<p>
The following code shows how the schema above can be used to parse our input into a POJO:
</p>
<p class='bpcode w800'>
<jc>// Our input being parsed.</jc>
String input = <js>"1,2,3|4,5,6|7,8,9"</js>
<jc>// The parser to use.</jc>
HttpPartParser p = OpenApiParser.<jsf>DEFAULT</jsf>;
<jc>// Convert string to a POJO.</jc>
<jk>try</jk> {
Long[][] pojo = p.parse(schema, input, Long[][].<jk>class</jk>);
} <jk>catch</jk> (SchemaValidationException e) {
<jc>// Oops, one of the restrictions were not met.</jc>
}
</p>
<p>
As a general rule, any POJO convertible from the intermediate type for the <c>type/format</c> of the schema can
be parsed using the OpenAPI parser.
Here are the rules of POJO types allowed for various type/format combinations:
</p>
<table class='styled w800'>
<tr><th>Type</th><th>Format</th><th>Valid parameter types</th></tr>
<tr class='dark bb'>
<td rowspan='4'><c>string</c> or empty</td>
<td><c>byte<br>binary<br>binary-spaced</c></td>
<td>
<ul>
<li><c><jk>byte</jk>[]</c> (default)
<li>{@link java.io.InputStream} - Returns a {@link java.io.ByteArrayInputStream}.
<li>{@link java.io.Reader} - Returns a {@link java.io.InputStreamReader} wrapped around a {@link java.io.ByteArrayInputStream}.
<li>{@link java.lang.String} - Constructed using {@link java.lang.String#String(byte[])}.
<li>{@link java.lang.Object} - Returns the default <c><jk>byte</jk>[]</c>.
<li>Any POJO transformable from a <c><jk>byte</jk>[]</c> (via constructors or static create methods).
</ul>
</td>
</tr>
<tr class='dark bb'>
<td><c>date<br>date-time</c></td>
<td>
<ul>
<li>{@link java.util.Calendar} (default)
<li>{@link java.util.Date}
<li>{@link java.util.GregorianCalendar}
<li>{@link java.lang.String} - Converted using {@link java.util.Calendar#toString()}.
<li>{@link java.lang.Object} - Returns the default {@link java.util.Calendar}.
<li>Any POJO transformable from a {@link java.util.Calendar} (via constructors or static create methods).
</ul>
</td>
</tr>
<tr class='dark bb'>
<td><c>uon</c></td>
<td>
<ul>
<li>Any {@doc PojoCategories Parsable POJO} type.
</ul>
</td>
</tr>
<tr class='dark bb'>
<td>empty</td>
<td>
<ul>
<li>{@link java.lang.String} (default)
<li>{@link java.lang.Object} - Returns the default {@link java.lang.String}.
<li>Any POJO transformable from a {@link java.lang.String} (via constructors, static create methods, or swaps).
</ul>
</td>
</tr>
<tr class='light bb'>
<td rowspan='1'><c>boolean</c></td>
<td>empty</td>
<td>
<ul>
<li>{@link java.lang.Boolean} (default)
<li><jk>boolean</jk>
<li>{@link java.lang.String}
<li>{@link java.lang.Object} - Returns the default {@link java.lang.Boolean}.
<li>Any POJO transformable from a {@link java.lang.Boolean} (via constructors, static create methods, or swaps).
</ul>
</td>
</tr>
<tr class='dark bb'>
<td rowspan='2'><c>integer</c></td>
<td><c>int32</c></td>
<td>
<ul>
<li>{@link java.lang.Integer} (default)
<li>Any subclass of {@link java.lang.Number}
<li>Any primitive number: (e.g <jk>int</jk>, <jk>float</jk>...)
<li>{@link java.lang.String}
<li>{@link java.lang.Object} - Returns the default {@link java.lang.Integer}.
<li>Any POJO transformable from an {@link java.lang.Integer} (via constructors, static create methods, or swaps).
</ul>
</td>
</tr>
<tr class='dark bb'>
<td><c>int64</c></td>
<td>
<ul>
<li>{@link java.lang.Long} (default)
<li>Any subclass of {@link java.lang.Number}
<li>Any primitive number: (e.g <jk>int</jk>, <jk>float</jk>...)
<li>{@link java.lang.String}
<li>{@link java.lang.Object} - Returns the default {@link java.lang.Long}.
<li>Any POJO transformable from an {@link java.lang.Long} (via constructors, static create methods, or swaps).
</ul>
</td>
</tr>
<tr class='light bb'>
<td rowspan='2'><c>number</c></td>
<td><c>float</c></td>
<td>
<ul>
<li>{@link java.lang.Float} (default)
<li>Any subclass of {@link java.lang.Number}
<li>Any primitive number: (e.g <jk>int</jk>, <jk>float</jk>...)
<li>{@link java.lang.String}
<li>{@link java.lang.Object} - Returns the default {@link java.lang.Float}.
<li>Any POJO transformable from an {@link java.lang.Float} (via constructors, static create methods, or swaps).
</ul>
</td>
</tr>
<tr class='light bb'>
<td><c>double</c></td>
<td>
<ul>
<li>{@link java.lang.Double} (default)
<li>Any subclass of {@link java.lang.Number}
<li>Any primitive number: (e.g <jk>int</jk>, <jk>float</jk>...)
<li>{@link java.lang.String}
<li>{@link java.lang.Object} - Returns the default {@link java.lang.Double}.
<li>Any POJO transformable from an {@link java.lang.Double} (via constructors, static create methods, or swaps).
</ul>
</td>
</tr>
<tr class='dark bb'>
<td rowspan='2'><c>array</c></td>
<td>empty</td>
<td>
<ul>
<li>Arrays or Collections of anything on this list.
<li>Any POJO transformable from arrays of the default types (e.g. <c>Integer[]</c>, <c>Boolean[][]</c>, etc...).
</ul>
</td>
</tr>
<tr class='dark bb'>
<td><c>uon</c></td>
<td>
<ul>
<li>Any {@doc PojoCategories Parsable POJO} type.
</ul>
</td>
</tr>
<tr class='light bb'>
<td rowspan='2'><c>object</c></td>
<td>empty</td>
<td>
<ul>
<li><c>Map&lt;String,Object&gt;</c> (default)
<li>Beans with properties of anything on this list.
<li>Maps with string keys.
</ul>
</td>
</tr>
<tr class='light bb'>
<td><c>uon</c></td>
<td>
<ul>
<li>Any {@doc PojoCategories Parsable POJO} type.
</ul>
</td>
</tr>
</table>
<p>
Additionally, any of the type above can also be wrapped as {@link java.util.Optional Optionals}.
</p>
<p>
For arrays, an example of "Any POJO transformable from arrays of the default types" is:
</p>
<p class='bpcode w800'>
<jc>// Sample POJO class convertable from a Long[][].</jc>
<jk>public class</jk> MyPojo {
<jc>// Constructor used by parser.</jc>
<jk>public</jk> MyPojo(Long[][] from2dLongs) {...}
}
</p>
<p>
In the example above, our POJO class can be constructed from our pipe-delimited list of comma-delimited numbers:
</p>
<p class='bpcode w800'>
<jc>// Our input being parsed.</jc>
String input = <js>"1,2,3|4,5,6|7,8,9"</js>
<jc>// The parser to use.</jc>
HttpPartParser p = OpenApiParser.<jsf>DEFAULT</jsf>;
<jc>// Convert string to a POJO.</jc>
<jk>try</jk> {
MyPojo pojo = p.parse(schema, input, MyPojo.<jk>class</jk>);
} <jk>catch</jk> (SchemaValidationException e) {
<jc>// Oops, one of the restrictions were not met.</jc>
}
</p>
<p>
Just like serialization, the <c>object</c> type is not officially part of the OpenAPI standard, but
Juneau supports parsing HTTP parts in UON notation to Maps and beans.
</p>
<p>
The following shows an example of a bean with several properties of various types.
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
<jk>public</jk> String <jf>f1</jf>;
<jk>public byte</jk>[] <jf>f2</jf>;
<jk>public byte</jk>[] <jf>f3</jf>;
<jk>public byte</jk>[] <jf>f4</jf>;
<jk>public</jk> Calendar <jf>f5</jf>;
<jk>public</jk> String <jf>f6</jf>;
<jk>public int</jk> <jf>f7</jf>;
<jk>public</jk> Long <jf>f8</jf>;
<jk>public float</jk> <jf>f9</jf>;
<jk>public</jk> Double <jf>f10</jf>;
<jk>public</jk> Boolean <jf>f11</jf>;
<jk>public</jk> Object <jf>fExtra</jf>;
}
</p>
<p>
We define the following schema again:
</p>
<p class='bpcode w800'>
<jk>import static</jk> org.apache.juneau.httppart.HttpPartSchema.*;
HttpPartSchema ps = <jsm>schema</jsm>(<js>"object"</js>)
.property(<js>"f1"</js>, <jsm>schema</jsm>(<js>"string"</js>))
.property(<js>"f2"</js>, <jsm>schema</jsm>(<js>"string"</js>, <js>"byte"</js>))
.property(<js>"f3"</js>, <jsm>schema</jsm>(<js>"string"</js>, <js>"binary"</js>))
.property(<js>"f4"</js>, <jsm>schema</jsm>(<js>"string"</js>, <js>"binary-spaced"</js>))
.property(<js>"f5"</js>, <jsm>schema</jsm>(<js>"string"</js>, <js>"date-time"</js>))
.property(<js>"f6"</js>, <jsm>schema</jsm>(<js>"string"</js>, "<js>uon"</js>))
.property(<js>"f7"</js>, <jsm>schema</jsm>(<js>"integer"</js>))
.property(<js>"f8"</js>, <jsm>schema</jsm>(<js>"integer"</js>, <js>"int64"</js>))
.property(<js>"f9"</js>, <jsm>schema</jsm>(<js>"number"</js>))
.property(<js>"f10"</js>, <jsm>schema</jsm>(<js>"number"</js>, <js>"double"</js>))
.property(<js>"f11"</js>, <jsm>schema</jsm>(<js>"boolean"</js>))
.additionalProperties(<jsm>schema</jsm>(<js>"integer"</js>))
.build();
</p>
<p>
Then we parse our input into our POJO:
</p>
<p class='bpcode w800'>
String input =
<js>"(f1=foo,f2=Zm9v,f3=666F6F,f4='66 6F 6F',f5=2012-12-21T12:34:56Z,f6=foo,"</js>
+ <js>"f7=1,f8=2,f9=1.0,f10=1.0,f11=true,fExtra=1)"</js>;
HttpPartParser p = OpenApiParser.<jsf>DEFAULT</jsf>;
MyBean b = p.parse(schema, input, MyBean.<jk>class</jk>);
</p>
<p>
Note that serializing into generic <c>Object</c> properties would have produced similar results:
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
<jk>public</jk> Object <jf>f1</jf>;
<jk>public</jk> Object <jf>f2</jf>;
<jk>public</jk> Object <jf>f3</jf>;
<jk>public</jk> Object <jf>f4</jf>;
<jk>public</jk> Object <jf>f5</jf>;
<jk>public</jk> Object <jf>f6</jf>;
<jk>public</jk> Object <jf>f7</jf>;
<jk>public</jk> Object <jf>f8</jf>;
<jk>public</jk> Object <jf>f9</jf>;
<jk>public</jk> Object <jf>f10</jf>;
<jk>public</jk> Object <jf>f11</jf>;
<jk>public</jk> Object <jf>fExtra</jf>;
}
</p>
<p>
We can also parse into Maps as well:
</p>
<p class='bpcode w800'>
String input =
<js>"(f1=foo,f2=Zm9v,f3=666F6F,f4='66 6F 6F',f5=2012-12-21T12:34:56Z,f6=foo,"</js>
+ <js>"f7=1,f8=2,f9=1.0,f10=1.0,f11=true,fExtra=1)"</js>;
HttpPartParser p = OpenApiParser.<jsf>DEFAULT</jsf>;
ObjectMap m = p.parse(schema, input, ObjectMap.<jk>class</jk>);
</p>
<ul class='notes'>
<li>
Array properties can also use CSV/SSV/PIPES for array notation.
<br>Various notations can be mixed throughout.
<li>
Schemas and POJOs can be defined arbitrarily deep.
<li>
Schemas are optional.
They can be skipped or partially defined.
<li>
We make our best attempt to convert the output to the matching type.
However, you will get <c>ParseExceptions</c> if you attempt an impossible conversion.
(e.g. trying to parse the string "foo" into a boolean).
</ul>
</div><!-- END: 2.27.3 - juneau-marshall.OpenApiDetails.Parsers -->
</div><!-- END: 2.27 - juneau-marshall.OpenApiDetails -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.SimpleVariableLanguage' id='juneau-marshall.SimpleVariableLanguage'>2.28 - Simple Variable Language</a></h3>
<div class='topic'><!-- START: 2.28 - juneau-marshall.SimpleVariableLanguage -->
<p>
The <l>org.apache.juneau.svl</l> packages defines an API for a language called <l>Simple Variable Language</l>.
In a nutshell, Simple Variable Language (or SVL) is text that contains variables of the form <js>"$varName{varKey}"</js>.
It is used extensively in the Config, REST and Microservice APIs.
</p>
<p>
Most variables can be recursively nested within the varKey (e.g. <js>"$FOO{$BAR{xxx},$BAZ{xxx}}"</js>)
and can return values that themselves contain more variables.
</p>
<p>
The {@link org.apache.juneau.svl.VarResolver} class is used to resolve variables.
The {@link org.apache.juneau.svl.VarResolver#DEFAULT} resolver is a reusable instance of this class
configured with the following basic variables:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.svl.vars.SystemPropertiesVar} - <c>$S{key[,default]}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.EnvVariablesVar} - <c>$E{key[,default]}</c>
</ul>
<p>
The following logic variables are also provided:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.svl.vars.IfVar} - <c>$IF{arg,then[,else]}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.SwitchVar} - <c>$SW{arg,pattern1:then1[,pattern2:then2...]}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.CoalesceVar} - <c>$CO{arg1[,arg2...]}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.PatternMatchVar} - <c>$PM{arg,pattern}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.PatternReplaceVar} - <c>$PR{arg,pattern,replace}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.PatternExtractVar} - <c>$PE{arg,pattern,groupIndex}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.NotEmptyVar} - <c>$NE{arg}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.UpperCaseVar} - <c>$UC{arg}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.LowerCaseVar} - <c>$LC{arg}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.LenVar} - <c>$LN{arg[,delimiter]}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.SubstringVar} - <c>$ST{arg,start[,end]}</c>
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<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='bpcode w800'>
<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>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.SimpleVariableLanguage.SvlVariables' id='juneau-marshall.SimpleVariableLanguage.SvlVariables'>2.28.1 - SVL Variables</a></h4>
<div class='topic'><!-- START: 2.28.1 - juneau-marshall.SimpleVariableLanguage.SvlVariables -->
<p>
Variables are defined through the {@link org.apache.juneau.svl.Var} API.
The API comes with several predefined variables and is easily extensible.
</p>
<p>
The following is an example of a variable that performs URL-Encoding on strings.
</p>
<p class='bpcode w800'>
<jc>// First create our var.</jc>
<jk>public class</jk> UrlEncodeVar <jk>extends</jk> SimpleVar {
<jc>// Must have a no-arg constructor!</jc>
<jk>public</jk> UrlEncodeVar() {
<jk>super</jk>(<js>"UE"</js>);
}
<jc>// The method we must implement</jc>
<ja>@Override</ja>
<jk>public</jk> String resolve(VarResolverSession session, String key) {
<jk>return</jk> URLEncoder.<jsm>encode</jsm>(key, <js>"UTF-8"</js>);
}
}
<jc>// Next create a var resolver that extends the existing DEFAULT resolver
// that supports resolving system properties.</jc>
VarResolver r = VarResolver.<jsf>DEFAULT</jsf>
.builder()
.vars(UrlEncodeVar.<jk>class</jk>)
.build();
<jc>// Retrieve a system property and URL-encode it if necessary.</jc>
String myProperty = r.resolve(<js>"$UE{$S{my.property}}"</js>);
</p>
<p>
The following shows the class hierarchy of the {@link org.apache.juneau.svl.Var} class:
</p>
<ul class='javatree'>
<li class='jac'>{@link org.apache.juneau.svl.Var} - Superclass of all vars.
<ul>
<li class='jac'>{@link org.apache.juneau.svl.SimpleVar} - Superclass of all vars that return strings.
<ul>
<li class='jac'>{@link org.apache.juneau.svl.DefaultingVar} - Variables that define a default value if the resolve method returns null.
<ul>
<li class='jac'>{@link org.apache.juneau.svl.MapVar} - Variables that pull values from maps.
</ul>
<li class='jac'>{@link org.apache.juneau.svl.MultipartVar} - Variables that consist of 2 or more comma-delimited arguments.
</ul>
<li class='jac'>{@link org.apache.juneau.svl.StreamedVar} - Superclass of all vars that stream their value to writers.
</ul>
</ul>
<p>
The following is the list of default variables defined in all modules:
</p>
<table class='styled w800'>
<tr>
<th>Module</th><th>Class</th><th>Pattern</th>
</tr>
<tr class='dark'>
<td rowspan='15' style='text-align:center;font-weight:bold;padding:20px;' class='code'>juneau-svl</td>
<td>{@link org.apache.juneau.svl.vars.EnvVariablesVar}</td>
<td class='code'>$E{key[,default]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.SystemPropertiesVar}</td>
<td class='code'>$S{key[,default]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.ArgsVar}</td>
<td class='code'>$A{key[,default]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.ManifestFileVar}</td>
<td class='code'>$MF{key[,default]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.IfVar}</td>
<td class='code'>$IF{arg,then[,else]}</td>
</tr>
<tr class='dark dd'>
<td>{@link org.apache.juneau.svl.vars.SwitchVar}</td>
<td class='code'>$SW{arg,pattern1:then1[,pattern2:then2...]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.CoalesceVar}</td>
<td class='code'>$CO{arg1[,arg2...]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.PatternMatchVar}</td>
<td class='code'>$PM{arg,pattern}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.PatternReplaceVar}</td>
<td class='code'>$PR{arg,pattern,replace}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.PatternExtractVar}</td>
<td class='code'>$PE{arg,pattern,groupdIndex}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.NotEmptyVar}</td>
<td class='code'>$NE{arg}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.UpperCaseVar}</td>
<td class='code'>$UC{arg}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.LowerCaseVar}</td>
<td class='code'>$LC{arg}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.LenVar}</td>
<td class='code'>$LN{arg[,delimiter]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.SubstringVar}</td>
<td class='code'>$ST{arg,start[,end]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.html.HtmlWidgetVar}</td>
<td class='code'>$W{name}</td>
</tr>
<tr class='light dd'>
<td rowspan='1' style='text-align:center;font-weight:bold;padding:20px;' class='code'>juneau-config</td>
<td>{@link org.apache.juneau.config.vars.ConfigVar}</td>
<td class='code'>$C{key[,default]}</td>
</tr>
<tr class='dark'>
<td rowspan='15' style='text-align:center;font-weight:bold;padding:20px;' class='code'>juneau-rest-server</td>
<td>{@link org.apache.juneau.rest.vars.FileVar}</td>
<td class='code'>$F{path[,default]}}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.ServletInitParamVar}</td>
<td class='code'>$I{name[,default]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.LocalizationVar}</td>
<td class='code'>$L{key[,args...]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.RequestAttributeVar}</td>
<td class='code'>$RA{key1[,key2...]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.RequestFormDataVar}</td>
<td class='code'>$RF{key1[,key2...]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.RequestHeaderVar}</td>
<td class='code'>$RH{key1[,key2...]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.RequestHeaderVar}</td>
<td class='code'>$RI{key}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.RequestPathVar}</td>
<td class='code'>$RP{key1[,key2...]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.RequestQueryVar}</td>
<td class='code'>$RQ{key1[,key2...]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.RequestVar}</td>
<td class='code'>$R{key1[,key2...]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.SerializedRequestAttrVar}</td>
<td class='code'>$SA{contentType,key[,default]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.SwaggerVar}</td>
<td class='code'>$SS{key1[,key2...]}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.UrlVar}</td>
<td class='code'>$U{uri}></td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.UrlEncodeVar}</td>
<td class='code'>$UE{uriPart}</td>
</tr>
<tr class='dark dd'>
<td>{@link org.apache.juneau.rest.vars.WidgetVar} <i>(deprecated)</i></td>
<td class='code'>$W{name}</td>
</tr>
</table>
</div><!-- END: 2.28.1 - juneau-marshall.SimpleVariableLanguage.SvlVariables -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.SimpleVariableLanguage.VarResolvers' id='juneau-marshall.SimpleVariableLanguage.VarResolvers'>2.28.2 - VarResolvers and VarResolverSessions</a></h4>
<div class='topic'><!-- START: 2.28.2 - juneau-marshall.SimpleVariableLanguage.VarResolvers -->
<p>
The main class for performing variable resolution is {@link org.apache.juneau.svl.VarResolver}.
Two methods are provided for resolving variables:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.svl.VarResolver}
<ul>
<li class='jm'>{@link org.apache.juneau.svl.VarResolver#resolve(String) resolve(String)}
- Resolves variables and returns the results as a simple string.
<li class='jm'>{@link org.apache.juneau.svl.VarResolver#resolveTo(String,Writer) resolveTo(String,Writer)}
- Resolves variables and sends results to a writer.
</ul>
</ul>
<p>
Var resolvers can rely on the existence of other objects.
For example, {@link org.apache.juneau.config.vars.ConfigVar} relies on the existence of a {@link org.apache.juneau.config.Config}.
This is accomplished through the following:
</p>
<ul class='spaced-list'>
<li>Context-objects - Objects set on the resolver.
<li>Session-objects - Objects set on the resolver session.
</ul>
<p>
The following two classes are identical in behavior except for which objects they can access:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.svl.VarResolver} - Has access to context objects only.
<li class='jc'>{@link org.apache.juneau.svl.VarResolverSession} - Has access to context and session objects.
</ul>
<p>
Context and session objects are set through the following methods:
</p>
<ul class='javatree'>
<li class='jm'>{@link org.apache.juneau.svl.VarResolverBuilder#contextObject(String,Object)} - Context objects.
<li class='jm'>{@link org.apache.juneau.svl.VarResolverSession#sessionObject(String,Object)} - Session objects.
<li class='jm'>{@link org.apache.juneau.svl.VarResolver#createSession(Map)} - Session objects.
</ul>
<p>
Both kinds of objects are accessible through the following method:
</p>
<ul class='javatree'>
<li class='jm'>{@link org.apache.juneau.svl.VarResolverSession#getSessionObject(Class, String, boolean)}
</ul>
<p>
Var resolvers can be cloned and extended by using the {@link org.apache.juneau.svl.VarResolver#builder()} method.
Cloning a resolver will copy it's {@link org.apache.juneau.svl.Var} class names and context objects.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Create a resolver that copies the default resolver and adds $C and $A vars.</jc>
VarResolver myVarResolver = VarResolver.<jsf>DEFAULT</jsf>
.builder()
.vars(ConfigVar.<jk>class</jk>, ArgsVar.<jk>class</jk>)
.build();
</p>
</div><!-- END: 2.28.2 - juneau-marshall.SimpleVariableLanguage.VarResolvers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.SimpleVariableLanguage.DefaultVarResolver' id='juneau-marshall.SimpleVariableLanguage.DefaultVarResolver'>2.28.3 - VarResolver.DEFAULT</a></h4>
<div class='topic'><!-- START: 2.28.3 - juneau-marshall.SimpleVariableLanguage.DefaultVarResolver -->
<p>
{@link org.apache.juneau.svl.VarResolver#DEFAULT} is a reusable variable resolver with default support for the following variables:
</p>
<ul>
<li><c>$S{key[,default]}</c> - {@link org.apache.juneau.svl.vars.SystemPropertiesVar}
<li><c>$E{key[,default]}</c> - {@link org.apache.juneau.svl.vars.EnvVariablesVar}
<li><c>$A{key[,default]}</c> - {@link org.apache.juneau.svl.vars.ArgsVar}
<li><c>$MF{key[,default]}</c> - {@link org.apache.juneau.svl.vars.ManifestFileVar}
<li><c>$SW{stringArg,pattern:thenValue[,pattern:thenValue...]}</c> - {@link org.apache.juneau.svl.vars.SwitchVar}
<li><c>$IF{arg,then[,else]}</c> - {@link org.apache.juneau.svl.vars.IfVar}
<li><c>$CO{arg[,arg2...]}</c> - {@link org.apache.juneau.svl.vars.CoalesceVar}
<li><c>$PM{arg,pattern}</c> - {@link org.apache.juneau.svl.vars.PatternMatchVar}
<li><c>$PR{stringArg,pattern,replace}</c>- {@link org.apache.juneau.svl.vars.PatternReplaceVar}
<li><c>$PE{arg,pattern,groupIndex}</c> - {@link org.apache.juneau.svl.vars.PatternExtractVar}
<li><c>$UC{arg}</c> - {@link org.apache.juneau.svl.vars.UpperCaseVar}
<li><c>$LC{arg}</c> - {@link org.apache.juneau.svl.vars.LowerCaseVar}
<li><c>$NE{arg}</c> - {@link org.apache.juneau.svl.vars.NotEmptyVar}
<li><c>$LN{arg[,delimiter]}</c> - {@link org.apache.juneau.svl.vars.LenVar}
<li><c>$ST{arg,start[,end]}</c> - {@link org.apache.juneau.svl.vars.SubstringVar}
</ul>
</div><!-- END: 2.28.3 - juneau-marshall.SimpleVariableLanguage.DefaultVarResolver -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.SimpleVariableLanguage.OtherNotes' id='juneau-marshall.SimpleVariableLanguage.OtherNotes'>2.28.4 - Other Notes</a></h4>
<div class='topic'><!-- START: 2.28.4 - juneau-marshall.SimpleVariableLanguage.OtherNotes -->
<ul class='spaced-list'>
<li>
The escape character <js>'\'</js> can be used when necessary to escape the following characters:
<c>$ , { }</c>
<li>
<b>WARNING:</b> It is possible to cause {@link java.lang.StackOverflowError StackOverflowErrors} if
your nested variables result in a recursive loop (e.g. the environment variable
<c>'MYPROPERTY'</c> has the value <c>'$E{MYPROPERTY}'</c>).
So don't do that!
<li>
As a general rule, this class tries to be as efficient as possible by not creating new strings when not
needed.
<br>For example, calling the resolve method on a string that doesn't contain variables (e.g.
<c>resolver.resolve(<js>"foobar"</js>)</c>) will simply be a no-op and return the same string.
</ul>
</div><!-- END: 2.28.4 - juneau-marshall.SimpleVariableLanguage.OtherNotes -->
</div><!-- END: 2.28 - juneau-marshall.SimpleVariableLanguage -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall.BestPractices' id='juneau-marshall.BestPractices'>2.29 - Best Practices</a></h3>
<div class='topic'><!-- START: 2.29 - juneau-marshall.BestPractices -->
<ol class='spaced-list'>
<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.
<li>
The {@link org.apache.juneau.BeanTraverseContext#BEANTRAVERSE_detectRecursions BEANTRAVERSE_detectRecursions}
option on the {@link org.apache.juneau.serializer.Serializer} class can cause a performance penalty of
around 20%.
<br>Therefore, it's recommended that this option be used only when necessary.
<li>
In general, JSON serialization and parsing is about 20% faster than XML.
JSON is also more compact than XML.
<br>MessagePack is fastest and most compact of all.
<li>
The RDF parsers are SLOW.
<br>RDF simply isn't efficient with node traversal, so creating tree structures out of RDF models
is highly inefficient.
<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.
</ol>
</div><!-- END: 2.29 - juneau-marshall.BestPractices -->
</div><!-- END: 2 - juneau-marshall -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall-rdf' id='juneau-marshall-rdf'>3 - juneau-marshall-rdf</a></h2>
<div class='topic'><!-- START: 3 - juneau-marshall-rdf -->
<h5 class='figure'>Maven Dependency</h5>
<p class='bpcode w500'>
<xt>&lt;dependency&gt;</xt>
<xt>&lt;groupId&gt;</xt>org.apache.juneau<xt>&lt;/groupId&gt;</xt>
<xt>&lt;artifactId&gt;</xt>juneau-marshall-rdf<xt>&lt;/artifactId&gt;</xt>
<xt>&lt;version&gt;</xt>{@property juneauVersion}<xt>&lt;/version&gt;</xt>
<xt>&lt;/dependency&gt;</xt>
</p>
<h5 class='figure'>Java Library</h5>
<p class='bpcode w500'>
juneau-marshall-rdf-{@property juneauVersion}.jar
</p>
<h5 class='figure'>OSGi Module</h5>
<p class='bpcode w500'>
org.apache.juneau.marshall.rdf_{@property juneauVersion}.jar
</p>
<p>
The <c>juneau-marshall-rdf</c> library provides additional serializers and parsers for RDF.
These rely on the Apache Jena library to provide support for the following languages:
</p>
<ul>
<li>RDF/XML
<li>RDF/XML-Abbrev
<li>N-Triple
<li>Turtle
<li>N3
</ul>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall-rdf.RdfDetails' id='juneau-marshall-rdf.RdfDetails'>3.1 - RDF Details</a></h3>
<div class='topic'><!-- START: 3.1 - juneau-marshall-rdf.RdfDetails -->
<p>
Juneau supports serializing and parsing arbitrary POJOs to and from the following RDF formats:
</p>
<ul>
<li>RDF/XML
<li>Abbreviated RDF/XML
<li>N-Triple
<li>Turtle
<li>N3
</ul>
<p>
The serializers and parsers work identically to those in <c>juneau-marshall</c>, but are
packaged separately so that you don't need to pull in the Jena dependency unless you need it.
</p>
<p class='bpcode w800'>
<jc>// A simple bean</jc>
<jk>public class</jk> Person {
<jk>public</jk> String name = <js>"John Smith"</js>;
<jk>public int</jk> age = 21;
}
<jc>// Serialize a bean to JSON, XML, or HTML</jc>
Person p = <jk>new</jk> Person();
<jc>// Produces:
// &lt;rdf:RDF
// xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
// xmlns:jp="http://www.apache.org/juneaubp/"
// xmlns:j="http://www.apache.org/juneau/"&gt;
// &lt;rdf:Description&gt;
// &lt;jp:name&gt;John Smith&lt;/jp:name&gt;
// &lt;jp:age&gt;21&lt;/jp:age&gt;
// &lt;/rdf:Description&gt;
// &lt;/rdf:RDF&gt;</jc>
String rdfXml = RdfSerializer.<jsf>DEFAULT_XMLABBREV</jsf>.serialize(p);
<jc>// Produces:
// @prefix jp: &lt;http://www.apache.org/juneaubp/&gt; .
// @prefix j: &lt;http://www.apache.org/juneau/&gt; .
// [] jp:age "21" ;
// jp:name "John Smith" .</jc>
String rdfN3 = N3Serializer.<jsf>DEFAULT</jsf>.serialize(p);
<jc>// Produces:
// _:A3bf53c85X3aX157cf407e2dX3aXX2dX7ffd &lt;http://www.apache.org/juneaubp/name&gt; "John Smith" .
// _:A3bf53c85X3aX157cf407e2dX3aXX2dX7ffd &lt;http://www.apache.org/juneaubp/age&gt; "21" .</jc>
String rdfNTriple = RdfSerializer.<jsf>DEFAULT_NTRIPLE</jsf>.serialize(p);
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall-rdf.RdfDetails.Serializers' id='juneau-marshall-rdf.RdfDetails.Serializers'>3.1.1 - RDF Serializers</a></h4>
<div class='topic'><!-- START: 3.1.1 - juneau-marshall-rdf.RdfDetails.Serializers -->
<p>
The {@link org.apache.juneau.jena.RdfSerializer} class is the top-level class for all Jena-based serializers.
Language-specific serializers are defined as inner subclasses of the <c>RdfSerializer</c> class:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.jena.RdfSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.jena.RdfXmlSerializer}
<li class='jc'>{@link org.apache.juneau.jena.RdfXmlAbbrevSerializer}
<li class='jc'>{@link org.apache.juneau.jena.N3Serializer}
<li class='jc'>{@link org.apache.juneau.jena.NTripleSerializer}
<li class='jc'>{@link org.apache.juneau.jena.TurtleSerializer}
</ul>
</ul>
<ul class='javatree'>
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.Common Common Properties}
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.CommonSerializer Common Serializer Properties}
<li class='jic'>{@link org.apache.juneau.jena.RdfCommon}
<ul>
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_embedding RDF_arp_embedding}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_err_ RDF_arp_err_}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_errorMode RDF_arp_errorMode}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_ign_ RDF_arp_ign_}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_iriRules RDF_arp_iriRules}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_warn_ RDF_arp_warn_}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_collectionFormat RDF_collectionFormat}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_juneauBpNs RDF_juneauBpNs}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_juneauNs RDF_juneauNs}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_language RDF_language}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_looseCollections RDF_looseCollections}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_abbrevBaseUri RDF_n3_abbrevBaseUri}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_indentProperty RDF_n3_indentProperty}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_minGap RDF_n3_minGap}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_objectLists RDF_n3_objectLists}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_propertyColumn RDF_n3_propertyColumn}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_subjectColumn RDF_n3_subjectColumn}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_useDoubles RDF_n3_useDoubles}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_usePropertySymbols RDF_n3_usePropertySymbols}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_useTripleQuotedStrings RDF_n3_useTripleQuotedStrings}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_widePropertyLen RDF_n3_widePropertyLen}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_allowBadUris RDF_rdfxml_allowBadUris}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_attributeQuoteChar RDF_rdfxml_attributeQuoteChar}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_blockRules RDF_rdfxml_blockRules}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_longId RDF_rdfxml_longId}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_relativeUris RDF_rdfxml_relativeUris}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_showDoctypeDeclaration RDF_rdfxml_showDoctypeDeclaration}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_showXmlDeclaration RDF_rdfxml_showXmlDeclaration}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_tab RDF_rdfxml_tab}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_xmlBase RDF_rdfxml_xmlBase}
</ul>
<li class='jc'>{@link org.apache.juneau.jena.RdfSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.jena.RdfSerializer#RDF_addBeanTypes RDF_addBeanTypes}
<li class='jf'>{@link org.apache.juneau.jena.RdfSerializer#RDF_addLiteralTypes RDF_addLiteralTypes}
<li class='jf'>{@link org.apache.juneau.jena.RdfSerializer#RDF_addRootProperty RDF_addRootProperty}
<li class='jf'>{@link org.apache.juneau.jena.RdfSerializer#RDF_autoDetectNamespaces RDF_autoDetectNamespaces}
<li class='jf'>{@link org.apache.juneau.jena.RdfSerializer#RDF_namespaces RDF_namespaces}
<li class='jf'>{@link org.apache.juneau.jena.RdfSerializer#RDF_useXmlNamespaces RDF_useXmlNamespaces}
</ul>
</ul>
<p>
The following pre-configured serializers are provided for convenience:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.jena.RdfSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.jena.RdfXmlSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.jena.RdfXmlSerializer#DEFAULT DEFAULT}
</ul>
<li class='jc'>{@link org.apache.juneau.jena.RdfXmlAbbrevSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.jena.RdfXmlAbbrevSerializer#DEFAULT DEFAULT}
</ul>
<li class='jc'>{@link org.apache.juneau.jena.N3Serializer}
<ul>
<li class='jf'>{@link org.apache.juneau.jena.N3Serializer#DEFAULT DEFAULT}
</ul>
<li class='jc'>{@link org.apache.juneau.jena.NTripleSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.jena.NTripleSerializer#DEFAULT DEFAULT}
</ul>
<li class='jc'>{@link org.apache.juneau.jena.TurtleSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.jena.TurtleSerializer#DEFAULT DEFAULT}
</ul>
</ul>
</ul>
<p>
Abbreviated RDF/XML is currently the most widely accepted and readable RDF syntax, so the examples shown here
will use that format.
</p>
</div><!-- END: 3.1.1 - juneau-marshall-rdf.RdfDetails.Serializers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall-rdf.RdfDetails.Parsers' id='juneau-marshall-rdf.RdfDetails.Parsers'>3.1.2 - RDF Parsers</a></h4>
<div class='topic'><!-- START: 3.1.2 - juneau-marshall-rdf.RdfDetails.Parsers -->
<p>
The {@link org.apache.juneau.jena.RdfParser} class is the top-level class for all Jena-based parsers.
Language-specific parsers are defined as inner subclasses of the <c>RdfParser</c> class:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.jena.RdfParser}
<ul>
<li class='jc'>{@link org.apache.juneau.jena.RdfXmlParser}
<li class='jc'>{@link org.apache.juneau.jena.NTripleParser}
<li class='jc'>{@link org.apache.juneau.jena.TurtleParser}
<li class='jc'>{@link org.apache.juneau.jena.N3Parser}
</ul>
</ul>
<p>
The <c>RdfParser.Xml</c> parser handles both regular and abbreviated RDF/XML.
</p>
<p>
The RDF parser provides the following settings:
</p>
<ul class='javatree'>
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.Common Common Properties}
<li class='link'>{@doc juneau-marshall.ConfigurableProperties.CommonParser Common Parser Properties}
<li class='jic'>{@link org.apache.juneau.jena.RdfCommon}
<ul>
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_embedding RDF_arp_embedding}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_err_ RDF_arp_err_}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_errorMode RDF_arp_errorMode}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_ign_ RDF_arp_ign_}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_iriRules RDF_arp_iriRules}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_warn_ RDF_arp_warn_}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_collectionFormat RDF_collectionFormat}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_juneauBpNs RDF_juneauBpNs}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_juneauNs RDF_juneauNs}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_language RDF_language}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_looseCollections RDF_looseCollections}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_abbrevBaseUri RDF_n3_abbrevBaseUri}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_indentProperty RDF_n3_indentProperty}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_minGap RDF_n3_minGap}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_objectLists RDF_n3_objectLists}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_propertyColumn RDF_n3_propertyColumn}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_subjectColumn RDF_n3_subjectColumn}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_useDoubles RDF_n3_useDoubles}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_usePropertySymbols RDF_n3_usePropertySymbols}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_useTripleQuotedStrings RDF_n3_useTripleQuotedStrings}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_widePropertyLen RDF_n3_widePropertyLen}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_allowBadUris RDF_rdfxml_allowBadUris}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_attributeQuoteChar RDF_rdfxml_attributeQuoteChar}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_blockRules RDF_rdfxml_blockRules}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_longId RDF_rdfxml_longId}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_relativeUris RDF_rdfxml_relativeUris}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_showDoctypeDeclaration RDF_rdfxml_showDoctypeDeclaration}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_showXmlDeclaration RDF_rdfxml_showXmlDeclaration}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_tab RDF_rdfxml_tab}
<li class='jf'>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_xmlBase RDF_rdfxml_xmlBase}
</ul>
<li class='jc'>{@link org.apache.juneau.jena.RdfParser}
<ul>
<li class='jf'>{@link org.apache.juneau.jena.RdfParser#RDF_trimWhitespace RDF_trimWhitespace}
</ul>
</ul>
<p>
The following pre-configured parsers are provided for convenience:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.jena.RdfParser}
<ul>
<li class='jc'>{@link org.apache.juneau.jena.RdfXmlParser}
<ul>
<li class='jf'>{@link org.apache.juneau.jena.RdfXmlParser#DEFAULT DEFAULT}
</ul>
<li class='jc'>{@link org.apache.juneau.jena.N3Parser}
<ul>
<li class='jf'>{@link org.apache.juneau.jena.N3Parser#DEFAULT DEFAULT}
</ul>
<li class='jc'>{@link org.apache.juneau.jena.NTripleParser}
<ul>
<li class='jf'>{@link org.apache.juneau.jena.NTripleParser#DEFAULT DEFAULT}
</ul>
<li class='jc'>{@link org.apache.juneau.jena.TurtleParser}
<ul>
<li class='jf'>{@link org.apache.juneau.jena.TurtleParser#DEFAULT DEFAULT}
</ul>
</ul>
</ul>
</div><!-- END: 3.1.2 - juneau-marshall-rdf.RdfDetails.Parsers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall-rdf.RdfDetails.RdfAnnotation' id='juneau-marshall-rdf.RdfDetails.RdfAnnotation'>3.1.3 - @Rdf Annotation</a></h4>
<div class='topic'><!-- START: 3.1.3 - juneau-marshall-rdf.RdfDetails.RdfAnnotation -->
<p>
The {@link org.apache.juneau.jena.annotation.Rdf @Rdf} annotation
is used to override the behavior of the RDF serializers and parsers on individual bean classes or properties.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.jena.annotation.Rdf}
<ul>
<li class='jf'>{@link org.apache.juneau.jena.annotation.Rdf#beanUri() beanUri}
<li class='jf'>{@link org.apache.juneau.jena.annotation.Rdf#collectionFormat() collectionFormat}
<li class='jf'>{@link org.apache.juneau.jena.annotation.Rdf#namespace() namespace}
<li class='jf'>{@link org.apache.juneau.jena.annotation.Rdf#prefix() prefix}
</ul>
</ul>
</div><!-- END: 3.1.3 - juneau-marshall-rdf.RdfDetails.RdfAnnotation -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall-rdf.RdfDetails.Namespaces' id='juneau-marshall-rdf.RdfDetails.Namespaces'>3.1.4 - Namespaces</a></h4>
<div class='topic'><!-- START: 3.1.4 - juneau-marshall-rdf.RdfDetails.Namespaces -->
<p>
You'll notice in the previous example that Juneau namespaces are used to represent bean property names.
These are used by default when namespaces are not explicitly specified.
</p>
<p>
The <c>juneau</c> namespace is used for generic names for objects that don't have namespaces
associated with them.
</p>
<p>
The <c>juneaubp</c> namespace is used on bean properties that don't have namespaces associated with
them.
</p>
<p>
The easiest way to specify namespaces is through annotations.
In this example, we're going to associate the prefix <c>'per'</c> to our bean class and all properties
of this class.
We do this by adding the following annotation to our class:
</p>
<p class='bpcode w800'>
<ja>@Rdf</ja>(prefix=<js>"per"</js>)
<jk>public class</jk> Person {
</p>
<p>
In general, the best approach is to define the namespace URIs at the package level using a
<c>package-info.java</c> class, like so:
</p>
<p class='bpcode w800'>
<jc>// RDF namespaces used in this package</jc>
<ja>@RdfSchema</ja>(
prefix=<js>"ab"</js>,
rdfNs={
<ja>@RdfNs</ja>(prefix=<js>"ab"</js>, namespaceURI=<js>"http://www.apache.org/addressBook/"</js>),
<ja>@RdfNs</ja>(prefix=<js>"per"</js>, namespaceURI=<js>"http://www.apache.org/person/"</js>),
<ja>@RdfNs</ja>(prefix=<js>"addr"</js>, namespaceURI=<js>"http://www.apache.org/address/"</js>),
<ja>@RdfNs</ja>(prefix=<js>"mail"</js>, namespaceURI=<js>"http://www.apache.org/mail/"</js>)
}
)
<jk>package</jk> org.apache.juneau.sample.addressbook;
<jk>import</jk> org.apache.juneau.xml.annotation.*;
</p>
<p>
This assigns a default prefix of <js>"ab"</js> for all classes and properties within the project, and
specifies various other prefixes used within this project.
</p>
<p>
Now when we rerun the sample code, we'll get the following:
</p>
<p class='bpcode w800'>
<xt>&lt;rdf:RDF</xt>
<xa>xmlns:rdf</xa>=<xs>"http://www.w3.org/1999/02/22-rdf-syntax-ns#"</xs>
<xa>xmlns:j</xa>=<xs>"http://www.apache.org/juneau/"</xs>
<xa>xmlns:jp</xa>=<xs>"http://www.apache.org/juneaubp/"</xs>
<xa>xmlns:per</xa>=<xs>"http://www.apache.org/person/"</xs><xt>&gt;</xt>
<xt>&lt;rdf:Description&gt;</xt>
<xt>&lt;per:id&gt;</xt>1<xt>&lt;/per:id&gt;</xt>
<xt>&lt;per:name&gt;</xt>John Smith<xt>&lt;/per:name&gt;</xt>
<xt>&lt;/rdf:Description&gt;</xt>
<xt>&lt;/rdf:RDF&gt;</xt>
</p>
<p>
Namespace auto-detection ({@link org.apache.juneau.xml.XmlSerializer#XML_autoDetectNamespaces}) is
enabled on serializers by default.
This causes the serializer to make a first-pass over the data structure to look for namespaces.
In high-performance environments, you may want to consider disabling auto-detection and providing an
explicit list of namespaces to the serializer to avoid this scanning step.
</p>
<p class='bpcode w800'>
<jc>// Create a new serializer, but manually specify the namespaces.</jc>
RdfSerializer s = RdfSerializer.<jsm>create</jsm>()
.xmlabbrev()
.set(RdfProperties.<jsf>RDF_rdfxml_tab</jsf>, 3)
.autoDetectNamespaces(<jk>false</jk>)
.namespaces(<js>"{per:'http://www.apache.org/person/'}"</js>)
.build();
</p>
<p>
This code change will produce the same output as before, but will perform slightly better since it doesn't
have to crawl the POJO tree before serializing the result.
</p>
</div><!-- END: 3.1.4 - juneau-marshall-rdf.RdfDetails.Namespaces -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall-rdf.RdfDetails.UriProperties' id='juneau-marshall-rdf.RdfDetails.UriProperties'>3.1.5 - URI Properties</a></h4>
<div class='topic'><!-- START: 3.1.5 - juneau-marshall-rdf.RdfDetails.UriProperties -->
<p>
Bean properties of type <c>java.net.URI</c> or <c>java.net.URL</c> have special meaning to the
RDF serializer.
They are interpreted as resource identifiers.
</p>
<p>
In the following code, we're adding 2 new properties.
The first property is annotated with <ja>@Beanp</ja> to identify that this property is the resource
identifier for this bean.
The second un-annotated property is interpreted as a reference to another resource.
</p>
<p class='bpcode w800'>
<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>;
...
<jc>// Normal constructor</jc>
<jk>public</jk> Person(<jk>int</jk> id, String name, String uri, String addressBookUri) <jk>throws</jk> URISyntaxException {
<jk>this</jk>.<jf>id</jf> = id;
<jk>this</jk>.<jf>name</jf> = name;
<jk>this</jk>.<jf>uri</jf> = <jk>new</jk> URI(uri);
<jk>this</jk>.<jf>addressBookUri</jf> = <jk>new</jk> URI(addressBookUri);
}
}
</p>
<p>
We alter our code to pass in values for these new properties.
</p>
<p class='bpcode w800'>
<jc>// Create our bean.</jc>
Person p = <jk>new</jk> Person(1, <js>"John Smith"</js>, <js>"http://sample/addressBook/person/1"</js>,
<js>"http://sample/addressBook"</js>);
</p>
<p>
Now when we run the sample code, we get the following:
</p>
<p class='bpcode w800'>
<xt>&lt;rdf:RDF</xt>
<xa>xmlns:rdf</xa>=<xs>"http://www.w3.org/1999/02/22-rdf-syntax-ns#"</xs>
<xa>xmlns:j</xa>=<xs>"http://www.apache.org/juneau/"</xs>
<xa>xmlns:jp</xa>=<xs>"http://www.apache.org/juneaubp/"</xs>
<xa>xmlns:per</xa>=<xs>"http://www.apache.org/person/"</xs><xt>&gt;</xt>
<xt>&lt;rdf:Description <b><xa>rdf:about</xa>=<xs>"http://sample/addressBook/person/1"</xs></b>&gt;</xt>
<xt>&lt;per:addressBookUri</xt> <xa>rdf:resource</xa>=<xs>"http://sample/addressBook"</xs><xt>/&gt;</xt>
<xt>&lt;per:id&gt;</xt>1<xt>&lt;/per:id&gt;</xt>
<xt>&lt;per:name&gt;</xt>John Smith<xt>&lt;/per:name&gt;</xt>
<xt>&lt;/rdf:Description&gt;</xt>
<xt>&lt;/rdf:RDF&gt;</xt>
</p>
<p>
The {@link org.apache.juneau.annotation.URI @URI} annotation can also be used on classes and properties
to identify them as URLs when they're not instances of <c>java.net.URI</c> or <c>java.net.URL</c>
(not needed if <c><ja>@Rdf</ja>(beanUri=<jk>true</jk>)</c> is already specified).
</p>
<p>
The following properties would have produced the same output as before.
Note that the <ja>@URI</ja> annotation is only needed on the second property.
</p>
<p class='bpcode w800'>
<jk>public class</jk> Person {
<jc>// Bean properties</jc>
<ja>@Rdf</ja>(beanUri=<jk>true</jk>) <jk>public</jk> String <jf>uri</jf>;
<ja>@URI</ja> <jk>public</jk> String <jf>addressBookUri</jf>;
</p>
<p>
Also take note of the {@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriResolution},
{@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriRelativity}, and
and {@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriContext}
settings that can be specified on the serializer to resolve relative and context-root-relative URIs to
fully-qualified URIs.
</p>
<p>
This can be useful if you want to keep the URI authority and context root information out of the bean logic
layer.
</p>
<p>
The following code produces the same output as before, but the URIs on the beans are relative.
</p>
<p class='bpcode w800'>
<jc>// Create a new serializer with readable output.</jc>
RdfSerializer s = RdfSerializer.<jsm>create</jsm>()
.xmlabbrev()
.set(RdfProperties.<jsf>RDF_rdfxml_tab</jsf>, 3);
.relativeUriBase(<js>"http://myhost/sample"</js>);
.absolutePathUriBase(<js>"http://myhost"</js>)
.build();
<jc>// Create our bean.</jc>
Person p = <jk>new</jk> Person(1, <js>"John Smith"</js>, <js>"person/1"</js>, <js>"/"</js>);
<jc>// Serialize the bean to RDF/XML.</jc>
String rdfXml = s.serialize(p);
</p>
</div><!-- END: 3.1.5 - juneau-marshall-rdf.RdfDetails.UriProperties -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall-rdf.RdfDetails.RootProperty' id='juneau-marshall-rdf.RdfDetails.RootProperty'>3.1.6 - Root Property</a></h4>
<div class='topic'><!-- START: 3.1.6 - juneau-marshall-rdf.RdfDetails.RootProperty -->
<p>
For all RDF languages, the POJO objects get broken down into simple triplets.
Unfortunately, for tree-structured data like the POJOs shown above, this causes the root node of the tree
to become lost.
There is no easy way to identify that <c>person/1</c> is the root node in our tree once in triplet
form, and in some cases it's impossible.
</p>
<p>
By default, the {@link org.apache.juneau.jena.RdfParser} class handles this by scanning all the nodes and
identifying the nodes without incoming references.
However, this is inefficient, especially for large models.
And in cases where the root node is referenced by another node in the model by URL, it's not possible to
locate the root at all.
</p>
<p>
To resolve this issue, the property {@link org.apache.juneau.jena.RdfSerializer#RDF_addRootProperty}
was introduced.
When enabled, this adds a special <c>root</c> attribute to the root node to make it easy to locate
by the parser.
</p>
<p>
To enable, set the <jsf>RDF_addRootProperty</jsf> property to <jk>true</jk> on the serializer:
</p>
<p class='bpcode w800'>
<jc>// Create a new serializer.</jc>
RdfSerializer s = RdfSerializer.<jsm>create</jsm>()
.xmlabbrev()
.set(RdfProperties.<jsf>RDF_rdfxml_tab</jsf>, 3),
.addRootProperty(<jk>true</jk>)
.build();
</p>
<p>
Now when we rerun the sample code, we'll see the added <c>root</c> attribute on the root resource.
</p>
<p class='bpcode w800'>
<xt>&lt;rdf:RDF</xt>
<xa>xmlns:rdf</xa>=<xs>"http://www.w3.org/1999/02/22-rdf-syntax-ns#"</xs>
<xa>xmlns:j</xa>=<xs>"http://www.apache.org/juneau/"</xs>
<xa>xmlns:jp</xa>=<xs>"http://www.apache.org/juneaubp/"</xs>
<xa>xmlns:per</xa>=<xs>"http://www.apache.org/person/"</xs>
<xa>xmlns:mail</xa>=<xs>"http://www.apache.org/mail/"</xs>
<xa>xmlns:addr</xa>=<xs>"http://www.apache.org/address/"</xs><xt>&gt;</xt>
<xt>&lt;rdf:Description <xa>rdf:about</xa>=<xs>"http://sample/addressBook/person/1"</xs>&gt;</xt>
<b><xt>&lt;j:root&gt;</xt>true<xt>&lt;/j:root&gt;</xt></b>
<xt>&lt;per:addressBookUri</xt> <xa>rdf:resource</xa>=<xs>"http://sample/addressBook"</xs><xt>/&gt;</xt>
<xt>&lt;per:id&gt;</xt>1<xt>&lt;/per:id&gt;</xt>
<xt>&lt;per:name&gt;</xt>John Smith<xt>&lt;/per:name&gt;</xt>
<xt>&lt;per:addresses&gt;</xt>
<xt>&lt;rdf:Seq&gt;</xt>
<xt>&lt;rdf:li&gt;</xt>
<xt>&lt;rdf:Description <xa>rdf:about</xa>=<xs>"http://sample/addressBook/address/1"</xs>&gt;</xt>
<xt>&lt;addr:personUri <xa>rdf:resource</xa>=<xs>"http://sample/addressBook/person/1"</xs>/&gt;</xt>
<xt>&lt;addr:id&gt;</xt>1<xt>&lt;/addr:id&gt;</xt>
<xt>&lt;mail:street&gt;</xt>100 Main Street<xt>&lt;/mail:street&gt;</xt>
<xt>&lt;mail:city&gt;</xt>Anywhereville<xt>&lt;/mail:city&gt;</xt>
<xt>&lt;mail:state&gt;</xt>NY<xt>&lt;/mail:state&gt;</xt>
<xt>&lt;mail:zip&gt;</xt>12345<xt>&lt;/mail:zip&gt;</xt>
<xt>&lt;addr:isCurrent&gt;</xt>true<xt>&lt;/addr:isCurrent&gt;</xt>
<xt>&lt;/rdf:Description&gt;</xt>
<xt>&lt;/rdf:li&gt;</xt>
<xt>&lt;/rdf:Seq&gt;</xt>
<xt>&lt;/per:addresses&gt;</xt>
<xt>&lt;/rdf:Description&gt;</xt>
<xt>&lt;/rdf:RDF&gt;</xt>
</p>
</div><!-- END: 3.1.6 - juneau-marshall-rdf.RdfDetails.RootProperty -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-marshall-rdf.RdfDetails.TypedLiterals' id='juneau-marshall-rdf.RdfDetails.TypedLiterals'>3.1.7 - Typed Literals</a></h4>
<div class='topic'><!-- START: 3.1.7 - juneau-marshall-rdf.RdfDetails.TypedLiterals -->
<p>
XML-Schema data-types can be added to non-<c>String</c> literals through the
{@link org.apache.juneau.jena.RdfSerializer#RDF_addLiteralTypes} setting.
</p>
<p>
To enable, set the <jsf>RDF_addLiteralTypes</jsf> property to <jk>true</jk> on the serializer:
</p>
<p class='bpcode w800'>
<jc>// Create a new serializer (revert back to namespace autodetection).</jc>
RdfSerializer s = RdfSerializer.<jsm>create</jsm>()
.xmlabbrev()
.set(RdfProperties.<jsf>RDF_rdfxml_tab</jsf>, 3),
.addLiteralTypes(<jk>true</jk>)
.build();
</p>
<p>
Now when we rerun the sample code, we'll see the added <c>root</c> attribute on the root resource.
</p>
<p class='bpcode w800'>
<xt>&lt;rdf:RDF</xt>
<xa>xmlns:rdf</xa>=<xs>"http://www.w3.org/1999/02/22-rdf-syntax-ns#"</xs>
<xa>xmlns:j</xa>=<xs>"http://www.apache.org/juneau/"</xs>
<xa>xmlns:jp</xa>=<xs>"http://www.apache.org/juneaubp/"</xs>
<xa>xmlns:per</xa>=<xs>"http://www.apache.org/person/"</xs>
<xa>xmlns:mail</xa>=<xs>"http://www.apache.org/mail/"</xs>
<xa>xmlns:addr</xa>=<xs>"http://www.apache.org/address/"</xs><xt>&gt;</xt>
<xt>&lt;rdf:Description <xa>rdf:about</xa>=<xs>"http://sample/addressBook/person/1"</xs>&gt;</xt>
<xt>&lt;per:addressBookUri</xt> <xa>rdf:resource</xa>=<xs>"http://sample/addressBook"</xs><xt>/&gt;</xt>
<xt>&lt;per:id</xt> <b><xa>rdf:datatype</xa>=<xs>"http://www.w3.org/2001/XMLSchema#int"</xs></b><xt>&gt;</xt>1<xt>&lt;/per:id&gt;</xt>
<xt>&lt;per:name&gt;</xt>John Smith<xt>&lt;/per:name&gt;</xt>
<xt>&lt;per:addresses&gt;</xt>
<xt>&lt;rdf:Seq&gt;</xt>
<xt>&lt;rdf:li&gt;</xt>
<xt>&lt;rdf:Description <xa>rdf:about</xa>=<xs>"http://sample/addressBook/address/1"</xs>&gt;</xt>
<xt>&lt;addr:personUri <xa>rdf:resource</xa>=<xs>"http://sample/addressBook/person/1"</xs>/&gt;</xt>
<xt>&lt;addr:id</xt> <b><xa>rdf:datatype</xa>=<xs>"http://www.w3.org/2001/XMLSchema#int"</xs></b>&gt;</xt>1<xt>&lt;/addr:id&gt;</xt>
<xt>&lt;mail:street&gt;</xt>100 Main Street<xt>&lt;/mail:street&gt;</xt>
<xt>&lt;mail:city&gt;</xt>Anywhereville<xt>&lt;/mail:city&gt;</xt>
<xt>&lt;mail:state&gt;</xt>NY<xt>&lt;/mail:state&gt;</xt>
<xt>&lt;mail:zip</xt> <b><xa>rdf:datatype</xa>=<xs>"http://www.w3.org/2001/XMLSchema#int"</xs></b>&gt;</xt>12345<xt>&lt;/mail:zip&gt;</xt>
<xt>&lt;addr:isCurrent</xt> <b><xa>rdf:datatype</xa>=<xs>"http://www.w3.org/2001/XMLSchema#boolean"</xs></b>&gt;</xt>true<xt>&lt;/addr:isCurrent&gt;</xt>
<xt>&lt;/rdf:Description&gt;</xt>
<xt>&lt;/rdf:li&gt;</xt>
<xt>&lt;/rdf:Seq&gt;</xt>
<xt>&lt;/per:addresses&gt;</xt>
<xt>&lt;/rdf:Description&gt;</xt>
<xt>&lt;/rdf:RDF&gt;</xt>
</p>
</div><!-- END: 3.1.7 - juneau-marshall-rdf.RdfDetails.TypedLiterals -->
</div><!-- END: 3.1 - juneau-marshall-rdf.RdfDetails -->
</div><!-- END: 3 - juneau-marshall-rdf -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-dto' id='juneau-dto'>4 - juneau-dto</a></h2>
<div class='topic'><!-- START: 4 - juneau-dto -->
<h5 class='figure'>Maven Dependency</h5>
<p class='bpcode w500'>
<xt>&lt;dependency&gt;</xt>
<xt>&lt;groupId&gt;</xt>org.apache.juneau<xt>&lt;/groupId&gt;</xt>
<xt>&lt;artifactId&gt;</xt>juneau-dto<xt>&lt;/artifactId&gt;</xt>
<xt>&lt;version&gt;</xt>{@property juneauVersion}<xt>&lt;/version&gt;</xt>
<xt>&lt;/dependency&gt;</xt>
</p>
<h5 class='figure'>Java Library</h5>
<p class='bpcode w500'>
juneau-dto-{@property juneauVersion}.jar
</p>
<h5 class='figure'>OSGi Module</h5>
<p class='bpcode w500'>
org.apache.juneau.dto_{@property juneauVersion}.jar
</p>
<p>
The <c>juneau-dto</c> library contains several predefined POJOs for generating commonly-used document types.
This section describes support for these POJOs.
</p>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-dto.HTML5' id='juneau-dto.HTML5'>4.1 - HTML5</a></h3>
<div class='topic'><!-- START: 4.1 - juneau-dto.HTML5 -->
<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 w800'>
<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 fragments.
</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>
<h5 class='toc'>Additional Information - org.apache.juneau.dto.html5</h5>
<ol class='toc'>
<li><p>{@doc org.apache.juneau.dto.html5#Overview Overview}</p>
<ol>
<li><p>{@doc org.apache.juneau.dto.html5#Serialize Generating HTML5}</p>
<li><p>{@doc org.apache.juneau.dto.html5#Parse Parsing HTML5}</p>
<li><p>{@doc org.apache.juneau.dto.html5#Templates HTML5 Templates}</p>
</ol>
</ol>
</div><!-- END: 4.1 - juneau-dto.HTML5 -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-dto.Atom' id='juneau-dto.Atom'>4.2 - Atom</a></h3>
<div class='topic'><!-- START: 4.2 - juneau-dto.Atom -->
<p>
The Juneau ATOM feed DTOs are simply beans with fluent-style setters.
The following code shows a feed being created programmatically using the
{@link org.apache.juneau.dto.atom.AtomBuilder} class.
</p>
<p class='bpcode w800'>
<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) ..."</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>
<h5 class='figure'>Example with no namespaces</h5>
<p class='bpcode w800'>
<jc>// Create a serializer with readable output, no namespaces yet.</jc>
XmlSerializer s = XmlSerializer.<jsm>create</jsm>().sq().ws().build();
<jc>// Serialize to ATOM/XML</jc>
String atomXml = s.serialize(feed);
</p>
<h5 class='figure'>Results</h5>
<p class='bpcode w800'>
<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) ...
<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>
<h5 class='toc'>Additional Information - org.apache.juneau.dto.atom</h5>
<ol class='toc'>
<li><p>{@doc org.apache.juneau.dto.atom#Overview Overview}</p>
<ol>
<li><p>{@doc org.apache.juneau.dto.atom#Serialize Serializing ATOM feeds}</p>
<ol>
<li><p>{@doc org.apache.juneau.dto.atom#AtomJson ATOM/JSON}</p>
<li><p>{@doc org.apache.juneau.dto.atom#AtomRdfXml ATOM/RDF/XML}</p>
<li><p>{@doc org.apache.juneau.dto.atom#AtomHtml ATOM/HTML}</p>
</ol>
<li><p>{@doc org.apache.juneau.dto.atom#Parse Parsing ATOM feeds}</p>
</ol>
</ol>
</div><!-- END: 4.2 - juneau-dto.Atom -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-dto.Swagger' id='juneau-dto.Swagger'>4.3 - Swagger</a></h3>
<div class='topic'><!-- START: 4.3 - juneau-dto.Swagger -->
<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='bpcode w800'>
{
<jok>"swagger"</jok>: <jov>"2.0"</jov>,
<jok>"info"</jok>: {
<jok>"title"</jok>: <jov>"Swagger Petstore"</jov>,
<jok>"description"</jok>: <jov>"This is a sample server Petstore server."</jov>,
<jok>"version"</jok>: <jov>"1.0.0"</jov>,
<jok>"termsOfService"</jok>: <jov>"http://swagger.io/terms/"</jov>,
<jok>"contact"</jok>: {
<jok>"email"</jok>: <jov>"apiteam@swagger.io"</jov>
},
<jok>"license"</jok>: {
<jok>"name"</jok>: <jov>"Apache 2.0"</jov>,
<jok>"url"</jok>: <jov>"http://www.apache.org/licenses/LICENSE-2.0.html"</jov>
}
},
<jok>"host"</jok>: <jov>"petstore.swagger.io"</jov>,
<jok>"basePath"</jok>: <jov>"/v2"</jov>,
<jok>"tags"</jok>: [
{
<jok>"name"</jok>: <jov>"pet"</jov>,
<jok>"description"</jok>: <jov>"Everything about your Pets"</jov>,
<jok>"externalDocs"</jok>: {
<jok>"description"</jok>: <jov>"Find out more"</jov>,
<jok>"url"</jok>: <jov>"http://swagger.io"</jov>
}
}
],
<jok>"schemes"</jok>: [
<jov>"http"</jov>
],
<jok>"paths"</jok>: {
<jok>"/pet"</jok>: {
<jok>"post"</jok>: {
<jok>"tags"</jok>: [
<jov>"pet"</jov>
],
<jok>"summary"</jok>: <jov>"Add a new pet to the store"</jov>,
<jok>"description"</jok>: <jov>""</jov>,
<jok>"operationId"</jok>: <jov>"addPet"</jov>,
<jok>"consumes"</jok>: [
<jov>"application/json"</jov>,
<jov>"text/xml"</jov>
],
<jok>"produces"</jok>: [
<jov>"application/json"</jov>,
<jov>"text/xml"</jov>
],
<jok>"parameters"</jok>: [
{
<jok>"in"</jok>: <jov>"body"</jov>,
<jok>"name"</jok>: <jov>"body"</jov>,
<jok>"description"</jok>: <jov>"Pet object that needs to be added to the store"</jov>,
<jok>"required"</jok>: <jov>true</jov>
}
],
<jok>"responses"</jok>: {
<jok>"405"</jok>: {
<jok>"description"</jok>: <jov>"Invalid input"</jov>
}
}
}
}
}
}
</p>
<p>
This document can be generated by the following Java code:
</p>
<p class='bpcode w800'>
<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>))
);
<jc>// Serialize using JSON serializer.</jc>
String swaggerJson = JsonSerializer.<jsf>DEFAULT_READABLE</jsf>.serialize(swagger);
<jc>// Or just use toString().</jc>
String swaggerJson = swagger.toString();
</p>
<p>
Methods that take in beans and collections of beans can also take in JSON representations
of those objects.
</p>
<p class='bpcode w800'>
<jc>// Pass in a JSON object representation of an Info object.</jc>
swagger.info(<js>"{title:'Swagger Petstore',...}"</js>);
</p>
<p>
Properties can also be accessed via the {@link org.apache.juneau.dto.swagger.SwaggerElement#get(String,Class)}
and {@link org.apache.juneau.dto.swagger.SwaggerElement#set(String,Object)} methods.
These methods can also be used to set and retrieve non-Swagger attributes such as
<js>"$ref"</js> (which is not a part of the Swagger spec, but is part of the JSON Schema spec).
</p>
<p class='bpcode w800'>
<jc>// Set a non-standard attribute.</jc>
swagger.set(<js>"$ref"</js>, <js>"http://foo.com"</js>);
<jc>// Retrieve a non-standard attribute.</jc>
URI ref = swagger.get(<js>"$ref"</js>, URI.<jk>class</jk>);
</p>
<p>
Swagger docs can be parsed back into Swagger beans using the following code:
</p>
<p class='bpcode w800'>
Swagger swagger = JsonParser.<jsf>DEFAULT</jsf>.parse(swaggerJson, Swagger.<jk>class</jk>);
</p>
</div><!-- END: 4.3 - juneau-dto.Swagger -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-dto.SwaggerUI' id='juneau-dto.SwaggerUI'>4.4 - Swagger UI</a></h3>
<div class='topic'><!-- START: 4.4 - juneau-dto.SwaggerUI -->
<p>
The {@link org.apache.juneau.dto.swagger.ui.SwaggerUI} class is a DTO class for generating Swagger user interfaces
from {@link org.apache.juneau.dto.swagger.Swagger} beans.
</p>
<p>
The <c>PetStore</c> example described later provides an example of auto-generated Swagger JSON:
</p>
<img class='bordered w900' src='doc-files/SwaggerUI.json.png'>
<p>
Using {@link org.apache.juneau.dto.swagger.ui.SwaggerUI}, we're able to render that JSON as a Swagger user interface
when the request is asking for HTML:
</p>
<img class='bordered w900' src='doc-files/SwaggerUI.html.png'>
<p>
The class itself is nothing more than a POJO swap that swaps out {@link org.apache.juneau.dto.swagger.Swagger} beans
with {@link org.apache.juneau.dto.html5.Div} elements:
</p>
<p class='bpcode w800'>
<jk>public class</jk> SwaggerUI <jk>extends</jk> PojoSwap&lt;Swagger,Div&gt; {
<ja>@Override</ja>
<jk>public</jk> MediaType[] forMediaTypes() {
<jc>// Only use this swap when the Accept type is HTML.</jc>
<jk>return new</jk> MediaType[] {MediaType.<jsf>HTML</jsf>};
}
<ja>@Override</ja>
<jk>public</jk> Div swap(BeanSession beanSession, Swagger swagger) <jk>throws</jk> Exception {
...
}
}
</p>
<p>
The {@link org.apache.juneau.rest.BasicRestServlet} class (describe later) shows how this swap is used in the REST interface to
generate the Swagger UI shown above:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
<jc>// Allow OPTIONS requests to be simulated using ?method=OPTIONS query parameter.</jc>
allowedMethodParams=<js>"OPTIONS"</js>,
<jc>// POJO swaps to apply to all serializers/parsers.</jc>
pojoSwaps={
<jc>// Use the SwaggerUI swap when rendering Swagger beans.</jc>
SwaggerUI.<jk>class</jk>
},
...
)
<jk>public abstract class</jk> BasicRestServlet <jk>extends</jk> RestServlet <jk>implements</jk> BasicRestConfig {
<jd>/**
* [OPTIONS /*] - Show resource options.
*/</jd>
<ja>@RestMethod</ja>(
name=<jsf>OPTIONS</jsf>,
path=<js>"/*"</js>,
summary=<js>"Swagger documentation"</js>,
description=<js>"Swagger documentation for this resource."</js>,
htmldoc=<ja>@HtmlDoc</ja>(
<jc>// Override the nav links for the swagger page.</jc>
navlinks={
<js>"back: servlet:/"</js>,
<js>"json: servlet:/?method=OPTIONS&amp;Accept=text/json&amp;plainText=true"</js>
},
<jc>// Never show aside contents of page inherited from class.</jc>
aside="<js>NONE"</js>
)
)
<jk>public</jk> Swagger getOptions(RestRequest req) {
<jc>// Localized Swagger for this resource is available through the RestRequest object.</jc>
<jk>return</jk> req.getSwagger();
}
}
</p>
</div><!-- END: 4.4 - juneau-dto.SwaggerUI -->
</div><!-- END: 4 - juneau-dto -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-config' id='juneau-config'>5 - juneau-config</a></h2>
<div class='topic'><!-- START: 5 - juneau-config -->
<h5 class='figure'>Maven Dependency</h5>
<p class='bpcode w500'>
<xt>&lt;dependency&gt;</xt>
<xt>&lt;groupId&gt;</xt>org.apache.juneau<xt>&lt;/groupId&gt;</xt>
<xt>&lt;artifactId&gt;</xt>juneau-config<xt>&lt;/artifactId&gt;</xt>
<xt>&lt;version&gt;</xt>{@property juneauVersion}<xt>&lt;/version&gt;</xt>
<xt>&lt;/dependency&gt;</xt>
</p>
<h5 class='figure'>Java Library</h5>
<p class='bpcode w500'>
juneau-config-{@property juneauVersion}.jar
</p>
<h5 class='figure'>OSGi Module</h5>
<p class='bpcode w500'>
org.apache.juneau.config_{@property juneauVersion}.jar
</p>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.Overview' id='juneau-config.Overview'>5.1 - Overview</a></h3>
<div class='topic'><!-- START: 5.1 - juneau-config.Overview -->
<p>
The <c>juneau-config</c> library contains a powerful API for creating and using INI-style config files.
</p>
<h5 class='figure'>Example configuration file:</h5>
<p class='bpcode w800'>
<cc># A set of entries</cc>
<cs>[Section1]</cs>
<cc># An integer</cc>
<ck>key1</ck> = <cv>1</cv>
<cc># A boolean</cc>
<ck>key2</ck> = <cv>true</cv>
<cc># An array</cc>
<ck>key3</ck> = <cv>1,2,3</cv>
<cc># A POJO</cc>
<ck>key4</ck> = <cv>http://bar</cv>
</p>
<p>
Config files are accessed through the {@link org.apache.juneau.config.Config} class which
are created through the {@link org.apache.juneau.config.ConfigBuilder} class.
Builder creator methods are provided on the <c>Config</c> class:
</p>
<p class='bpcode w800'>
<jc>// Create a Config object</jc>
Config c = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
<jc>// Shortcut</jc>
Config c = Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).build();
</p>
<p>
Once instantiated, reading values from the config are simple:
</p>
<p class='bpcode w800'>
<jc>// Read values from section #1</jc>
<jk>int</jk> key1 = c.getInt(<js>"Section1/key1"</js>);
<jk>boolean</jk> key2 = c.getBoolean(<js>"Section1/key2"</js>);
<jk>int</jk>[] key3 = c.getObject(<js>"Section1/key3"</js>, <jk>int</jk>[].<jk>class</jk>);
URL key4 = c.getObject(<js>"Section1/key4"</js>, URL.<jk>class</jk>);
</p>
<p>
The config language may look simple, but it is a very powerful feature with many capabilities including:
</p>
<ul class='spaced-list'>
<li>
Support for storing and retrieving any of the following data types:
<ul>
<li>Primitives
<li>POJOs
<li>Beans
<li>Arrays, Maps, and Collections of anything
<li>Binary data
</ul>
<li>
Transactional modifications with commit/rollback capabilities.
<li>
A listener API.
<li>
Filesystem watcher integration allowing changes on the file system to be reflected in real-time.
<li>
Modifications through the Config class (e.g. add/remove/modify sections and keys, add/remove comments and whitespace, etc...)
<b>DO NOT</b> cause loss of formatting in the file.
<br>All existing whitespace and comments are preserved for you!
<li>
Value encoding for added security.
<li>
Support for SVL variables.
<li>
Directly populate beans from config sections.
<li>
Accessing config sections through Java interface proxies.
<li>
An extensible storage API allows you to write your own config storage (e.g. storage in databases or the cloud).
</ul>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-config.Overview.SyntaxRules' id='juneau-config.Overview.SyntaxRules'>5.1.1 - Syntax Rules</a></h4>
<div class='topic'><!-- START: 5.1.1 - juneau-config.Overview.SyntaxRules -->
<ul class='spaced-list'>
<li>
Each config file contains zero or more sections containing zero or more entries:
<p class='bcode w800'>
<cs>[Section1]</cs>
<ck>key1</ck> = <cv>1</cv>
<cs>[Section2]</cs>
<ck>key1</ck> = <cv>2</cv>
</p>
<li>
Unicode escapes can be used in values.
<p class='bcode w800'>
<ck>key1</ck> = <cv>\u0070\u0075\u0062\u006c\u0069\u0063</cv>
</p>
<li>
Comment lines start with the <js>'#'</js> character and can be placed on lines before sections and entries:
<p class='bcode w800'>
<cc># A comment about this section</cc>
<cs>[Section1]</cs>
<cc># A comment about this entry</cc>
<ck>key1</ck> = <cv>1</cv>
</p>
<li>
Comments can also be placed on the same line as entries:
<p class='bcode w800'>
<ck>key1</ck> = <cv>1</cv> <cc># A comment about this entry</cc>
</p>
<li>
Values containing <js>'#'</js> must be escaped to prevent identification as a comment character:
<p class='bcode w800'>
<ck>valueContainingPound</ck> = <cv>Value containing \u0023 character</cv>
</p>
<br>Likewise, <js>'\'</js> should be escaped to prevent confusion with unicode escapes.
<li>
Values containing newlines can span multiple lines.
<br>Subsequent lines start with a tab character.
<p class='bcode w800'>
<ck>multiLineValue</ck> =
<cv>line 1,</cv>
<cv>line 2,</cv>
<cv>line 3</cv>
</p>
<br>When retrieved, the above translates to <js>"line1,\nline2,\nline3"</js>.
<li>
Leading and trailing whitespace on values are ignored.
<li>
Whitespace is not ignored within multi-line values (except for the leading tab character on each line).
<li>
Blank lines can be used anywhere in the file.
<p class='bcode w800'>
<cc># A comment line</cc>
<cc># Another comment line</cc>
<cs>[Section1]</cs>
...
</p>
<li>
Values located before any sections are considered part of the no-name section, meaning
they are accessed simply by key and not section/key.
<p class='bcode w800'>
<cc># Top of file</cc>
<cc># Use config.getString("key1") to retrieve.</cc>
<ck>key1</ck> = <cv>val1</cv>
<cc># The first section</cc>
<cs>[Section1]</cs>
<cc># Use config.getString("Section1/key2") to retrieve.</cc>
<ck>key2</ck> = <cv>val2</cv>
</p>
<li>
Section and key names must be at least one character long and not consist of any of the following
characters:
<p class='bcode w800'>
/ \ [ ] = #
</p>
<li>
Whitespace in section and key names is technically allowed but discouraged.
</ul>
</div><!-- END: 5.1.1 - juneau-config.Overview.SyntaxRules -->
</div><!-- END: 5.1 - juneau-config.Overview -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.EntryTypes' id='juneau-config.EntryTypes'>5.2 - Entry Types</a></h3>
<div class='topic'><!-- START: 5.2 - juneau-config.EntryTypes -->
<p>
Configuration files can contain entries for anything from primitive types up to complex hierarchies of POJOs consisting of maps, collections, and/or beans.
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-config.EntryTypes.PrimitiveTypes' id='juneau-config.EntryTypes.PrimitiveTypes'>5.2.1 - Primitive Types</a></h4>
<div class='topic'><!-- START: 5.2.1 - juneau-config.EntryTypes.PrimitiveTypes -->
<p>
The most common case for configuration values are primitives.
</p>
<p class='bpcode w800'>
<cc># A string</cc>
<ck>key1</ck> = <cv>foo</cv>
<cc># A boolean</cc>
<ck>key2</ck> = <cv>true</cv>
<cc># An integer</cc>
<ck>key3</ck> = <cv>123</cv>
<cc># A long</cc>
<ck>key4</ck> = <cv>10000000000</cv>
<cc># Doubles</cc>
<ck>key5</ck> = <cv>6.67e−11</cv>
<ck>key6</ck> = <cv>Infinity</cv>
</p>
<p>
The following methods are provided for accessing primitive values:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.Config}
<ul>
<li class='jm'>{@link org.apache.juneau.config.Config#getString(String) getString(String)}
<li class='jm'>{@link org.apache.juneau.config.Config#getString(String,String) getString(String,String)}
<li class='jm'>{@link org.apache.juneau.config.Config#getBoolean(String) getBoolean(String)}
<li class='jm'>{@link org.apache.juneau.config.Config#getBoolean(String,boolean) getBoolean(String,boolean)}
<li class='jm'>{@link org.apache.juneau.config.Config#getInt(String) getInt(String)}
<li class='jm'>{@link org.apache.juneau.config.Config#getInt(String,int) getInt(String,int)}
<li class='jm'>{@link org.apache.juneau.config.Config#getLong(String) getLong(String)}
<li class='jm'>{@link org.apache.juneau.config.Config#getLong(String,long) getLong(String,long)}
<li class='jm'>{@link org.apache.juneau.config.Config#getFloat(String) getFloat(String)}
<li class='jm'>{@link org.apache.juneau.config.Config#getFloat(String,float) getFloat(String,long)}
<li class='jm'>{@link org.apache.juneau.config.Config#getDouble(String) getDouble(String)}
<li class='jm'>{@link org.apache.juneau.config.Config#getDouble(String,double) getDouble(String,long)}
</ul>
</ul>
<p>
On integers and longs, <js>"K"</js>, <js>"M"</js>, and <js>"G"</js> can be used to identify kilo, mega, and giga.
</p>
<p class='bpcode w800'>
<ck>key1</ck> = <cv>100K</cv> <cc># Same as 1024000</cc>
<ck>key2</ck> = <cv>100M</cv> <cc># Same as 104857600</cc>
</p>
<p>
Numbers can also use hexadecimal and octal notation:
</p>
<p class='bpcode w800'>
<ck>hex1</ck> = <cv>0x12FE</cv>
<ck>hex2</ck> = <cv>0X12FE</cv>
<ck>octal1</ck> = <cv>01234</cv>
</p>
<p>
Strings with newlines are treated as multi-line values that get broken into separate lines:
</p>
<p class='bpcode w800'>
<ck>key1</ck> = <cv>This is a particularly long sentence that we want to split</cv>
<cv>onto separate lines</cv>.
</p>
<p>
Typically, multi-line values are started on the next line for clarity like so:
</p>
<p class='bpcode w800'>
<ck>key1</ck> =
<cv>This is a particularly long sentence that we want to split</cv>
<cv>onto separate lines</cv>.
</p>
</div><!-- END: 5.2.1 - juneau-config.EntryTypes.PrimitiveTypes -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-config.EntryTypes.POJOs' id='juneau-config.EntryTypes.POJOs'>5.2.2 - POJOs</a></h4>
<div class='topic'><!-- START: 5.2.2 - juneau-config.EntryTypes.POJOs -->
<p>
The following methods are provided for accessing POJO values:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.Config}
<ul>
<li class='jm'>{@link org.apache.juneau.config.Config#getObject(String,Class) getObject(String,Class)}
<li class='jm'>{@link org.apache.juneau.config.Config#getObjectWithDefault(String,Object,Class) getObjectWithDefault(String,T,Class)}
</ul>
</ul>
<p>
In theory, any {@doc PojoCategories parsable} POJO type can be represented
as a config value.
However in practice, we're typically talking about the following:
</p>
<ul>
<li>Objects convertible from Strings.
<li>Beans.
</ul>
<p>
An example of an object convertible from a String was already shown in an example above.
In that case, it was a URL which has a public constructor that takes in a String:
</p>
<p class='bpcode w800'>
<cc># A POJO</cc>
<ck>key4</ck> = <cv>http://bar</cv>
</p>
<p class='bpcode w800'>
<jc>// Read values from section #1</jc>
URL key4 = c.getObject(<js>"Section1/key4"</js>, URL.<jk>class</jk>);
</p>
<p>
Beans are represented as {@doc juneau-marshall.JsonDetails.SimplifiedJson Simplified JSON} by default:
</p>
<p class='bpcode w800'>
<jc>// Contact information</jc>
<cs>[ContactInfo]</cs>
<ck>address</ck> =
<cv>{
street: '123 Main Street',
city: 'Anywhere',
state: 'NY',
zip: 12345
}</cv>
</p>
<p class='bpcode w800'>
<jc>// Example bean</jc>
<jk>public class</jk> Address {
<jk>public</jk> String <jf>street</jf>, <jf>city</jf>;
<jk>public</jk> StateEnum <jf>state</jf>;
<jk>public int</jk> <jf>zip</jf>;
}
<jc>// Example usage</jc>
Config c = Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).build();
Address myAddress = c.getObject(<js>"ContactInfo/address"</js>, Address.<jk>class</jk>);
</p>
<p>
The format for beans depends on the serializer and parser registered on the Config which
is defined in the builder via the following methods:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.ConfigBuilder}
<ul>
<li class='jm'>{@link org.apache.juneau.config.ConfigBuilder#serializer(Class) serializer(Class)}
<li class='jm'>{@link org.apache.juneau.config.ConfigBuilder#serializer(WriterSerializer) serializer(WriterSerializer)}
<li class='jm'>{@link org.apache.juneau.config.ConfigBuilder#parser(Class) parser(Class)}
<li class='jm'>{@link org.apache.juneau.config.ConfigBuilder#parser(ReaderParser) parser(ReaderParser)}
</ul>
</ul>
<p>
The default parser can also be overridden on the following getters:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.Config}
<ul>
<li class='jm'>{@link org.apache.juneau.config.Config#getObject(String,Parser,Class) getObject(String,Parser,Class)}
<li class='jm'>{@link org.apache.juneau.config.Config#getObjectWithDefault(String,Parser,Object,Class) getObjectWithDefault(String,T,Parser,Class)}
</ul>
</ul>
</div><!-- END: 5.2.2 - juneau-config.EntryTypes.POJOs -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-config.EntryTypes.Arrays' id='juneau-config.EntryTypes.Arrays'>5.2.3 - Arrays</a></h4>
<div class='topic'><!-- START: 5.2.3 - juneau-config.EntryTypes.Arrays -->
<p>
The following methods are provided for accessing arrays:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.Config}
<ul>
<li class='jm'>{@link org.apache.juneau.config.Config#getStringArray(String) getStringArray(String)}
<li class='jm'>{@link org.apache.juneau.config.Config#getStringArray(String,String[]) getStringArray(String,String)}
<li class='jm'>{@link org.apache.juneau.config.Config#getObject(String,Class) getObject(String,Class)}
<li class='jm'>{@link org.apache.juneau.config.Config#getObject(String,Parser,Class) getObject(String,Parser,Class)}
</ul>
</ul>
<p>
The <c>getStringArray()</c> methods allow you to retrieve comma-delimited lists of values:
<p class='bpcode w800'>
<ck>key1</ck> = <cv>foo, bar, baz</cv>
</p>
<p class='bpcode w800'>
String[] key1 = c.getStringArray(<js>"key1"</js>);
</p>
<p>
String arrays can also be represented in JSON when using the <c>getObject()</c> methods:
</p>
<p class='bpcode w800'>
<ck>key1</ck> = <cv>['foo','bar','baz']</cv>
</p>
<p class='bpcode w800'>
String[] key1 = c.getObject(<js>"key1"</js>, String[].<jk>class</jk>);
</p>
<p>
Primitive arrays can also be retrieved using the <c>getObject()</c> methods:
</p>
<p class='bpcode w800'>
<ck>key1</ck> = <cv>[1,2,3]</cv>
</p>
<p class='bpcode w800'>
<jk>int</jk>[] key1 = c.getObject(<js>"key1"</js>, <jk>int</jk>[].<jk>class</jk>);
</p>
<p>
Arrays of POJOs can also be retrieved using the <c>getObject()</c> methods:
</p>
<p class='bpcode w800'>
<ck>addresses</ck> =
<cv>[
{
street: '123 Main Street',
city: 'Anywhere',
state: 'NY',
zip: 12345
}</cv>,
<cv>{
street: '456 Main Street',
city: 'Anywhere',
state: 'NY',
zip: 12345
}
]</cv>
</p>
<p class='bpcode w800'>
Address[] addresses = c.getObject(<js>"addresses"</js>, Address[].<jk>class</jk>);
</p>
</div><!-- END: 5.2.3 - juneau-config.EntryTypes.Arrays -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-config.EntryTypes.Collections' id='juneau-config.EntryTypes.Collections'>5.2.4 - Collections</a></h4>
<div class='topic'><!-- START: 5.2.4 - juneau-config.EntryTypes.Collections -->
<p>
The following methods are provided for accessing maps and collections:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.Config}
<ul>
<li class='jm'>{@link org.apache.juneau.config.Config#getObject(String,Type,Type...) getObject(String,Type,Type...)}
<li class='jm'>{@link org.apache.juneau.config.Config#getObject(String,Parser,Type,Type...) getObject(String,Parser,Type,Type...)}
<li class='jm'>{@link org.apache.juneau.config.Config#getObjectWithDefault(String,Object,Type,Type...) getObjectWithDefault(String,T,Type,Type...)}
<li class='jm'>{@link org.apache.juneau.config.Config#getObjectWithDefault(String,Parser,Object,Type,Type...) getObjectWithDefault(String,T,Parser,Type,Type...)}
</ul>
</ul>
<p>
The <c>Type,Type...</c> arguments allow you to specify the component types for maps and collections.
<c>List</c> class arguments can be followed by zero or one arguments representing the entry types.
<c>Map</c> class arguments can be followed by zero or two arguments representing the key and value types.
The arguments can be chained to produce any data structure consisting of maps, collections, or POJOs.
</p>
<p>
Examples are shown below:
</p>
<ul class='spaced-list'>
<li><c>getObject(<js>"..."</js>, List.<jk>class</jk>)</c>
<br>Produces: <c>List&lt;?&gt;</c>
<li><c>getObject(<js>"..."</js>, LinkedList.<jk>class</jk>)</c>
<br>Produces: <c>LinkedList&lt;?&gt;</c>
<li><c>getObject(<js>"..."</js>, HashSet.<jk>class</jk>, Integer.<jk>class</jk>)</c>
<br>Produces: <c>HashSet&lt;Integer&gt;</c>
<li><c>getObject(<js>"..."</js>, Map.<jk>class</jk>)</c>
<br>Produces: <c>Map&lt;?,?&gt;</c>
<li><c>getObject(<js>"..."</js>, HashMap.<jk>class</jk>)</c>
<br>Produces: <c>HashMap&lt;?,?&gt;</c>
<li><c>getObject(<js>"..."</js>, LinkedHashMap.<jk>class</jk>, String.<jk>class</jk>, MyBean.<jk>class</jk>)</c>
<br>Produces: <c>LinkedHashMap&lt;String,MyBean&gt;</c>
<li><c>getObject(<js>"..."</js>, HashMap.<jk>class</jk>, Integer.<jk>class</jk>, ArrayList.<jk>class</jk>, MyBean[].<jk>class</jk>)</c>
<br>Produces: <c>LinkedHashMap&lt;Integer,ArrayList&lt;MyBean[]&gt;&gt;</c>
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ck>addresses</ck> =
<cv>[
{
street: '123 Main Street',
city: 'Anywhere',
state: 'NY',
zip: 12345
}</cv>,
<cv>{
street: '456 Main Street',
city: 'Anywhere',
state: 'NY',
zip: 12345
}
]</cv>
</p>
<p class='bpcode w800'>
List&lt;Address&gt; addresses = c.getObject(<js>"addresses"</js>, ArrayList.<jk>class</jk>, Address.<jk>class</jk>);
</p>
<p>
Oftentimes, it might be useful to parse into the {@link org.apache.juneau.ObjectList} and {@link org.apache.juneau.ObjectMap}
classes that provide the various convenience methods for working with JSON-like data structures:
</p>
<p class='bpcode w800'>
ObjectMap m = c.getObject(<js>"key1"</js>, ObjectMap.<jk>class</jk>);
ObjectList l = c.getObject(<js>"key2"</js>, ObjectList.<jk>class</jk>);
</p>
</div><!-- END: 5.2.4 - juneau-config.EntryTypes.Collections -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-config.EntryTypes.BinaryData' id='juneau-config.EntryTypes.BinaryData'>5.2.5 - Binary Data</a></h4>
<div class='topic'><!-- START: 5.2.5 - juneau-config.EntryTypes.BinaryData -->
<p>
The following methods are provided for accessing binary data:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.Config}
<ul>
<li class='jm'>{@link org.apache.juneau.config.Config#getBytes(String) getBytes(String)}
<li class='jm'>{@link org.apache.juneau.config.Config#getBytes(String,byte[]) getBytes(String,byte[])}
</ul>
</ul>
<p>
Binary data can be represented in 3 formats:
</p>
<ul class='spaced-list'>
<li>BASE-64 (default)
<br>Example: <c><js>"Zm9vYmFycw=="</js></c>
<li>Hexadecimal
<br>Example: <c><js>"666F6F62617273"</js></c>
<li>Spaced hexadecimal
<br>Example: <c><js>"66 6F 6F 62 61 72 73"</js></c>
</ul>
<p>
The binary data format is controlled via the following setting:
</p>
<ul class='javatree'>
<li class='jf'>{@link org.apache.juneau.config.Config#CONFIG_binaryFormat}
</ul>
<p>
For example:
</p>
<p class='bpcode w800'>
<ck>key</ck> = <cv>Zm9vYmFycw==</cv>
</p>
<p class='bpcode w800'>
<jk>byte</jk>[] bytes = c.getBytes(<js>"key"</js>);
</p>
<p>
Binary lines can be split up into separate lines for readability:
</p>
<p class='bpcode w800'>
<ck>key</ck> =
<cv>Zm9vYm
Fycw==</cv>
</p>
<p>
Binary data line wrapping can be controlled via the following setting:
</p>
<ul class='javatree'>
<li class='jf'>{@link org.apache.juneau.config.Config#CONFIG_binaryLineLength}
</ul>
</div><!-- END: 5.2.5 - juneau-config.EntryTypes.BinaryData -->
</div><!-- END: 5.2 - juneau-config.EntryTypes -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.Variables' id='juneau-config.Variables'>5.3 - Variables</a></h3>
<div class='topic'><!-- START: 5.3 - juneau-config.Variables -->
<p>
Config files can contain variables that get resolved dynamically using the previously-described {@link org.apache.juneau.svl.VarResolver} API.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<cc>#--------------------------</cc>
<cc># My section</cc>
<cc>#--------------------------</cc>
<cs>[MySection]</cs>
<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># Another value in this config file</cc>
<ck>anotherLocale</ck> = <cv>$C{MySection/locale}</cv>
<cc># Look for system property, or env var if that doesn't exist, or a default value if that doesn't exist.</cc>
<ck>nested</ck> = <cv>$S{mySystemProperty,$E{MY_ENV_VAR,$C{MySection/anotherLocale}}}</cv>
<cc># A POJO with embedded variables</cc>
<ck>aBean</ck> = <cv>{foo:'$S{foo}',baz:$C{MySection/anInt}}</cv>
</p>
<p class='bpcode w800'>
Config c = Config.<jsf>create</jsf>().build();
Locale locale = cf.getObject(<js>"MySection/locale"</js>, Locale.<jk>class</jk>);
String path = cf.getString(<js>"MySection/path"</js>);
<jk>int</jk> sameAsAnInt = cf.getInt(<js>"MySection/sameAsAnInt"</js>);
ABean bean = cf.getObject(<js>"MySection/aBean"</js>, ABean.<jk>class</jk>);
</p>
<p>
By default, <c>Configs</c> use the {@link org.apache.juneau.svl.VarResolver#DEFAULT} variable resolver
which provides support for the following variables and constructs:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.svl.vars.SystemPropertiesVar} - <c>$S{key[,default]}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.EnvVariablesVar} - <c>$E{key[,default]}</c>
<li class='jc'>{@link org.apache.juneau.config.vars.ConfigVar} - <c>$C{key[,default]}</c>
</ul>
<p>
The variable resolver is controlled via the following setting:
</p>
<ul class='javatree'>
<li class='jf'>{@link org.apache.juneau.config.Config#CONFIG_varResolver}
</ul>
<p>
Additionally, the following method can be used to retrieve a <c>Config</c> with a different variable resolver:
</p>
<ul class='javatree'>
<li class='jm'>{@link org.apache.juneau.config.Config#resolving(VarResolverSession)}
</ul>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-config.Variables.LogicVariables' id='juneau-config.Variables.LogicVariables'>5.3.1 - Logic Variables</a></h4>
<div class='topic'><!-- START: 5.3.1 - juneau-config.Variables.LogicVariables -->
<p>
The default variable resolver also provides the following logic variables for performing simple logical operations:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.svl.vars.IfVar} - <c>$IF{arg,then[,else]}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.SwitchVar} - <c>$SW{arg,pattern1:then1[,pattern2:then2...]}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.CoalesceVar} - <c>$CO{arg1[,arg2...]}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.PatternMatchVar} - <c>$PM{arg,pattern}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.NotEmptyVar} - <c>$NE{arg}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.UpperCaseVar} - <c>$UC{arg}</c>
<li class='jc'>{@link org.apache.juneau.svl.vars.LowerCaseVar} - <c>$LC{arg}</c>
</ul>
<p>
The <c>$IF</c> variable can be used for simple if/else logic:
</p>
<p class='bpcode w800'>
<cc># Value set to 'foo' if myBooleanProperty is true</cc>
<ck>key1</ck> =
<cv>$IF{
$S{myBooleanProperty},
foo
}</cv>
<cc># Value set to 'foo' if myBooleanProperty is true, 'bar' if false.</cc>
<ck>key2</ck> =
<cv>$IF{
$S{myBooleanProperty},
foo,
bar
}</cv>
<cc># Value set to key1 value if myBooleanProperty is true, key2 value if false.</cc>
<ck>key3</ck> =
<cv>$IF{
$S{myBooleanProperty},
$C{key1},
$C{key2}
}</cv>
</p>
<p>
The <c>$SW</c> variable can be used for switch blocks based on pattern matching:
</p>
<p class='bpcode w800'>
<cc># Shell command depends on the OS</cc>
<ck>shellCommand</ck> =
<cv>$SW{
$LC{$S{os.name}},
*win*: bat,
linux: bash,
*: sh
}</cv>
</p>
<p>
The <c>$CO</c> variable can be used for coalescing of values (finding the first non-null/empty match):
</p>
<p class='bpcode w800'>
<cc># Debug flag can be enabled by system property or environment variable.</cc>
<ck>debug</ck> =
<cv>$CO{
$S{debug},
$E{DEBUG},
false
}</cv>
</p>
<p>
The <c>$PM</c> variable can be used for calculating boolean values:
</p>
<p class='bpcode w800'>
<cc># Debug flag can be enabled by system property or environment variable.</cc>
<ck>isWindows</ck> =
<cv>$PM{
$LC{$S{os.name}},
*win*
}</cv>
</p>
</div><!-- END: 5.3.1 - juneau-config.Variables.LogicVariables -->
</div><!-- END: 5.3 - juneau-config.Variables -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.EncodedEntries' id='juneau-config.EncodedEntries'>5.4 - Encoded Entries</a></h3>
<div class='topic'><!-- START: 5.4 - juneau-config.EncodedEntries -->
<p>
Encoded entries allow for sensitive information such as passwords to be obfuscated.
</p>
<p>
Encoded entries are denoted with a <js>'*'</js> character at the end of the key name.
</p>
<p>
For example, the following password is marked for encoding:
</p>
<p class='bpcode w800'>
<cs>[MyHost]</cs>
<ck>url</ck> = <cv>http://localhost:9080/foo</cv>
<ck>user</ck> = <cv>me</cv>
<ck>password*</ck> = <cv>{AwwJVhwUQFZEMg==}</cv>
</p>
<p>
The default encoder is {@link org.apache.juneau.config.encode.ConfigXorEncoder} which is a simple XOR+Base64 encoder.
</p>
<p>
Custom encoders can be used to provide your own encoding support by implementing the {@link org.apache.juneau.config.encode.ConfigEncoder} interface.
</p>
<ul class='javatree'>
<li class='jic'>{@link org.apache.juneau.config.encode.ConfigEncoder}
<ul>
<li class='jm'>{@link org.apache.juneau.config.encode.ConfigEncoder#encode(String,String) encode(String,String)}
<li class='jm'>{@link org.apache.juneau.config.encode.ConfigEncoder#decode(String,String) decode(String,String)}
<li class='jm'>{@link org.apache.juneau.config.encode.ConfigEncoder#isEncoded(String) isEncoded(String)}
</ul>
</ul>
<p>
Encoders are controlled via the following setting:
</p>
<ul class='javatree'>
<li class='jf'>{@link org.apache.juneau.config.Config#CONFIG_encoder}
</ul>
<p>
Encoded values can be set to plain-text values.
The curly brackets around the value identify whether the value has been encoded or not.
</p>
<p>
Unencoded values are encoded when the file is saved using the {@link org.apache.juneau.config.Config#commit()} method.
They can also be encoded immediately by calling {@link org.apache.juneau.config.Config#encodeEntries()}.
</p>
</div><!-- END: 5.4 - juneau-config.EncodedEntries -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.SectionMaps' id='juneau-config.SectionMaps'>5.5 - Section Maps</a></h3>
<div class='topic'><!-- START: 5.5 - juneau-config.SectionMaps -->
<p>
Config sections can be retrieved in-bulk using
{@link org.apache.juneau.config.Config#getSectionAsMap(String)}.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Example config file</jc>
<cs>[MyAddress]</cs>
<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>
</p>
<p class='bpcode w800'>
<jc>// Example usage</jc>
Config c = Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).build();
ObjectMap m = c.getSectionAsMap(<js>"MyAddress"</js>);
String street = m.getString(<js>"street"</js>);
String city = m.getString(<js>"city"</js>);
String state = m.getString(<js>"state"</js>);
<jk>int</jk> zip = m.getInt(<js>"zip"</js>);
</p>
<p>
Maps created this way are snapshot copies of the section at the time of the method call.
</p>
</div><!-- END: 5.5 - juneau-config.SectionMaps -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.SectionBeans' id='juneau-config.SectionBeans'>5.6 - Section Beans</a></h3>
<div class='topic'><!-- START: 5.6 - juneau-config.SectionBeans -->
<p>
Config files can also be used to directly populate beans using
{@link org.apache.juneau.config.Config#getSectionAsBean(String,Class,boolean)}.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Example config file</jc>
<cs>[MyAddress]</cs>
<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>
</p>
<p class='bpcode w800'>
<jc>// Example bean</jc>
<jk>public class</jk> Address {
<jk>public</jk> String <jf>street</jf>, <jf>city</jf>;
<jk>public</jk> StateEnum <jf>state</jf>;
<jk>public int</jk> <jf>zip</jf>;
}
<jc>// Example usage</jc>
Config c = Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).build();
Address myAddress = c.getSectionAsBean(<js>"MyAddress"</js>, Address.<jk>class</jk>);
</p>
<p>
Like maps, beans created this way are snapshot copies of the section at the time of the method call.
</p>
</div><!-- END: 5.6 - juneau-config.SectionBeans -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.SectionInterfaces' id='juneau-config.SectionInterfaces'>5.7 - Section Interfaces</a></h3>
<div class='topic'><!-- START: 5.7 - juneau-config.SectionInterfaces -->
<p>
Config sections can also be accessed via interface proxies using
{@link org.apache.juneau.config.Config#getSectionAsInterface(String,Class)}.
</p>
<p>
While section maps and beans retrieve copies of the configuration data at the time of the method
call, section interfaces can also be use to set values in the underlying configuration.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<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>
</p>
<p class='bpcode w800'>
<jc>// Example interface.</jc>
<jc>// Setters are optional.</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>
Config c = Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).build();
MyConfigInterface ci = c.getSectionAsInterface(<js>"MySection"</js>, MyConfigInterface.<jk>class</jk>);
<jc>// Read a value.</jc>
<jk>int</jk> myInt = ci.getInt();
<jc>// Write a value.</jc>
ci.setBean(<jk>new</jk> MyBean());
<jc>// Commit your changes to the store.</jc>
c.commit();
</p>
</div><!-- END: 5.7 - juneau-config.SectionInterfaces -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.SettingValues' id='juneau-config.SettingValues'>5.8 - Setting Values</a></h3>
<div class='topic'><!-- START: 5.8 - juneau-config.SettingValues -->
<p>
The following methods allow you to add, remove, and modify entries and sections in a config file:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.Config}
<ul>
<li class='jm'>{@link org.apache.juneau.config.Config#set(String,Object) set(String,Object)}
<li class='jm'>{@link org.apache.juneau.config.Config#set(String,Object,Serializer) set(String,Object,Serializer)}
<li class='jm'>{@link org.apache.juneau.config.Config#set(String,Object,Serializer,ConfigMod,String,List) set(String,Object,Serializer,ConfigMod,String,List)}
<li class='jm'>{@link org.apache.juneau.config.Config#set(String,Object,Serializer,ConfigMod[],String,List) set(String,Object,Serializer,ConfigMod[],String,List)}
<li class='jm'>{@link org.apache.juneau.config.Config#set(String,String) set(String,String)}
<li class='jm'>{@link org.apache.juneau.config.Config#remove(String) remove(String)}
<li class='jm'>{@link org.apache.juneau.config.Config#setSection(String,List) setSection(String,List)}
<li class='jm'>{@link org.apache.juneau.config.Config#setSection(String,List,Map) setSection(String,List,Map)}
<li class='jm'>{@link org.apache.juneau.config.Config#removeSection(String) removeSection(String)}
</ul>
</ul>
<p class='bpcode w800'>
<jc>// Construct the sample config file programmatically</jc>
Config c = Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).build()
.set(<js>"key1"</js>, 1)
.set(<js>"key2"</js>, <jk>true</jk>)
.set(<js>"key3"</js>, <jk>new int</jk>[]{1,2,3})
.set(<js>"key4"</js>, <jk>new</jk> URI(<js>"http://foo"</js>))
.set(<js>"Section1/key1"</js>, 2)
.set(<js>"Section1/key2"</js>, <jk>false</jk>)
.set(<js>"Section1/key3"</js>, <jk>new int</jk>[]{4,5,6})
.set(<js>"Section1/key4"</js>, <jk>new</jk> URI(<js>"http://bar"</js>))
.commit();
</p>
<p>
The method {@link org.apache.juneau.config.Config#set(String,Object,Serializer,ConfigMod[],String,List)} can be used
for adding comments and pre-lines to entries, and specifying encoded values.
</p>
<p class='bpcode w800'>
<jc>// Set an encoded value with some comments.</jc>
c.set(<js>"key1"</js>, 1, <jk>null</jk>, ConfigMod.<jsf>ENCODED</jsf>, <js>"Same-line comment"</js>,
Arrays.asList(
<js>"# Comment 1"</js>, <js>""</js>, <js>"# Comment 2"</js>
)
);
</p>
<p class='bpcode w800'>
<cc># Comment 1</cc>
<cc># Comment 2</cc>
<ck>key1</ck> = <cv>1</cv> <cc># Same-line comment</cc>
</p>
<p>
The last 4 arguments in {@link org.apache.juneau.config.Config#set(String,Object,Serializer,ConfigMod[],String,List)}
are optional in that if you pass <jk>null</jk>, the current value will not be overwritten.
To unset the same-line comment, you should pass in a blank string.
To remove pre-lines, you should pass in an empty list.
</p>
<p>
Sections can be added with optional pre-lines using the <c>setSection</c> methods:
</p>
<p class='bpcode w800'>
<jc>// Set an encoded value with some comments.</jc>
c.setSection(<js>"NewSection"</js>,
Arrays.asList(
<js>"# Section comment 1"</js>, <js>""</js>, <js>"# Section comment 2"</js>
)
);
</p>
<p class='bpcode w800'>
<cc># Section comment 1</cc>
<cc># Section comment 2</cc>
<cs>[NewSection]</cs>
</p>
<p>
Changes made to the configuration are transactional in nature.
They are kept in memory until you call the {@link org.apache.juneau.config.Config#commit()} method.
Until then, you still see the modified values when you call any of the getters, but the modified values
exist only in memory.
</p>
<p>
Changes can be rolled back using the {@link org.apache.juneau.config.Config#rollback()} method.
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-config.SettingValues.FileSystemChanges' id='juneau-config.SettingValues.FileSystemChanges'>5.8.1 - File System Changes</a></h4>
<div class='topic'><!-- START: 5.8.1 - juneau-config.SettingValues.FileSystemChanges -->
<p>
In general, external file modifications will be detected immediately in the <c>Config</c>
object when a watcher thread is enabled (explained later).
Otherwise, they are detected when a commit is performed.
</p>
<p>
The <c>Config</c> object maintains an in-memory record of all changes that have been applied to it
through getters and setters.
When the underlying file changes, the new contents are loaded and the in-memory changes are then
applied to the new configuration.
This provides the benefits of real-time updates of configurations while not losing any changes made in the JVM.
</p>
<p>
If the <c>commit()</c> method is called on the <c>Config</c> objects after the file system
contents have been modified, we will then reload the configuration from the file system, apply the
changes, and then try to save to the file system again (up to 10 times).
</p>
<p>
If the same entry is both internally and externally modified, the external modification will be
overwritten (although both change events will be seen by listeners).
</p>
</div><!-- END: 5.8.1 - juneau-config.SettingValues.FileSystemChanges -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-config.SettingValues.CustomEntrySerialization' id='juneau-config.SettingValues.CustomEntrySerialization'>5.8.2 - Custom Entry Serialization</a></h4>
<div class='topic'><!-- START: 5.8.2 - juneau-config.SettingValues.CustomEntrySerialization -->
<p>
Setter methods that take in a <c>Serializer</c> can be used to provide custom serialization of entries
instead of using the predefined serializer.
</p>
<p class='bpcode w800'>
<jc>// Set an XML value instead of JSON.</jc>
c.set(<js>"key1"</js>, myAddress, XmlSerializer.<jsf>DEFAULT_SQ_READABLE</jsf>);
</p>
<p class='bpcode w800'>
<ck>key1</ck> =
<cv>&lt;address&gt;
&lt;street&gt;123 Main Street&lt;/street&gt;
&lt;city&gt;Anywhere&lt;/city&gt;
&lt;state&gt;NY&lt;/state&gt;
&lt;zip&gt;12345&lt;/zip&gt;
&lt;/address&gt;</cv>
</p>
<p>
The value can then be retrieved using the equivalent parser:
</p>
<p class='bpcode w800'>
Address myAddress = c.getObject(<js>"key1"</js>, XmlParser.<jsf>DEFAULT</jsf>, Address.<jk>class</jk>);
</p>
</div><!-- END: 5.8.2 - juneau-config.SettingValues.CustomEntrySerialization -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-config.SettingValues.BulkSettingValues' id='juneau-config.SettingValues.BulkSettingValues'>5.8.3 - Setting Values in Bulk</a></h4>
<div class='topic'><!-- START: 5.8.3 - juneau-config.SettingValues.BulkSettingValues -->
<p>
The following methods can be used to bulk-load configuration values:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.Config}
<ul>
<li class='jm'>{@link org.apache.juneau.config.Config#setSection(String,List,Map) setSection(String,List,Map)}
<li class='jm'>{@link org.apache.juneau.config.Config#load(Map) load(Map)}
<li class='jm'>{@link org.apache.juneau.config.Config#load(Reader,boolean) load(Reader,boolean)}
<li class='jm'>{@link org.apache.juneau.config.Config#load(String,boolean) load(String,boolean)}
</ul>
</ul>
<p>
Changes can then be committed using the {@link org.apache.juneau.config.Config#commit()} method.
</p>
</div><!-- END: 5.8.3 - juneau-config.SettingValues.BulkSettingValues -->
</div><!-- END: 5.8 - juneau-config.SettingValues -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.Listeners' id='juneau-config.Listeners'>5.9 - Listeners</a></h3>
<div class='topic'><!-- START: 5.9 - juneau-config.Listeners -->
<p>
Configuration change events can be listened for using the following methods:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.Config}
<ul>
<li class='jm'>{@link org.apache.juneau.config.Config#addListener(ConfigEventListener) addListener(ConfigEventListener)}
<li class='jm'>{@link org.apache.juneau.config.Config#removeListener(ConfigEventListener) removeListener(ConfigEventListener)}
</ul>
</ul>
<p>
The {@link org.apache.juneau.config.event.ConfigEventListener} interface consists of the following method:
</p>
<ul class='javatree'>
<li class='jic'>{@link org.apache.juneau.config.event.ConfigEventListener}
<ul>
<li class='jm'>{@link org.apache.juneau.config.event.ConfigEventListener#onConfigChange(ConfigEvents) onConfigChange(ConfigEvents)}
</ul>
</ul>
<p>
The {@link org.apache.juneau.config.event.ConfigEvent} class provides access to all the information about the updated entry:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.event.ConfigEvent}
<ul>
<li class='jm'>{@link org.apache.juneau.config.event.ConfigEvent#getType() getType()}
<li class='jm'>{@link org.apache.juneau.config.event.ConfigEvent#getSection() getSection()}
<li class='jm'>{@link org.apache.juneau.config.event.ConfigEvent#getKey() getKey()}
<li class='jm'>{@link org.apache.juneau.config.event.ConfigEvent#getValue() getValue()}
<li class='jm'>{@link org.apache.juneau.config.event.ConfigEvent#getModifiers() getModifiers()}
<li class='jm'>{@link org.apache.juneau.config.event.ConfigEvent#getComment() getComment()}
<li class='jm'>{@link org.apache.juneau.config.event.ConfigEvent#getPreLines() getPreLines}
</ul>
</ul>
<p>
The listener method is triggered:
</p>
<ul class='spaced-list'>
<li>After {@link org.apache.juneau.config.Config#commit()} is called.
<li>When the file changes on the file system.
</ul>
<p>
In both cases, the listener is triggered after the changes have been committed.
</p>
<p class='bpcode w800'>
<jk>final</jk> Config c = Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).build();
<jc>// Add a listener for changes to MySection/key1</jc>
c.addListener(
<jk>new</jk> ConfigEventListener() {
<ja>@Override</ja>
<jk>public void</jk> onConfigChange(ConfigEvents) {
<jk>for</jk> (ConfigEvent event : events) {
<jk>if</jk> (event.getType() == <jsf>SET_ENTRY</jsf>) {
String section = event.getSection();
String key = event.getKey();
<jk>if</jk> (section.equals(<js>"MySection"</js>) &amp;&amp; key.equals(<js>"key1"</js>)) {
<jc>// Get the new value from the event.</jc>
String newVal = event.getValue();
<jc>// Or get the new value from the config (since the change has already been committed).</jc>
newVal = c.getString(<js>"MySection/key1"</js>);
}
}
}
}
}
)
</p>
</div><!-- END: 5.9 - juneau-config.Listeners -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.Serializing' id='juneau-config.Serializing'>5.10 - Serializing</a></h3>
<div class='topic'><!-- START: 5.10 - juneau-config.Serializing -->
<p>
The following methods are used for serializing <c>Config</c> objects back into INI files:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.Config}
<ul>
<li class='jm'>{@link org.apache.juneau.config.Config#writeTo(Writer) writeTo(Writer)}
<li class='jm'>{@link org.apache.juneau.config.Config#toString() toString()}
</ul>
</ul>
<p>
Both methods are thread safe.
</p>
<p>
The <c>Config</c> class implements the {@link org.apache.juneau.Writable} which means it can be
returned as-is by REST methods to be serialized as INI text.
</p>
</div><!-- END: 5.10 - juneau-config.Serializing -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.Imports' id='juneau-config.Imports'>5.11 - Imports</a></h3>
<div class='topic'><!-- START: 5.11 - juneau-config.Imports -->
<p>
Configurations can import values from other configurations using the following syntax:
</p>
<p class='bpcode w800'>
<cc># Import values from configuration 'ParentConfig'</cc>
<ci>&lt;ParentConfig&gt;</ci>
<cc># Our normal section</cc>
<cs>[Section1]</cs>
...
</p>
<p>
A configuration can contain zero or more imports anywhere in the file.
However, for clarity, imports should normally be placed in the default section of the configuration file.
The resolved configuration is retrieved from the configuration store used for the child configuration.
</p>
<p>
Configuration imports can be nested arbitrarily deep.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<cc># MyConfig contents</cc>
<ci>&lt;ParentConfig1&gt;</ci>
</p>
<p class='bpcode w800'>
<cc># ParentConfig1 contents</cc>
<ci>&lt;ParentConfig2&gt;</ci>
</p>
<p class='bpcode w800'>
<cc># ParentConfig2 contents</cc>
<cs>[Foo]</cs>
<ck>bar</ck> = <cv>baz</cv>
</p>
<p class='bpcode w800'>
<jc>// Java code</jc>
Config c = ConfigBuilder.<jsm>create</jsm>(<js>"MyConfig"</js>).build();
String foo = c.getString(<js>"Foo/bar"</js>); <jc>// == "baz"</jc>
</p>
<p>
Values can be overridden by child configurations.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<cc># MyConfig contents</cc>
<ci>&lt;ParentConfig1&gt;</ci>
<cs>[Foo]</cs>
<ck>bar</ck> = <cv>baz</cv>
</p>
<p class='bpcode w800'>
<cc># ParentConfig1 contents</cc>
<ci>&lt;ParentConfig2&gt;</ci>
<cs>[Foo]</cs>
<ck>bar</ck> = <cv>qux</cv>
</p>
<p class='bpcode w800'>
<cc># ParentConfig2 contents</cc>
<cs>[Foo]</cs>
<ck>bar</ck> = <cv>quux</cv>
</p>
<p class='bpcode w800'>
Config c = ConfigBuilder.<jsm>create</jsm>(<js>"MyConfig"</js>).build();
String foo = c.getString(<js>"Foo/bar"</js>); <jc>// == "baz"</jc>
</p>
<p>
Changes made to imported configurations are automatically reflected in the child configuration and
partake in the listener API as if the entries were part of the child configuration.
Only non-overridden values trigger listener events. For example, if an imported configuration
defines a value for <js>"Foo/bar"</js> and the child configuration does not, modifications to
<js>"Foo/bar"</js> value in the parent configuration will trigger a listener event in the child config.
However, if the child configuration does also specify a value for <js>"Foo/bar"</js>, a change to the parent
<js>"Foo/bar"</js> will NOT trigger a listener event because the value ends up not being changed from
the perspective of the child configuration.
</p>
<p>
Values can be overwritten in child configurations, but the values will only be set in that configuration
and not the imported configuration.
</p>
<p>
Dynamically adding an import will cause change events to be generated for imported values.
</p>
<p class='bpcode w800'>
<cc># MyConfig contents starting empty</cc>
</p>
<p class='bpcode w800'>
<cc># ParentConfig contents</cc>
<cs>[Foo]</cs>
<ck>bar</ck> = <cv>baz</cv>
</p>
<p class='bpcode w800'>
<jc>// Create our configuration.</jc>
Config c = ConfigBuilder.<jsm>create</jsm>(<js>"MyConfig"</js>).build();
<jc>// Create a listener that sets a flag if "Foo/bar" is set.</jc>
<jk>final boolean</jk>[] triggered = <jk>new boolean</jk>[1];
ConfigEventListener l = <jk>new</jk> ConfigEventListener() {
<jk>public void</jk> onConfigChange(ConfigEvents events) {
triggered[0] = events.isKeyModified(<js>"Foo"</js>, <js>"bar"</js>));
}
};
c.addListener(l);
<jc>// Dynamically add an import to ParentConfig in the default section.</jc>
c.setImport(<js>""</js>, <js>"ParentConfig"</js>);
c.commit();
<jc>// The new import statement should have triggered a config changes for imported values.</jc>
<jsm>assertTrue</jsm>(triggered[0]);
</p>
<p>
Dynamically removing an import has the same effect as removing keys and generates <jsf>REMOVE_ENTRY</jsf> events.
</p>
<p>
Note that when dynamically adding or removing imports, overridden keys in the child config will be filtered
from the change events.
</p>
</div><!-- END: 5.11 - juneau-config.Imports -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.ConfigStores' id='juneau-config.ConfigStores'>5.12 - Config Stores</a></h3>
<div class='topic'><!-- START: 5.12 - juneau-config.ConfigStores -->
<p>
Configuration files are stored in entities called Stores.
</p>
<p>
The methods that need to be implemented on a store are:
</p>
<ul class='javatree'>
<li class='jac'>{@link org.apache.juneau.config.store.ConfigStore}
<ul>
<li class='jm'>{@link org.apache.juneau.config.store.ConfigStore#read(String) read(String)} - Read a config file.
<li class='jm'>{@link org.apache.juneau.config.store.ConfigStore#write(String,String,String) write(String,String,String)} - Write a config file.
<li class='jm'>{@link org.apache.juneau.config.store.ConfigStore#update(String,String) update(String,String)} - Update the contents of a config file.
</ul>
</ul>
<p>
Read is self-explanatory:
</p>
<p class='bpcode w800'>
<jk>public</jk> String read(String name) {
<jc>// Return the contents of the specified configuration.</jc>
}
</p>
<p>
Write is slightly trickier:
</p>
<p class='bpcode w800'>
<jk>public</jk> String write(String name, String oldContents, String newContents) {
<jc>// If the old contents match the current stored contents, the new contents will get stored,
// and the method returns null indicating success.
// If the old contents DO NOT match the current stored contents (i.e. it was modified in some way),
// the new contents are NOT stored, and the method returns the current stored contents.
// If the old contents are null, then just always write the new contents.</jc>
}
</p>
<p>
The update method is called whenever the stored file gets modified externally:
</p>
<p class='bpcode w800'>
<jk>public</jk> String update(String name, String newContents) {
<jc>// Do something with the updated contents.</jc>
}
</p>
<p>
Two configuration stores are provided by default:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.store.ConfigFileStore} - File-system storage.
<li class='jc'>{@link org.apache.juneau.config.store.ConfigMemoryStore} - In-memory storage.
</ul>
<p>
The store is defined on the <c>Config</c> object via the following setting:
</p>
<ul class='javatree'>
<li class='jf'>{@link org.apache.juneau.config.Config#CONFIG_store}
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Create a config with in-memory storage.</jc>
Config c = Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).store(ConfigMemoryStore.<jsf>DEFAULT</jsf>).build();
</p>
<p>
The default store used is {@link org.apache.juneau.config.store.ConfigFileStore#DEFAULT} which defines
the execution directory as the file system directory to store and retrieve files.
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-config.ConfigStores.ConfigMemoryStore' id='juneau-config.ConfigStores.ConfigMemoryStore'>5.12.1 - ConfigMemoryStore</a></h4>
<div class='topic'><!-- START: 5.12.1 - juneau-config.ConfigStores.ConfigMemoryStore -->
<p>
The {@link org.apache.juneau.config.store.ConfigMemoryStore} class is simply an in-memory storage
location for configuration files.
There is no hard persistence and is used primarily for testing purposes.
</p>
<p>
However, the implementation provides a good idea on how stores work (especially the write method):
</p>
<p class='bpcode w800'>
<jk>public class</jk> ConfigMemoryStore <jk>extends</jk> ConfigStore {
<jc>// Some methods ommitted.</jc>
<jk>private final</jk> ConcurrentHashMap&lt;String,String&gt; <jf>cache</jf> = <jk>new</jk> ConcurrentHashMap&lt;&gt;();
<ja>@Override</ja> <jc>/* ConfigStore */</jc>
<jk>public synchronized</jk> String read(String name) {
<jk>return</jk> <jsm>emptyIfNull</jsm>(<jf>cache</jf>.get(name));
}
<ja>@Override</ja> <jc>/* ConfigStore */</jc>
<jk>public synchronized</jk> String write(String name, String expectedContents, String newContents) {
<jc>// This is a no-op.</jc>
<jk>if</jk> (<jsm>isEquals</jsm>(expectedContents, newContents))
<jk>return null</jk>;
String currentContents = read(name);
<jk>if</jk> (expectedContents != <jk>null</jk> &amp;&amp; ! <jsm>isEquals</jsm>(currentContents, expectedContents))
<jk>return</jk> currentContents;
update(name, newContents);
<jc>// Success!</jc>
<jk>return null</jk>;
}
<ja>@Override</ja> <jc>/* ConfigStore */</jc>
<jk>public synchronized</jk> ConfigMemoryStore update(String name, String newContents) {
<jf>cache</jf>.put(name, newContents);
<jk>super</jk>.update(name, newContents); <jc>// Trigger any listeners.</jc>
<jk>return this</jk>;
}
}
</p>
</div><!-- END: 5.12.1 - juneau-config.ConfigStores.ConfigMemoryStore -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-config.ConfigStores.ConfigFileStore' id='juneau-config.ConfigStores.ConfigFileStore'>5.12.2 - ConfigFileStore</a></h4>
<div class='topic'><!-- START: 5.12.2 - juneau-config.ConfigStores.ConfigFileStore -->
<p>
The {@link org.apache.juneau.config.store.ConfigFileStore} is the typical store used for configuration files.
It provides the following configurable settings:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.store.ConfigFileStore}
<ul>
<li class='jm'>{@link org.apache.juneau.config.store.ConfigFileStore#FILESTORE_charset FILESTORE_charset}
<li class='jm'>{@link org.apache.juneau.config.store.ConfigFileStore#FILESTORE_directory FILESTORE_directory}
<li class='jm'>{@link org.apache.juneau.config.store.ConfigFileStore#FILESTORE_updateOnWrite FILESTORE_updateOnWrite}
<li class='jm'>{@link org.apache.juneau.config.store.ConfigFileStore#FILESTORE_useWatcher FILESTORE_useWatcher}
<li class='jm'>{@link org.apache.juneau.config.store.ConfigFileStore#FILESTORE_watcherSensitivity FILESTORE_watcherSensitivity}
</ul>
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Create a config store with a watcher thread and high sensitivity.</jc>
ConfigFileStore fs = ConfigFileStore.<jsm>create</jsm>().directory(<js>"configs"</js>).useWatcher().watcherSensitivity(<jsf>HIGH</jsf>).build();
<jc>// Create a config using the store defined above.</jc>
Config c = Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).store(fs).build();
</p>
</div><!-- END: 5.12.2 - juneau-config.ConfigStores.ConfigFileStore -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-config.ConfigStores.CustomConfigStores' id='juneau-config.ConfigStores.CustomConfigStores'>5.12.3 - Custom ConfigStores</a></h4>
<div class='topic'><!-- START: 5.12.3 - juneau-config.ConfigStores.CustomConfigStores -->
<p>
The <c>ConfigStore</c> API has been written to allow easy development of custom configuration storage classes.
</p>
<p>
The example below shows a starting point for an implementation based on polling a relational database.
Completing it is left as an exercise:
</p>
<h5 class='figure'>Example Store Class:</h5>
<p class='bpcode w800'>
<jk>public class</jk> ConfigSqlStore <jk>extends</jk> ConfigStore {
<jc>// Configurable properties</jc>
<jk>static final</jk> String
<jsf>CONFIGSQLSTORE_jdbcUrl</jsf> = <js>"ConfigSqlStore.jdbcUrl.s"</js>,
<jsf>CONFIGSQLSTORE_tableName</jsf> = <js>"ConfigSqlStore.tableName.s"</js>,
<jsf>CONFIGSQLSTORE_nameColumn</jsf> = <js>"ConfigSqlStore.nameColumn.s"</js>,
<jsf>CONFIGSQLSTORE_valueColumn</jsf> = <js>"ConfigSqlStore.valueColumn.s"</js>,
<jsf>CONFIGSQLSTORE_pollInterval</jsf> = <js>"ConfigSqlStore.pollInterval.i"</js>;
<jc>// Instance fields</jc>
<jk>private final</jk> String <jf>jdbcUrl</jf>;
<jk>private final</jk> String <jf>tableName</jf>, <jf>nameColumn</jf>, <jf>valueColumn</jf>;
<jk>private final</jk> Timer <jf>watcher</jf>;
<jk>private final</jk> ConcurrentHashMap&lt;String,String&gt; <jf>cache</jf> = <jk>new</jk> ConcurrentHashMap&lt;&gt;();
<jc>// Constructor called from builder.</jc>
<jk>protected</jk> ConfigSqlStore(PropertyStore ps) {
<jk>super</jk>(ps);
<jk>this</jk>.<jf>jdbcUrl</jf> = getStringProperty(<jsf>CONFIGSQLSTORE_jdbcUrl</jsf>, <js>"jdbc:derby:mydb"</js>);
<jk>this</jk>.<jf>tableName</jf> = getStringProperty(<jsf>CONFIGSQLSTORE_tableName</jsf>);
<jk>this</jk>.<jf>nameColumn</jf> = getStringProperty(<jsf>CONFIGSQLSTORE_nameColumn</jsf>);
<jk>this</jk>.<jf>valueColumn</jf> = getStringProperty(<jsf>CONFIGSQLSTORE_valueColumn</jsf>);
<jk>int</jk> pollInterval = getStringProperty(<jsf>CONFIGSQLSTORE_pollInterval</jsf>, 600); <jc>// Time in seconds.</jc>
TimerTask timerTask = <jk>new</jk> TimerTask() {
<ja>@Override</ja>
<jk>public void</jk> run() {
ConfigSqlStore.<jk>this</jk>.poll();
}
};
<jk>this</jk>.<jf>watcher</jf> = <jk>new</jk> Timer(<js>"MyTimer"</js>);
<jf>watcher</jf>.scheduleAtFixedRate(timerTask, 0, pollInterval * 1000);
}
<jk>private synchronized void</jk> poll() {
<jc>// Loop through all our entries and find the latest values.</jc>
<jk>for</jk> (Map.Entry&lt;String,String&gt; e : cache.entrySet()) {
String name = e.getKey();
String cacheContents = e.getValue();
String newContents = getDatabaseValue(name);
<jc>// Change detected!</jc>
<jk>if</jk> (! cacheContents.equals(newContents))
update(name, newContents);
}
}
<jc>// Reads the value from the database.</jc>
<jk>protected</jk> String getDatabaseValue(String name) {
<jc>// Implement me!</jc>
}
<ja>@Override</ja> <jc>/* ConfigStore */</jc>
<jk>public synchronized</jk> String read(String name) {
String contents = <jf>cache</jf>.get(name);
<jk>if</jk> (contents == <jk>null</jk>) {
contents = getDatabaseValue(name);
update(name, contents);
}
<jk>return</jk> contents;
}
<ja>@Override</ja> <jc>/* ConfigStore */</jc>
<jk>public synchronized</jk> String write(String name, String expectedContents, String newContents) {
<jc>// This is a no-op.</jc>
<jk>if</jk> (<jsm>isEquals</jsm>(expectedContents, newContents))
<jk>return null</jk>;
String currentContents = read(name);
<jk>if</jk> (expectedContents != <jk>null</jk> &amp;&amp; ! <jsm>isEquals</jsm>(currentContents, expectedContents))
<jk>return</jk> currentContents;
update(name, newContents);
<jc>// Success!</jc>
<jk>return null</jk>;
}
<ja>@Override</ja> <jc>/* ConfigStore */</jc>
<jk>public synchronized</jk> ConfigSqlStore update(String name, String newContents) {
<jf>cache</jf>.put(name, newContents);
<jk>super</jk>.update(name, newContents); <jc>// Trigger any listeners.</jc>
<jk>return this</jk>;
}
<ja>@Override</ja> <jc>/* Closeable */</jc>
<jk>public synchronized void</jk> close() {
<jk>if</jk> (watcher != <jk>null</jk>)
watcher.cancel();
}
}
</p>
<p>
The purpose of the builder class is to simply set values in the {@link org.apache.juneau.PropertyStore}
that's passed to the <c>ConfigStore</c>:
</p>
<h5 class='figure'>Example Builder Class:</h5>
<p class='bpcode w800'>
<jk>public class</jk> ConfigSqlStoreBuilder <jk>extends</jk> ConfigStoreBuilder {
<jk>public</jk> ConfigSqlStoreBuilder() {
<jk>super</jk>();
}
<jk>public</jk> ConfigSqlStoreBuilder(PropertyStore ps) {
<jk>super</jk>(ps);
}
<jk>public</jk> ConfigSqlStoreBuilder jdbcUrl(String value) {
<jk>super</jk>.set(<jsf>CONFIGSQLSTORE_jdbcUrl</jsf>, value);
<jk>return this</jk>;
}
<jk>public</jk> ConfigSqlStoreBuilder tableName(String value) {
<jk>super</jk>.set(<jsf>CONFIGSQLSTORE_tableName</jsf>, value);
<jk>return this</jk>;
}
<jk>public</jk> ConfigSqlStoreBuilder nameColumn(String value) {
<jk>super</jk>.set(<jsf>CONFIGSQLSTORE_nameColumn</jsf>, value);
<jk>return this</jk>;
}
<jk>public</jk> ConfigSqlStoreBuilder valueColumn(String value) {
<jk>super</jk>.set(<jsf>CONFIGSQLSTORE_valueColumn</jsf>, value);
<jk>return this</jk>;
}
<jk>public</jk> ConfigSqlStoreBuilder pollInterval(<jk>int</jk> value) {
<jk>super</jk>.set(<jsf>CONFIGSQLSTORE_pollInterval</jsf>, value);
<jk>return this</jk>;
}
<ja>@Override</ja> <jc>/* ContextBuilder */</jc>
<jk>public</jk> ConfigFileStore build() {
<jk>return new</jk> ConfigFileStore(getPropertyStore());
}
}
</p>
</div><!-- END: 5.12.3 - juneau-config.ConfigStores.CustomConfigStores -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-config.ConfigStores.ConfigStoreListeners' id='juneau-config.ConfigStores.ConfigStoreListeners'>5.12.4 - ConfigStore Listeners</a></h4>
<div class='topic'><!-- START: 5.12.4 - juneau-config.ConfigStores.ConfigStoreListeners -->
<p>
The <c>ConfigStore</c> class has the following listener methods:
</p>
<ul class='javatree'>
<li class='jac'>{@link org.apache.juneau.config.store.ConfigStore}
<ul>
<li class='jm'>{@link org.apache.juneau.config.store.ConfigStore#register(String,ConfigStoreListener) register(String,ConfigStoreListener)} - Register a listener on the specified config name.
<li class='jm'>{@link org.apache.juneau.config.store.ConfigStore#unregister(String,ConfigStoreListener) unregister(String,ConfigStoreListener)} - Unregister a listener on the specified config name.
</ul>
</ul>
<p>
Note that this is a different listener than {@link org.apache.juneau.config.event.ConfigEventListener}.
In this case, we're just listening for changed files:
</p>
<ul class='javatree'>
<li class='jic'>{@link org.apache.juneau.config.store.ConfigStoreListener}
<ul>
<li class='jm'>{@link org.apache.juneau.config.store.ConfigStoreListener#onChange(String)} - Called when file changes. New contents are passed in.
</ul>
</ul>
<p>
This listener is used by the <c>Config</c> class to listen for changes on the file system so that it can be
updated in real-time.
</p>
</div><!-- END: 5.12.4 - juneau-config.ConfigStores.ConfigStoreListeners -->
</div><!-- END: 5.12 - juneau-config.ConfigStores -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.ReadOnlyConfigs' id='juneau-config.ReadOnlyConfigs'>5.13 - Read-only Configs</a></h3>
<div class='topic'><!-- START: 5.13 - juneau-config.ReadOnlyConfigs -->
<p>
The following settings can be used to create read-only <c>Config</c> objects:
</p>
<ul class='javatree'>
<li class='jf'>{@link org.apache.juneau.config.Config#CONFIG_readOnly}
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Create a read-only config</jc>
Config c = Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).readOnly().build();
</p>
<p>
This causes all methods that make modifications to throw {@link java.lang.UnsupportedOperationException}.
</p>
</div><!-- END: 5.13 - juneau-config.ReadOnlyConfigs -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.ClosingConfigs' id='juneau-config.ClosingConfigs'>5.14 - Closing Configs</a></h3>
<div class='topic'><!-- START: 5.14 - juneau-config.ClosingConfigs -->
<p>
In general, it's good practice to close Config if you're only creating them temporarily so that
their listeners get unregistered from the underlying storage APIs.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Create a transient config.</jc>
Config c = Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).build();
<jc>// Do stuff with it.</jc>
<jc>// Then close the config to unregister the listeners.</jc>
c.close();
</p>
</div><!-- END: 5.14 - juneau-config.ClosingConfigs -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-config.SystemDefaultConfig' id='juneau-config.SystemDefaultConfig'>5.15 - System Default Config</a></h3>
<div class='topic'><!-- START: 5.15 - juneau-config.SystemDefaultConfig -->
<p>
Each JVM has a system default config. This is a configuration file that serves as the default
configuration for the system. It's accessed using the following static methods:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.Config}
<ul>
<li class='jm'>{@link org.apache.juneau.config.Config#getSystemDefault() getSystemDefault()}
<li class='jm'>{@link org.apache.juneau.config.Config#setSystemDefault(Config) setSystemDefault(Config)}
</ul>
</ul>
<p>
If you do not specify a system default config, one will be automatically searched for.
The search is done in the following order:
</p>
<ol class='spaced-list'>
<li>
If the system property <js>"juneau.configFile"</js> is set, we search for this file in first the home
directory and then the classpath.
<li>
In the home directory:
<ol>
<li><c>&lt;jar-name&gt;.cfg</c>
<li>Any file that end with <c>.cfg</c>. First one matched alphabetically is used.
</ol>
<li>
In the context classpath root package (i.e. inside the jar itself):
<ol>
<li><c>&lt;jar-name&gt;.cfg</c>
<li><c>juneau.cfg</c>
<li><c>default.cfg</c>
<li><c>application.cfg</c>
<li><c>app.cfg</c>
<li><c>settings.cfg</c>
<li><c>application.properties</c>
</ol>
</ol>
<p>
Later in the section on REST resources, we describe how to associate configurations with REST resources
using the {@link org.apache.juneau.rest.annotation.Rest#config() @Rest(config)} annotation.
The system default configuration can be referenced with the keyword <c>SYSTEM_DEFAULT</c> like so:
</p>
<p class='bpcode w800'>
<jc>// Always use system default.</jc>
<ja>@Rest</ja>(config=<js>"SYSTEM_DEFAULT"</js>)
<jc>// Use system property if set or the system default if not.</jc>
<ja>@Rest</ja>(config=<js>"$S{juneau.configFile,SYSTEM_DEFAULT}"</js>)
</p>
<p>
By default, all properties in the system default configuration are automatically set as system properties.
This can be disabled by setting the system property <js>"juneau.disableAutoSystemProps"</js> to <js>"true"</js>.
</p>
</div><!-- END: 5.15 - juneau-config.SystemDefaultConfig -->
</div><!-- END: 5 - juneau-config -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server' id='juneau-rest-server'>6 - juneau-rest-server</a></h2>
<div class='topic'><!-- START: 6 - juneau-rest-server -->
<h5 class='figure'>Maven Dependency</h5>
<p class='bpcode w500'>
<xt>&lt;dependency&gt;</xt>
<xt>&lt;groupId&gt;</xt>org.apache.juneau<xt>&lt;/groupId&gt;</xt>
<xt>&lt;artifactId&gt;</xt>juneau-rest-server<xt>&lt;/artifactId&gt;</xt>
<xt>&lt;version&gt;</xt>{@property juneauVersion}<xt>&lt;/version&gt;</xt>
<xt>&lt;/dependency&gt;</xt>
</p>
<h5 class='figure'>Java Library</h5>
<p class='bpcode w500'>
juneau-rest-server-{@property juneauVersion}.jar
</p>
<h5 class='figure'>OSGi Module</h5>
<p class='bpcode w500'>
org.apache.juneau.rest.server_{@property juneauVersion}.jar
</p>
<p>
The <l>juneau-rest-server</l> library allows you to quickly wrap POJOs and expose them as full-fledged REST
resources served up in a servlet container using a bare-minimum amount of code.
The primary goal for Juneau was to make it as easy as possible to implement easy-to-read and self-documenting
REST resources using very little code.
</p>
<p>
One of the biggest advantages of the Juneau REST framework over similar architectures is that it hides the
serialization layer from the developer.
The developer can work entirely with POJOs and let the Juneau framework handle all the serialization and
parsing work.
The developer need never know what the <l>Accept</l> or <l>Content-Type</l> or <l>Accept-Encoding</l> (etc...)
header values are because those details are all handled by the framework.
</p>
<p>
The API builds upon the existing JEE Servlet API.
The root class, {@link org.apache.juneau.rest.RestServlet} is nothing but a specialized
{@link javax.servlet.http.HttpServlet}, and the {@link org.apache.juneau.rest.RestRequest} and
{@link org.apache.juneau.rest.RestResponse} classes are nothing more than specialized
{@link javax.servlet.http.HttpServletRequest} and {@link javax.servlet.http.HttpServletResponse} objects.
This allows maximum flexibility for the developer since you can let Juneau handle operations such as
serialization, or you can revert to the existing servlet APIs to do low-level processing of requests yourself.
It also means you need nothing more than a Servlet container such as Jetty to use the REST framework.
</p>
<h5 class='topic'>Features</h5>
<ul class='spaced-list'>
<li>
Serializes POJOs to JSON, XML, HTML, URL-Encoding, UON, RDF/XML, N-Triple, Turtle, N3, SOAP, or
Java-serialized-object based on value of <l>Accept</l> header.
<br>No user code is required to handle these types.
<ul>
<li>Extensible design that provides ability to override existing content type handlers, or add the
ability to handle other kinds of content types.
</ul>
<li>
Parses content of POST/PUT request bodies to POJOs.
<li>
Automatic built-in ability to serialize POJO metadata to JSON+SCHEMA, XML+SCHEMA, or HTML+SCHEMA based on
<l>Accept</l> header.
<li>
Automatic negotiation of output Writer based on HTTP headers.
<ul>
<li>Automatic handling of <l>Accept-Charset</l> header for all character sets supported by the JVM.
<li>Automatic handling of <l>Accept-Encoding</l> header with registered encoders.
</ul>
<li>
Automatic error handling.
<ul>
<li>Automatic 401 errors (Unauthorized) on failed guards.
<li>Automatic 404 errors (Not Found) on unmatched path patterns.
<li>Automatic 405 errors (Method Not Implemented) on unimplemented methods.
<li>Automatic 406 errors (Not Acceptable) when no matching serializer was found to handle the
<l>Accept</l> header.
<li>Automatic 412 errors (Precondition Failed) when all matchers failed to match.
<li>Automatic 415 errors (Unsupported Media Type) when no matching parser was found was found to handle
the <l>Content-Type</l> header.
<li>Automatic 500 errors on uncaught exceptions.
</ul>
<li>
Support for parsing all HTTP parts (headers, query, formData, path variables) using Swagger formatting rules and validations.
<br>Not limited to simple POJOs, but rather you can represent arbitrarily-complex POJOs in any HTTP part using UON notation.
<li>
Auto-created Swagger JSON and Swagger UI available through OPTIONS requests of resources.
<li>
Various useful debugging features that make debugging using a browser extremely simple...
<ul>
<li>Ability to pass HTTP header values as URL GET parameters (e.g. <l>&amp;Accept=text/xml</l>).
<li>Ability to pass HTTP content on PUT/POST requests as a URL GET parameter
(e.g. <l>&amp;content=(foo=bar)</l>).
<li>Ability to simulate non-GET requests using a <l>&amp;method</l> GET parameter
(e.g. <l>&amp;method=POST</l>).
<li>Ability to force <js>"text/plain"</js> on response using GET parameter <l>&amp;plainText=true</l>.
</ul>
<li>
Ability to implement overloaded HTTP methods through the use of the <l>&amp;method</l> attribute
(e.g. <l>&amp;method=FOO</l>).
<li>
Ability to match URL patterns (e.g. <l>/foo/{fooId}/bar/{barId}</l>) against URLs
(e.g. <l>/foo/123/bar/456/bing</l>).
<li>
Ability to associate guards at the resource or method levels through annotations.
<br>Typically useful for security, but can be used for a variety of purposes.
<li>
Ability to associate converters at the resource or method levels through annotations.
<br>Typically useful for performing conversions on input and output, such as for supporting older input and
output formats.
</ul>
<p>
Many of the examples in this document are pulled directly from <l>juneau-examples-rest</l>.
</p>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HelloWorldExample' id='juneau-rest-server.HelloWorldExample'>6.1 - Hello World Example</a></h3>
<div class='topic'><!-- START: 6.1 - juneau-rest-server.HelloWorldExample -->
<p>
A REST resource is simply a Java class annotated with {@link org.apache.juneau.rest.annotation.Rest}.
The most common case is a class that extends {@link org.apache.juneau.rest.RestServlet}, which itself is simply an
extension of {@link javax.servlet.http.HttpServlet} which allows it to be deployed as a servlet.
</p>
<p>
In this example, we define a resource called <l>HelloWorldResource</l>.
This example is located in the <l>juneau-examples-rest</l> project.
It's assumed the reader is familiar with defining servlets in web applications.
</p>
<p>
Like any servlet, we could define our resource in the <l>web.xml</l> file of the web application like so...
</p>
<p class='bpcode w800'>
<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>HelloWorldResource<xt>&lt;/servlet-name&gt;</xt>
<xt>&lt;servlet-class&gt;</xt>com.foo.sample.HelloWorldResource<xt>&lt;/servlet-class&gt;</xt>
<xt>&lt;/servlet&gt;</xt>
<xt>&lt;servlet-mapping&gt;</xt>
<xt>&lt;servlet-name&gt;</xt>HelloWorldResource<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>
Our servlet code is shown below:
</p>
<p class='bpcode w800'>
<jc>// Sample REST resource that prints out a simple "Hello world!" message.</jc>
<ja>@Rest</ja>(
path=<js>"/helloWorld"</js>,
title=<js>"Hello World"</js>,
description=<js>"An example of the simplest-possible resource"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
navlinks={
<js>"up: request:/.."</js>,
<js>"options: servlet:/?method=OPTIONS"</js>
},
aside={
<js>"&lt;div style='max-width:400px' class='text'&gt;"</js>,
<js>" &lt;p&gt;This page shows a resource that simply response with a 'Hello world!' message&lt;/p&gt;"</js>,
<js>" &lt;p&gt;The POJO serialized is a simple String.&lt;/p&gt;"</js>,
<js>"&lt;/div&gt;"</js>
}
)
)
<jk>public class</jk> HelloWorldResource <jk>extends</jk> BasicRestServlet {
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>, summary=<js>"Responds with \"Hello world!\""</js>)
<jk>public</jk> String sayHello() {
<jk>return</jk> <js>"Hello world!"</js>;
}
}
</p>
<p>
This is what it looks like in a browser:
</p>
<p class='bpcode w800'>
http://localhost:10000/helloWorld
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.HelloWorldExample.1.png'>
<p>
It doesn't much simpler than that.
In this case, we're simply returning a string that will be converted to any of the supported languages (e.g.
JSON, XML, HTML, ...).
However, we could have returned any POJO consisting of beans, maps, collections, etc...
</p>
<p>
The {@link org.apache.juneau.rest.BasicRestServlet} class that we're using here is a subclass of
{@link org.apache.juneau.rest.RestServlet} that provides default support for a variety of content types.
Implementers can choose to use this class, or create their own subclass of
{@link org.apache.juneau.rest.RestServlet} with their own specialized serializers and parsers.
</p>
</div><!-- END: 6.1 - juneau-rest-server.HelloWorldExample -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.ClassHierarchy' id='juneau-rest-server.ClassHierarchy'>6.2 - Class Hierarchy</a></h3>
<div class='topic'><!-- START: 6.2 - juneau-rest-server.ClassHierarchy -->
<p>
The class hierarchy for the REST servlet class is shown below:
</p>
<ul class='javatree'>
<li class='jac'>
{@link javax.servlet.http.HttpServlet javax.servlet.http.HttpServlet}
<ul>
<li class='jac'>
{@link org.apache.juneau.rest.RestServlet org.apache.juneau.rest.RestServlet}
<br>Contains all the main logic.
<ul>
<li class='jac'>{@link org.apache.juneau.rest.BasicRestServlet org.apache.juneau.rest.BasicRestServlet}
<br>Provides a default set of serializers, parsers, options page, stylesheet, and other common settings.
<ul>
<li class='jac'>{@link org.apache.juneau.rest.BasicRestServletGroup org.apache.juneau.rest.BasicRestServletGroup}
<br>A default implementation for "router" pages.
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>
For top-level resources, you'll typically extend from one of the classes above.
</p>
<p>
For child resources, you can either extend from one of the classes above, or extend from one of the following
that provides identical support but does not extent from <c>HttpServlet</c>:
</p>
<ul class='javatree'>
<li class='jic'>
{@link org.apache.juneau.rest.BasicRestConfig}
<ul>
<li class='jac'>{@link org.apache.juneau.rest.BasicRest org.apache.juneau.rest.BasicRest}
<br>Provides a default set of serializers, parsers, options page, stylesheet, and other common settings.
<ul>
<li class='jac'>{@link org.apache.juneau.rest.BasicRestGroup org.apache.juneau.rest.BasicRestGroup}
<br>A default implementation for "router" pages.
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>
One reason to use the latter classes as your base classes is when you're implementing REST resources as
<ja>@Bean</ja>-annotated Spring Beans and you don't want them to be automatically registered as top-level servlets.
</p>
<p>
The servlets with RDF support require Jena on the classpath.
All other serializers and parsers do not have any external library dependencies.
For this reason, we have separate servlets for supporting RDF so that you don't need Jena if you don't need to
support RDF.
</p>
<p>
Everything is configured through the following classes which you will see a lot:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.RestContext} - Each resource class instance has one copy that holds all of its configuration.
<li class='jc'>{@link org.apache.juneau.rest.RestContextBuilder} - Builder for the class above.
</ul>
</div><!-- END: 6.2 - juneau-rest-server.ClassHierarchy -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Instantiation' id='juneau-rest-server.Instantiation'>6.3 - Instantiation</a></h3>
<div class='topic'><!-- START: 6.3 - juneau-rest-server.Instantiation -->
<p>
REST resources are deployed in one of two ways:
</p>
<ul class='spaced-list'>
<li>Deployed in a J2EE container as a servlet.
<li>Deployed as a child of another REST resource.
</ul>
<p>
When deployed in a J2EE container, you MUST extend from one of the servlet classes.
</p>
<p>
<b>When deployed as a child of another resource, you MAY extend from one of the servlet classes but it's
not necessary.</b>
The only requirement is that the class be annotated with <ja>@Rest</ja> and have one of the following constructors:
</p>
<ul class='javatree'>
<li class='jm'><c><jk>public</jk> T()</c>
<li class='jm'><c><jk>public</jk> T(RestContextBuilder)</c>
</ul>
<p>
And even that requirement is relaxed if you implement your own REST resource resolver (described later).
</p>
<p>
For example:
</p>
<p class='bpcode w800'>
<jc>// Top level resource is deployed like any other servlet and must subclass from RestServlet.</jc>
<ja>@Rest</ja>(
path=<js>"/top"</js>,
children={
ChildResource.<jk>class</jk> <jc>// Accessed via URI "/top/child"</jc>
}
)
<jk>public class</jk> TopLevelResource <jk>extends</jk> BasicRestServlet {...}
</p>
<p class='bpcode w800'>
<jc>// Child resources can inherit from RestServlet but it's not a requirement.</jc>
<ja>@Rest</ja>(
path=<js>"/child"</js>
)
<jk>public class</jk> ChildResource <jk>extends</jk> WhateverYouWant {...}
</p>
<p>
That's all there is to it!
There's no code scanning, module configuration/initialization classes, or anything complex like that.
It's just a servlet.
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Instantiation.RestServlet' id='juneau-rest-server.Instantiation.RestServlet'>6.3.1 - RestServlet</a></h4>
<div class='topic'><!-- START: 6.3.1 - juneau-rest-server.Instantiation.RestServlet -->
<p>
The {@link org.apache.juneau.rest.RestServlet} class is the entry point for your REST resources.
It extends directly from <l>HttpServlet</l> and is deployed like any other servlet.
</p>
<p>
When the servlet <l>init()</l> method is called, it triggers the code to find and process the <l>@Rest</l>
annotations on that class and all child classes.
These get constructed into a {@link org.apache.juneau.rest.RestContext} object that holds all the configuration
information about your resource in a read-only object.
</p>
<p>
Most developers are not going to be using the <l>RestServlet</l> class itself, and instead will
extend from one of the preconfigured default servlets such as {@link org.apache.juneau.rest.BasicRestServlet}.
The <l>RestServlet</l> class by itself is not configured with any serializers and parsers, and therefore
not very useful on it's own.
However, the class does provide a couple of convenience methods to be aware of:
</p>
<ul class='javatree'>
<li class='jac'><c>{@link org.apache.juneau.rest.RestServlet} <jk>extends</jk> HttpServlet</c>
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RestServlet#init(ServletConfig) init(ServletConfig)} - Can override to provide custom initialization.
<li class='jm'>{@link org.apache.juneau.rest.RestServlet#service(HttpServletRequest,HttpServletResponse) service(HttpServletRequest,HttpServletResponse)} - Can override to provide custom request handling.
<li class='jm'>{@link org.apache.juneau.rest.RestServlet#destroy() destroy()} - Can override to provide custom cleanup.
<li class='jm'>{@link org.apache.juneau.rest.RestServlet#getContext() getContext()} - Returns all aspects of the configuration of your resource pulled from all annotations on the class/parent-classes and methods.
<li class='jm'>{@link org.apache.juneau.rest.RestServlet#log(Level,String,Object...) log(Level,String,Object...)} - Convenience logging method.
<li class='jm'>{@link org.apache.juneau.rest.RestServlet#log(Level,Throwable,String,Object...) log(Level,Throwable,String,Object...)} - Convenience logging method.
</ul>
</ul>
</div><!-- END: 6.3.1 - juneau-rest-server.Instantiation.RestServlet -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Instantiation.BasicRestServlet' id='juneau-rest-server.Instantiation.BasicRestServlet'>6.3.2 - BasicRestServlet</a></h4>
<div class='topic'><!-- START: 6.3.2 - juneau-rest-server.Instantiation.BasicRestServlet -->
<p>
The {@link org.apache.juneau.rest.BasicRestServlet} class is a subclass of {@link org.apache.juneau.rest.RestServlet}
preconfigured with the following:
</p>
<ul class='spaced-list'>
<li>A default set of serializers and parsers (pretty much all of them except for the RDF ones).
<li>Some basic HTML boilerplate for the HTML representation of your POJOs.
<li>Support for auto-generated Swagger documentation through OPTIONS page requests.
<li>Configuration of default CSS stylesheets.
<li>Default contents for HTML views.
</ul>
<p>
The contents of the class is shown below.
You should notice that very little code is being used and everything is configurable through
annotations:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
<jc>// Allow OPTIONS requests to be simulated using ?method=OPTIONS query parameter. </jc>
allowedMethodParams=<js>"OPTIONS"</js>,
<jc>// HTML-page specific settings.</jc>
htmldoc=<ja>@HtmlDoc</ja>(
<jc>// Basic page navigation links.</jc>
navlinks={
<js>"up: request:/.."</js>,
<js>"options: servlet:/?method=OPTIONS"</js>
}
)
)
<jk>public abstract class</jk> BasicRestServlet <jk>extends</jk> RestServlet <jk>implements</jk> BasicRestConfig {
<jd>/**
* [OPTIONS /*] - Show resource options.
*
* <ja>@param</ja> req The HTTP request.
* <ja>@return</ja> A bean containing the contents for the OPTIONS page.
*/</jd>
<ja>@RestMethod</ja>(name=<jsf>OPTIONS</jsf>, path=<js>"/*"</js>,
summary=<js>"Swagger documentation"</js>,
description=<js>"Swagger documentation for this resource."</js>,
htmldoc=<ja>@HtmlDoc</ja>(
<jc>// Override the nav links for the swagger page.</jc>
navlinks={
<js>"back: servlet:/"</js>,
<js>"json: servlet:/?method=OPTIONS&amp;Accept=text/json&amp;plainText=true"</js>
},
<jc>// Never show aside contents of page inherited from class.</jc>
aside=<js>"NONE"</js>
)
)
<ja>@JsonSchemaConfig</ja>(
<jc>// Add descriptions to the following types when not specified:</jc>
addDescriptionsTo=<js>"bean,collection,array,map,enum"</js>,
<jc>// Add x-example to the following types:</jc>
addExamplesTo=<js>"bean,collection,array,map"</js>,
<jc>// Don't generate schema information on the Swagger bean itself or HTML beans.</jc>
ignoreTypes=<js>"Swagger,org.apache.juneau.dto.html5.*"</js>,
<jc>// Use $ref references for bean definitions to reduce duplication in Swagger.</jc>
useBeanDefs=<js>"true"</js>
)
<ja>@BeanConfig</ja>(
<jc>// When parsing generated beans, ignore unknown properties that may only exist as getters and not setters.</jc>
ignoreUnknownBeanProperties=<js>"true"</js>,
<jc>// POJO swaps to apply to all serializers/parsers on this method.</jc>
pojoSwaps={
<jc>// Use the SwaggerUI swap when rendering Swagger beans.</jc>
<jc>// This is a per-media-type swap that only applies to text/html requests.</jc>
SwaggerUI.<jk>class</jk>
}
)
<jk>public</jk> Swagger getOptions(RestRequest req) {
<jc>// Localized Swagger for this resource is available through the RestRequest object.</jc>
<jk>return</jk> req.getSwagger();
}
}
</p>
<p>
Additional annotations are pulled in from the {@link org.apache.juneau.rest.BasicRestConfig} interface which simply
exists to define a common set of annotations.
Notice that it has no code at all.
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
<jc>// Default serializers for all Java methods in the class.</jc>
serializers={
HtmlDocSerializer.<jk>class</jk>,
HtmlStrippedDocSerializer.<jk>class</jk>,
HtmlSchemaDocSerializer.<jk>class</jk>,
JsonSerializer.<jk>class</jk>,
JsonSerializer.Simple.<jk>class</jk>,
JsonSchemaSerializer.<jk>class</jk>,
XmlDocSerializer.<jk>class</jk>,
XmlSchemaDocSerializer.<jk>class</jk>,
UonSerializer.<jk>class</jk>,
UrlEncodingSerializer.<jk>class</jk>,
MsgPackSerializer.<jk>class</jk>,
SoapXmlSerializer.<jk>class</jk>,
PlainTextSerializer.<jk>class</jk>
},
<jc>// Default parsers for all Java methods in the class.</jc>
parsers={
JsonParser.<jk>class</jk>,
JsonParser.Simple.<jk>class</jk>,
XmlParser.<jk>class</jk>,
HtmlParser.<jk>class</jk>,
UonParser.<jk>class</jk>,
UrlEncodingParser.<jk>class</jk>,
MsgPackParser.<jk>class</jk>,
PlainTextParser.<jk>class</jk>
},
<jc>// HTML-page specific settings</jc>
htmldoc=<ja>@HtmlDoc</ja>(
<jc>// Default page header contents.</jc>
header={
<js>"&lt;h1&gt;$R{resourceTitle}&lt;/h1&gt;"</js>, <jc>// Use @Rest(title)</jc>
<js>"&lt;h2&gt;$R{methodSummary,resourceDescription}&lt;/h2&gt;"</js>, <jc>// Use either @RestMethod(summary) or @Rest(description)</jc>
<js>"$C{REST/header}"</js> <jc>// Extra header HTML defined in external config file.</jc>
},
<jc>// Basic page navigation links.</jc>
navlinks={
<js>"up: request:/.."</js>
},
<jc>// Default stylesheet to use for the page.
// Can be overridden from external config file.
// Default is DevOps look-and-feel (aka Depression look-and-feel).</jc>
stylesheet=<js>"$C{REST/theme,servlet:/htdocs/themes/devops.css}"</js>,
<jc>// Default contents to add to the &lt;head&gt; section of the HTML page.
// Use it to add a favicon link to the page.</jc>
head={
<js>"&lt;link rel='icon' href='$U{$C{REST/favicon}}'/&gt;"</js>
},
<jc>// No default page footer contents.
// Can be overridden from external config file.</jc>
footer=<js>"$C{REST/footer}"</js>,
<jc>// By default, table cell contents should not wrap.</jc>
nowrap=<js>"true"</js>
),
<jc>// Optional external configuration file.</jc>
config=<js>"$S{juneau.configFile}"</js>,
<jc>// These are static files that are served up by the servlet under the specified sub-paths.
// For example, "/servletPath/htdocs/javadoc.css" resolves to the file "[servlet-package]/htdocs/javadoc.css"
// By default, we define static files through the external configuration file.</jc>
staticFiles={<js>"$C{REST/staticFiles}"</js>}
)
<ja>@SerializerConfig</ja>(
<jc>// Enable automatic resolution of URI objects to root-relative values.</jc>
uriResolution=<js>"ROOT_RELATIVE"</js>
)
<jk>public interface</jk> BasicRestConfig {}
</p>
<p>
Your top-level resource will simply extend from this class, as shown in the Hello World example
from a couple sections back.
</p>
<p>
It's important to notice that the <ja>@Rest</ja> annotation is inheritable and overridable from parent
class and interfaces.
They'll all get merged into a single set of annotation values for the resource class.
</p>
<p>
Not shown but equally important is that all of the annotations shown have programmatic equivalents via the {@link org.apache.juneau.rest.RestContextBuilder} class
which can be manipulated during servlet initialization.
(As a general rule, all annotations throughout Juneau have programmatic equivalents.)
</p>
<p>
There's a lot going on in this class.
But not to worry, the details will be described later.
</p>
</div><!-- END: 6.3.2 - juneau-rest-server.Instantiation.BasicRestServlet -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Instantiation.BasicRest' id='juneau-rest-server.Instantiation.BasicRest'>6.3.3 - BasicRest</a></h4>
<div class='topic'><!-- START: 6.3.3 - juneau-rest-server.Instantiation.BasicRest -->
<p>
The {@link org.apache.juneau.rest.BasicRest} class is identical to the {@link org.apache.juneau.rest.BasicRestServlet} class except that
it does not extend from <c>HttpServlet</c>.
It defines the exact same set of serializers, parsers, etc., but it cannot be deployed as a top-level
servlet. It can however be used for child resources registered via the {@link org.apache.juneau.rest.annotation.Rest#children() @Rest(children)}
annotation.
</p>
<p>
The code for this class is virtually identical to {@link org.apache.juneau.rest.BasicRestServlet} but lacks a parent class:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
<jc>// Allow OPTIONS requests to be simulated using ?method=OPTIONS query parameter. </jc>
allowedMethodParams=<js>"OPTIONS"</js>,
<jc>// HTML-page specific settings.</jc>
htmldoc=<ja>@HtmlDoc</ja>(
<jc>// Basic page navigation links.</jc>
navlinks={
<js>"up: request:/.."</js>,
<js>"options: servlet:/?method=OPTIONS"</js>
}
)
)
<jk>public abstract class</jk> BasicRest <jk>implements</jk> BasicRestConfig {
<jd>/**
* [OPTIONS /*] - Show resource options.
*
* <ja>@param</ja> req The HTTP request.
* <ja>@return</ja> A bean containing the contents for the OPTIONS page.
*/</jd>
<ja>@RestMethod</ja>(name=<jsf>OPTIONS</jsf>, path=<js>"/*"</js>,
summary=<js>"Swagger documentation"</js>,
description=<js>"Swagger documentation for this resource."</js>,
htmldoc=<ja>@HtmlDoc</ja>(
<jc>// Override the nav links for the swagger page.</jc>
navlinks={
<js>"back: servlet:/"</js>,
<js>"json: servlet:/?method=OPTIONS&amp;Accept=text/json&amp;plainText=true"</js>
},
<jc>// Never show aside contents of page inherited from class.</jc>
aside=<js>"NONE"</js>
)
)
<ja>@JsonSchemaConfig</ja>(
<jc>// Add descriptions to the following types when not specified:</jc>
addDescriptionsTo=<js>"bean,collection,array,map,enum"</js>,
<jc>// Add x-example to the following types:</jc>
addExamplesTo=<js>"bean,collection,array,map"</js>,
<jc>// Don't generate schema information on the Swagger bean itself or HTML beans.</jc>
ignoreTypes=<js>"Swagger,org.apache.juneau.dto.html5.*"</js>,
<jc>// Use $ref references for bean definitions to reduce duplication in Swagger.</jc>
useBeanDefs=<js>"true"</js>
)
<ja>@BeanConfig</ja>(
<jc>// When parsing generated beans, ignore unknown properties that may only exist as getters and not setters.</jc>
ignoreUnknownBeanProperties=<js>"true"</js>,
<jc>// POJO swaps to apply to all serializers/parsers on this method.</jc>
pojoSwaps={
<jc>// Use the SwaggerUI swap when rendering Swagger beans.</jc>
<jc>// This is a per-media-type swap that only applies to text/html requests.</jc>
SwaggerUI.<jk>class</jk>
}
)
<jk>public</jk> Swagger getOptions(RestRequest req) {
<jc>// Localized Swagger for this resource is available through the RestRequest object.</jc>
<jk>return</jk> req.getSwagger();
}
}
</p>
</div><!-- END: 6.3.3 - juneau-rest-server.Instantiation.BasicRest -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Instantiation.Children' id='juneau-rest-server.Instantiation.Children'>6.3.4 - Children</a></h4>
<div class='topic'><!-- START: 6.3.4 - juneau-rest-server.Instantiation.Children -->
<p>
Child Resources are REST servlets or objects that are linked to parent resources through the
{@link org.apache.juneau.rest.annotation.Rest#children() @Rest(children)} annotation.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jd>/** Parent Resource */</jd>
<ja>@Rest</ja>(
path=<js>"/parent"</js>,
children={FooResource.<jk>class</jk>}
)
<jk>public</jk> MyResource <jk>extends</jk> BasicRestServlet {...}
</p>
<p class='bpcode w800'>
<jd>/** Child Resource */</jd>
<ja>@Rest</ja>(
path=<js>"/foo"</js> <jc>// Path relative to parent resource.</jc>
)
<jk>public</jk> FooResource {...} <jc>// Note that we don't need to extend from RestServlet.</jc>
</p>
<p>
The path of the child resource gets appended to the path of the parent resource.
So in the example above, the child resource is accessed through the URL <l>/parent/foo</l>.
</p>
<p>
A HUGE advantage of using child resources is that they do not need to be declared in the JEE <l>web.xml</l>
file.
Initialization of and access to the child resources occurs through the parent resource.
Children can be nested arbitrary deep to create complex REST interfaces with a single top-level REST servlet.
</p>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_children}
</ul>
</div><!-- END: 6.3.4 - juneau-rest-server.Instantiation.Children -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Instantiation.BasicRestServletGroup' id='juneau-rest-server.Instantiation.BasicRestServletGroup'>6.3.5 - BasicRestServletGroup</a></h4>
<div class='topic'><!-- START: 6.3.5 - juneau-rest-server.Instantiation.BasicRestServletGroup -->
<p>
The {@link org.apache.juneau.rest.BasicRestServletGroup} class provides a default "router" page for
child resources when a parent resource is nothing more than a grouping of child resources.
</p>
<p>
The <l>RootResources</l> class in the Samples project is an example of a router page:
</p>
<p class='bpcode w800'>
<jd>/**
* Sample REST resource showing how to implement a "router" resource page.
*/</jd>
<ja>@Rest</ja>(
path=<js>"/"</js>,
title=<js>"Root resources"</js>,
description=<js>"Example of a router resource page."</js>,
children={
HelloWorldResource.<jk>class</jk>,
PetStoreResource.<jk>class</jk>,
DtoExamples.<jk>class</jk>,
ConfigResource.<jk>class</jk>,
LogsResource.<jk>class</jk>,
ShutdownResource.<jk>class</jk>
}
)
<jk>public class</jk> RootResources <jk>extends</jk> BasicRestServletGroup {
<jc>// NO CODE!!!</jc>
}
</p>
<p>
When you bring up this resource in a browser, you see the following that provides a list
of navigable links to your child resources:
</p>
<p class='bpcode w800'>
http://localhost:10000
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.RouterPages.1.png'/>
<p>
The {@link org.apache.juneau.rest.BasicRestServletGroup} class is nothing more than a subclass of
{@link org.apache.juneau.rest.BasicRestServlet} with a <l>getChildren()</l> method mapped to the servlet
root path.
The method returns a POJO with is just a linked-list of beans with name/description properties.
</p>
<p class='bpcode w800'>
<jc>// The entire contents of the BasicRestServletGroup class.</jc>
<jk>public class</jk> BasicRestServletGroup <jk>extends</jk> BasicRestServlet {
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>, description=<js>"Child resources"</js>)
<jk>public</jk> ChildResourceDescriptions getChildren(RestRequest req) {
<jk>return new</jk> ChildResourceDescriptions(<jk>this</jk>, req);
}
}
</p>
</div><!-- END: 6.3.5 - juneau-rest-server.Instantiation.BasicRestServletGroup -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Instantiation.BasicRestGroup' id='juneau-rest-server.Instantiation.BasicRestGroup'>6.3.6 - BasicRestGroup</a></h4>
<div class='topic'><!-- START: 6.3.6 - juneau-rest-server.Instantiation.BasicRestGroup -->
<p>
The {@link org.apache.juneau.rest.BasicRestGroup} class is identical to the {@link org.apache.juneau.rest.BasicRestServletGroup} class except that
it does not extend from <c>HttpServlet</c>.
It defines the exact same set of serializers, parsers, etc., but it cannot be deployed as a top-level
servlet. It can however be used for child resources registered via the {@link org.apache.juneau.rest.annotation.Rest#children() @Rest(children)}
annotation.
</p>
<p class='bpcode w800'>
<jc>// The entire contents of the BasicRestGroup class.</jc>
<jk>public class</jk> BasicRestGroup <jk>extends</jk> BasicRest {
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>, description=<js>"Child resources"</js>)
<jk>public</jk> ChildResourceDescriptions getChildren(RestRequest req) {
<jk>return new</jk> ChildResourceDescriptions(<jk>this</jk>, req);
}
}
</p>
</div><!-- END: 6.3.6 - juneau-rest-server.Instantiation.BasicRestGroup -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Instantiation.ResourceResolvers' id='juneau-rest-server.Instantiation.ResourceResolvers'>6.3.7 - Resource Resolvers</a></h4>
<div class='topic'><!-- START: 6.3.7 - juneau-rest-server.Instantiation.ResourceResolvers -->
<p>
By default, you can add the {@link org.apache.juneau.rest.annotation.Rest @Rest}
to any class as long as it has one of the following constructors:
</p>
<ul class='javatree'>
<li class='jm'><c><jk>public</jk> T()</c>
<li class='jm'><c><jk>public</jk> T(RestContextBuilder)</c>
</ul>
<p>
The latter constructor can be used to get access to the {@link org.apache.juneau.rest.RestContextBuilder} object to make
any configurations to the resource before it's initialized.
</p>
<p>
Resource object resolution is controlled through the following API:
</p>
<ul class='javatree'>
<li class='jic'>{@link org.apache.juneau.rest.RestResourceResolver}
<ul>
<li class='jc'>{@link org.apache.juneau.rest.BasicRestResourceResolver}
</ul>
</ul>
<p>
This API can be extended to provide your own custom resource resolution.
Later topics discuss how to use this API to instantiate resources using Spring.
</p>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_resourceResolver}
</ul>
</div><!-- END: 6.3.7 - juneau-rest-server.Instantiation.ResourceResolvers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Instantiation.LifecycleHooks' id='juneau-rest-server.Instantiation.LifecycleHooks'>6.3.8 - Lifecycle Hooks</a></h4>
<div class='topic'><!-- START: 6.3.8 - juneau-rest-server.Instantiation.LifecycleHooks -->
<p>
Lifecycle hooks allow you to hook into lifecycle events of the servlet/resource creation and REST calls.
</p>
<p>
For example, if you want to add an initialization method to your resource:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(...)
<jk>public class</jk> MyResource {
<jc>// Our database.</jc>
<jk>private</jk> Map&lt;Integer,Object&gt; <jf>myDatabase</jf>;
<ja>@RestHook</ja>(<jsf>INIT</jsf>)
<jk>public void</jk> initMyDatabase(RestContextBuilder builder) <jk>throws</jk> Exception {
<jf>myDatabase</jf> = <jk>new</jk> LinkedHashMap&lt;&gt;();
}
}
</p>
<p>
Or if you want to intercept REST calls:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(...)
<jk>public class</jk> MyResource {
<jc>// Add a request attribute to all incoming requests.</jc>
<ja>@RestHook</ja>(<jsf>PRE_CALL</jsf>)
<jk>public void</jk> onPreCall(RestRequest req) {
req.setAttribute(<js>"foo"</js>, <js>"bar"</js>);
}
}
</p>
<p>
The hook events can be broken down into two categories:
</p>
<ul class='spaced-list'>
<li>Resource lifecycle events:
<ul>
<li class='jf'>{@link org.apache.juneau.rest.annotation.HookEvent#INIT INIT} - Right before initialization.
<li class='jf'>{@link org.apache.juneau.rest.annotation.HookEvent#POST_INIT POST_INIT} - Right after initialization.
<li class='jf'>{@link org.apache.juneau.rest.annotation.HookEvent#POST_INIT_CHILD_FIRST POST_INIT_CHILD_FIRST} - Right after initialization, but run child methods first.
<li class='jf'>{@link org.apache.juneau.rest.annotation.HookEvent#DESTROY DESTROY} - Right before servlet destroy.
</ul>
<li>REST call lifecycle events:
<ul>
<li class='jf'>{@link org.apache.juneau.rest.annotation.HookEvent#START_CALL START_CALL} - At the beginning of a REST call.
<li class='jf'>{@link org.apache.juneau.rest.annotation.HookEvent#PRE_CALL PRE_CALL} - Right before the <ja>@RestMethod</ja> method is invoked.
<li class='jf'>{@link org.apache.juneau.rest.annotation.HookEvent#POST_CALL POST_CALL} - Right after the <ja>@RestMethod</ja> method is invoked.
<li class='jf'>{@link org.apache.juneau.rest.annotation.HookEvent#END_CALL END_CALL} - At the end of the REST call after the response has been flushed.
</ul>
</ul>
<ul class='seealso'>
<li class='ja'>{@link org.apache.juneau.rest.annotation.RestHook}
</ul>
</div><!-- END: 6.3.8 - juneau-rest-server.Instantiation.LifecycleHooks -->
</div><!-- END: 6.3 - juneau-rest-server.Instantiation -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Rest' id='juneau-rest-server.Rest'>6.4 - @Rest</a></h3>
<div class='topic'><!-- START: 6.4 - juneau-rest-server.Rest -->
<p>
The {@link org.apache.juneau.rest.annotation.Rest @Rest} annotation is the primary way of defining
and configuring REST resource classes.
The functionality of the class itself is covered in detail in the topics below.
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Rest.AnnotationInheritance' id='juneau-rest-server.Rest.AnnotationInheritance'>6.4.1 - Annotation Inheritance</a></h4>
<div class='topic'><!-- START: 6.4.1 - juneau-rest-server.Rest.AnnotationInheritance -->
<p>
The {@link org.apache.juneau.rest.annotation.Rest @Rest} annotation can also be used on parents and interfaces of resource classes.
When multiple annotations are defined at different levels, the annotation values are combined.
</p>
<p>
This is a particularly useful feature because it allows you to define your own configured parent
resource classes that can be extended by all your child resources so that they all share common
settings.
</p>
<h5 class='figure'>Inheritance rules</h5>
<table class='styled w800'>
<tr>
<th><l>Annotation</l></th>
<th><l>Inheritence Rules</l></th>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#guards() guards()}</td>
<td>
Guards on child are combined with those on parent class.
<br>Guards are executed child-to-parent in the order they appear in the annotation.
<br>Guards on methods are executed before those on classes.
</td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#converters() converters()}</td>
<td>
Converters on child are combined with those on parent class.
<br>Converters are executed child-to-parent in the order they appear in the annotation.
<br>Converters on methods are executed before those on classes.
</td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#properties() properties()}</td>
<td>
Properties on child are combined with those on parent class.
<br>Properties are applied parent-to-child in the order they appear in the annotation.
<br>Properties on methods take precedence over those on classes.
</td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#serializers() serializers()}</td>
<td>
Serializers on child override those on parent class.
<br>{@link org.apache.juneau.rest.Inherit} class can be used to inherit and augment values from parent.
<br>{@link org.apache.juneau.rest.None} class can be used to suppress inheriting from parent.
<br>Serializers on methods take precedence over those on classes.
</td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#parsers() parsers()}</td>
<td>
Parsers on child override those on parent class.
<br>{@link org.apache.juneau.rest.Inherit} class can be used to inherit and augment values from parent.
<br>{@link org.apache.juneau.rest.None} class can be used to suppress inheriting from parent.
<br>Parsers on methods take precedence over those on classes.
</td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#responseHandlers() responseHandlers()}</td>
<td>
Response handlers on child are combined with those on parent class.
</td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#encoders() encoders()}</td>
<td>
Encoders on child are combined with those on parent class.
</td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#reqHeaders() reqHeaders()}</td>
<td>
Headers on child are combined with those on parent class.
<br>Headers are applied parent-to-child in the order they appear in the annotation.
<br>Headers on methods take precedence over those on classes.
</td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#resHeaders() resHeaders()}</td>
<td>
Headers on child are combined with those on parent class.
<br>Headers are applied parent-to-child in the order they appear in the annotation.
</td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#children() children()}</td>
<td>
Children on child are combined with those on parent class.
<br>Children are list parent-to-child in the order they appear in the annotation.
</td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#path() path()}</td>
<td>
Path is searched for in child-to-parent order.
</td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#title() title()}</td>
<td>
Label is searched for in child-to-parent order.
</td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#description() description()}</td>
<td>
Description is searched for in child-to-parent order.
</td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#config() config()}</td>
<td>
Config file is searched for in child-to-parent order.
</td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.annotation.Rest#staticFiles() staticFiles()}</td>
<td>
Static files on child are combined with those on parent class.
<br>Static files are are executed child-to-parent in the order they appear in the annotation.
</td>
</tr>
</table>
</div><!-- END: 6.4.1 - juneau-rest-server.Rest.AnnotationInheritance -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Rest.RestPath' id='juneau-rest-server.Rest.RestPath'>6.4.2 - @Rest(path)</a></h4>
<div class='topic'><!-- START: 6.4.2 - juneau-rest-server.Rest.RestPath -->
<p>
The {@link org.apache.juneau.rest.annotation.RestResource#path() @RestResource(path)} annotation is used in the following situations:
<p>
<ul class='spaced-list'>
<li>
On child resources (resource classes attached to parents via the {@link org.apache.juneau.rest.annotation.RestResource#children() @RestResource(children)} annotation) to identify
the subpath used to access the child resource relative to the parent.
<li>
On top-level {@link org.apache.juneau.rest.RestServlet} classes deployed as Spring beans when {@link org.apache.juneau.rest.springboot.JuneauRestInitializer} is being used.
</ul>
<h5 class='topic'>On child resources</h5>
<p>
The typical usage is to define a path to a child resource relative to the parent resource.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestResource</ja>(
children={
ChildResource.<jk>class</jk>
}
)
<jk>public class</jk> TopLevelResource <jk>extends</jk> BasicRestServlet {...}
</p>
<p class='bpcode w800'>
<ja>@RestResource</ja>(
path=<js>"/child"</js>,
children={
GrandchildResource.<jk>class</jk>
}
)
<jk>public class</jk> ChildResource {...}
</p>
<p class='bpcode w800'>
<ja>@RestResource</ja>(
path=<js>"/grandchild"</js>
)
<jk>public class</jk> GrandchildResource {
<ja>@RestMethod</ja>(
path=<js>"/"</js>
)
<jk>public</jk> String sayHello() {
<jk>return</jk> <js>"Hello!"</js>;
}
}
</p>
<p>
In the example above, assuming the <c>TopLevelResource</c> servlet is deployed to path <c>/myContext/myServlet</c>,
then the <c>sayHello</c> method is accessible through the URI <c>/myContext/myServlet/child/grandchild</c>.
</p>
<p>
Note that in this scenario, the <c>path</c> attribute is not defined on the top-level resource.
Specifying the path on the top-level resource has no effect, but can be used for readability purposes.
</p>
<h5 class='topic'>On top-level resources deployed as Spring beans</h5>
<p>
The path can also be used on top-level resources deployed as Spring beans when used with the {@link org.apache.juneau.rest.springboot.JuneauRestInitializer}
Spring Boot initializer class:
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@SpringBootApplication</ja>
<ja>@Controller</ja>
<jk>public class</jk> App {
<jc>// Our entry-point method.</jc>
<jk>public static void</jk> main(String[] args) {
<jk>new</jk> SpringApplicationBuilder(App.<jk>class</jk>)
.initializers(<jk>new</jk> JuneauRestInitializer(App.<jk>class</jk>))
.run(args);
}
<jc>// Our top-level servlet.</jc>
<ja>@Bean</ja>
<ja>@JuneauRestRoot</ja>
<jk>public</jk> MyResource getMyResource() {
<jk>return new</jk> MyResource();
}
}
</p>
<p class='bpcode w800'>
<ja>@RestResource</ja>(
path=<js>"/myResource"</js>
)
<jk>public class</jk> MyResource <jk>extends</jk> BasicRestServlet {...}
</p>
<p>
In this case, the servlet will get registered using the path defined on the resource class.
</p>
<h5 class='topic'>Path variables</h5>
<p>
The path can contain variables that get resolved to {@link org.apache.juneau.http.annotation.Path @Path} parameters
or access through the {@link org.apache.juneau.rest.RestRequest#getPathMatch()} method.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode'>
<ja>@RestResource</ja>(
path=<js>"/myResource/{foo}/{bar}"</js>
)
<jk>public class</jk> MyResource <jk>extends</jk> BasicRestServlet {
<ja>@RestMethod</ja>(
path=<js>"/{baz}"</js>
)
<jk>public void</jk> String doX(<ja>@Path</ja> String foo, <ja>@Path</ja> <jk>int</jk> bar, <ja>@Path</ja> MyPojo baz) {
...
}
}
</p>
<p>
Variables can be used on either top-level or child resources and can be defined on multiple levels.
</p>
<div class='info'>
All variables in the path must be specified or else the target will not resolve and a <c>404</c> will result.
</div>
<p>
When variables are used on a path of a top-level resource deployed as a Spring bean in a Spring Boot application,
the first part of the URL must be a literal which will be used as the servlet path of the registered servlet.
</p>
</div><!-- END: 6.4.2 - juneau-rest-server.Rest.RestPath -->
</div><!-- END: 6.4 - juneau-rest-server.Rest -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestContext' id='juneau-rest-server.RestContext'>6.5 - RestContext</a></h3>
<div class='topic'><!-- START: 6.5 - juneau-rest-server.RestContext -->
<p>
The {@link org.apache.juneau.rest.RestContext} object is the workhorse class for all of the configuration
of a single REST resource class.
It's by-far the most important class in the REST API.
</p>
<p>
Every class annotated with <l>@Rest</l> ends up with an instance of this object.
The object itself is read-only and unchangeable.
It is populated through the following:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.rest.annotation.Rest} - Settings copied from the annotation during servlet initialization.
<li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder} - Builder used during servlet initialization.
</ul>
<p>
The annotation should be self-explanatory at this point.
The builder allows you to perform all of the same configuration as the annotation programmatically.
</p>
<p>
The {@link org.apache.juneau.rest.RestContextBuilder} class extends {@link org.apache.juneau.BeanContextBuilder}
allowing you to programmatically set any properties defined on that builder class.
It also implements {@link javax.servlet.ServletConfig}
</p>
<p>
To access this object, simply pass it in as a constructor argument or in an INIT hook:
</p>
<p class='bpcode w800'>
<jc>// Option #1 - Pass in through constructor.</jc>
<jk>public</jk> MyResource(RestContextBuilder builder) {
builder
.pojoSwaps(TemporalCalendarSwap.Rfc1123DateTime.<jk>class</jk>)
.set(<jsf>PARSER_debug</jsf>, <jk>true</jk>);
}
<jc>// Option #2 - Use an INIT hook.</jc>
<ja>@RestHook</ja>(<jsf>INIT</jsf>)
<jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
builder
.pojoSwaps(TemporalCalendarSwap.Rfc1123DateTime.<jk>class</jk>)
.set(<jsf>PARSER_debug</jsf>, <jk>true</jk>);
}
</p>
<p>
Warning: The builder class is huge.
Through it, you can configure bean/serializer/parser settings, define config files, children,
resource finders, info providers, etc...
</p>
</div><!-- END: 6.5 - juneau-rest-server.RestContext -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod' id='juneau-rest-server.RestMethod'>6.6 - @RestMethod</a></h3>
<div class='topic'><!-- START: 6.6 - juneau-rest-server.RestMethod -->
<p>
REST Java methods are identified on REST servlets using the
{@link org.apache.juneau.rest.annotation.RestMethod @RestMethod} annotation.
The annotation allows the framework to identify the available REST methods through reflection.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>)
<jk>public</jk> String sayHello() {
<jk>return</jk> <js>"Hello world!"</js>;
}
</p>
<p>
When the <c>name</c> and/or <c>path</c> values are not specified, their values are inferred
from the Java method name.
</p>
<p>
The HTTP method can be inferred from the Java method by starting the method name with any of the following:
</p>
<ul>
<li><c>get</c>
<li><c>put</c>
<li><c>post</c>
<li><c>delete</c>
<li><c>options</c>
<li><c>head</c>
<li><c>trace</c>
<li><c>patch</c>
</ul>
<p>
If <c>path</c> is not defined, it's inferred from the Java method name (minus the prefix above).
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Method="GET", path="/foo"</jc>
<ja>@RestMethod</ja>
<jk>public</jk> String getFoo() {...}
</p>
<p class='bpcode w800'>
<jc>// Method="DELETE", path="/foo"</jc>
<ja>@RestMethod</ja>
<jk>public</jk> String deleteFoo() {...}
</p>
<p class='bpcode w800'>
<jc>// Method="GET", path="/foo"</jc>
<jc>// "GET" is default</jc>
<ja>@RestMethod</ja>
<jk>public</jk> String foo() {...}
</p>
<p class='bpcode w800'>
<jc>// Method="GET", path="/"</jc>
<ja>@RestMethod</ja>(path=<js>"/"</js>)
<jk>public</jk> String foo() {...}
</p>
<p class='bpcode w800'>
<jc>// Method="GET", path="/"</jc>
<ja>@RestMethod</ja>
<jk>public</jk> String get() {...}
</p>
<p class='bpcode w800'>
<jc>// Method="POST", path="/"</jc>
<ja>@RestMethod</ja>
<jk>public</jk> String post() {...}
</p>
<p>
If <c>name</c> and <c>path</c> are both specified, the Java method name can be anything.
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.MethodParameters' id='juneau-rest-server.RestMethod.MethodParameters'>6.6.1 - Java Method Parameters</a></h4>
<div class='topic'><!-- START: 6.6.1 - juneau-rest-server.RestMethod.MethodParameters -->
<p>
Java methods can contain any of the following parameters in any order:
</p>
<ul class='spaced-list'>
<li>
<b>Parameters based on class types:</b>
<ul class='spaced-list'>
<li><b>Request/response objects:</b>
<ul>
<li class='jc'>{@link org.apache.juneau.rest.RestRequest} - The request object.
<li class='jc'>{@link javax.servlet.http.HttpServletRequest} - The superclass of <c>RestRequest</c>.
<li class='jc'>{@link org.apache.juneau.rest.RestResponse} - The response object.
<li class='jc'>{@link javax.servlet.http.HttpServletResponse} - The superclass of <c>RestResponse</c>.
</ul>
<li><b>Parsed request header values:</b>
<ul>
<li class='jc'>{@link org.apache.juneau.http.Accept}
<li class='jc'>{@link org.apache.juneau.http.AcceptCharset}
<li class='jc'>{@link org.apache.juneau.http.AcceptEncoding}
<li class='jc'>{@link org.apache.juneau.http.AcceptLanguage}
<li class='jc'>{@link org.apache.juneau.http.Authorization}
<li class='jc'>{@link org.apache.juneau.http.CacheControl}
<li class='jc'>{@link org.apache.juneau.http.Connection}
<li class='jc'>{@link org.apache.juneau.http.ContentLength}
<li class='jc'>{@link org.apache.juneau.http.ContentType}
<li class='jc'>{@link org.apache.juneau.http.Date}
<li class='jc'>{@link org.apache.juneau.http.Expect}
<li class='jc'>{@link org.apache.juneau.http.From}
<li class='jc'>{@link org.apache.juneau.http.Host}
<li class='jc'>{@link org.apache.juneau.http.IfMatch}
<li class='jc'>{@link org.apache.juneau.http.IfModifiedSince}
<li class='jc'>{@link org.apache.juneau.http.IfNoneMatch}
<li class='jc'>{@link org.apache.juneau.http.IfRange}
<li class='jc'>{@link org.apache.juneau.http.IfUnmodifiedSince}
<li class='jc'>{@link org.apache.juneau.http.MaxForwards}
<li class='jc'>{@link org.apache.juneau.http.Pragma}
<li class='jc'>{@link org.apache.juneau.http.ProxyAuthorization}
<li class='jc'>{@link org.apache.juneau.http.Range}
<li class='jc'>{@link org.apache.juneau.http.Referer}
<li class='jc'>{@link org.apache.juneau.http.TE}
<li class='jc'>{@link org.apache.juneau.http.UserAgent}
<li class='jc'>{@link org.apache.juneau.http.Upgrade}
<li class='jc'>{@link org.apache.juneau.http.Via}
<li class='jc'>{@link org.apache.juneau.http.Warning}
<li class='jc'>{@link java.util.TimeZone}
</ul>
<li><b>Direct streams on request/response:</b>
<ul>
<li class='jc'>{@link java.io.InputStream}
<li class='jc'>{@link javax.servlet.ServletInputStream}
<li class='jc'>{@link java.io.Reader}
<li class='jc'>{@link java.io.OutputStream}
<li class='jc'>{@link javax.servlet.ServletOutputStream}
<li class='jc'>{@link java.io.Writer}
</ul>
<li><b>Localization:</b>
<ul>
<li class='jc'>{@link java.util.ResourceBundle} - Client-localized resource bundle.
<li class='jc'>{@link org.apache.juneau.utils.MessageBundle} - A resource bundle with additional features.
<li class='jc'>{@link java.util.Locale} - Client locale.
</ul>
<li><b>Request APIs:</b>
<ul>
<li class='jc'>{@link org.apache.juneau.rest.RequestHeaders} - API for accessing request headers.
<li class='jc'>{@link org.apache.juneau.rest.RequestQuery} - API for accessing request query parameters.
<li class='jc'>{@link org.apache.juneau.rest.RequestFormData} - API for accessing request form data.
<li class='jc'>{@link org.apache.juneau.rest.RequestPath} - API for accessing path variables.
<li class='jc'>{@link org.apache.juneau.rest.RequestBody} - API for accessing request body.
</ul>
<li><b>Other:</b>
<ul>
<li class='jc'>{@link org.apache.juneau.http.HttpMethod} - The method name matched (when using <c><ja>@RestMethod</ja>(name=<js>"*"</js>)</c>)
<li class='jc'>{@link org.apache.juneau.rest.RestLogger} - Logger with additional features.
<li class='jc'>{@link org.apache.juneau.rest.RestContext} - The resource read-only context.
<li class='jc'>{@link org.apache.juneau.parser.Parser} - The parser matching the request content type.
<li class='jc'>{@link org.apache.juneau.parser.ReaderParser} - The reader parser matching the request content type.
<li class='jc'>{@link org.apache.juneau.parser.InputStreamParser} - The input stream parser matching the request content type.
<li class='jc'>{@link org.apache.juneau.dto.swagger.Swagger} - The auto-generated Swagger doc.
<li class='jc'>{@link org.apache.juneau.config.Config} - The external config for the resource.
<li class='jc'>{@link org.apache.juneau.rest.RequestProperties} - API for modifying request-time configuration properties.
</ul>
</ul>
<li><b>Annotated parameters:</b>
<ul>
<li class='ja'>{@link org.apache.juneau.http.annotation.Path} - Variables in matched URL path patterns.
<li class='ja'>{@link org.apache.juneau.http.annotation.FormData} - Multipart form post parameter values.
<li class='ja'>{@link org.apache.juneau.http.annotation.HasFormData} - Denotes whether the form data parameter exists.
<li class='ja'>{@link org.apache.juneau.http.annotation.Query} - Query parameters. Using this prevents the HTTP body from being processed as a URL-Encoded form post.
<li class='ja'>{@link org.apache.juneau.http.annotation.HasQuery} - Denotes whether the query parameter exists.
<li class='ja'>{@link org.apache.juneau.http.annotation.Header} - A header value.
<li class='ja'>{@link org.apache.juneau.http.annotation.Body} - The HTTP content parsed as a POJO.
<li class='ja'>{@link org.apache.juneau.rest.annotation.Method} - The HTTP method name.
<li class='ja'>{@link org.apache.juneau.http.annotation.Request} - HTTP request parts available through a proxy bean interface.
<li class='ja'>{@link org.apache.juneau.http.annotation.Response} - HTTP response parts available through a POJO.
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseHeader} - HTTP response header.
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseStatus} - HTTP response status code.
</ul>
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/example1/{a1}/{a2}/{a3}/*"</js>)
<jk>public</jk> String doGetExample1(
RestRequest req,
RestResponse res,
<ja>@Method</ja> String method,
<ja>@Path</ja>(<js>"a1"</js>) String a1,
<ja>@Path</ja>(<js>"a2"</js>) <jk>int</jk> a2,
<ja>@Path</ja>(<js>"a3"</js>) 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>@HasQuery</ja>(<js>"p3"</js>) boolean hasP3,
<ja>@Path</ja>(<js>"/*"</js>) String remainder,
<ja>@Header</ja>(<js>"Accept-Language"</js>) String lang,
<ja>@Header</ja>(<js>"Accept"</js>) String accept,
<ja>@Header</ja>(<js>"DNT"</js>) <jk>int</jk> doNotTrack,
RequestProperties properties,
ResourceBundle nls
) {
<jc>// Do something with all of those</jc>
}
</p>
<ul class='notes'>
<li>All annotations have programmatic equivalents on the {@link org.apache.juneau.rest.RestRequest} class.
</ul>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_paramResolvers} - For configuring custom parameter types.
</ul>
</div><!-- END: 6.6.1 - juneau-rest-server.RestMethod.MethodParameters -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.RestRequest' id='juneau-rest-server.RestMethod.RestRequest'>6.6.2 - RestRequest</a></h4>
<div class='topic'><!-- START: 6.6.2 - juneau-rest-server.RestMethod.RestRequest -->
<p>
The {@link org.apache.juneau.rest.RestRequest} object is an extension of the <l>HttpServletRequest</l> class
with various built-in convenience methods for use in building REST interfaces.
It can be accessed by passing it as a parameter on your REST Java method:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public</jk> Object myMethod(RestRequest req) {...}
</p>
<p>
There are many useful methods on this object, but the main ones are shown below:
</p>
<ul class='javatree'>
<li class='jc'><c>{@link org.apache.juneau.rest.RestRequest} <jk>extends</jk> HttpServletRequest</c>
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getHeaders() getHeaders()} - HTTP request headers.
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getQuery() getQuery()} - Query parameters.
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getFormData() getFormData()} - Form-data parameters.
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getBody() getBody()} - HTTP request body.
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getPathMatch() getPathMatch()} - Path match variables.
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getLogger() getLogger()} - Logging.
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getInfoProvider() getInfoProvider()} - Swagger documentation provider.
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getSwagger() getSwagger()} - Generated Swagger information.
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getConfig() getConfig()} - External configuration API.
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getVarResolverSession() getVarResolverSession()} - String variable resolver.
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getMessageBundle() getMessageBundle()} - Localized messages.
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getProperties() getProperties()} - Configuration properties.
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getClasspathReaderResource(String,boolean,MediaType,boolean) getClasspathReaderResource(String,boolean,MediaType,boolean)} - Various methods for retrieving static files from classpath.
</ul>
</ul>
</div><!-- END: 6.6.2 - juneau-rest-server.RestMethod.RestRequest -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.RestResponse' id='juneau-rest-server.RestMethod.RestResponse'>6.6.3 - RestResponse</a></h4>
<div class='topic'><!-- START: 6.6.3 - juneau-rest-server.RestMethod.RestResponse -->
<p>
The {@link org.apache.juneau.rest.RestResponse} object is an extension of the <l>HttpServletResponse</l> class
with various built-in convenience methods for use in building REST interfaces.
It can be accessed by passing it as a parameter on your REST Java method:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public</jk> Object myMethod(RestResponse req) {...}
</p>
<p>
Some important methods on this class are:
</p>
<ul class='javatree'>
<li class='jc'><c>{@link org.apache.juneau.rest.RestResponse} <jk>extends</jk> HttpServletResponse</c>
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RestResponse#setOutput(Object) setOutput(Object)} - Set response output programmatically.
<li class='jm'>{@link org.apache.juneau.rest.RestResponse#getHtmlDocBuilder() getHtmlDocBuilder()} - Set HTTP page contents programmatically.
<li class='jm'>{@link org.apache.juneau.rest.RestResponse#getDirectWriter(String) getDirectWriter(String)} - Direct access to underlying response writer.
</ul>
</ul>
</div><!-- END: 6.6.3 - juneau-rest-server.RestMethod.RestResponse -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.RequestBody' id='juneau-rest-server.RestMethod.RequestBody'>6.6.4 - RequestBody</a></h4>
<div class='topic'><!-- START: 6.6.4 - juneau-rest-server.RestMethod.RequestBody -->
<p>
The {@link org.apache.juneau.rest.RequestBody} object is the API for accessing the body of an HTTP request.
It can be accessed by passing it as a parameter on your REST Java method:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public</jk> Object myMethod(RequestBody body) {...}
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public void</jk> doPost(RequestBody body) {
<jc>// Convert body to a linked list of Person objects.</jc>
List&lt;Person&gt; l = body.asType(LinkedList.<jk>class</jk>, Person.<jk>class</jk>);
...
}
</p>
<p>
Some important methods on this class are:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.RequestBody}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RequestBody#getReader() getReader()} - Get body as a Reader.
<li class='jm'>{@link org.apache.juneau.rest.RequestBody#getInputStream() getInputStream()} - Get body as an InputStream.
<li class='jm'>{@link org.apache.juneau.rest.RequestBody#asType(Class) asType(Class)} - Get body converted to a POJO.
<li class='jm'>{@link org.apache.juneau.rest.RequestBody#asType(Type,Type...) asType(Type,Type...)} - Get body converted to a map or collection of POJOs.
<li class='jm'>{@link org.apache.juneau.rest.RequestBody#asString() asString()} - Get body as a simple string.
<li class='jm'>{@link org.apache.juneau.rest.RequestBody#asHex() asHex()} - Get body as a hex-encoded string.
<li class='jm'>{@link org.apache.juneau.rest.RequestBody#asSpacedHex() asSpacedHex()} - Get body as spaced-hex-encoded string.
</ul>
</ul>
<ul class='seealso'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Body}
</ul>
</div><!-- END: 6.6.4 - juneau-rest-server.RestMethod.RequestBody -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.RequestHeaders' id='juneau-rest-server.RestMethod.RequestHeaders'>6.6.5 - RequestHeaders</a></h4>
<div class='topic'><!-- START: 6.6.5 - juneau-rest-server.RestMethod.RequestHeaders -->
<p>
The {@link org.apache.juneau.rest.RequestHeaders} object is the API for accessing the headers of an HTTP request.
It can be accessed by passing it as a parameter on your REST Java method:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public</jk> Object myMethod(RequestHeaders headers) {...}
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public</jk> Object myMethod(RequestHeaders headers) {
<jc>// Add a default value.</jc>
headers.addDefault(<js>"ETag"</js>, <jsf>DEFAULT_UUID</jsf>);
<jc>// Get a header value as a POJO.</jc>
UUID etag = headers.get(<js>"ETag"</js>, UUID.<jk>class</jk>);
<jc>// Get a standard header.</jc>
CacheControl = headers.getCacheControl();
}
</p>
<p>
Some important methods on this class are:
</p>
<ul class='javatree'>
<li class='jc'><c>{@link org.apache.juneau.rest.RequestHeaders} <jk>extends</jk> TreeMap&lt;String,String[]&gt;</c>
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RequestHeaders#get(String,Class) get(String,Class)} - Get header value converted to a POJO.
<li class='jm'>{@link org.apache.juneau.rest.RequestHeaders#get(String,Type,Type...) get(String,Type,Type)} - Get header value converted to a map or collection of POJOs.
<li class='jm'>{@link org.apache.juneau.rest.RequestHeaders#getString(String,String) getString(String,String)} - Get header value as a simple string.
<li class='jm'>{@link org.apache.juneau.rest.RequestHeaders#getInt(String,int) getInt(String,int)} - Get header value as an integer.
<li class='jm'>{@link org.apache.juneau.rest.RequestHeaders#getBoolean(String,boolean) getBoolean(String,boolean)} - Get header value as a boolean.
<li class='jm'>{@link org.apache.juneau.rest.RequestHeaders#addDefault(String,Object) addDefault(String,Object)} - Programmatically set a default value for a header.
</ul>
</ul>
<ul class='seealso'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Header}
</ul>
</div><!-- END: 6.6.5 - juneau-rest-server.RestMethod.RequestHeaders -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.RequestAttributes' id='juneau-rest-server.RestMethod.RequestAttributes'>6.6.6 - RequestAttributes</a></h4>
<div class='topic'><!-- START: 6.6.6 - juneau-rest-server.RestMethod.RequestAttributes -->
<p>
The {@link org.apache.juneau.rest.RequestAttributes} object is the API for accessing the standard servlet attributes on an HTTP request
(i.e. {@link javax.servlet.ServletRequest#getAttribute(String)}.
It wraps the request attributes in a {@link java.util.Map} interface and provides several convenience methods.
</p>
<p>
The <c>RequestAttributes</c> object extends from {@link org.apache.juneau.ObjectMap} so all the convenience methods defined on
that API are also available when working with request attributes:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public</jk> Object myMethod(RequestAttributes attributes) {...}
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public</jk> Object myMethod(RequestAttributes attributes) {
<jc>// Add a default value.</jc>
attributes.putIfNotExists(<js>"Foo"</js>, 123);
<jc>// Get an attribute value as a POJO.</jc>
UUID etag = attributes.get(<js>"ETag"</js>, UUID.<jk>class</jk>);
}
</p>
<p>
Modifications made to request attributes through the <c>RequestAttributes</c> bean are automatically reflected in
the underlying servlet request attributes making it possible to mix the usage of both APIs.
</p>
</div><!-- END: 6.6.6 - juneau-rest-server.RestMethod.RequestAttributes -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.RequestQuery' id='juneau-rest-server.RestMethod.RequestQuery'>6.6.7 - RequestQuery</a></h4>
<div class='topic'><!-- START: 6.6.7 - juneau-rest-server.RestMethod.RequestQuery -->
<p>
The {@link org.apache.juneau.rest.RequestQuery} object is the API for accessing the GET query parameters of an HTTP request.
It can be accessed by passing it as a parameter on your REST Java method:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public</jk> Object myMethod(RequestQuery query) {...}
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public</jk> Object myMethod(RequestQuery query) {
<jc>// Get query parameters converted to various types.</jc>
<jk>int</jk> p1 = query.get(<js>"p1"</js>, 0, <jk>int</jk>.<jk>class</jk>);
String p2 = query.get(<js>"p2"</js>, String.<jk>class</jk>);
UUID p3 = query.get(<js>"p3"</js>, UUID.<jk>class</jk>);
}
</p>
<p>
An important distinction between the behavior of this object and <l>HttpServletRequest.getParameter(String)</l> is
that the former will NOT load the body of the request on FORM POSTS and will only look at parameters
found in the query string.
This can be useful in cases where you're mixing GET parameters and FORM POSTS and you don't want to
inadvertently read the body of the request to get a query parameter.
</p>
<p>
Some important methods on this class are:
</p>
<ul class='javatree'>
<li class='jc'><c>{@link org.apache.juneau.rest.RequestQuery} <jk>extends</jk> LinkedHashMap&lt;String,String[]&gt;</c>
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RequestQuery#get(String,Class) get(String,Class)} - Get query parameter value converted to a POJO.
<li class='jm'>{@link org.apache.juneau.rest.RequestQuery#get(String,Type,Type...) get(String,Type,Type)} - Get query parameter value converted to a map or collection of POJOs.
<li class='jm'>{@link org.apache.juneau.rest.RequestQuery#getString(String,String) getString(String,String)} - Get query parameter value as a simple string.
<li class='jm'>{@link org.apache.juneau.rest.RequestQuery#getInt(String,int) getInt(String,int)} - Get query parameter value as an integer.
<li class='jm'>{@link org.apache.juneau.rest.RequestQuery#getBoolean(String,boolean) getBoolean(String,boolean)} - Get query parameter value as a boolean.
<li class='jm'>{@link org.apache.juneau.rest.RequestQuery#addDefault(String,Object) addDefault(String,Object)} - Programmatically set a default value for a query parameter.
<li class='jm'>{@link org.apache.juneau.rest.RequestQuery#getSearchArgs() getSearchArgs()} - Returns query parameter search arguments.
</ul>
</ul>
<ul class='seealso'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Query}
<li class='ja'>{@link org.apache.juneau.http.annotation.HasQuery}
</ul>
</div><!-- END: 6.6.7 - juneau-rest-server.RestMethod.RequestQuery -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.RequestFormData' id='juneau-rest-server.RestMethod.RequestFormData'>6.6.8 - RequestFormData</a></h4>
<div class='topic'><!-- START: 6.6.8 - juneau-rest-server.RestMethod.RequestFormData -->
<p>
The {@link org.apache.juneau.rest.RequestFormData} object is the API for accessing the HTTP request body as form data.
It can be accessed by passing it as a parameter on your REST Java method:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public</jk> Object myMethod(RequestFormData query) {...}
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public</jk> Object myMethod(RequestFormData formData) {
<jc>// Get query parameters converted to various types.</jc>
<jk>int</jk> p1 = formData.get(<js>"p1"</js>, 0, <jk>int</jk>.<jk>class</jk>);
String p2 = formData.get(<js>"p2"</js>, String.<jk>class</jk>);
UUID p3 = formData.get(<js>"p3"</js>, UUID.<jk>class</jk>);
}
</p>
<p>
Note that this object does NOT take GET parameters into account and only returns values found in the body of the request.
</p>
<p>
Some important methods on this class are:
</p>
<ul class='javatree'>
<li class='jc'><c>{@link org.apache.juneau.rest.RequestFormData} <jk>extends</jk> LinkedHashMap&lt;String,String[]&gt;</c>
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RequestFormData#get(String,Class) get(String,Class)} - Get form-data parameter values converted to a POJO.
<li class='jm'>{@link org.apache.juneau.rest.RequestFormData#get(String,Type,Type...) get(String,Type,Type)} - Get form-data parameter value converted to a map or collection of POJOs.
<li class='jm'>{@link org.apache.juneau.rest.RequestFormData#getString(String,String) getString(String,String)} - Get form-data parameter value as a simple string.
<li class='jm'>{@link org.apache.juneau.rest.RequestFormData#getInt(String,int) getInt(String,int)} - Get form-data parameter value as an integer.
<li class='jm'>{@link org.apache.juneau.rest.RequestFormData#getBoolean(String,boolean) getBoolean(String,boolean)} - Get form-data parameter value as a boolean.
<li class='jm'>{@link org.apache.juneau.rest.RequestFormData#addDefault(String,Object) addDefault(String,Object)} - Programmatically set a default value for a form-data parameter.
</ul>
</ul>
<ul class='seealso'>
<li class='ja'>{@link org.apache.juneau.http.annotation.FormData}
<li class='ja'>{@link org.apache.juneau.http.annotation.HasFormData}
</ul>
</div><!-- END: 6.6.8 - juneau-rest-server.RestMethod.RequestFormData -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.RestMethodPath' id='juneau-rest-server.RestMethod.RestMethodPath'>6.6.9 - @RestMethod(path)</a></h4>
<div class='topic'><!-- START: 6.6.9 - juneau-rest-server.RestMethod.RestMethodPath -->
<p>
The {@link org.apache.juneau.rest.annotation.RestMethod#path() @RestMethod(path)} annotation allows
you to define URL path patterns to match against.
These patterns can contain variables of the form <l>"{xxx}"</l> that can be passed in directly to the
Java methods as extra parameters.
</p>
<p>
In the following example, 3 separate GET request handlers are defined with different path patterns.
Note how the variables are passed in as additional arguments on the method, and how those arguments are
automatically converted to the specified class type...
</p>
<p class='bpcode w800'>
<jc>// Default method</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>)
<jk>public void</jk> doGetDefault() {
...
}
<jc>// Method with path pattern</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/xxx"</js>)
<jk>public void</jk> doGetNoArgs(...) {
...
}
<jc>// Method with path pattern with arguments</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/xxx/{foo}/{bar}/{baz}/{bing}"</js>)
<jk>public void</jk> doGetWithArgs(<ja>@Path</ja>(<js>"foo"</js>) String foo, <ja>@Path</ja>(<js>"bar"</js>) <jk>int</jk> bar, <ja>@Path</ja>(<js>"baz"</js>) MyEnum baz, <ja>@Path</ja>(<js>"bing"</js>) UUID bing) {
...
}
</p>
<p>
By default, path patterns are matched using a best-match heuristic.
When overlaps occur, URLs are matched from most-specific to most-general order:
</p>
<p class='bpcode w800'>
<jc>// Try first </jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foo/bar"</js>)
<jk>public void</jk> method1() {
...
}
<jc>// Try second</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foo/{bar}"</js>)
<jk>public void</jk> method2(...) {
...
}
<jc>// Try third</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foo/*"</js>)
<jk>public void</jk> method3(...) {
...
}
<jc>// Try last</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>)
<jk>public void</jk> method4(...) {
...
}
</p>
<p>
The match heuristic behavior can be overridden by the
{@link org.apache.juneau.rest.annotation.RestMethod#priority() @RestMethod(priority)} annotation
property.
However, in practice this is almost never needed.
</p>
<p>
Paths that end with <js>"/*"</js> will do a prefix match on the incoming URL.
Any remainder after the match can be accessed through
{@link org.apache.juneau.rest.RequestPath#getRemainder()} or parameters with the
<c><ja>@Path</ja>(<js>"/*"</js>)</c> annotation.
On the other hand, paths that don't end with <js>"/*"</js> (e.g. <js>"/"</js> or <js>"/foo"</js>) will
require an exact URL match, and if any remainder exists, a 404 (not found) error will be thrown.
</p>
<p>
The following example shows the distinction.
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>)
<jk>public void</jk> doGet(<ja>@Path</ja>(<js>"/*"</js>) String remainder) {
<jc>// URL path pattern can have remainder accessible through req.getRemainder().</jc>
}
<ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, path=<js>"/"</js>)
<jk>public void</jk> doPut() {
<jc>// URL path pattern must match exactly and will cause a 404 error if a remainder exists.</jc>
}
</p>
<p>
Annotations are provided for easy access to URL parameters with automatic conversion to any {@doc PojoCategories parsable} type.
For example, the following example can process the URL <l>"/urlWithParams?foo=foo&amp;bar=[1,2,3]&amp;baz=067e6162-3b6f-4ae2-a171-2470b63dff00"</l>...
</p>
<p class='bpcode w800'>
<jc>// Example GET request with access to query parameters</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/urlWithParams"</js>)
<jk>public</jk> String doGetWithParams(<ja>@Query</ja>(<js>"foo"</js>) String foo, <ja>@Query</ja>(<js>"bar"</js>) <jk>int</jk> bar, <ja>@Query</ja>(<js>"baz"</js>) UUID baz) <jk>throws</jk> Exception {
<jk>return</jk> <js>"GET /urlWithParams?foo="</js>+foo+<js>"&amp;bar="</js>+bar+<js>"&amp;baz="</js>+baz;
}
</p>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_path}
<li class='ja'>{@link org.apache.juneau.http.annotation.Path}
<li class='jc'>{@link org.apache.juneau.rest.RequestPath}
</ul>
</div><!-- END: 6.6.9 - juneau-rest-server.RestMethod.RestMethodPath -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.RequestPathMatch' id='juneau-rest-server.RestMethod.RequestPathMatch'>6.6.10 - RequestPathMatch</a></h4>
<div class='topic'><!-- START: 6.6.10 - juneau-rest-server.RestMethod.RequestPathMatch -->
<p>
The {@link org.apache.juneau.rest.RequestPath} object is the API for accessing the matched variables
and remainder on the URL path.
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public</jk> Object myMethod(RequestPathMatch path) {...}
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(..., path=<js>"/{foo}/{bar}/{baz}/*"</js>)
<jk>public void</jk> doGet(RequestPathMatch path) {
<jc>// Example URL: /123/qux/true/quux</jc>
<jk>int</jk> foo = pm.getInt(<js>"foo"</js>); <jc>// =123</jc>
String bar = pm.getString(<js>"bar"</js>); <jc>// =qux</jc>
<jk>boolean</jk> baz = pm.getBoolean(<js>"baz"</js>); <jc>// =true</jc>
String remainder = pm.getRemainder(); <jc>// =quux</jc>
}
</p>
<p>
Some important methods on this class are:
</p>
<ul class='javatree'>
<li class='jc'><c>{@link org.apache.juneau.rest.RequestPath} <jk>extends</jk> TreeMap&lt;String,String&gt;</c>
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RequestPath#get(String,Class) get(String,Class)} - Get path match variable converted to a POJO.
<li class='jm'>{@link org.apache.juneau.rest.RequestPath#get(String,Type,Type...) get(String,Type,Type)} - Get path match variable converted to a map or collection of POJOs.
<li class='jm'>{@link org.apache.juneau.rest.RequestPath#getString(String) getString(String)} - Get patch match variable as a simple string.
<li class='jm'>{@link org.apache.juneau.rest.RequestPath#getInt(String) getInt(String)} - Get path match variable as an integer.
<li class='jm'>{@link org.apache.juneau.rest.RequestPath#getBoolean(String) getBoolean(String)} - Get path match variable as a boolean.
<li class='jm'>{@link org.apache.juneau.rest.RequestPath#getRemainder() getRemainder()} - Get the path match remainder.
</ul>
</ul>
<ul class='seealso'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Path}
</ul>
</div><!-- END: 6.6.10 - juneau-rest-server.RestMethod.RequestPathMatch -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.MethodReturnTypes' id='juneau-rest-server.RestMethod.MethodReturnTypes'>6.6.11 - Method Return Types</a></h4>
<div class='topic'><!-- START: 6.6.11 - juneau-rest-server.RestMethod.MethodReturnTypes -->
<p>
The return type can be any serializable POJO as defined in {@doc PojoCategories}.
It can also be <jk>void</jk> if the method is not sending any output (e.g. a request redirect) or is
setting the output using the {@link org.apache.juneau.rest.RestResponse#setOutput(Object)} method.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
<jk>public</jk> String doGet() {
<jk>return</jk> <js>"Hello World!"</js>;
}
</p>
<p>
Out-of-the-box, besides POJOs, the following return types are handled as special cases:
</p>
<ul class='spaced-list'>
<li class='jc'>{@link java.io.InputStream}
<br>The contents are simply piped to the output stream returned by
{@link org.apache.juneau.rest.RestResponse#getNegotiatedOutputStream()}.
<br>Note that you should call {@link org.apache.juneau.rest.RestResponse#setContentType(String)} to set
the <l>Content-Type</l> header if you use this object type.
<li class='jc'>{@link java.io.Reader}
<br>The contents are simply piped to the output stream returned by
{@link org.apache.juneau.rest.RestResponse#getNegotiatedWriter()}.
<br>Note that you should call {@link org.apache.juneau.rest.RestResponse#setContentType(String)} to set
the <l>Content-Type</l> header if you use this object type.
<li class='jc'>{@link org.apache.juneau.Streamable}
<br>Interface that identifies that an object can be serialized directly to an output stream.
<li class='jc'>{@link org.apache.juneau.Writable}
<br>Interface that identifies that an object can be serialized directly to a writer.
<li class='jc'>{@link org.apache.juneau.utils.ZipFileList}
<br>Special interface for sending zip files as responses.
</ul>
<p>
This is controlled through the following extensible API:
</p>
<ul class='javatree'>
<li class='jic'>{@link org.apache.juneau.rest.ResponseHandler}
<ul>
<li class='jc'>{@link org.apache.juneau.rest.reshandlers.DefaultHandler}
<li class='jc'>{@link org.apache.juneau.rest.reshandlers.InputStreamHandler}
<li class='jc'>{@link org.apache.juneau.rest.reshandlers.ReaderHandler}
</ul>
</ul>
<p>
REST Java methods can generate output in any of the following ways:
</p>
<ul class='spaced-list'>
<li>
By returning a serializable POJO, or any of the following:
<br>{@link java.io.Reader}, {@link java.io.InputStream}, {@link org.apache.juneau.Streamable},
{@link org.apache.juneau.Writable}
<li>
By calling {@link org.apache.juneau.rest.RestResponse#setOutput(Object)} with any of the types above.
<li>
By accessing the {@link java.io.Writer} directly by calling
{@link org.apache.juneau.rest.RestResponse#getNegotiatedWriter()} and writing the output yourself.
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Equivalent method 1</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/example1/{personId}"</js>)
<jk>public</jk> Person doGet1(<ja>@Path</ja>(<js>"personId"</js>) UUID personId) {
Person p = getPersonById(personId);
<jk>return</jk> p;
}
<jc>// Equivalent method 2</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/example2/{personId}"</js>)
<jk>public void</jk> doGet2(RestResponse res, <ja>@Path</ja>(<js>"personId"</js>) UUID personId) {
Person p = getPersonById(personId);
res.setOutput(p);
}
<jc>// (Sorta) Equivalent method 3</jc>
<jc>// (Ignores any converters or method-level properties)</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/example3/{personId}"</js>)
<jk>public void</jk> doGet3(RestRequest req, RestResponse res, <ja>@Path</ja>(<js>"personId"</js>) UUID personId) {
Person p = getPersonById(personId);
String accept = req.getHeader(<js>"Accept"</js>, <js>"text/json"</js>);
WriterSerializer s = res.getSerializerGroup().getWriterSerializer(accept);
res.setContentType(s.getResponseContentType());
s.serialize(p, res.getNegotiatedWriter());
}
</p>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_responseHandlers} - For configuring custom response handlers.
</ul>
</div><!-- END: 6.6.11 - juneau-rest-server.RestMethod.MethodReturnTypes -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.ReaderResource' id='juneau-rest-server.RestMethod.ReaderResource'>6.6.12 - ReaderResource</a></h4>
<div class='topic'><!-- START: 6.6.12 - juneau-rest-server.RestMethod.ReaderResource -->
<p>
The {@link org.apache.juneau.http.ReaderResource} class is a convenience object for defining thread-safe
reusable character-based responses.
In essence, it's a container for character data with optional response headers and support for
resolving SVL variables.
</p>
<p>
The class is annotated with {@link org.apache.juneau.http.annotation.Response @Response}
which allows it to be returned as responses by REST methods.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>
<jk>public</jk> Object sayHello(RestRequest req) {
<jc>// Return a reader resource loaded from a file with support for request-time SVL variables.</jc>
<jk>return</jk> ReaderResource.<jsm>create</jsm>()
.contents(<jk>new</jk> File(<js>"helloWorld.txt"</js>))
.varResolver(req.getVarResolver())
.header(<js>"Cache-Control"</js>, <js>"no-cache"</js>)
.mediaType(<jsf>TEXT_PLAIN</jsf>)
.build();
}
</p>
</div><!-- END: 6.6.12 - juneau-rest-server.RestMethod.ReaderResource -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.StreamResource' id='juneau-rest-server.RestMethod.StreamResource'>6.6.13 - StreamResource</a></h4>
<div class='topic'><!-- START: 6.6.13 - juneau-rest-server.RestMethod.StreamResource -->
<p>
The {@link org.apache.juneau.http.StreamResource} class is the binary equivalent to the {@link org.apache.juneau.http.ReaderResource} object.
In essence, it's a container for binary data with optional response headers.
</p>
<p>
The class is annotated with {@link org.apache.juneau.http.annotation.Response @Response}
which allows it to be returned as responses by REST methods.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public</jk> Object showPicture(RestRequest req) {
<jc>// Return a stream resource loaded from a file.</jc>
<jk>return</jk> StreamResource.<jsm>create</jsm>()
.contents(<jk>new</jk> File(<js>"mypicture.png"</js>))
.header(<js>"Cache-Control"</js>, <js>"no-cache"</js>)
.mediaType(<jsf>IMAGE_PNG</jsf>)
.build();
}
</p>
</div><!-- END: 6.6.13 - juneau-rest-server.RestMethod.StreamResource -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.RestMethodMatchers' id='juneau-rest-server.RestMethod.RestMethodMatchers'>6.6.14 - @RestMethod(matchers)</a></h4>
<div class='topic'><!-- START: 6.6.14 - juneau-rest-server.RestMethod.RestMethodMatchers -->
<p>
{@link org.apache.juneau.rest.RestMatcher RestMatchers} are used to allow multiple Java methods to be
tied to the same HTTP method and path, but differentiated by some request attribute such as a specific
header value.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// GET method that gets invoked for administrators</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>, matchers=IsAdminMatcher.<jk>class</jk>)
<jk>public</jk> Object doGetForAdmin() {
...
}
<jc>// GET method that gets invoked for everyone else</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>)
<jk>public</jk> Object doGetForEveryoneElse() {
...
}
</p>
<p>
The interface for matchers is simple:
</p>
<p class='bpcode w800'>
<jk>public class</jk> IsAdminMatcher <jk>extends</jk> RestMatcher {
<ja>@Override</ja> <jc>/* RestMatcher */</jc>
<jk>public boolean</jk> matches(RestRequest req) {
<jk>return</jk> req.isUserInRole(<js>"ADMINS_GROUP"</js>);
}
}
</p>
<ul class='notes'>
<li>
If no methods are found with a matching matcher, a <l>412 Precondition Failed</l> status is returned.
<li>
If multiple matchers are specified on the same method, ONLY ONE matcher needs to match for the
method to be invoked.
<li>
Note that you CANNOT define identical paths on different methods UNLESS you use matchers.
<br>That includes paths that are only different in variable names (e.g. <l>"/foo/{bar}"</l> and
<l>"/foo/{baz}"</l>).
<br>If you try to do so, a <l>ServletException</l> will be thrown on startup.
<li>
Methods with matchers take precedence over methods without.
<br>Otherwise, methods are attempted in the order they appear in the class.
</ul>
<ul class='seealso'>
<li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#matchers RestMethod(matchers)}
<li class='jc'>{@link org.apache.juneau.rest.matchers.MultipartFormDataMatcher}
<li class='jc'>{@link org.apache.juneau.rest.matchers.UrlEncodedFormMatcher}
</ul>
</div><!-- END: 6.6.14 - juneau-rest-server.RestMethod.RestMethodMatchers -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.PredefinedResponses' id='juneau-rest-server.RestMethod.PredefinedResponses'>6.6.15 - Predefined Responses</a></h4>
<div class='topic'><!-- START: 6.6.15 - juneau-rest-server.RestMethod.PredefinedResponses -->
<p>
Predefined response beans are provided for all standard HTTP responses.
These can be used as-is or extended to provide customized HTTP responses.
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/pets"</js>)
<jk>public</jk> Ok addPet(<ja>@Body</ja> Pet pet) {
<jsm>addPet</jsm>(Pet);
<jc>// Predefined "200 OK" response bean.</jc>
<jk>return new</jk> Ok(); <jc>// Could also use Ok.OK instance</jc>
}
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/pets"</js>)
<jk>public</jk> SeeOther addPet(<ja>@Body</ja> Pet pet) {
<jsm>addPet</jsm>(Pet);
<jc>// Predefined "302 See Other" response bean with redirect to /pets.</jc>
<jk>return new</jk> SeeOther(<js>"servlet:/pets"</js>);
}
</p>
<ul class='javatree'>
<li class='jp'>{@link org.apache.juneau.http.response}
<ul>
<li class='jc'>{@link org.apache.juneau.http.response.Accepted}
<li class='jc'>{@link org.apache.juneau.http.response.AlreadyReported}
<li class='jc'>{@link org.apache.juneau.http.response.Continue}
<li class='jc'>{@link org.apache.juneau.http.response.Created}
<li class='jc'>{@link org.apache.juneau.http.response.EarlyHints}
<li class='jc'>{@link org.apache.juneau.http.response.Found}
<li class='jc'>{@link org.apache.juneau.http.response.IMUsed}
<li class='jc'>{@link org.apache.juneau.http.response.MovedPermanently}
<li class='jc'>{@link org.apache.juneau.http.response.MultipleChoices}
<li class='jc'>{@link org.apache.juneau.http.response.MultiStatus}
<li class='jc'>{@link org.apache.juneau.http.response.NoContent}
<li class='jc'>{@link org.apache.juneau.http.response.NonAuthoritiveInformation}
<li class='jc'>{@link org.apache.juneau.http.response.NotModified}
<li class='jc'>{@link org.apache.juneau.http.response.Ok}
<li class='jc'>{@link org.apache.juneau.http.response.PartialContent}
<li class='jc'>{@link org.apache.juneau.http.response.PermanentRedirect}
<li class='jc'>{@link org.apache.juneau.http.response.Processing}
<li class='jc'>{@link org.apache.juneau.http.response.ResetContent}
<li class='jc'>{@link org.apache.juneau.http.response.SeeOther}
<li class='jc'>{@link org.apache.juneau.http.response.SwitchingProtocols}
<li class='jc'>{@link org.apache.juneau.http.response.TemporaryRedirect}
<li class='jc'>{@link org.apache.juneau.http.response.UseProxy}
</ul>
</ul>
<p>
These predefined response beans are an example of {@link org.apache.juneau.http.annotation.Response @Response}-annotated
objects that are describe in detail later.
Without going into details, this is how the {@link org.apache.juneau.http.response.SeeOther} is defined:
</p>
<p class='bpcode w800'>
<ja>@Response</ja>(
code=303 <jc>// Set automatically on response</jc>,
description=<js>"See Other"</js> <jc>// Used in generated Swagger</jc>
)
<jk>public class</jk> SeeOther {
<jk>private final</jk> String <jf>message</jf>;
<jk>private final</jk> URI <jf>location</jf>;
<jc>// Constructors omitted.</jc>
<jc>// Used to populate Location response header.</jc>
<ja>@ResponseHeader</ja>(name=<js>"Location"</js>)
<jk>public</jk> URI getLocation() {
<jk>return</jk> <jf>location</jf>;
}
<jc>// Used during serialization.</jc>
<ja>@ResponseBody</ja>
<jk>public</jk> String toString() {
<jk>return</jk> <jf>message</jf>;
}
}
</p>
<p>
The {@link org.apache.juneau.rest.helper.SeeOtherRoot} class shows how these predefined beans can be extended.
</p>
<p class='bpcode w800'>
<ja>@Response</ja>(
description=<js>"Redirect to servlet root"</js> <jc>// Override description in generated Swagger.</jc>
)
<jk>public class</jk> SeeOtherServletRoot <jk>extends</jk> SeeOther {
<jk>public</jk> SeeOtherServletRoot() {
<jk>super</jk>(URI.create("servlet:/"));
}
}
</p>
<p>
Note that the runtime behavior of the following code is identical to the example above.
However, the important distinction is that in the previous example, the 302 response would show in
the generated Swagger (since we can see the response through reflection), whereas it will NOT show up
in the following example (since all we see is an Object response).
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/pets"</js>)
<jk>public</jk> Object addPet(<ja>@Body</ja> Pet pet) {
<jsm>addPet</jsm>(Pet);
<jc>// Note the Object return type.</jc>
<jk>return new</jk> SeeOther(<js>"servlet:/pets"</js>);
}
</p>
</div><!-- END: 6.6.15 - juneau-rest-server.RestMethod.PredefinedResponses -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.PredefinedExceptions' id='juneau-rest-server.RestMethod.PredefinedExceptions'>6.6.16 - Predefined Exceptions</a></h4>
<div class='topic'><!-- START: 6.6.16 - juneau-rest-server.RestMethod.PredefinedExceptions -->
<p>
Exceptions are defined for all standardized HTTP responses.
These can be used to trigger HTTP errors simply by throwing an exception.
</p>
<p>
These are identical in behavior to the Predefined Responses in the previous section, except these are meant
to be thrown instead of returned.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/user/login"</js>)
<jk>public</jk> Ok login(
<ja>@FormData</ja>(<js>"username"</js>) String username,
<ja>@FormData</ja>(<js>"password"</js>) String password,
) <jk>throws</jk> Unauthorized
{
<jk>if</jk> (! <jsm>isOK</jsm>(username, password))
<jk>throw new</jk> Unauthorized(<js>"You're not welcome!"</js>);
<jk>return</jk> Ok.<jsf>OK</jsf>;
}
</p>
<ul class='javatree'>
<li class='jp'>{@link org.apache.juneau.http.exception}
<ul>
<li class='jc'>{@link org.apache.juneau.http.exception.BadRequest}
<li class='jc'>{@link org.apache.juneau.http.exception.Conflict}
<li class='jc'>{@link org.apache.juneau.http.exception.ExpectationFailed}
<li class='jc'>{@link org.apache.juneau.http.exception.FailedDependency}
<li class='jc'>{@link org.apache.juneau.http.exception.Forbidden}
<li class='jc'>{@link org.apache.juneau.http.exception.Gone}
<li class='jc'>{@link org.apache.juneau.http.exception.HttpVersionNotSupported}
<li class='jc'>{@link org.apache.juneau.http.exception.InsufficientStorage}
<li class='jc'>{@link org.apache.juneau.http.exception.InternalServerError}
<li class='jc'>{@link org.apache.juneau.http.exception.LengthRequired}
<li class='jc'>{@link org.apache.juneau.http.exception.Locked}
<li class='jc'>{@link org.apache.juneau.http.exception.LoopDetected}
<li class='jc'>{@link org.apache.juneau.http.exception.MethodNotAllowed}
<li class='jc'>{@link org.apache.juneau.http.exception.MisdirectedRequest}
<li class='jc'>{@link org.apache.juneau.http.exception.NetworkAuthenticationRequired}
<li class='jc'>{@link org.apache.juneau.http.exception.NotAcceptable}
<li class='jc'>{@link org.apache.juneau.http.exception.NotExtended}
<li class='jc'>{@link org.apache.juneau.http.exception.NotFound}
<li class='jc'>{@link org.apache.juneau.http.exception.NotImplemented}
<li class='jc'>{@link org.apache.juneau.http.exception.PayloadTooLarge}
<li class='jc'>{@link org.apache.juneau.http.exception.PreconditionFailed}
<li class='jc'>{@link org.apache.juneau.http.exception.PreconditionRequired}
<li class='jc'>{@link org.apache.juneau.http.exception.RangeNotSatisfiable}
<li class='jc'>{@link org.apache.juneau.http.exception.RequestHeaderFieldsTooLarge}
<li class='jc'>{@link org.apache.juneau.http.exception.ServiceUnavailable}
<li class='jc'>{@link org.apache.juneau.http.exception.TooManyRequests}
<li class='jc'>{@link org.apache.juneau.http.exception.Unauthorized}
<li class='jc'>{@link org.apache.juneau.http.exception.UnavailableForLegalReasons}
<li class='jc'>{@link org.apache.juneau.http.exception.UnprocessableEntity}
<li class='jc'>{@link org.apache.juneau.http.exception.UnsupportedMediaType}
<li class='jc'>{@link org.apache.juneau.http.exception.UpgradeRequired}
<li class='jc'>{@link org.apache.juneau.http.exception.UriTooLong}
<li class='jc'>{@link org.apache.juneau.http.exception.VariantAlsoNegotiates}
</ul>
</ul>
<p>
These exception extend from {@link java.lang.RuntimeException}, so they can optionally be specified in the thrown
declaration of the method.
The important distinction is that when part of the thrown declaration, they show up in the generated Swagger
documentation, whereas they don't if not. This behavior can be used to define what error conditions show in your Swagger doc.
</p>
</div><!-- END: 6.6.16 - juneau-rest-server.RestMethod.PredefinedExceptions -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestMethod.PredefinedHelperBeans' id='juneau-rest-server.RestMethod.PredefinedHelperBeans'>6.6.17 - Predefined Helper Beans</a></h4>
<div class='topic'><!-- START: 6.6.17 - juneau-rest-server.RestMethod.PredefinedHelperBeans -->
<p>
The {@link org.apache.juneau.rest.helper} package contains several predefined beans to help when constructing
REST interfaces.
</p>
<ul class='javatree'>
<li class='jp'>{@link org.apache.juneau.rest.helper}
<ul>
<li class='jc'>{@link org.apache.juneau.rest.helper.BeanDescription}
<li class='jc'>{@link org.apache.juneau.rest.helper.ChildResourceDescriptions}
<li class='jc'>{@link org.apache.juneau.rest.helper.ResourceDescription}
<li class='jc'>{@link org.apache.juneau.rest.helper.ResourceDescriptions}
<li class='jc'>{@link org.apache.juneau.rest.helper.SeeOtherRoot}
</ul>
</ul>
<h5 class='topic'>ResourceDescription, ResourceDescrptions</h5>
<p>
The {@link org.apache.juneau.rest.helper.ResourceDescription} class is a bean with name/description
properties for labeling and linking to child resources.
The following examples is pulled from the REST examples:
</p>
<p class='bpcode w800'>
<ja>@Resource</ja>
<jk>public class</jk> PredefinedLabelsResource {
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>)
<jk>public</jk> ResourceDescription[] getChildMethods() {
<jk>return new</jk> ResourceDescription[] {
<jk>new</jk> ResourceDescription(<js>"beanDescription"</js>, <js>"BeanDescription"</js>),
<jk>new</jk> ResourceDescription(<js>"htmlLinks"</js>, <js>"HtmlLink"</js>)
};
}
}
</p>
<p>
It get rendered as a table of name/description columns with links to child methods:
</p>
<img class='bordered' src='doc-files/juneau-rest-server.PredefinedLabelBeans.1.png' style='width:240px'/>
<p>
The internals of the class show it simply has two bean properties with a link annotation
defined on the name property:
</p>
<p class='bpcode w800'>
<jk>public class</jk> ResourceDescription {
<jc>// Renders as hyperlink when serialized as HTML.</jc>
<ja>@Html</ja>(link=<js>"servlet:/{name}"</js>)
<jk>public</jk> String getName() {...}
<jk>public</jk> String getDescription() {...}
}
</p>
<p>
{@link org.apache.juneau.rest.helper.ResourceDescriptions} is a convenience class for doing the same.
The example above can also be written as follows (which you'll notice is more concise):
</p>
<p class='bpcode w800'>
<ja>@Resource</ja>
<jk>public class</jk> PredefinedLabelsResource {
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>)
<jk>public</jk> ResourceDescriptions getChildMethods() {
<jk>return new</jk> ResourceDescriptions()
.append(<js>"beanDescription"</js>, <js>"BeanDescription"</js>)
.append(<js>"htmlLinks"</js>, <js>"HtmlLink"</js>);
}
}
</p>
<h5 class='topic'>@HtmlLink, LinkString</h5>
<p>
The {@link org.apache.juneau.html.annotation.HtmlLink @HtmlLink} annotation can also be useful
for rendering custom hyperlinks:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>
<jk>public</jk> MyLink[] htmlLinks() {
<jk>return new</jk> MyLink[] {
<jk>new</jk> MyLink(<js>"apache"</js>, <js>"http://apache.org"</js>),
<jk>new</jk> MyLink(<js>"juneau"</js>, <js>"http://juneau.apache.org"</js>)
};
}
</p>
<p class='bpcode w800'>
<ja>@HtmlLink</ja>(nameProperty=<js>"name"</js>, hrefProperty=<js>"href"</js>)
<jk>public class</jk> MyLink {
<jc>// Simple bean properties.</jc>
<jk>public</jk> String <jf>name</jf>, <jf>href</jf>;
<jk>public</jk> MyLink(String name, String href) {
<jk>this</jk>.<jf>name</jf> = name;
<jk>this</jk>.<jf>href</jf> = href;
}
}
</p>
<p>
The {@link org.apache.juneau.dto.LinkString LinkString} bean is a predefined <ja>@HtmlLink</ja> bean provided
to simplify specifying actions.
The following is equivalent to above.
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>
<jk>public</jk> LinkString[] htmlLinks() {
<jk>return new</jk> LinkString[] {
<jk>new</jk> LinkString(<js>"apache"</js>, <js>"http://apache.org"</js>),
<jk>new</jk> LinkString(<js>"juneau"</js>, <js>"http://juneau.apache.org"</js>)
};
}
</p>
<p>
Both examples render the following consisting of a list of hyperlinks:
</p>
<img class='bordered' src='doc-files/juneau-rest-server.PredefinedLabelBeans.3.png' style='width:92px'/>
<p>
In all other languages, it gets serialized as a simple bean with two properties.
</p>
<h5 class='topic'>BeanDescription</h5>
<p>
The {@link org.apache.juneau.rest.helper.BeanDescription} class provides a simple view
of a bean and it's properties.
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/beanDescription"</js>)
<jk>public</jk> BeanDescription getBeanDescription() {
<jk>return new</jk> BeanDescription(Person.<jk>class</jk>);
}
</p>
<p>
This example renders the following:
</p>
<img class='bordered' src='doc-files/juneau-rest-server.PredefinedLabelBeans.2.png' style='width:584px'/>
<h5 class='topic'>ChildResourceDescriptions</h5>
<p>
The {@link org.apache.juneau.rest.helper.ChildResourceDescriptions} is a convenience bean for generating
a table of child resources.
</p>
<p>
The {@link org.apache.juneau.rest.BasicRestServletGroup} class uses this to generate router pages:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>
<jk>public abstract class</jk> BasicRestServletGroup <jk>extends</jk> BasicRestServlet {
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>, summary=<js>"Navigation page"</js>)
<jk>public</jk> ChildResourceDescriptions getChildren(RestRequest req) <jk>throws</jk> Exception {
<jk>return new</jk> ChildResourceDescriptions(req);
}
}
</p>
<p>
Note that all it requires is a {@link org.apache.juneau.rest.RestRequest} object and it will generate a router
page using reflection against the resource class.
</p>
<p>
For example, the <c>RootResources</c> page in the REST examples renders the child resources attached to the root resource:
</p>
<img class='bordered' src='doc-files/juneau-rest-server.PredefinedLabelBeans.4.png' style='width:800px'/>
<p>
The <c>RootResources</c> page consists of the following and extends from the {@link org.apache.juneau.rest.BasicRestServletGroup} class:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
...
children={
HelloWorldResource.<jk>class</jk>,
PetStoreResource.<jk>class</jk>,
DtoExamples.<jk>class</jk>,
PhotosResource.<jk>class</jk>,
SqlQueryResource.<jk>class</jk>,
ConfigResource.<jk>class</jk>,
LogsResource.<jk>class</jk>,
DebugResource.<jk>class</jk>,
ShutdownResource.<jk>class</jk>
}
)
<jk>public class</jk> RootResources <jk>extends</jk> BasicRestServletJenaGroup {}
</p>
<h5 class='topic'>SeeOtherRoot</h5>
<p>
The {@link org.apache.juneau.rest.helper.SeeOtherRoot} class can be used to redirect to the root URI
of a resource class.
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/pets"</js>)
<jk>public</jk> SeeOtherRoot addPet(<ja>@Body</ja> Pet pet) {
<jsm>addPet</jsm>(Pet);
<jc>// Redirects to the servlet root URL.</jc>
<jk>return</jk> SeeOtherRoot.INSTANCE;
}
</p>
<p>
The runtime behavior is the same as the following:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/pets"</js>)
<jk>public</jk> SeeOther addPet(<ja>@Body</ja> Pet pet) {
<jsm>addPet</jsm>(Pet);
<jc>// Redirects to the servlet root URL.</jc>
<jk>return new</jk> SeeOther(URI.<jsm>create</jsm>(<js>"servlet:/"</js>));
}
</p>
<p>
One distinction is that the former defines the description <js>"Redirect to servlet root"</js> in the generated Swagger documentation.
</p>
</div><!-- END: 6.6.17 - juneau-rest-server.RestMethod.PredefinedHelperBeans -->
</div><!-- END: 6.6 - juneau-rest-server.RestMethod -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.restRPC' id='juneau-rest-server.restRPC'>6.7 - restRPC</a></h3>
<div class='topic'><!-- START: 6.7 - juneau-rest-server.restRPC -->
<p>
The restRPC (RPC over REST) API allows the creation of client-side remote proxy interfaces for calling methods on server-side POJOs using entirely REST.
</p>
<h5 class='topic'>Remote Interfaces</h5>
<p>
The following example shows a remote interface:
</p>
<p class='bpcode w800'>
<ja>@RemoteInterface</ja> <jc>// Annotation is optional</jc>
<jk>public interface</jk> IAddressBook {
<jk>void</jk> init() <jk>throws</jk> Exception;
List&lt;Person&gt; getPeople();
List&lt;Address&gt; getAddresses();
<jk>int</jk> createPerson(CreatePerson cp) <jk>throws</jk> Exception;
Person findPerson(<jk>int</jk> id);
Address findAddress(<jk>int</jk> id);
Person findPersonWithAddress(<jk>int</jk> id);
Person removePerson(<jk>int</jk> id);
}
</p>
<p>
The requirements for a remote interface method are:
</p>
<ul class='spaced-list'>
<li>
Must be public.
<li>
Can be called anything.
<li>
Can have any number of {@doc PojoCategories serializable and parsable} parameters.
<li>
Can return a {@doc PojoCategories serializable and parsable} value.
<li>
Can throw any <c>Throwables</c>.
</ul>
<p>
Throwables with public no-arg or single-arg-string constructors are automatically recreated on the client side
when thrown on the server side.
</p>
<h5 class='topic'>Client side</h5>
<p>
Remote Interface proxies are instantiated on the client side using one of the following methods:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.client.RestClient}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.client.RestClient#getRrpcInterface(Class) getRrpcInterface(Class)}
<li class='jm'>{@link org.apache.juneau.rest.client.RestClient#getRrpcInterface(Class,Object) getRrpcInterface(Class,Object)}
<li class='jm'>{@link org.apache.juneau.rest.client.RestClient#getRrpcInterface(Class,Object,Serializer,Parser) getRrpcInterface(Class,Object,Serializer,Parser)}
</ul>
</ul>
<p>
Since we build upon the existing <c>RestClient</c> API, we inherit all of it's features.
For example, convenience methods for setting POJO filters and properties to customize the behavior of the
serializers and parsers, and the ability to provide your own customized Apache <c>HttpClient</c> for
handling various scenarios involving authentication and Internet proxies.
</p>
<p>
Here's an example of the above interface being used:
</p>
<p class='bpcode w800'>
<jc>// Create a RestClient using JSON for serialization, and point to the server-side remote interface servlet.</jc>
RestClient client = RestClient.<jsm>create</jsm>()
.json()
.rootUrl(<js>"http://localhost:10000/remote"</js>)
.build();
<jc>// Create a proxy interface.</jc>
IAddressBook ab = client.getRrpcInterface(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='bpcode w800'>
HTTP POST http://localhost:10000/remote/org.apache.juneau.examples.addressbook.IAddressBook/createPerson(org.apache.juneau.examples.addressbook.Person)
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>
<h5 class='topic'>Server side</h5>
<p>
There are two ways to expose remote interfaces on the server side:
</p>
<ol class='spaced-list'>
<li>
Extending from {@link org.apache.juneau.rest.remote.RrpcServlet}.
<li>
Using a <c><ja>@RestMethod</ja>(name=<jsf>RRPC</jsf>)</c> annotation on a Java method.
</ol>
<p>
In either case, the proxy communications layer is pure REST.
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.
This can also aid significantly in debugging, since calls to the remote interface service can be made directly from
a browser with no coding involved.
</p>
<h5 class='topic'>RrpcServlet</h5>
<p>
The {@link org.apache.juneau.rest.remote.RrpcServlet} class is a simple specialized servlet with an abstract
<c>getServiceMap()</c> method to define the server-side POJOs:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/remote"</js>
)
<jk>public class</jk> SampleRrpcServlet <jk>extends</jk> RrpcServlet {
<jc>// Our server-side POJO.</jc>
<jk>private</jk> AddressBook <jf>addressBook</jf> = <jk>new</jk> AddressBook();
<ja>@Override</ja> <jc>/* RrpcServlet */</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>
<h5 class='topic'>@RestMethod(name=RRPC)</h5>
<p>
The <c><ja>@RestMethod</ja>(name=<jsf>RRPC</jsf>)</c> 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='bpcode w800'>
<jc>// Our exposed interface.</jc>
<ja>@RestMethod</ja>(name=<jsf>RRPC</jsf>, path=<js>"/addressbookproxy/*"</js>)
<jk>public</jk> IAddressBook getProxy() {
<jk>return</jk> addressBook;
}
</p>
<h5 class='topic'>RrpcServlet in a browser</h5>
<p>
If you point your browser to the servlet above, you get a list of available interfaces:
</p>
<p class='bpcode w800'>
http://localhost:10000/remote
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.restRPC.1.png'>
<p>
Clicking the hyperlinks on each shows you the list of methods that can be invoked on that service.
Note that the <c>IAddressBook</c> link shows that you can only invoke methods defined on that
interface, whereas the <c>AddressBook</c> link shows ALL public methods defined on that class.
</p>
<h5 class='figure'>IAddressBook</h5>
<p class='bpcode w800'>
http://localhost:10000/remote/org.apache.juneau.examples.addressbook.IAddressBook
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.restRPC.2.png'>
<p>
Since <c>AddressBook</c> extends from <c>LinkedList</c>, you may notice familiar collections
framework methods listed.
</p>
<h5 class='figure'>AddressBook</h5>
<p class='bpcode w800'>
http://localhost:10000/remote/org.apache.juneau.examples.addressbook.AddressBook
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.restRPC.3.png'>
<p>
Let's see how we can interact with this interface through nothing more than REST calls to get a better idea on
how this works.
We'll use the same method call as in the introduction.
First, we need to create the serialized form of the arguments:
</p>
<p class='bpcode w800'>
Object[] args = <jk>new</jk> Object[] {
<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>))
};
String asJson = SimpleJsonSerializer.<jsf>DEFAULT_READABLE</jsf>.toString(args);
System.<jsf>err</jsf>.println(asJson);
</p>
<p>
That produces the following JSON output:
</p>
<p class='bpcode w800'>
[
{
name: <js>'Test Person'</js>,
birthDate: <js>'Aug 1, 1999'</js>,
addresses: [
{
street: <js>'Test street'</js>,
city: <js>'Test city'</js>,
state: <js>'Test state'</js>,
zip: 12345,
isCurrent: <jk>true</jk>
}
]
}
]
</p>
<p>
Note that in this example we're using JSON.
However, various other content types can also be used such as XML, URL-Encoding, UON, or HTML.
In practice however, JSON will preferred since it is often the most efficient.
</p>
<p>
Next, we can use a tool such as Poster to make the REST call.
Methods are invoked by POSTing the serialized object array to the URI of the interface method.
In this case, we want to POST our JSON to the following URL:
</p>
<p class='bpcode w800'>
http://localhost:10000/remote/org.apache.juneau.examples.addressbook.IAddressBook/createPerson(org.apache.juneau.examples.addressbook.CreatePerson)
</p>
<p>
Make sure that we specify the <c>Content-Type</c> of the body as <c>text/json</c>.
We also want the results to be returned as JSON, so we set the <c>Accept</c> header to
<c>text/json</c> as well.
</p>
<img class='bordered w400' src='doc-files/juneau-rest-server.restRPC.4.png'>
<p>
When we execute the POST, we should see the following successful response whose body contains the returned
<c>Person</c> bean serialized to JSON:
</p>
<img class='bordered w400' src='doc-files/juneau-rest-server.restRPC.5.png'>
<p>
From there, we could use the following code snippet to reconstruct the response object from JSON:
</p>
<p class='bpcode w800'>
String response = <js>"<i>output from above</i>"</js>;
Person p = JsonParser.<jsf>DEFAULT</jsf>.parse(response, Person.<jk>class</jk>);
</p>
<p>
If we alter our servlet to allow overloaded GET requests, we can invoke methods using nothing more than a
browser...
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/remote"</js>,
<jc>// Allow us to use method=POST from a browser.</jc>
allowedMethodParams=<js>"*"</js>
)
<jk>public class</jk> SampleRrpcServlet <jk>extends</jk> RrpcServlet {
</p>
<p>
For example, to invoke the <c>getPeople()</c> method on our bean:
</p>
<p class='bpcode w800'>
http://localhost:10000/remote/org.apache.juneau.examples.addressbook.IAddressBook/getPeople?method=POST
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.restRPC.6.png'>
<p>
Here we call the <c>findPerson(<jk>int</jk>)</c> method to retrieve a person and get the
returned POJO (in this case as HTML since that's what's in the <c>Accept</c> header when calling from a
browser):
</p>
<p class='bpcode w800'>
http://localhost:10000/remote/org.apache.juneau.examples.addressbook.IAddressBook/findPerson(int)?method=POST&amp;body=@(3)
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.restRPC.7.png'>
<p>
When specifying the POST body as a <c>&amp;body</c> parameter, the method arguments should be in UON
notation.
See {@link org.apache.juneau.uon.UonSerializer} for more information about this encoding.
Usually you can also pass in JSON if you specify <c>&amp;Content-Type=text/json</c> in the URL parameters
but passing in unencoded JSON in a URL may not work in all browsers.
Therefore, UON is preferred.
</p>
<p>
The hyperlinks on the method names above lead you to a simple form-entry page where you can test
passing parameters in UON notation as URL-encoded form posts.
</p>
<h5 class='figure'>Sample form entry page</h5>
<img class='bordered w800' src='doc-files/juneau-rest-server.restRPC.8.png'>
<h5 class='figure'>Sample form entry page results</h5>
<img class='bordered w800' src='doc-files/juneau-rest-server.restRPC.9.png'>
</div><!-- END: 6.7 - juneau-rest-server.restRPC -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.OpenApiSchemaPartParsing' id='juneau-rest-server.OpenApiSchemaPartParsing'>6.8 - OpenAPI Schema Part Parsing</a></h3>
<div class='topic'><!-- START: 6.8 - juneau-rest-server.OpenApiSchemaPartParsing -->
<p>
Parameters annotated with any of the following are parsed using the registered {@link org.apache.juneau.oapi.OpenApiParser} and
therefore support OpenAPI syntax and validation:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Header}
<li class='ja'>{@link org.apache.juneau.http.annotation.Query}
<li class='ja'>{@link org.apache.juneau.http.annotation.FormData}
<li class='ja'>{@link org.apache.juneau.http.annotation.Path}
<li class='ja'>{@link org.apache.juneau.http.annotation.Body} (<c>Content-Type</c> must match <js>"text/openapi"</js>)
</ul>
<p>
For example, the following shows how a pipe-delimited list of comma-delimited numbers (e.g. <js>"1,2,3|4,5,6|7,8,9"</js>) in a query parameter can be converted to a 2-dimensional array of <c>Longs</c>:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(method=<js>"GET"</js>, path=<js>"/testQuery"</js>)
<jk>public void</jk> testQuery(
<ja>@Query</ja>(
name=<js>"queryParamName"</js>,
collectionFormat=<js>"pipes"</js>,
items=<ja>@SubItems</ja>(
collectionFormat=<js>"csv"</js>,
type=<js>"integer"</js>,
format=<js>"int64"</js>,
minimum=<js>"0"</js>,
maximum=<js>"100"</js>
minLength=1,
maxLength=10
),
minLength=1,
maxLength=10
)
Long[][] queryParameter
) {...}
</p>
<p>
Input will be converted based on the types and formats defined in the schema definition.
Input validations such as <c>minLength/maxLength</c> that don't match the input will result in automatic <c>400 Bad Request</c> responses.
</p>
<p>
The following shows the same for a request body:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(method=<js>"POST"</js>, path=<js>"/testBody"</js>)
<jk>public void</jk> testBody(
<ja>@Body</ja>(
parsers=OpenApiParser.<jk>class</jk>,
defaultContentType=<js>"text/openapi"</js>,
schema=<ja>@Schema</ja>(
items=<ja>@Items</ja>(
collectionFormat=<js>"pipes"</js>,
items=<ja>@SubItems</ja>(
collectionFormat=<js>"csv"</js>,
type=<js>"integer"</js>,
format=<js>"int64"</js>,
minimum=<js>"0"</js>,
maximum=<js>"100"</js>
minLength=1,
maxLength=10
)
),
minLength=1,
maxLength=10
)
)
Long[][] body
) {...}
</p>
<p>
The list of valid POJO types for parameters depends on type and format of the value or items/entries of the value.
For example, instead of <c>Longs</c> in the example above, we could also define a 2-dimensional array of POJOs convertible from <c>Longs</c>:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(method=<js>"POST"</js>, path=<js>"/2dLongArray"</js>)
<jk>public void</jk> testBody(<ja>@Body</ja>(...) MyPojo[][] body) {...}
<jc>// POJO convertible from a Long.</jc>
<jk>public class</jk> MyPojo {
<jk>public</jk> MyPojo(Long input) {...}
}
</p>
<p>
Or even POJOs that take in arrays of <c>Longs[]</c>:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(method=<js>"POST"</js>, path=<js>"/2dLongArray"</js>)
<jk>public void</jk> testBody(<ja>@Body</ja>(...) MyPojo[] body) {...}
<jc>// POJO convertible from a Long[].</jc>
<jk>public class</jk> MyPojo {
<jk>public</jk> MyPojo(Long[] input) {...}
}
</p>
<p>
Or even POJOs that take in the whole 2-dimensional array:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(method=<js>"POST"</js>, path=<js>"/2dLongArray"</js>)
<jk>public void</jk> testBody(<ja>@Body</ja>(...) MyPojo body) {...}
<jc>// POJO convertible from a Long[][].</jc>
<jk>public class</jk> MyPojo {
<jk>public</jk> MyPojo(Long[][] input) {...}
}
</p>
<p>
As you can see, the complexity of possible input types expands significantly.
For more information about valid parameter types, see {@doc juneau-marshall.OpenApiDetails.Parsers OpenAPI Parsers}
</p>
</div><!-- END: 6.8 - juneau-rest-server.OpenApiSchemaPartParsing -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.OpenApiSchemaPartSerializing' id='juneau-rest-server.OpenApiSchemaPartSerializing'>6.9 - OpenAPI Schema Part Serializing</a></h3>
<div class='topic'><!-- START: 6.9 - juneau-rest-server.OpenApiSchemaPartSerializing -->
<p>
Parameters annotated with any of the following are serialized using the registered {@link org.apache.juneau.oapi.OpenApiSerializer} and
therefore support OpenAPI syntax and validation:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseHeader}
<li class='ja'>{@link org.apache.juneau.http.annotation.Response} (<c>Accept</c> must match <js>"text/openapi"</js>)
</ul>
<p>
For example, the following shows how a pipe-delimited list of comma-delimited numbers (e.g. <js>"1,2,3|4,5,6|7,8,9"</js>) in a response header can be converted to a 2-dimensional array of <c>Longs</c>:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(method=<js>"GET"</js>, path=<js>"/testResponseHeader"</js>)
<jk>public void</jk> testResponseHeader(
<ja>@ResponseHeader</ja>(
name=<js>"My-Header"</js>,
collectionFormat=<js>"pipes"</js>,
items=<ja>@SubItems</ja>(
collectionFormat=<js>"csv"</js>,
type=<js>"integer"</js>,
format=<js>"int64"</js>,
minimum=<js>"0"</js>,
maximum=<js>"100"</js>
minLength=1,
maxLength=10
),
minLength=1,
maxLength=10
)
Value&lt;Long[][]&gt; header
) {
header.set(<jk>new</jk> Long[][]{...});
}
</p>
<p>
The following shows the same for a response body:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(method=<js>"GET"</js>, path=<js>"/testResponseBody"</js>)
<jk>public void</jk> testResponseBody(
<ja>@Response</ja>(
serializers=OpenApiSerialier.<jk>class</jk>,
defaultAccept=<js>"text/openapi"</js>,
schema=<ja>@Schema</ja>(
items=<ja>@Items</ja>(
collectionFormat=<js>"pipes"</js>,
items=<ja>@SubItems</ja>(
collectionFormat=<js>"csv"</js>,
type=<js>"integer"</js>,
format=<js>"int64"</js>,
minimum=<js>"0"</js>,
maximum=<js>"100"</js>
minLength=1,
maxLength=10
)
),
minLength=1,
maxLength=10
)
)
Value&lt;Long[][]&gt; responseBody
) {...}
</p>
<p>
For more information about the valid parameter types, see {@doc juneau-marshall.OpenApiDetails.Serializers OpenAPI Serializers}
</p>
</div><!-- END: 6.9 - juneau-rest-server.OpenApiSchemaPartSerializing -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HttpPartAnnotations' id='juneau-rest-server.HttpPartAnnotations'>6.10 - HTTP-Part Annotations</a></h3>
<div class='topic'><!-- START: 6.10 - juneau-rest-server.HttpPartAnnotations -->
<p>
The annotations used for defining the schema for request HTTP parts are:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Body}
<li class='ja'>{@link org.apache.juneau.http.annotation.Header}
<li class='ja'>{@link org.apache.juneau.http.annotation.FormData}
<li class='ja'>{@link org.apache.juneau.http.annotation.Query}
<li class='ja'>{@link org.apache.juneau.http.annotation.Path}
<li class='ja'>{@link org.apache.juneau.http.annotation.HasFormData}
<li class='ja'>{@link org.apache.juneau.http.annotation.HasQuery}
<li class='ja'>{@link org.apache.juneau.http.annotation.Request}
</ul>
<p>
The annotations used for defining the schema for response HTTP parts are:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseBody}
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseHeader}
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseStatus}
<li class='ja'>{@link org.apache.juneau.http.annotation.Response}
</ul>
<p>
The sub-annotations used in the annotation above are:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.jsonschema.annotation.Schema}
<li class='ja'>{@link org.apache.juneau.jsonschema.annotation.Items}
</ul>
<ul class='notes'>
<li>
Annotation parameter values will be aggregated when used on POJO parent and child classes.
<br>Values on child classes override values on parent classes.
<li>
Annotation parameter values will be aggregated when used on both POJOs and REST methods.
<br>Values on methods override values on POJO classes.
</ul>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HttpPartAnnotations.Body' id='juneau-rest-server.HttpPartAnnotations.Body'>6.10.1 - @Body</a></h4>
<div class='topic'><!-- START: 6.10.1 - juneau-rest-server.HttpPartAnnotations.Body -->
<p>
The {@link org.apache.juneau.http.annotation.Body @Body} annotation is used to identify POJOs to be used as the body of an HTTP request.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Body}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.Body#api() api} - Free-form Swagger JSON.
<li class='jf'>{@link org.apache.juneau.http.annotation.Body#description() description} - Description.
<li class='jf'>{@link org.apache.juneau.http.annotation.Body#example() example} - Serialized example.
<li class='jf'>{@link org.apache.juneau.http.annotation.Body#examples() examples} - Serialized examples per media type.
<li class='jf'>{@link org.apache.juneau.http.annotation.Body#required() required} - Input validation. Body must be present.
<li class='jf'>{@link org.apache.juneau.http.annotation.Body#schema() schema} - Swagger schema.
<li class='jf'>{@link org.apache.juneau.http.annotation.Body#value() value} - Free-form Swagger JSON.
</ul>
</ul>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Defined on parameter</jc>
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
<jk>public void</jk> addPet(<ja>@Body</ja> Pet pet) {...}
</p>
<p class='bpcode w800'>
<jc>// Defined on POJO class</jc>
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
<jk>public void</jk> addPet(Pet pet) {...}
<ja>@Body</ja>
<jk>public class</jk> Pet {...}
</p>
<p>
This is functionally equivalent to the following code:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
<jk>public void</jk> addPet(RestRequest req) {
Person person = req.getBody().asType(Pet.<jk>class</jk>);
...
}
</p>
<p>
Any of the following types can be used for the parameter or POJO class (matched in the specified order):
</p>
<ol class='spaced-list'>
<li>
{@link java.io.Reader}
<br><ja>@Body</ja> annotation is optional.
<br><c>Content-Type</c> is ignored.
<li>
{@link java.io.InputStream}
<br><ja>@Body</ja> annotation is optional.
<br><c>Content-Type</c> is ignored.
<li>
Any {@doc PojoCategories Parsable POJO} type.
<br><c>Content-Type</c> is required to identify correct parser.
<li>
Objects convertible from {@link java.io.Reader} by having one of the following non-deprecated methods:
<ul>
<li><c><jk>public</jk> T(Reader in) {...}</c>
<li><c><jk>public static</jk> T <jsm>create</jsm>(Reader in) {...}</c>
<li><c><jk>public static</jk> T <jsm>fromReader</jsm>(Reader in) {...}</c>
</ul>
<c>Content-Type</c> must not be present or match an existing parser so that it's not parsed as a POJO.
<li>
Objects convertible from {@link java.io.InputStream} by having one of the following non-deprecated methods:
<ul>
<li><c><jk>public</jk> T(InputStream in) {...}</c>
<li><c><jk>public static</jk> T <jsm>create</jsm>(InputStream in) {...}</c>
<li><c><jk>public static</jk> T <jsm>fromInputStream</jsm>(InputStream in) {...}</c>
</ul>
<c>Content-Type</c> must not be present or match an existing parser so that it's not parsed as a POJO.
<li>
Objects convertible from {@link java.lang.String} by having one of the following non-deprecated methods:
<ul>
<li><c><jk>public</jk> T(String in) {...}</c>
<li><c><jk>public static</jk> T <jsm>create</jsm>(String in) {...}</c>
<li><c><jk>public static</jk> T <jsm>fromString</jsm>(String in) {...}</c>
<li><c><jk>public static</jk> T <jsm>parse</jsm>(String in) {...}</c>
<li><c><jk>public static</jk> T <jsm>parseString</jsm>(String in) {...}</c>
<li><c><jk>public static</jk> T <jsm>forName</jsm>(String in) {...}</c>
<li><c><jk>public static</jk> T <jsm>forString</jsm>(String in) {...}</c>
</ul>
Note that this also includes all enums.
<li>
Any {@link java.util.Optional} of anything on this list.
</ol>
<p>
The {@link org.apache.juneau.oapi.OpenApiSerializer} class can be used to serialize HTTP bodies to OpenAPI-based output.
</p>
<p>
For example, the following shows how a pipe-delimited list of comma-delimited numbers (e.g. <js>"1,2,3|4,5,6|7,8,9"</js>) can be converted to a 2-dimensional array of <c>Longs</c>:
</p>
<p class='bpcode w800'>
<jc>// Body is a pipe-delimited list of comma-delimited lists of longs.</jc>
<ja>@RestMethod</ja>(
method=<js>"POST"</js>,
path=<js>"/testBody"</js>,
serializers=OpenApiSerializers.<jk>class</jk>,
defaultAccept=<js>"text/openapi"</js>
)
<jk>public void</jk> testBody(
<ja>@Body</ja>(
schema=<ja>@Schema</ja>(
items=<ja>@Items</ja>(
collectionFormat=<js>"pipes"</js>,
items=<ja>@SubItems</ja>(
collectionFormat=<js>"csv"</js>,
type=<js>"integer"</js>,
format=<js>"int64"</js>,
minimum=<js>"0"</js>,
maximum=<js>"100"</js>
minLength=1,
maxLength=10
)
),
minLength=1,
maxLength=10
)
)
Long[][] body
) {...}
</p>
<p>
Input will be converted based on the types and formats defined in the schema definition.
Input validations such as <c>minLength/maxLength</c> that don't match the input will result in automatic <c>400 Bad Request</c> responses.
</p>
<p>
For more information about valid parameter types when using OpenAPI parsing, see {@doc juneau-marshall.OpenApiDetails.Parsers OpenAPI Parsers}
</p>
<p>
The <ja>@Body</ja> annotation is also used for supplying swagger information about the body of the request.
This information is used to populate the auto-generated Swagger documentation and UI.
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Normal</jc>
<ja>@Body</ja>(
description=<js>"Pet object to add to the store"</js>,
required=<jk>true</jk>,
example=<js>"{name:'Doggie',price:9.99,species:'Dog',tags:['friendly','cute']}"</js>
)
</p>
<p class='bpcode w800'>
<jc>// Free-form</jc>
<jc>// Note the extra field</jc>
<ja>@Body</ja>({
<js>"description: 'Pet object to add to the store',"</js>,
<js>"required: true,"</js>,
<js>"example: {name:'Doggie',price:9.99,species:'Dog',tags:['friendly','cute']},"</js>
<js>"x-extra: 'extra field'"</js>
})
</p>
<p>
{@doc DefaultRestSvlVariables} (e.g. "$L{my.localized.variable}")
are supported on annotation fields.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Localized</jc>
<ja>@Body</ja>(
description=<js>"$L{PetObjectDescription}"</js>
)
</p>
<ul class='notes'>
<li>
Annotation parameter values will be aggregated when used on POJO parent and child classes.
<br>Values on child classes override values on parent classes.
<li>
Annotation parameter values will be aggregated when used on both POJOs and REST methods.
<br>Values on methods override values on POJO classes.
</ul>
<div class='warn'>
If using this annotation on a Spring bean, note that you are likely to encounter issues when using on parameterized
types such as <code>List&lt;MyBean&gt;</code>. This is due to the fact that Spring uses CGLIB to recompile classes
at runtime, and CGLIB was written before generics were introduced into Java and is a virtually-unsupported library.
Therefore, parameterized types will often be stripped from class definitions and replaced with unparameterized types
(e.g. <code>List</code>). Under these circumstances, you are likely to get <code>ClassCastExceptions</code>
when trying to access generalized <code>ObjectMaps</code> as beans. The best solution to this issue is to either
specify the parameter as a bean array (e.g. <code>MyBean[]</code>) or declare the method as final so that CGLIB
will not try to recompile it.
</div>
<ul class='seealso'>
<li class='jc'>{@link org.apache.juneau.rest.RequestBody}
<li class='link'>{@doc juneau-rest-server.OpenApiSchemaPartParsing}
</ul>
</div><!-- END: 6.10.1 - juneau-rest-server.HttpPartAnnotations.Body -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HttpPartAnnotations.FormData' id='juneau-rest-server.HttpPartAnnotations.FormData'>6.10.2 - @FormData</a></h4>
<div class='topic'><!-- START: 6.10.2 - juneau-rest-server.HttpPartAnnotations.FormData -->
<p>
The {@link org.apache.juneau.http.annotation.FormData @FormData} annotation is used to retrieve request form post entries.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.FormData}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#_default() _default} - Default value if not present.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#_enum() _enum} - Input validation. Must match one of the values.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#allowEmptyValue() allowEmptyValue} - Input validation. Allow empty value.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#api() api()} - Free-form Swagger JSON.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#collectionFormat() collectionFormat} - How collections of items are formatted.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#description() description} - Description.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#example() example()} - Serialized example.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#exclusiveMaximum() exclusiveMaximum} - Input validation. Whether maximum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#exclusiveMinimum() exclusiveMinimum} - Input validation. Whether minimum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#format() format} - The schema type format.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#items() items} - The schema of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#maximum() maximum} - Input validation. Maximum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#maxItems() maxItems} - Input validation. Maximum number of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#maxLength() maxLength} - Input validation. Maximum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#minimum() minimum} - Input validation. Minimum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#minItems() minItems} - Input validation. Minimum number of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#minLength() minLength} - Input validation. Minimum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#multipleOf() multipleOf} - Input validation. Number must be a multiple of.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#name() name} - Form data entry name.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#parser() parser} - Override the part parser.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#pattern() pattern} - Input validation. Must match regular expression.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#required() required} - Input validation. Form data entry must be present.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#type() type} - The schema type.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#uniqueItems() uniqueItems} - Input validation. Collections must contain unique items only.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#value() value} - Free-form Swagger JSON.
</ul>
</ul>
<p>
The most typical scenario is to simply use the <c>value</c> field to define form data parameter names:
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
<jk>public void</jk> doPost(
<ja>@FormData</ja>(<js>"p1"</js>) <jk>int</jk> p1,
<ja>@FormData</ja>(<js>"p2"</js>) String p2,
<ja>@FormData</ja>(<js>"p3"</js>) UUID p3) {...}
</p>
<p>
This is functionally equivalent to the following code:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
<jk>public void</jk> doPost(RestRequest req) {
RequestFormData fd = req.getFormData();
<jk>int</jk> p1 = fd.get(<js>"p1"</js>, 0, <jk>int</jk>.<jk>class</jk>);
String p2 = fd.get(<js>"p2"</js>, String.<jk>class</jk>);
UUID p3 = fd.get(<js>"p3"</js>, UUID.<jk>class</jk>);
}
</p>
<p>
The special name <js>"*"</js> (or blank) can be used to represent all values.
When used, the data type must be a <c>Map</c> or bean.
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Multiple values passed as a map.</jc>
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
<jk>public void</jk> doPost(<ja>@FormData</ja>(<js>"*"</js>) Map&lt;String,Object&gt; map) {...}
</p>
<p class='bpcode w800'>
<jc>// Same, but name "*" is inferred.</jc>
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
<jk>public void</jk> doPost(<ja>@FormData</ja> Map&lt;String,Object&gt; map) {...}
</p>
<p class='bpcode w800'>
<jc>// Multiple values passed as a bean.</jc>
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
<jk>public void</jk> doPost(<ja>@FormData</ja> MyBean bean) {...}
</p>
<p>
The registered {@link org.apache.juneau.rest.RestContext#REST_partParser REST_partParser} is used to convert strings
to POJOs and controls what POJO types are supported.
By default, this is the {@link org.apache.juneau.oapi.OpenApiParser} which supports the standard Swagger-based rules for parsing.
</p>
<p>
For example, the following shows how a pipe-delimited list of comma-delimited numbers (e.g. <js>"1,2,3|4,5,6|7,8,9"</js>) can be converted to a 2-dimensional array of <c>Longs</c>:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(method=<js>"POST"</js>, path=<js>"/testFormData"</js>)
<jk>public void</jk> testFormData(
<ja>@FormData</ja>(
name=<js>"formDataParamName"</js>,
collectionFormat=<js>"pipes"</js>,
items=<ja>@SubItems</ja>(
collectionFormat=<js>"csv"</js>,
type=<js>"integer"</js>,
format=<js>"int64"</js>,
minimum=<js>"0"</js>,
maximum=<js>"100"</js>
minLength=1,
maxLength=10
),
minLength=1,
maxLength=10
)
Long[][] formDataParameter
) {...}
</p>
<p>
Input will be converted based on the types and formats defined in the schema definition.
Input validations such as <c>minLength/maxLength</c> that don't match the input will result in automatic <c>400 Bad Request</c> responses.
</p>
<p>
For more information about valid parameter types, see {@doc juneau-marshall.OpenApiDetails.Parsers OpenAPI Parsers}
</p>
<p>
The <ja>@FormData</ja> annotation is also used for supplying swagger information about the HTTP part.
This information is used to populate the auto-generated Swagger documentation and UI.
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Normal</jc>
<ja>@FormData</ja>(
name=<js>"name"</js>,
description=<js>"Pet name"</js>,
required=<jk>true</jk>,
example=<js>"Doggie"</js>
)
</p>
<p class='bpcode w800'>
<jc>// Free-form</jc>
<jc>// Note the extra field</jc>
<ja>@FormData</ja>(
name=<js>"name"</js>,
api={
<js>"description: 'Pet name',"</js>,
<js>"required: true,"</js>,
<js>"example: 'Doggie',"</js>
<js>"x-extra: 'extra field'"</js>
}
)
</p>
<p>
{@doc DefaultRestSvlVariables} (e.g. "$L{my.localized.variable}")
are supported on annotation fields.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@FormData</ja>(
description=<js>"$L{PetNameDescription}"</js>
)
</p>
<div class='warn'>
This annotation should not be combined with the {@link org.apache.juneau.http.annotation.Body @Body} annotation or {@link org.apache.juneau.rest.RestRequest#getBody()} method
for <c>application/x-www-form-urlencoded POST</c> posts, since it will trigger the underlying servlet
API to parse the body content as key-value pairs resulting in empty content.
<br>The {@link org.apache.juneau.http.annotation.Query @Query} annotation can be used to retrieve a URL parameter in the URL string without triggering the
servlet to drain the body content.
</div>
<div class='warn'>
If using this annotation on a Spring bean, note that you are likely to encounter issues when using on parameterized
types such as <code>List&lt;MyBean&gt;</code>. This is due to the fact that Spring uses CGLIB to recompile classes
at runtime, and CGLIB was written before generics were introduced into Java and is a virtually-unsupported library.
Therefore, parameterized types will often be stripped from class definitions and replaced with unparameterized types
(e.g. <code>List</code>). Under these circumstances, you are likely to get <code>ClassCastExceptions</code>
when trying to access generalized <code>ObjectMaps</code> as beans. The best solution to this issue is to either
specify the parameter as a bean array (e.g. <code>MyBean[]</code>) or declare the method as final so that CGLIB
will not try to recompile it.
</div>
<ul class='seealso'>
<li class='jc'>{@link org.apache.juneau.rest.RequestFormData}
<li class='link'>{@doc juneau-rest-server.OpenApiSchemaPartParsing}
</ul>
</div><!-- END: 6.10.2 - juneau-rest-server.HttpPartAnnotations.FormData -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HttpPartAnnotations.HasFormData' id='juneau-rest-server.HttpPartAnnotations.HasFormData'>6.10.3 - @HasFormData</a></h4>
<div class='topic'><!-- START: 6.10.3 - juneau-rest-server.HttpPartAnnotations.HasFormData -->
<p>
This annotation can be used to detect the existence of a parameter when it's not set to a particular value.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.HasFormData}
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
<jk>public void</jk> doPost(<ja>@HasFormData</ja>(<js>"p1"</js>) <jk>boolean</jk> p1) {...}
</p>
<p>
This is functionally equivalent to the following code:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
<jk>public void</jk> doPost(RestRequest req) {
<jk>boolean</jk> p1 = req.hasFormData(<js>"p1"</js>);
...
}
</p>
<p>
The parameter type must be either <jk>boolean</jk> or {@link java.lang.Boolean}.
</p>
<p>
The following table shows the behavioral differences between <ja>@HasFormData</ja> and <ja>@FormData</ja>:
</p>
<table class='styled w400'>
<tr>
<th><c>Body content</c></th>
<th><c><ja>@HasFormData</ja>(<js>"a"</js>)</c></th>
<th><c><ja>@FormData</ja>(<js>"a"</js>)</c></th>
</tr>
<tr>
<td><c>a=foo</c></td>
<td><jk>true</jk></td>
<td><js>"foo"</js></td>
</tr>
<tr>
<td><c>a=</c></td>
<td><jk>true</jk></td>
<td><js>""</js></td>
</tr>
<tr>
<td><c>a</c></td>
<td><jk>true</jk></td>
<td><jk>null</jk></td>
</tr>
<tr>
<td><c>b=foo</c></td>
<td><jk>false</jk></td>
<td><jk>null</jk></td>
</tr>
</table>
<h5 class='topic'>Important note concerning FORM posts</h5>
<p>
This annotation should not be combined with the {@link org.apache.juneau.http.annotation.Body @Body} annotation or {@link org.apache.juneau.rest.RestRequest#getBody()} method
for <c>application/x-www-form-urlencoded POST</c> posts, since it will trigger the underlying servlet API to
parse the body content as key-value pairs, resulting in empty content.
</p>
<p>
The {@link org.apache.juneau.http.annotation.HasQuery @HasQuery} annotation can be used to check for the existing of a URL parameter in the URL string
without triggering the servlet to drain the body content.
</p>
</div><!-- END: 6.10.3 - juneau-rest-server.HttpPartAnnotations.HasFormData -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HttpPartAnnotations.Query' id='juneau-rest-server.HttpPartAnnotations.Query'>6.10.4 - @Query</a></h4>
<div class='topic'><!-- START: 6.10.4 - juneau-rest-server.HttpPartAnnotations.Query -->
<p>
The {@link org.apache.juneau.http.annotation.Query @Query} annotation is used to retrieve request URL query parameters.
It's identical to {@link org.apache.juneau.http.annotation.FormData @FormData}, but only retrieves the parameter from the URL string, not URL-encoded form posts.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Query}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#_default() _default} - Default value if not present.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#_enum() _enum} - Input validation. Must match one of the values.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#allowEmptyValue() allowEmptyValue} - Input validation. Allow empty value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#api() api} - Free-form Swagger JSON.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#collectionFormat() collectionFormat} - How collections of items are formatted.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#description() description} - Description.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#example() example} - Serialized example.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#exclusiveMaximum() exclusiveMaximum} - Input validation. Whether maximum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#exclusiveMinimum() exclusiveMinimum} - Input validation. Whether minimum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#format() format} - The schema type format.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#items() items} - The schema of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#maximum() maximum} - Input validation. Maximum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#maxItems() maxItems} - Input validation. Maximum number of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#maxLength() maxLength} - Input validation. Maximum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#minimum() minimum} - Input validation. Minimum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#minItems() minItems} - Input validation. Minimum number of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#minLength() minLength} - Input validation. Minimum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#multipleOf() multipleOf} - Input validation. Number must be a multiple of.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#name() name} - Query parameter name.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#parser() parser} - Override the part parser.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#pattern() pattern} - Input validation. Must match regular expression.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#required() required} - Input validation. Query parameter must be present.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#type() type} - The schema type.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#uniqueItems() uniqueItems} - Input validation. Collections must contain unique items only.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#value() value} - Free-form Swagger JSON.
</ul>
</ul>
<p>
Unlike {@link org.apache.juneau.http.annotation.FormData @FormData}, using this annotation does not result in the servlet reading the contents of
URL-encoded form posts.
Therefore, this annotation can be used in conjunction with the {@link org.apache.juneau.http.annotation.Body @Body} annotation or
{@link org.apache.juneau.rest.RestRequest#getBody()} method for <c>application/x-www-form-urlencoded POST</c> calls.
</p>
<p>
The most typical scenario is to simply use the <c>value</c> field to define query parameter names:
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
<jk>public void</jk> doGet(
<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) {...}
</p>
<p>
This is functionally equivalent to the following code:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
<jk>public void</jk> doGet(RestRequest req) {
RequestQuery q = req.getQuery();
<jk>int</jk> p1 = q.get(<js>"p1"</js>, 0, <jk>int</jk>.<jk>class</jk>);
String p2 = q.get(<js>"p2"</js>, String.<jk>class</jk>);
UUID p3 = q.get(<js>"p3"</js>, UUID.<jk>class</jk>);
}
</p>
<p>
The special name <js>"*"</js> (or blank) can be used to represent all values.
When used, the data type must be a <c>Map</c> or bean.
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Multiple values passed as a map.</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
<jk>public void</jk> doGet(<ja>@Query</ja>(<js>"*"</js>) Map&lt;String,Object&gt; map) {...}
</p>
<p class='bpcode w800'>
<jc>// Same, but name "*" is inferred.</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
<jk>public void</jk> doGet(<ja>@Query</ja> Map&lt;String,Object&gt; map) {...}
</p>
<p class='bpcode w800'>
<jc>// Multiple values passed as a bean.</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
<jk>public void</jk> doGet(<ja>@Query</ja> MyBean bean) {...}
</p>
<p>
The registered {@link org.apache.juneau.rest.RestContext#REST_partParser REST_partParser} is used to convert strings
to POJOs and controls what POJO types are supported.
By default, this is the {@link org.apache.juneau.oapi.OpenApiParser} which supports the standard Swagger-based rules for parsing.
</p>
<p>
For example, the following shows how a pipe-delimited list of comma-delimited numbers (e.g. <js>"1,2,3|4,5,6|7,8,9"</js>) can be converted to a 2-dimensional array of <c>Longs</c>:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(method=<js>"GET"</js>, path=<js>"/testQuery"</js>)
<jk>public void</jk> testQuery(
<ja>@Query</ja>(
name=<js>"queryParamName"</js>,
collectionFormat=<js>"pipes"</js>,
items=<ja>@SubItems</ja>(
collectionFormat=<js>"csv"</js>,
type=<js>"integer"</js>,
format=<js>"int64"</js>,
minimum=<js>"0"</js>,
maximum=<js>"100"</js>
minLength=1,
maxLength=10
),
minLength=1,
maxLength=10
)
Long[][] queryParameter
) {...}
</p>
<p>
Input will be converted based on the types and formats defined in the schema definition.
Input validations such as <c>minLength/maxLength</c> that don't match the input will result in automatic <c>400 Bad Request</c> responses.
</p>
<p>
For more information about valid parameter types, see {@doc juneau-marshall.OpenApiDetails.Parsers OpenAPI Parsers}
</p>
<p>
The <ja>@Query</ja> annotation is also used for supplying swagger information about the HTTP part.
This information is used to populate the auto-generated Swagger documentation and UI.
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Normal</jc>
<ja>@Query</ja>(
name=<js>"name"</js>,
description=<js>"Pet name"</js>,
required=<jk>true</jk>,
example=<js>"Doggie"</js>
)
</p>
<p class='bpcode w800'>
<jc>// Free-form</jc>
<jc>// Note the extra field</jc>
<ja>@Query</ja>(
name=<js>"name"</js>,
api={
<js>"description: 'Pet name',"</js>,
<js>"required: true,"</js>,
<js>"example: 'Doggie',"</js>
<js>"x-extra: 'extra field'"</js>
}
)
</p>
<p>
{@doc DefaultRestSvlVariables} (e.g. "$L{my.localized.variable}")
are supported on annotation fields.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Query</ja>(
description=<js>"$L{PetNameDescription}"</js>
)
</p>
<ul class='seealso'>
<li class='jc'>{@link org.apache.juneau.rest.RequestQuery}
<li class='link'>{@doc juneau-rest-server.OpenApiSchemaPartParsing}
</ul>
</div><!-- END: 6.10.4 - juneau-rest-server.HttpPartAnnotations.Query -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HttpPartAnnotations.HasQuery' id='juneau-rest-server.HttpPartAnnotations.HasQuery'>6.10.5 - @HasQuery</a></h4>
<div class='topic'><!-- START: 6.10.5 - juneau-rest-server.HttpPartAnnotations.HasQuery -->
<p>
Identical to {@link org.apache.juneau.http.annotation.HasFormData @HasFormData}, but only checks the existing of the parameter in the URL string, not
URL-encoded form posts.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.HasQuery}
</ul>
<p>
Unlike {@link org.apache.juneau.http.annotation.HasFormData @HasFormData}, using this annotation does not result in the servlet reading the contents
of URL-encoded form posts.
Therefore, this annotation can be used in conjunction with the {@link org.apache.juneau.http.annotation.Body @Body} annotation or
{@link org.apache.juneau.rest.RestRequest#getBody()} method for <c>application/x-www-form-urlencoded POST</c> calls.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
<jk>public void</jk> doGet(<ja>@HasQuery</ja>(<js>"p1"</js>) <jk>boolean</jk> p1) {...}
</p>
<p>
This is functionally equivalent to the following code:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
<jk>public void</jk> doGet(RestRequest req) {
<jk>boolean</jk> p1 = req.hasQuery(<js>"p1"</js>);
...
}
</p>
<p>
The parameter type must be either <jk>boolean</jk> or {@link java.lang.Boolean}.
</p>
<p>
The following table shows the behavioral differences between <ja>@HasQuery</ja> and <ja>@Query</ja>:
</p>
<table class='styled w400'>
<tr>
<th><c>Query content</c></th>
<th><c><ja>@HasQuery</ja>(<js>"a"</js>)</c></th>
<th><c><ja>@Query</ja>(<js>"a"</js>)</c></th>
</tr>
<tr>
<td><c>?a=foo</c></td>
<td><jk>true</jk></td>
<td><js>"foo"</js></td>
</tr>
<tr>
<td><c>?a=</c></td>
<td><jk>true</jk></td>
<td><js>""</js></td>
</tr>
<tr>
<td><c>?a</c></td>
<td><jk>true</jk></td>
<td><jk>null</jk></td>
</tr>
<tr>
<td><c>?b=foo</c></td>
<td><jk>false</jk></td>
<td><jk>null</jk></td>
</tr>
</table>
</div><!-- END: 6.10.5 - juneau-rest-server.HttpPartAnnotations.HasQuery -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HttpPartAnnotations.Header' id='juneau-rest-server.HttpPartAnnotations.Header'>6.10.6 - @Header</a></h4>
<div class='topic'><!-- START: 6.10.6 - juneau-rest-server.HttpPartAnnotations.Header -->
<p>
The {@link org.apache.juneau.http.annotation.Header @Header} annotation is used to retrieve request headers.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Header}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#_default() _default} - Default value if not present.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#_enum() _enum} - Input validation. Must match one of the values.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#allowEmptyValue() allowEmptyValue} - Input validation. Allow empty value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#api() api} - Free-form Swagger JSON.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#collectionFormat() collectionFormat} - How collections of items are formatted.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#description() description} - Description.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#example() example} - Serialized example.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#exclusiveMaximum() exclusiveMaximum} - Input validation. Whether maximum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#exclusiveMinimum() exclusiveMinimum} - Input validation. Whether minimum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#format() format} - The schema type format.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#items() items} - The schema of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#maximum() maximum} - Input validation. Maximum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#maxItems() maxItems} - Input validation. Maximum number of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#maxLength() maxLength} - Input validation. Maximum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#minimum() minimum} - Input validation. Minimum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#minItems() minItems} - Input validation. Minimum number of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#minLength() minLength} - Input validation. Minimum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#multipleOf() multipleOf} - Input validation. Number must be a multiple of.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#name() name} - Header name.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#parser() parser} - Override the part parser.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#pattern() pattern} - Input validation. Must match regular expression.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#required() required} - Input validation. Header must be present.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#type() type} - The schema type.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#uniqueItems() uniqueItems} - Input validation. Collections must contain unique items only.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#value() value} - Free-form Swagger JSON.
</ul>
</ul>
<p>
The most typical scenario is to simply use the <c>value</c> field to define header parameter names:
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
<jk>public void</jk> doGet(<ja>@Header</ja>(<js>"ETag"</js>) UUID etag) {...}
</p>
<p>
This is functionally equivalent to the following code:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
<jk>public void</jk> doGet(RestRequest req) {
RequestHeaders h = req.getHeaders();
UUID etag = h.get(<js>"ETag"</js>, UUID.<jk>class</jk>);
}
</p>
<p>
The special name <js>"*"</js> (or blank) can be used to represent all values.
When used, the data type must be a <c>Map</c> or bean.
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Multiple values passed as a map.</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
<jk>public void</jk> doGet(<ja>@Header</ja>(<js>"*"</js>) Map&lt;String,Object&gt; map) {...}
</p>
<p class='bpcode w800'>
<jc>// Same, but name "*" is inferred.</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
<jk>public void</jk> doGet(<ja>@Header</ja> Map&lt;String,Object&gt; map) {...}
</p>
<p class='bpcode w800'>
<jc>// Multiple values passed as a bean.</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
<jk>public void</jk> doGet(<ja>@Header</ja> MyBean bean) {...}
</p>
<p>
The registered {@link org.apache.juneau.rest.RestContext#REST_partParser REST_partParser} is used to convert strings
to POJOs and controls what POJO types are supported.
By default, this is the {@link org.apache.juneau.oapi.OpenApiParser} which supports the standard Swagger-based rules for parsing.
</p>
<p>
For example, the following shows how a pipe-delimited list of comma-delimited numbers (e.g. <js>"1,2,3|4,5,6|7,8,9"</js>) can be converted to a 2-dimensional array of <c>Longs</c>:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(method=<js>"GET"</js>, path=<js>"/testHeader"</js>)
<jk>public void</jk> testHeader(
<ja>@Header</ja>(
name=<js>"My-Header"</js>,
collectionFormat=<js>"pipes"</js>,
items=<ja>@SubItems</ja>(
collectionFormat=<js>"csv"</js>,
type=<js>"integer"</js>,
format=<js>"int64"</js>,
minimum=<js>"0"</js>,
maximum=<js>"100"</js>
minLength=1,
maxLength=10
),
minLength=1,
maxLength=10
)
Long[][] myHeader
) {...}
</p>
<p>
Input will be converted based on the types and formats defined in the schema definition.
Input validations such as <c>minLength/maxLength</c> that don't match the input will result in automatic <c>400 Bad Request</c> responses.
</p>
<p>
For more information about valid parameter types, see {@doc juneau-marshall.OpenApiDetails.Parsers OpenAPI Parsers}
</p>
<p>
The <ja>@Header</ja> annotation is also used for supplying swagger information about the HTTP part.
This information is used to populate the auto-generated Swagger documentation and UI.
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Normal</jc>
<ja>@Header</ja>(
name=<js>"Pet-Name"</js>,
description=<js>"Pet name"</js>,
required=<jk>true</jk>,
example=<js>"Doggie"</js>
)
</p>
<p class='bpcode w800'>
<jc>// Free-form</jc>
<jc>// Note the extra field</jc>
<ja>@Header</ja>(
name=<js>"Pet-Name"</js>,
api={
<js>"description: 'Pet name',"</js>,
<js>"required: true,"</js>,
<js>"example: 'Doggie',"</js>
<js>"x-extra: 'extra field'"</js>
}
)
</p>
<p>
{@doc DefaultRestSvlVariables} (e.g. "$L{my.localized.variable}")
are supported on annotation fields.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Header</ja>(
description=<js>"$L{PetNameDescription}"</js>
)
</p>
<ul class='seealso'>
<li class='jc'>{@link org.apache.juneau.rest.RequestHeaders}
<li class='link'>{@doc juneau-rest-server.OpenApiSchemaPartParsing}
</ul>
</div><!-- END: 6.10.6 - juneau-rest-server.HttpPartAnnotations.Header -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HttpPartAnnotations.Path' id='juneau-rest-server.HttpPartAnnotations.Path'>6.10.7 - @Path</a></h4>
<div class='topic'><!-- START: 6.10.7 - juneau-rest-server.HttpPartAnnotations.Path -->
<p>
The {@link org.apache.juneau.http.annotation.Path @Path} annotation is used to retrieve request path parameters.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Path}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#_enum() _enum} - Input validation. Must match one of the values.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#allowEmptyValue() allowEmptyValue} - Input validation. Allow empty value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#api() api} - Free-form Swagger JSON.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#collectionFormat() collectionFormat} - How collections of items are formatted.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#description() description} - Description.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#example() example} - Serialized example.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#exclusiveMaximum() exclusiveMaximum} - Input validation. Whether maximum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#exclusiveMinimum() exclusiveMinimum} - Input validation. Whether minimum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#format() format} - The schema type format.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#items() items} - The schema of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#maximum() maximum} - Input validation. Maximum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#maxLength() maxLength} - Input validation. Maximum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#minimum() minimum} - Input validation. Minimum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#minLength() minLength} - Input validation. Minimum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#multipleOf() multipleOf} - Input validation. Number must be a multiple of.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#name() name} - Path variable name.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#parser() parser} - Override the part parser.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#pattern() pattern} - Input validation. Must match regular expression.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#type() type} - The schema type.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#value() value} - Free-form Swagger JSON.
</ul>
</ul>
<p>
The most typical scenario is to simply use the <c>value</c> field to define path parameter names:
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/myurl/{foo}/{bar}/{baz}/*"</js>)
<jk>public void</jk> doGet(
<ja>@Path</ja>(<js>"foo"</js>) String foo,
<ja>@Path</ja>(<js>"bar"</js>) <jk>int</jk> bar,
<ja>@Path</ja>(<js>"baz"</js>) UUID baz,
<ja>@Path</ja>(<js>"/*"</js>) String remainder
) {...}
</p>
<p>
This is functionally equivalent to the following code:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/myurl/{foo}/{bar}/{baz}/*"</js>)
<jk>public void</jk> doGet(RestRequest req) {
RequestPath p = req.getPathMatch();
String foo = p.getString(<js>"foo"</js>);
<jk>int</jk> bar = p.get(<js>"bar"</js>, <jk>int</jk>.<jk>class</jk>);
UUID baz = p.get(<js>"baz"</js>, UUID.<jk>class</jk>);
String remainder = p.getRemainder();
}
</p>
<p>
Note that the path variable name <js>"/*"</js> can be used to represent the remainder of the path match.
</p>
<p>
The special name <js>"*"</js> (or blank) can be used to represent all values.
When used, the data type must be a <c>Map</c> or bean.
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Multiple values passed as a map.</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/{a}/{b}/{c}/*"</js>)
<jk>public void</jk> doGet(<ja>@Path</ja>(<js>"*"</js>) Map&lt;String,Object&gt; map) {...}
</p>
<p class='bpcode w800'>
<jc>// Same, but name "*" is inferred.</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/{a}/{b}/{c}/*"</js>)
<jk>public void</jk> doGet(<ja>@Path</ja> Map&lt;String,Object&gt; map) {...}
</p>
<p class='bpcode w800'>
<jc>// Multiple values passed as a bean.</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/{a}/{b}/{c}/*"</js>)
<jk>public void</jk> doGet(<ja>@Path</ja> MyBean bean) {...}
</p>
<p>
The registered {@link org.apache.juneau.rest.RestContext#REST_partParser REST_partParser} is used to convert strings
to POJOs and controls what POJO types are supported.
By default, this is the {@link org.apache.juneau.oapi.OpenApiParser} which supports the standard Swagger-based rules for parsing.
</p>
<p>
For example, the following shows how a pipe-delimited list of comma-delimited numbers (e.g. <js>"1,2,3|4,5,6|7,8,9"</js>) can be converted to a 2-dimensional array of <c>Longs</c>:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(method=<js>"POST"</js>, path=<js>"/testPath/{pathParam}"</js>)
<jk>public void</jk> testPath(
<ja>@Path</ja>(
name=<js>"pathParam"</js>,
collectionFormat=<js>"pipes"</js>,
items=<ja>@SubItems</ja>(
collectionFormat=<js>"csv"</js>,
type=<js>"integer"</js>,
format=<js>"int64"</js>,
minimum=<js>"0"</js>,
maximum=<js>"100"</js>
minLength=1,
maxLength=10
),
minLength=1,
maxLength=10
)
Long[][] pathParameter
) {...}
</p>
<p>
Input will be converted based on the types and formats defined in the schema definition.
Input validations such as <c>minLength/maxLength</c> that don't match the input will result in automatic <c>400 Bad Request</c> responses.
</p>
<p>
For more information about valid parameter types, see {@doc juneau-marshall.OpenApiDetails.Parsers OpenAPI Parsers}
</p>
<p>
The <ja>@Path</ja> annotation is also used for supplying swagger information about the HTTP part.
This information is used to populate the auto-generated Swagger documentation and UI.
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Normal</jc>
<ja>@Path</ja>(
name=<js>"name"</js>,
description=<js>"Pet name"</js>,
example=<js>"Doggie"</js>
)
</p>
<p class='bpcode w800'>
<jc>// Free-form</jc>
<jc>// Note the extra field</jc>
<ja>@Path</ja>(
name=<js>"name"</js>,
api={
<js>"description: 'Pet name',"</js>,
<js>"example: 'Doggie',"</js>
<js>"x-extra: 'extra field'"</js>
}
)
</p>
<p>
{@doc DefaultRestSvlVariables} (e.g. "$L{my.localized.variable}")
are supported on annotation fields.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Path</ja>(
description=<js>"$L{PetNameDescription}"</js>
)
</p>
<ul class='seealso'>
<li class='jc'>{@link org.apache.juneau.rest.RequestPath}
<li class='link'>{@doc juneau-rest-server.OpenApiSchemaPartParsing}
</ul>
</div><!-- END: 6.10.7 - juneau-rest-server.HttpPartAnnotations.Path -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HttpPartAnnotations.Request' id='juneau-rest-server.HttpPartAnnotations.Request'>6.10.8 - @Request</a></h4>
<div class='topic'><!-- START: 6.10.8 - juneau-rest-server.HttpPartAnnotations.Request -->
<p>
The {@link org.apache.juneau.http.annotation.Request @Request} annotation can be applied to a parameter interface type of a <ja>@RestMethod</ja>-annotated method
to identify it as an interface for retrieving HTTP parts through a bean-like interface.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Request}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.Request#partParser() partParser} - Override the part parser.
</ul>
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(path=<js>"/pets/{petId}"</js>)
<jk>public void</jk> putPet(UpdatePet updatePet) {...}
<ja>@Request</ja>
<jk>public interface</jk> UpdatePet {
<ja>@Path</ja>
<jk>int</jk> getPetId();
<ja>@Query</ja>(name=<js>"verbose"</js>)
<jk>boolean</jk> isDebug();
<ja>@Header</ja>(<js>"*"</js>)
Map&lt;String,Object&gt; getAllHeaders();
<ja>@Body</ja>
Pet getPet();
}
</p>
<p>
The example above is identical in behavior to specifying individual annotated parameters on the <ja>@RestMethod</ja>-annotated method:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(path=<js>"/pets/{petId}"</js>)
<jk>public void</jk> putPet(
<ja>@Path</ja>(<js>"petId"</js>) <jk>int</jk> petId,
<ja>@Query</ja>(<js>"verbose"</js>) <jk>boolean</jk> debug,
<ja>@Header</ja>(<js>"*"</js>) Map&lt;String,Object&gt; allHeaders,
<ja>@Body</ja> Pet pet
)
{...}
</p>
<p>
The return types of the getters must be the supported parameter types for the HTTP-part annotation used.
Schema-based serialization and parsing is used just as if used as individual parameter types.
Annotations used are the exact same used on REST parameters and have all the
same feature support including automatic Swagger validation and documentation.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Request</ja>
<jk>public interface</jk> Request {
<jc>// Schema-based query parameter: Pipe-delimited lists of comma-delimited lists of integers.</jc>
<ja>@Query</ja>(
collectionFormat=<js>"pipes"</js>
items=<ja>@Items</ja>(
items=<ja>@SubItems</ja>(
collectionFormat=<js>"csv"</js>
type=<js>"integer"</js>,
minimum=1,
maximum=100
),
maximumLength=10
)
)
<jk>int</jk>[][] getPipedCdlInts();
}
</p>
<p>
For clarity, the <ja>@Request</ja> annotation can be defined on the parameter, class, or both.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(path=<js>"/pets/{petId}"</js>)
<jk>public void</jk> putPet(<ja>@Request</ja> UpdatePet updatePet) {...}
<ja>@Request</ja>
<jk>public interface</jk> UpdatePet {...}
</p>
</div><!-- END: 6.10.8 - juneau-rest-server.HttpPartAnnotations.Request -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HttpPartAnnotations.Response' id='juneau-rest-server.HttpPartAnnotations.Response'>6.10.9 - @Response</a></h4>
<div class='topic'><!-- START: 6.10.9 - juneau-rest-server.HttpPartAnnotations.Response -->
<p>
The {@link org.apache.juneau.http.annotation.Response @Response} annotation is used to identify schema information about an HTTP response.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Response}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.Response#api() api} - Free-form Swagger JSON.
<li class='jf'>{@link org.apache.juneau.http.annotation.Response#code() code} - HTTP status code.
<li class='jf'>{@link org.apache.juneau.http.annotation.Response#description() description} - Description.
<li class='jf'>{@link org.apache.juneau.http.annotation.Response#example() example} - Serialized example.
<li class='jf'>{@link org.apache.juneau.http.annotation.Response#examples() examples} - Serialized examples per media type.
<li class='jf'>{@link org.apache.juneau.http.annotation.Response#headers() headers} - Swagger about headers added to response.
<li class='jf'>{@link org.apache.juneau.http.annotation.Response#partSerializer() partSerializer} - Override the part serializer.
<li class='jf'>{@link org.apache.juneau.http.annotation.Response#schema() schema} - Swagger schema.
<li class='jf'>{@link org.apache.juneau.http.annotation.Response#value() value} - Free-form Swagger JSON.
</ul>
</ul>
<p>
It can be used in the following locations:
</p>
<ul>
<li>Exception classes thrown from <ja>@RestMethod</ja>-annotated methods.
<li>Return type classes of <ja>@RestMethod</ja>-annotated methods.
<li><ja>@RestMethod</ja>-annotated methods themselves.
<li>Arguments and argument-types of <ja>@RestMethod</ja>-annotated methods.
</ul>
<p>
When the <ja>@Response</ja> annotation is applied to classes, the following annotations can be used on
public non-static methods of the class to identify parts of a response:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseStatus}
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseHeader}
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseBody}
</ul>
<h5 class='topic'>@Resource on exception classes</h5>
<p>
When applied to an exception class, this annotation defines Swagger schema and information on non-200 return types.
</p>
<p>
The following example shows the <ja>@Response</ja> annotation used to define an exception for an invalid login attempt:
</p>
<p class='bpcode w800'>
<jc>// Our annotated exception.</jc>
<ja>@Response</ja>(
code=401,
description=<js>"Invalid username or password provided"</js> <jc>// Description show in Swagger</jc>
)
<jk>public class</jk> InvalidLogin <jk>extends</jk> Exception {
<jk>public</jk> InvalidLogin() {
<jk>super</jk>(<js>"Invalid username or password."</js>); <jc>// Message sent in response</jc>
}
}
<jc>// Our REST method that throws an annotated exception.</jc>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/user/login"</js>)
<jk>public</jk> Ok login(
<ja>@FormData</ja>(<js>"username"</js>) String username,
<ja>@FormData</ja>(<js>"password"</js>) String password
) <jk>throws</jk> InvalidLogin
{
checkCredentials(username, password);
<jk>return new</jk> Ok();
}
</p>
<p>
Custom exceptions can also extend from one of the predefined HTTP exceptions such as the {@link org.apache.juneau.http.exception.Unauthorized} exception:
</p>
<p class='bpcode w800'>
<jc>// Our annotated exception.</jc>
<ja>@Response</ja>(
description=<js>"Invalid username or password provided"</js> <jc>// Overridden from parent class</jc>
)
<jk>public class</jk> InvalidLogin <jk>extends</jk> Unauthorized {
<jk>public</jk> InvalidLogin() {
<jk>super</jk>(<js>"Invalid username or password."</js>);
}
}
<jc>// Parent predefined exception class.</jc>
<ja>@Response</ja>(
code=401,
description=<js>"Unauthorized"</js>
)
<jk>public class</jk> Unauthorized <jk>extends</jk> RestException {...}
</p>
<h5 class='topic'>@Resource on return type classes</h5>
<p>
When applied type classes returned by a Java method, this annotation defines schema and Swagger information on the body of responses.
</p>
<p>
In the example above, we're using the <c>Ok</c> class which is defined like so:
</p>
<p class='bpcode w800'>
<ja>@Response</ja>(
code=200,
description=<js>"OK"</js>
)
<jk>public class</jk> Ok {
<ja>@ResponseBody</ja>
<jk>public</jk> String toString() {
<jk>return</jk> <js>"OK"</js>;
}
}
</p>
<p>
Another example showing how a redirect can be defined:
</p>
<p class='bpcode w800'>
<ja>@Response</ja>(
code=307,
description=<js>"Temporary Redirect"</js>
)
<jk>public class</jk> Redirect {
<jk>private final</jk> URI <jf>location</jf>;
<jk>public</jk> Redirect(URI location) {
<jk>this</jk>.<jf>location</jf> = location;
}
<ja>@ResponseHeader</ja>(
name=<js>"Location"</js>,
format=<js>"uri"</js>
)
<jk>public</jk> URI getLocation() {
<jk>return</jk> location;
}
<ja>@ResponseBody</ja>
<jk>public</jk> String toString() {
<jk>return</jk> <js>"Temporary Redirect"</js>;
}
}
</p>
<p class='bpcode w800'>
<jc>// Usage</jc>
<ja>@RestMethod</ja>(method=<jsf>POST</jsf>)
<jk>public</jk> Redirect addPet(Pet pet) {
<jc>// Redirect to servlet root</jc>
<jk>return new</jk> Redirect(URI.<jsm>create</jsm>(<js>"servlet:/"</js>));
}
</p>
<h5 class='topic'>@Resource on @RestMethod-annotated methods</h5>
<p>
The <ja>@Response</ja> annotation can also be applied to the Java method itself which is effectively
the same as applying it to the return type (albeit for this method only).
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/user/login"</js>)
<ja>@Response</ja>(code=200, description=<js>"OK"</js>)
<jk>public</jk> Ok login(
<ja>@FormData</ja>(<js>"username"</js>) String username,
<ja>@FormData</ja>(<js>"password"</js>) String password
) <jk>throws</jk> InvalidLogin
{
checkCredentials(username, password);
<jk>return new</jk> Ok();
}
</p>
<p>
The <ja>@Response</ja> annotation can be simultaneously on both the Java method and return type.
When used in both locations, the annotation values are combined, but values defined on the
method return annotation take precedence over the values defined on the type.
</p>
<h5 class='topic'>@Resource on @RestMethod-annotated method parameters</h5>
<p>
The <ja>@Response</ja> annotation can also be applied to the Java method parameters when the parameter type
is {@link org.apache.juneau.Value} (a placeholder for objects).
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/user/login"</js>)
<jk>public void</jk> login(
<ja>@FormData</ja>(<js>"username"</js>) String username,
<ja>@FormData</ja>(<js>"password"</js>) String password,
<ja>@Response</ja>(code=200, description=<js>"Login succeeded"</js>) Value&lt;String&gt; body
) <jk>throws</jk> InvalidLogin
{
checkCredentials(username, password);
body.set(<js>"OK"</js>);
}
</p>
<p>
<ja>@Response</ja>-annotated types can also be used as value parameters:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(...)
<jk>public void</jk> login(
...
<ja>@Response</ja> Value&lt;Ok&gt; res
) <jk>throws</jk> InvalidLogin
{
...
res.set(<jk>new</jk> Ok());
}
</p>
<p>
In the above example, the <ja>@Response</ja> annotation is optional since it is inferred from the class
that it's a <ja>@Response</ja> bean.
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/user/login"</js>)
<jk>public void</jk> login(
...
Value&lt;Ok&gt; res <jc>// @Response annotation not needed.</jc>
) <jk>throws</jk> InvalidLogin
{
...
res.set(<jk>new</jk> Ok());
}
</p>
<h5 class='topic'>@ResponseStatus on methods of @Response-annotated types</h5>
<p>
The {@link org.apache.juneau.http.annotation.ResponseStatus @ResponseStatus} annotation can be used on
the method of a <ja>@Response</ja>-annotated class to identify HTTP response
statuses other than <c>200</c> (the default).
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Response</ja>
<jk>public class</jk> AddPetSuccess {
<ja>@ResponseStatus</ja>
<jk>public int</jk> getStatus() {
<jk>return</jk> 201;
}
<ja>@Override</ja>
<jk>public</jk> String toString() {
<jk>return</jk> <js>"Pet was successfully added"</js>;
}
}
</p>
<h5 class='topic'>@ResponseHeader on methods of @Response-annotated types</h5>
<p>
The {@link org.apache.juneau.http.annotation.ResponseHeader @ResponseHeader} annotation can be used on
the method of a <ja>@Response</ja>-annotated class to identify a header
to add to the response.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Response</ja>
<jk>public class</jk> AddPetSuccess {
<ja>@ResponseHeader</ja>(
name=<js>"X-PetId"</js>,
type=<js>"integer"</js>,
format=<js>"int32"</js>,
description=<js>"ID of added pet."</js>,
example=<js>"123"</js>
)
<jk>public int</jk> getPetId() {...}
}
</p>
<h5 class='topic'>@ResponseBody on methods of @Response-annotated types</h5>
<p>
The {@link org.apache.juneau.http.annotation.ResponseBody @ResponseBody} annotation can be used on
the method of a <ja>@Response</ja>-annotated class to identify a POJO
as the body of the HTTP response.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Response</ja>
<jk>public class</jk> AddPetSuccess {
<ja>@ResponseBody</ja>
<jk>public</jk> Pet getPet() {...}
}
</p>
<p>
If a <ja>@Response</ja> class does not have a <ja>@ResponseBody</ja>-annotated method, then the response
object itself is serialized in the response (typically using <c>toString()</c>).
</p>
<h5 class='topic'>Notes about OpenAPI part serialization</h5>
<p>
By default, POJOs representing the body of the request are serialized using the Juneau serializer
matching the requesting <c>Accept</c> header.
The {@link org.apache.juneau.oapi.OpenApiSerializer} class can be used to serialize response bodies using OpenAPI rules.
</p>
<p>
The following examples show part-schema-based serialization of response bodies:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>
<jk>public class</jk> ExampleResource {
<jc>// Example 1 - String[] should be serialized using part serializer.</jc>
<ja>@Response</ja>(
serializers=OpenApiSerializer.<jk>class</jk>,
defaultAccept=<js>"text/openapi"</js>
)
<ja>@RestMethod</ja>
<jk>public</jk> String[] example1() {
<jk>return new</jk> String[]{<js>"foo"</js>,<js>"bar"</js>};
}
<jc>// Example 2 - Same as above. Annotation on parameter.</jc>
<ja>@RestMethod</ja>
<jk>public void</jk> example2(
<ja>@Response</ja>(
serializers=OpenApiSerializer.<jk>class</jk>,
defaultAccept=<js>"text/openapi"</js>
)
Value&lt;String[]&gt; body
)
{
body.set(<jk>new</jk> String[]{<js>"foo"</js>,<js>"bar"</js>});
}
}
</p>
<p>
The <c><ja>@Response</ja>(schema)</c> annotation can be used to define the format of the output using OpenAPI-based rules.
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>
<jk>public class</jk> ExampleResource {
<ja>@Response</ja>(
serializers=OpenApiSerializer.<jk>class</jk>,
defaultAccept=<js>"text/openapi"</js>,
schema=<ja>@Schema</ja>(collectionFormat=<js>"pipes"</js>)
)
<ja>@RestMethod</ja>
<jk>public</jk> String[] example1() {
<jk>return new</jk> String[]{<js>"foo"</js>,<js>"bar"</js>};
}
}
</p>
<h5 class='topic'>Swagger documentation</h5>
<p>
The attributes on this annotation are also used to populate the generated Swagger for the method.
For example, in the case of the <c>InvalidLogin</c> example above, the following Swagger is generated:
</p>
<p class='bpcode w800'>
<jok>'/user/login'</jok>: {
<jok>get</jok>: {
<jok>responses</jok>: {
<jok>401</jok>: {
<jok>description</jok>: <jov>'Invalid username or password provided'</jov>
}
}
}
}
</p>
<h5 class='topic'>Automatic HTTP status</h5>
<p>
When the {@link org.apache.juneau.http.annotation.Response#code() @Response(code)} value is specified,
the HTTP status is automatically set to that value on the response regardless of how it's used.
</p>
<p>
The following two examples are equivalent:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/ok"</js>)
<jk>public void</jk> sendContinue(
<ja>@Response</ja>(code=100) Value&lt;String&gt; body
)
{
body.set(<js>"OK"</js>);
}
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/ok"</js>)
<jk>public void</jk> sendContinue(RestResponse res) {
res.setStatus(100);
res.setOutput(<js>"OK"</js>);
}
</p>
<ul class='seealso'>
<li class='link'>{@doc juneau-rest-server.OpenApiSchemaPartSerializing}
</ul>
</div><!-- END: 6.10.9 - juneau-rest-server.HttpPartAnnotations.Response -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HttpPartAnnotations.ResponseHeader' id='juneau-rest-server.HttpPartAnnotations.ResponseHeader'>6.10.10 - @ResponseHeader</a></h4>
<div class='topic'><!-- START: 6.10.10 - juneau-rest-server.HttpPartAnnotations.ResponseHeader -->
<p>
The {@link org.apache.juneau.http.annotation.ResponseHeader @ResponseHeader} annotation can be applied to <ja>@RestMethod</ja>-annotated parameters to denote them as an HTTP response headers.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseHeader}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#_default() _default} - Default value if not present.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#_enum() _enum} - Output validation. Must match one of the values.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#$ref() $ref} - Schema reference.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#api() api} - Free-form Swagger JSON.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#code() code} - HTTP status codes that this header applies to.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#collectionFormat() collectionFormat} - How collections of items are formatted.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#description() description} - Description.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#example() example} - Serialized example.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#exclusiveMaximum() exclusiveMaximum} - Output validation. Whether maximum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#exclusiveMinimum() exclusiveMinimum} - Output validation. Whether minimum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#format() format} - The schema type format.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#items() items} - The schema of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#maximum() maximum} - Output validation. Maximum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#maxItems() maxItems} - Output validation. Maximum number of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#maxLength() maxLength} - Output validation. Maximum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#minimum() minimum} - Output validation. Minimum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#minItems() minItems} - Output validation. Minimum number of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#minLength() minLength} - Output validation. Minimum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#multipleOf() multipleOf} - Output validation. Number must be a multiple of.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#name() name} - Header name.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#pattern() pattern} - Output validation. Must match regular expression.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#serializer() serializer} - Override the part serializer.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#type() type} - The schema type.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#uniqueItems() uniqueItems} - Output validation. Collections must contain unique items only.
<li class='jf'>{@link org.apache.juneau.http.annotation.ResponseHeader#value() value} - Free-form Swagger JSON.
</ul>
</ul>
<p>
This annotation can only be applied to parameters of type {@link org.apache.juneau.Value}.
</p>
<p>
The following examples show 3 different ways of accomplishing the same task of setting an HTTP header
on a response:
</p>
<p class='bpcode w800'>
<jc>// Example #1 - Setting header directly on RestResponse object.</jc>
<ja>@RestMethod</ja>(...)
<jk>public void</jk> login(RestResponse res) {
res.setHeader(<js>"X-Rate-Limit"</js>, 1000);
...
}
<jc>// Example #2 - Use on parameter.</jc>
<ja>@RestMethod</ja>(...)
<jk>public void</jk> login(
<ja>@ResponseHeader</ja>(
name=<js>"X-Rate-Limit"</js>,
type=<js>"integer"</js>,
format=<js>"int32"</js>,
description=<js>"Calls per hour allowed by the user."</js>,
example=<js>"123"</js>
)
Value&lt;Integer&gt; rateLimit
)
{
rateLimit.set(1000);
...
}
<jc>// Example #3 - Use on type.</jc>
<ja>@RestMethod</ja>(...)
<jk>public void</jk> login(Value&lt;RateLimit&gt; rateLimit) {
rateLimit.set(<jk>new</jk> RateLimit());
...
}
<ja>@ResponseHeader</ja>(
name=<js>"X-Rate-Limit"</js>,
type=<js>"integer"</js>,
format=<js>"int32"</js>,
description=<js>"Calls per hour allowed by the user."</js>,
example=<js>"123"</js>
)
<jk>public class</jk> RateLimit {
<jc>// OpenApiSerializer knows to look for this method based on format/type.</jc>
<jk>public</jk> Integer toInteger() {
<jk>return</jk> 1000;
}
}
</p>
<h5 class='topic'>Swagger documentation</h5>
<p>
The attributes on this annotation are also used to populate the generated Swagger for the method.
For example, in the case of the <c>X-Rate-Limit</c> example above, the following Swagger is generated:
</p>
<p class='bpcode w800'>
<jok>'/user/login'</jok>: {
<jok>get</jok>: {
<jok>responses</jok>: {
<jok>200</jok>: {
<jok>headers</jok>: {
<jok>'X-Rate-Limit'</jok>: {
<jok>type</jok>: <jov>'integer'</jov>,
<jok>format</jok>: <jov>'int32'</jov>,
<jok>description</jok>: <jov>'Calls per hour allowed by the user.'</jov>,
<jok>example</jok>: <jov>'123'</jov>
}
}
}
}
}
}
</p>
</div><!-- END: 6.10.10 - juneau-rest-server.HttpPartAnnotations.ResponseHeader -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HttpPartAnnotations.ResponseStatus' id='juneau-rest-server.HttpPartAnnotations.ResponseStatus'>6.10.11 - @ResponseStatus</a></h4>
<div class='topic'><!-- START: 6.10.11 - juneau-rest-server.HttpPartAnnotations.ResponseStatus -->
<p>
The {@link org.apache.juneau.http.annotation.ResponseStatus @ResponseStatus} annotation annotation can be applied to <ja>@RestMethod</ja>-annotated parameters to denote them as an HTTP response status codes.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseStatus}
</ul>
<p>
This can only be applied to parameters of the {@link org.apache.juneau.Value} class with an {@link java.lang.Integer} type.
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Defined on parameter.</jc>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/user/login"</js>)
<jk>public void</jk> login(
<ja>@FormData</ja>(<js>"username"</js>) String username,
<ja>@FormData</ja>(<js>"password"</js>) String password,
<ja>@ResponseStatus</ja> Value&lt;Integer&gt; status
)
{
<jk>if</jk> (! isValid(username, password))
status.set(401);
}
</p>
</div><!-- END: 6.10.11 - juneau-rest-server.HttpPartAnnotations.ResponseStatus -->
</div><!-- END: 6.10 - juneau-rest-server.HttpPartAnnotations -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HandlingFormPosts' id='juneau-rest-server.HandlingFormPosts'>6.11 - Handling Form Posts</a></h3>
<div class='topic'><!-- START: 6.11 - juneau-rest-server.HandlingFormPosts -->
<p>
The best way to handle a form post is usually by using an input bean.
The following is a class that takes in URL-Encoded form post of the
form <l>"aString=foo&amp;aNumber=123&amp;aDate=2001-07-04T15:30:45Z"</l>.
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/urlEncodedForm"</js>
)
<jk>public class</jk> UrlEncodedFormResource <jk>extends</jk> BasicRestServlet {
<jd>/** POST request handler */</jd>
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>, 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 <jf>aString</jf>;
<jk>public int</jk> <jf>aNumber</jf>;
<ja>@Swap</ja>(TemporalCalendarSwap.IsoLocalDateTime.<jk>class</jk>)
<jk>public</jk> Calendar <jf>aDate</jf>;
}
}
</p>
<p>
Another possibility is to access the form parameters individually:
</p>
<p class='bpcode w800'>
<jd>/** POST request handler */</jd>
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>, path=<js>"/"</js>)
<jk>public</jk> Object doPost(<ja>@FormData</ja>(<js>"aString"</js>) String aString, <ja>@FormData</ja>(<js>"aNumber"</js>) <jk>int</jk> aNumber, <ja>@FormData</ja>(<js>"aDate"</js>) Calendar aDate) <jk>throws</jk> Exception {
...
}
</p>
<p>
The advantage to the form input bean is that it can handle any of the parsable types (e.g. JSON, XML...)
in addition to URL-Encoding.
The latter approach only supports URL-Encoding.
</p>
<div class='warn'>
If you're using form input beans, DO NOT use the <l>@FormData</l> attribute or
{@link org.apache.juneau.rest.RestRequest#getParameter(String)} method since this will cause the
underlying JEE servlet to parse the HTTP body as a form post.
<br>Your input bean will end up being null since there won't be any content left after the servlet
has parsed the body of the request.
<br>This applies to WHENEVER you use <l>@Body</l> or {@link org.apache.juneau.rest.RestRequest#getBody()}
</div>
</div><!-- END: 6.11 - juneau-rest-server.HandlingFormPosts -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HandlingMultiPartFormPosts' id='juneau-rest-server.HandlingMultiPartFormPosts'>6.12 - Handling Multi-Part Form Posts</a></h3>
<div class='topic'><!-- START: 6.12 - juneau-rest-server.HandlingMultiPartFormPosts -->
<p>
The Juneau framework does not natively support multipart form posts.
However, it can be done in conjunction with the Apache Commons File Upload library or through the Servlet 3.0 API directly.
</p>
<p>
The following is an example that uses the File Upload library to allow files to be uploaded as multipart form posts.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/tempDir"</js>
)
<jk>public class</jk> TempDirResource <jk>extends</jk> DirectoryResource {
<jd>/**
* [POST /upload] - Upload a file as a multipart form post.
* Shows how to use the Apache Commons ServletFileUpload class for handling multi-part form posts.
*/</jd>
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>, 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>
<p>
The following shows using the <l>HttpServletRequest.getParts()</l> method to retrieve multi-part form posts when using Jetty.
This example is pulled from the PetStore application.
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(
...
)
<jk>public</jk> SeeOtherRoot uploadFile(RestRequest req) <jk>throws</jk> Exception {
<jc>// Required for Jetty.</jc>
MultipartConfigElement mce = <jk>new</jk> MultipartConfigElement((String)<jk>null</jk>);
req.setAttribute(<js>"org.eclipse.jetty.multipartConfig"</js>, mce);
String id = UUID.<jsm>randomUUID</jsm>().toString();
BufferedImage img = <jk>null</jk>;
<jk>for</jk> (Part part : req.getParts()) {
<jk>switch</jk> (part.getName()) {
<jk>case</jk> <js>"id"</js>:
id = IOUtils.<jsm>read</jsm>(part.getInputStream());
<jk>break</jk>;
<jk>case</jk> <js>"file"</js>:
img = ImageIO.<jsm>read</jsm>(part.getInputStream());
}
}
addPhoto(id, img);
<jk>return new</jk> SeeOtherRoot(); <jc>// Redirect to the servlet root.</jc>
}
</p>
</div><!-- END: 6.12 - juneau-rest-server.HandlingMultiPartFormPosts -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Serializers' id='juneau-rest-server.Serializers'>6.13 - Serializers</a></h3>
<div class='topic'><!-- START: 6.13 - juneau-rest-server.Serializers -->
<p>
REST resources use the {@link org.apache.juneau.serializer.Serializer} API for defining serializers for
serializing response POJOs.
</p>
<p>
The servlet will pick which serializer to use by matching the request <l>Accept</l> header with the
media types defined through the {@link org.apache.juneau.serializer.Serializer#getMediaTypeRanges()} method.
</p>
<p>
Serializers can be associated with REST servlets in the following ways:
</p>
<ul class='javatree'>
<li class='ja'>
{@link org.apache.juneau.rest.annotation.Rest#serializers() Rest(serializers)}
- Annotation on resource Java class.
<li class='ja'>
{@link org.apache.juneau.rest.annotation.RestMethod#serializers() RestMethod(serializers)}
- Annotation on resource Java method.
<li class='jf'>
{@link org.apache.juneau.rest.RestContext#REST_serializers}
- Programmatic.
</ul>
<p>
The following are all equivalent ways of defining serializers used by a resource:
</p>
<p class='bpcode w800'>
<jc>// Option #1 - Defined via annotation.</jc>
<ja>@Rest</ja>(serializers={JsonSerializer.<jk>class</jk>, XmlSerializer.<jk>class</jk>})
<jk>public class</jk> MyResource {
<jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
<jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
<jc>// Using method on builder.</jc>
builder.serializers(JsonSerializer.<jk>class</jk>, XmlSerializer.<jk>class</jk>);
<jc>// Same, but use pre-instantiated parsers.</jc>
builder.serializers(JsonSerializer.<jsf>DEFAULT</jsf>, XmlSerializer.<jsf>DEFAULT</jsf>);
<jc>// Same, but using property.</jc>
builder.set(<jsf>REST_serializers</jsf>, JsonSerializer.<jk>class</jk>, XmlSerializer.<jk>class</jk>);
}
<jc>// Option #3 - Defined via builder passed in through init method.</jc>
<ja>@RestHook</ja>(<jsf>INIT</jsf>)
<jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
builder.serializers(JsonSerializer.<jk>class</jk>, XmlSerializer.<jk>class</jk>);
}
<jc>// Override at the method level.</jc>
<ja>@RestMethod</ja>(serializers={HtmlSerializer.<jk>class</jk>})
<jk>public</jk> MyPojo myMethod() {
<jc>// Return a POJO to be serialized.</jc>
<jk>return new</jk> MyPojo();
}
}
</p>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_serializers}
</ul>
</div><!-- END: 6.13 - juneau-rest-server.Serializers -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Parsers' id='juneau-rest-server.Parsers'>6.14 - Parsers</a></h3>
<div class='topic'><!-- START: 6.14 - juneau-rest-server.Parsers -->
<p>
REST resources use the {@link org.apache.juneau.parser.Parser} API for defining parsers for parsing request
body content and converting them into POJOs.
</p>
<p>
The servlet will pick which parser to use by matching the request <l>Content-Type</l> header with the
media types defined through the {@link org.apache.juneau.parser.Parser#getMediaTypes()} method.
</p>
<p>
Parsers can be associated with REST servlets in the following ways:
</p>
<ul class='javatree'>
<li class='ja'>
{@link org.apache.juneau.rest.annotation.Rest#parsers() Rest(parsers)}
- Annotation on resource Java class.
<li class='ja'>
{@link org.apache.juneau.rest.annotation.RestMethod#parsers() RestMethod(parsers)}
- Annotation on resource Java method.
<li class='jm'>
{@link org.apache.juneau.rest.RestContextBuilder#parsers(Class[])}
- Programmatic.
</ul>
<p>
The following are all equivalent ways of defining parsers used by a resource:
</p>
<p class='bpcode w800'>
<jc>// Option #1 - Defined via annotation.</jc>
<ja>@Rest</ja>(parsers={JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>})
<jk>public class</jk> MyResource {
<jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
<jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
<jc>// Using method on builder.</jc>
builder.parsers(JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>);
<jc>// Same, but use pre-instantiated parsers.</jc>
builder.parsers(JsonParser.<jsf>DEFAULT</jsf>, XmlParser.<jsf>DEFAULT</jsf>);
<jc>// Same, but using property.</jc>
builder.set(<jsf>REST_parsers</jsf>, JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>);
}
<jc>// Option #3 - Defined via builder passed in through init method.</jc>
<ja>@RestHook</ja>(<jsf>INIT</jsf>)
<jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
builder.parsers(JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>);
}
<jc>// Override at the method level.</jc>
<ja>@RestMethod</ja>(parsers={HtmlParser.<jk>class</jk>})
<jk>public</jk> Object myMethod(<ja>@Body</ja> MyPojo myPojo) {
<jc>// Do something with your parsed POJO.</jc>
}
}
</p>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_parsers}
</ul>
</div><!-- END: 6.14 - juneau-rest-server.Parsers -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.ConfigurableProperties' id='juneau-rest-server.ConfigurableProperties'>6.15 - Configurable Properties</a></h3>
<div class='topic'><!-- START: 6.15 - juneau-rest-server.ConfigurableProperties -->
<p>
As shown in previous sections, Juneau serializers and parsers are highly-configurable through properties.
(See {@doc ConfigurableProperties})
</p>
<p>
These properties can be defined for serializers and parsers registered on a REST resource via the following:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#properties() Rest(properties)}
<li class='jc'>{@link org.apache.juneau.rest.RestContextBuilder} - Various methods on the context builder.
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jk>import static</jk> org.apache.juneau.BeanContext.*;
<jk>import static</jk> org.apache.juneau.serializer.Serializer.*;
<jk>import static</jk> org.apache.juneau.json.JsonSerializer.*;
<jc>// Servlet with properties applied</jc>
<ja>@Rest</ja>(
properties={
<jc>// Bean properties should be sorted alphabetically.</jc>
<ja>@Property</ja>(name=<jsf>BEAN_sortProperties</jsf>, value=<js>"true"</js>),
<jc>// Nulls should not be serialized</jc>
<ja>@Property</ja>(name=<jsf>SERIALIZER_trimNulls</jsf>, value=<js>"true"</js>),
<jc>// Solidus characters should be escaped in JSON</jc>
<ja>@Property</ja>(name=<jsf>JSON_escapeSolidus</jsf>, value=<js>"true"</js>)
}
)
<jk>public</jk> MyRestServlet <jk>extends</jk> BasicRestServlet {...}
</p>
<p>
The programmatic equivalent to this is:
</p>
<p class='bpcode w800'>
<jc>// Servlet with properties applied</jc>
<ja>@Rest</ja>(...)
<jk>public</jk> MyRestServlet <jk>extends</jk> BasicRestServlet {
<jk>public</jk> MyRestServlet(RestContextBuilder builder) {
builder
.sortProperties(); <jc>// Note: RestContextBuilder extends from BeanContextBuilder</jc>
.set(<jsf>SERIALIZER_trimNulls</jsf>, <jk>true</jk>);
.set(<jsf>JSON_escapeSolidus</jsf>, <jk>true</jk>);
}
}
</p>
<p>
Properties can also be overridden at the Java method level:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#properties() RestMethod(properties)}
<li class='jc'>{@link org.apache.juneau.rest.RequestProperties}
</ul>
<p class='bpcode w800'>
<jc>// GET method with method-level properties</jc>
<ja>@RestMethod</ja>(
name=<jsf>GET</jsf>, path=<js>"/*"</js>,
properties={
<jc>// Bean properties should be sorted alphabetically.</jc>
<ja>@Property</ja>(name=<jsf>BEAN_sortProperties</jsf>, value=<js>"true"</js>),
<jc>// Nulls should not be serialized</jc>
<ja>@Property</ja>(name=<jsf>SERIALIZER_trimNulls</jsf>, value=<js>"true"</js>),
<jc>// Solidus characters should be escaped in JSON</jc>
<ja>@Property</ja>(name=<jsf>JSON_escapeSolidus</jsf>, value=<js>"true"</js>)
}
<jk>public</jk> Object doGet() {
...
}
</p>
<ul class='seealso'>
<li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#flags() Rest(flags)} - Shorthand for boolean properties.
<li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#flags() RestMethod(flags)} - Shorthand for boolean properties.
<li class='jc'>{@link org.apache.juneau.rest.RestContextProperties}
<li class='jc'>{@link org.apache.juneau.rest.RestMethodProperties}
</ul>
</div><!-- END: 6.15 - juneau-rest-server.ConfigurableProperties -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.ConfigurableAnnotations' id='juneau-rest-server.ConfigurableAnnotations'>6.16 - Configurable Annotations</a></h3>
<div class='topic'><!-- START: 6.16 - juneau-rest-server.ConfigurableAnnotations -->
<p>
Config annotations allow you to define serializer and parser properties using specialized annotations.
All configuration properties have annotation-equivalents.
</p>
<p>
The following shows the difference between the two approaches:
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Servlet with properties applied</jc>
<ja>@Rest</ja>(
properties={
<ja>@Property</ja>(name=<jsf>BEAN_sortProperties</jsf>, value=<js>"true"</js>),
<ja>@Property</ja>(name=<jsf>SERIALIZER_trimNulls</jsf>, value=<js>"true"</js>),
<ja>@Property</ja>(name=<jsf>JSON_escapeSolidus</jsf>, value=<js>"true"</js>)
}
)
<jk>public</jk> MyRestServlet <jk>extends</jk> BasicRestServlet {...}
</p>
<p class='bpcode w800'>
<jc>// Servlet with config annotations applied</jc>
<ja>@Rest</ja>(
...
)
<ja>@BeanConfig</ja>(sortProperties=<js>"true"</js>)
<ja>@SerializerConfig</ja>(trimNulls=<js>"true"</js>)
<ja>@JsonConfig</ja>(escapeSolidus=<js>"true"</js>)
<jk>public</jk> MyRestServlet <jk>extends</jk> BasicRestServlet {...}
</p>
<p>
Using config annotations is often cleaner and supports the same SVL variable support as those in the REST annotations.
</p>
<p>
Config annotations are defined for all serializers and parsers:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.annotation.BeanConfig BeanConfig}
<li class='ja'>{@link org.apache.juneau.csv.annotation.CsvConfig CsvConfig}
<li class='ja'>{@link org.apache.juneau.html.annotation.HtmlConfig HtmlConfig}
<li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig HtmlDocConfig}
<li class='ja'>{@link org.apache.juneau.jso.annotation.JsoConfig JsoConfig}
<li class='ja'>{@link org.apache.juneau.json.annotation.JsonConfig JsonConfig}
<li class='ja'>{@link org.apache.juneau.jsonschema.annotation.JsonSchemaConfig JsonSchemaConfig}
<li class='ja'>{@link org.apache.juneau.msgpack.annotation.MsgPackConfig MsgPackConfig}
<li class='ja'>{@link org.apache.juneau.oapi.annotation.OpenApiConfig OpenApiConfig}
<li class='ja'>{@link org.apache.juneau.parser.annotation.ParserConfig ParserConfig}
<li class='ja'>{@link org.apache.juneau.plaintext.annotation.PlainTextConfig PlainTextConfig}
<li class='ja'>{@link org.apache.juneau.jena.annotation.RdfConfig RdfConfig}
<li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig SerializerConfig}
<li class='ja'>{@link org.apache.juneau.soap.annotation.SoapXmlConfig SoapXmlConfig}
<li class='ja'>{@link org.apache.juneau.uon.annotation.UonConfig UonConfig}
<li class='ja'>{@link org.apache.juneau.urlencoding.annotation.UrlEncodingConfig UrlEncodingConfig}
<li class='ja'>{@link org.apache.juneau.xml.annotation.XmlConfig XmlConfig}
</ul>
<p>
Config annotations can be defined at both the class and method level just like properties.
</p>
</div><!-- END: 6.16 - juneau-rest-server.ConfigurableAnnotations -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Transforms' id='juneau-rest-server.Transforms'>6.17 - Transforms</a></h3>
<div class='topic'><!-- START: 6.17 - juneau-rest-server.Transforms -->
<p>
The Juneau serializers and parsers can be configured on how to handle POJOs through the use of Transforms.
(See {@doc juneau-marshall.Transforms Transforms})
</p>
<p>
Transforms are associated serializers and parsers registered on a REST resource via the following:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanFilters() BeanConfig(beanFilters)} - On class or methods.
<li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#pojoSwaps() BeanConfig(pojoSwaps)} - On class or methods.
<li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#beanFilters(Object...)}
<li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#pojoSwaps(Object...)}
</ul>
<p class='bpcode w800'>
<jc>// Servlet with transforms applied</jc>
<ja>@Rest</ja>(
...
)
<ja>@BeanConfig</ja>(
pojoSwaps={
<jc>// Calendars should be serialized/parsed as ISO8601 date-time strings</jc>
TemporalCalendarSwap.IsoInstant.<jk>class</jk>,
<jc>// Byte arrays should be serialized/parsed as BASE64-encoded strings</jc>
ByteArraySwap.Base64.<jk>class</jk>
},
beanFilters={
<jc>// Subclasses of MyInterface will be treated as MyInterface objects.</jc>
<jc>// Bean properties not defined on that interface will be ignored.</jc>
MyInterface.<jk>class</jk>
}
)
<jk>public</jk> MyRestServlet <jk>extends</jk> BasicRestServlet {...}
</p>
<p>
The programmatic equivalent to this is:
</p>
<p class='bpcode w800'>
<jc>// Servlet with properties applied</jc>
<ja>@Rest</ja>(...)
<jk>public</jk> MyRestServlet <jk>extends</jk> BasicRestServlet {
<jk>public</jk> MyRestServlet(RestContextBuilder builder) {
builder
.pojoSwaps(
TemporalCalendarSwap.IsoInstant.<jk>class</jk>,
ByteArraySwap.Base64.<jk>class</jk>
)
.beanFilters(MyInterface.<jk>class</jk>);
}
}
</p>
</div><!-- END: 6.17 - juneau-rest-server.Transforms -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.URIs' id='juneau-rest-server.URIs'>6.18 - URIs</a></h3>
<div class='topic'><!-- START: 6.18 - juneau-rest-server.URIs -->
<p>
As mention earlier {@doc juneau-marshall.URIs here}, Juneau serializers have sophisticated support for transforming relative URIs to absolute form.
</p>
<p>
The following example shows a REST method that returns a list of URIs of various forms:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
uriAuthority=<js>"http://foo.com:123"</js>,
uriContext=<js>"/myContext"</js>
)
<jk>public class</jk> MyResource {
<ja>@RestMethod</ja>
<jk>public</jk> URI[] getURIs() {
<jk>return new</jk> URI[] {
URI.<jsm>create</jsm>(<js>"http://www.apache.org/f1a"</js>),
URI.<jsm>create</jsm>(<js>"/f1b"</js>),
URI.<jsm>create</jsm>(<js>"/f1c/x/y"</js>),
URI.<jsm>create</jsm>(<js>"f1d"</js>),
URI.<jsm>create</jsm>(<js>"f1e/x/y"</js>),
URI.<jsm>create</jsm>(<js>""</js>),
URI.<jsm>create</jsm>(<js>"context:/f2a/x"</js>),
URI.<jsm>create</jsm>(<js>"context:/f2b"</js>),
URI.<jsm>create</jsm>(<js>"context:/"</js>),
URI.<jsm>create</jsm>(<js>"context:/.."</js>),
URI.<jsm>create</jsm>(<js>"servlet:/f3a/x"</js>),
URI.<jsm>create</jsm>(<js>"servlet:/f3b"</js>),
URI.<jsm>create</jsm>(<js>"servlet:/"</js>),
URI.<jsm>create</jsm>(<js>"servlet:/.."</js>),
URI.<jsm>create</jsm>(<js>"request:/f4a/x"</js>),
URI.<jsm>create</jsm>(<js>"request:/f4b"</js>),
URI.<jsm>create</jsm>(<js>"request:/"</js>),
URI.<jsm>create</jsm>(<js>"request:/.."</js>)
};
}
}
</p>
<p>
When requested as JSON, it produces the following result:
</p>
<p class='bpcode w800'>
{
<jok>f1a</jok>:<jov>'http://www.apache.org/f1a'</jov>,
<jok>f1b</jok>:<jov>'http://foo.com:123/f1b'</jov>,
<jok>f1c</jok>:<jov>'http://foo.com:123/f1c/x/y'</jov>,
<jok>f1d</jok>:<jov>'http://foo.com:123/myContext/myServlet/f1d'</jov>,
<jok>f1e</jok>:<jov>'http://foo.com:123/myContext/myServlet/f1e/x/y'</jov>,
<jok>f1f</jok>:<jov>'http://foo.com:123/myContext/myServlet'</jov>,
<jok>f2a</jok>:<jov>'http://foo.com:123/myContext/f2a/x'</jov>,
<jok>f2b</jok>:<jov>'http://foo.com:123/myContext/f2b'</jov>,
<jok>f2c</jok>:<jov>'http://foo.com:123/myContext'</jov>,
<jok>f2d</jok>:<jov>'http://foo.com:123'</jov>,
<jok>f3a</jok>:<jov>'http://foo.com:123/myContext/myServlet/f3a/x'</jov>,
<jok>f3b</jok>:<jov>'http://foo.com:123/myContext/myServlet/f3b'</jov>,
<jok>f3c</jok>:<jov>'http://foo.com:123/myContext/myServlet'</jov>,
<jok>f3d</jok>:<jov>'http://foo.com:123/myContext'</jov>,
<jok>f4a</jok>:<jov>'http://foo.com:123/myContext/myServlet/myPath/f4a/x'</jov>,
<jok>f4b</jok>:<jov>'http://foo.com:123/myContext/myServlet/myPath/f4b'</jov>,
<jok>f4c</jok>:<jov>'http://foo.com:123/myContext/myServlet/myPath'</jov>,
<jok>f4d</jok>:<jov>'http://foo.com:123/myContext/myServlet'</jov>
}
</p>
<p>
URI resolution is controlled by the following settings:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.RestContext}
<ul>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_uriAuthority REST_uriAuthority}
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_uriContext REST_uriContext}
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_uriRelativity REST_uriRelativity}
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_uriResolution REST_uriResolution}
</ul>
</ul>
<p>
URIs are resolved by both regular and part serializers.
</p>
</div><!-- END: 6.18 - juneau-rest-server.URIs -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Guards' id='juneau-rest-server.Guards'>6.19 - Guards</a></h3>
<div class='topic'><!-- START: 6.19 - juneau-rest-server.Guards -->
<p>
Guards are classes that control access to REST classes and methods.
</p>
<p>
Guards are associated with resource classes and methods via the following:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#guards() Rest(guards)}
<li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#guards() RestMethod(guards)}
<li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#guards(Class...)}
</ul>
<p class='bpcode w800'>
<jc>// Define a guard that only lets Billy make a request</jc>
<jk>public</jk> BillyGuard <jk>extends</jk> RestGuard {
<ja>@Override</ja> <jc>/* RestGuard */</jc>
<jk>public boolean</jk> isRequestAllowed(RestRequest req) {
<jk>return</jk> req.getUserPrincipal().getName().equals(<js>"Billy"</js>);
}
}
<jc>// Servlet with class-level guard applied</jc>
<ja>@Rest</ja>(guards=BillyGuard.<jk>class</jk>)
<jk>public</jk> MyRestServlet <jk>extends</jk> BasicRestServlet {
<jc>// Delete method that only Billy is allowed to call.</jc>
<ja>@RestMethod</ja>(name=<js>"DELETE"</js>)
<jk>public</jk> doDelete(RestRequest req, RestResponse res) <jk>throws</jk> Exception {...}
}
</p>
<p>
A common use for guards is to only allow admin access to certain Java methods...
</p>
<p class='bpcode w800'>
<jc>// DELETE method</jc>
<ja>@RestMethod</ja>(name=<jsf>DELETE</jsf>, guards={AdminGuard.<jk>class</jk>})
<jk>public void</jk> doDelete(RestRequest req, RestResponse res) <jk>throws</jk> Exception {...}
</p>
<p class='bpcode w800'>
<jk>public class</jk> AdminGuard <jk>extends</jk> RestGuard {
<ja>@Override</ja> <jc>/* RestGuard */</jc>
<jk>public boolean</jk> isRequestAllowed(RestRequest req) {
<jk>return</jk> req.getUserPrincipal().isUserInRole(<js>"ADMIN"</js>);
}
}
</p>
<p>
A guard failure results in an <l>HTTP 401 Unauthorized</l> response.
However, this can be configured by overriding the
{@link org.apache.juneau.rest.RestGuard#guard(RestRequest,RestResponse)} and processing the response
yourself.
</p>
<p class='bpcode w800'>
<jk>public class</jk> AdminGuard <jk>extends</jk> RestGuard {
<ja>@Override</ja> <jc>/* RestGuard */</jc>
<jk>public boolean</jk> guard(RestRequest req, RestResponse res) <jk>throws</jk> RestException {
<jk>if</jk> (! isOkay(req))
<jk>throw new</jk> RestException(<jsf>SC_FORBIDDEN</jsf>, <js>"Access denied!!!"</js>);
<jk>return true</jk>;
}
}
</p>
<p>
When guards are associated at the class-level, it's equivalent to associating guards on all Java methods on
the servlet.
If multiple guards are present, ALL guards must pass.
</p>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_guards}
</ul>
</div><!-- END: 6.19 - juneau-rest-server.Guards -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RoleGuards' id='juneau-rest-server.RoleGuards'>6.20 - Role guards</a></h3>
<div class='topic'><!-- START: 6.20 - juneau-rest-server.RoleGuards -->
<p>
Specialized guards are provided for controlling access to servlet classes and methods based on user roles.
These are controlled via annotations on the REST class and methods:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.rest.annotation.Rest}
<ul>
<li class='jf'>{@link org.apache.juneau.rest.annotation.Rest#roleGuard() roleGuard()}
<li class='jf'>{@link org.apache.juneau.rest.annotation.Rest#rolesDeclared() rolesDeclared()}
</ul>
<li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod}
<ul>
<li class='jf'>{@link org.apache.juneau.rest.annotation.RestMethod#roleGuard() roleGuard()}
<li class='jf'>{@link org.apache.juneau.rest.annotation.RestMethod#rolesDeclared() rolesDeclared()}
</ul>
</ul>
<p>
The <c>roleGuard()</c> annotation is an expression that defines whether a user with specified roles are allowed
to access methods.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Only admin users or users with both read/write and special access
// can run any methods on this class.</jc>
<ja>@Rest</ja>(
path=<js>"/foo"</js>,
roleGuard=<js>"ROLE_ADMIN || (ROLE_READ_WRITE &amp;&amp; ROLE_SPECIAL)"</js>
)
<jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
...
}
</p>
<p>
The syntax allows for any of the following:
</p>
<ul>
<li><js>"foo"</js> - Single arguments.
<li><js>"foo,bar,baz"</js> - Multiple OR'ed arguments.
<li><js>"foo | bar | baz"</js> - Multiple OR'ed arguments, pipe syntax.
<li><js>"foo || bar || baz"</js> - Multiple OR'ed arguments, Java-OR syntax.
<li><js>"fo*"</js> - Patterns including <js>'*'</js> and <js>'?'</js>.
<li><js>"fo* &amp; *oo"</js> - Multiple AND'ed arguments, ampersand syntax.
<li><js>"fo* &amp;&amp; *oo"</js> - Multiple AND'ed arguments, Java-AND syntax.
<li><js>"fo* || (*oo || bar)"</js> - Parenthesis.
</ul>
<p>
If patterns are used, you must specify the list of declared roles using the <c>rolesDeclared()</c> annotations.
This declares the list of all possible user roles and is needed because the servlet API does not provide this
capability.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Rest</ja>(
rolesDeclared=<js>"ROLE_ADMIN,ROLE_READ_WRITE,ROLE_READ_ONLY,ROLE_SPECIAL"</js>,
roleGuard=<js>"ROLE_ADMIN || (*WRITE* &amp;&amp; *SPECIAL*)"</js>
)
<jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
...
}
</p>
</div><!-- END: 6.20 - juneau-rest-server.RoleGuards -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Converters' id='juneau-rest-server.Converters'>6.21 - Converters</a></h3>
<div class='topic'><!-- START: 6.21 - juneau-rest-server.Converters -->
<p>
Converters can be thought of as "post-processors" for POJOs before they get passed to the serializers.
</p>
<p>
Converters are associated with resource classes and methods via the following:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#converters() Rest(converters)}
<li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#converters() RestMethod(converters)}
<li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#converters(Class...)}
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Associate the Traversable converter to all Java REST methods in this servlet</jc>
<ja>@Rest</ja>(converters=Traversable.<jk>class</jk>)
<jk>public</jk> MyRestServlet <jk>extends</jk> BasicRestServlet {
...
}
</p>
<p>
They can also be defined at the method level:
</p>
<p class='bpcode w800'>
<jc>// GET person request handler.</jc>
<jc>// Traversable conversion enabled to allow nodes in returned POJO tree to be addressed.</jc>
<jc>// Queryable conversion enabled to allow returned POJO to be searched/viewed/sorted.</jc>
<ja>@RestMethod</ja>(
name=<jsf>GET</jsf>, path=<js>"/people/{id}/*"</js>,
converters={Traversable.<jk>class</jk>,Queryable.<jk>class</jk>}
)
<jk>public</jk> Person getPerson(<ja>@Path</ja>(<js>"id"</js>) <jk>int</jk> id) {
<jk>return</jk> findPerson(id);
}
</p>
<p>
The following converter is used to provide support for addressing child nodes in a POJO tree with URL path
remainders.
In this code, the 3rd parameter is the object that was returned by the Java method.
The converter uses the {@link org.apache.juneau.utils.PojoRest} wrapper class to address nodes in the
tree.
</p>
<p class='bpcode w800'>
<jd>/**
* Converter for enablement of PojoRest support on response objects returned by a @RestMethod method.
* When enabled, objects in a POJO tree returned by the REST method can be addressed through additional URL path information.
*/</jd>
<jk>public class</jk> Traversable <jk>implements</jk> RestConverter {
<ja>@Override</ja> <jc>/* RestConverter */</jc>
<jk>public</jk> Object convert(RestRequest req, Object o) <jk>throws</jk> RestException {
if (o == <jk>null</jk>)
<jk>return null</jk>;
String pathRemainder = req.getPathMatch().getRemainder();
<jk>if</jk> (pathRemainder != <jk>null</jk>) {
<jk>try</jk> {
<jc>// Use the PojoRest class to traverse our POJO model.</jc>
PojoRest p = <jk>new</jk> PojoRest(o);
o = p.get(pathRemainder);
} <jk>catch</jk> (PojoRestException e) {
<jk>throw new</jk> RestException(e.getStatus(), e);
} <jk>catch</jk> (Exception e) {
<jk>throw new</jk> RestException(HttpServletResponse.<jsf>SC_INTERNAL_SERVER_ERROR</jsf>, e);
}
}
<jk>return</jk> o;
}
}
</p>
<p>
Juneau defines the following converters out-of-the-box:
</p>
<ul class='javatree'>
<li class='jic'>
{@link org.apache.juneau.rest.RestConverter}
<ul>
<li class='jc'>
{@link org.apache.juneau.rest.converters.Queryable}
<br>Provides query parameters that can be used to transform the response (i.e. search/view/sort the
POJO response before being serialized).
<li class='jc'>
{@link org.apache.juneau.rest.converters.Traversable}
<br>Allows nodes in the POJO response tree to be individually accessed through additional path info on
the request.
<li class='jc'>
{@link org.apache.juneau.rest.converters.Introspectable}
<br>Allows method calls to be made on the response POJO, and for the result of that method call to be
serialized as the response.
</ul>
</ul>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_converters}
</ul>
</div><!-- END: 6.21 - juneau-rest-server.Converters -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Messages' id='juneau-rest-server.Messages'>6.22 - Messages</a></h3>
<div class='topic'><!-- START: 6.22 - juneau-rest-server.Messages -->
<p>
The {@link org.apache.juneau.rest.annotation.Rest#messages @Rest(messages)} annotation is used to associate a resource bundle with a servlet class.
</p>
<p class='bpcode w800'>
<jc>// Servlet with associated resource bundle</jc>
<ja>@Rest</ja>(messages=<js>"nls/MyMessages"</js>)
<jk>public</jk> MyRestServlet <jk>extends</jk> BasicRestServlet {
<jc>// Returns the localized greeting from the "greeting" key in MyMessages.properties</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>)
<jk>public</jk> String printLocalizedGreeting(RestRequest req) {
<jk>return</jk> req.getMessage(<js>"greeting"</js>);
}
</p>
<p>
The resource bundle can also be passed into the method by simply specifying a parameter
of type {@link java.util.ResourceBundle} or {@link org.apache.juneau.utils.MessageBundle}:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
<jk>public</jk> String printLocalizedGreeting(MessageBundle messages) {
<jk>return</jk> messages.getString(<js>"greeting"</js>);
}
</p>
<p>
If a resource bundle is shared by multiple servlets, the label and description can be prefixed by the class
name:
</p>
<p class='bpcode w800'>
<cc>#--------------------------------------------------------------------------------
# Contents of MyMessages.properties
#--------------------------------------------------------------------------------</cc>
<ck>greeting</ck> = Hello!
</p>
<p class='bpcode w800'>
<cc>#--------------------------------------------------------------------------------
# Contents of shared MyMessages.properties
#--------------------------------------------------------------------------------</cc>
<ck>MyRestServlet.greeting</ck> = Hello!
</p>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_messages}
</ul>
</div><!-- END: 6.22 - juneau-rest-server.Messages -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Encoders' id='juneau-rest-server.Encoders'>6.23 - Encoders</a></h3>
<div class='topic'><!-- START: 6.23 - juneau-rest-server.Encoders -->
<p>
The {@link org.apache.juneau.rest.annotation.Rest#encoders @Rest(encoders)} annotation can
be used to associate character encoders with a servlet class.
Encoders can be used to enable various kinds of compression (e.g. <l>"gzip"</l>) on requests and responses
based on the request <l>Accept-Encoding</l> and <l>Content-Encoding</l> headers.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Servlet with automated support for GZIP compression</jc>
<ja>@Rest</ja>(encoders={GzipEncoder.<jk>class</jk>})
<jk>public</jk> MyRestServlet <jk>extends</jk> BasicRestServlet {
...
}
</p>
<p>
Juneau defines the following encoders out-of-the-box:
</p>
<ul class='javatree'>
<li class='jac'>
{@link org.apache.juneau.encoders.Encoder}
<ul>
<li class='jc'>
{@link org.apache.juneau.encoders.GzipEncoder}
<li class='jc'>
{@link org.apache.juneau.encoders.IdentityEncoder}
</ul>
</ul>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_encoders}
</ul>
</div><!-- END: 6.23 - juneau-rest-server.Encoders -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.SvlVariables' id='juneau-rest-server.SvlVariables'>6.24 - SVL Variables</a></h3>
<div class='topic'><!-- START: 6.24 - juneau-rest-server.SvlVariables -->
<p>
In the previous examples, there were several cases where embedded variables were contained within
annotation values:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
title=<js>"$L{my.label}"</js>
)
</p>
<p>
Variables take the form <l>$X{contents}</l> where <l>X</l> can consist of zero or more ASCII characters and <l>contents</l> can be virtually anything.
This is called Simple Variable Language, or SVL, and is defined here: {@doc juneau-marshall.SimpleVariableLanguage Simple Variable Language}.
</p>
<h5 class='topic'>Features</h5>
<ul class='spaced-list'>
<li>
Variables can be nested arbitrarily deep (e.g. <l>"$X{$Y{foo}}"</l>).
<li>
Variables can contain arguments (e.g. <l>"$L{my.label,arg1,arg2}"</l>).
<li>
Variables are recursively resolved.
<br>i.e., if a variable results to a value with another variable in it, that variable will also be
resolved (restricted for security reasons on some variables).
</ul>
<p>
Variables are configured on resources via the following API:
</p>
<ul class='javatree'>
<li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#vars(Class[])}
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Defined a variable that simply wrapps all strings inside [] brackets.</jc>
<jc>// e.g. "$BRACKET{foobar}" -> "[foobar]"</jc>
<jk>public class</jk> BracketVar <jk>extends</jk> SimpleVar {
<jk>public</jk> BracketVar() {
<jk>super</jk>(<js>"BRACKET"</js>);
}
<ja>@Override</ja> <jc>/* Var */</jc>
<jk>public</jk> String resolve(VarResolverSession session, String arg) {
<jk>return</jk> <js>'['</js> + arg + <js>']'</js>;
}
}
<jc>// Register it with our resource.</jc>
<ja>@Rest</ja>(...)
<jk>public class</jk> MyResource {
<jk>public</jk> MyResource(RestContextBuilder builder) {
builder.vars(BracketVar.<jk>class</jk>);
}
}
</p>
<p>
The methods involved with variables are:
</p>
<ul class='javatree'>
<li class='jm'>{@link org.apache.juneau.rest.RestContext#getVarResolver()}
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getVarResolverSession()}
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getClasspathReaderResource(String,boolean)}
</ul>
<p>
There are two distinct groups of variables:
</p>
<ul class='spaced-list'>
<li><l>Initialization-time variables</l>
<br>These are variables that can be used in many of the annotations in {@link org.apache.juneau.rest.annotation.Rest @Rest}.
<br>The {@link org.apache.juneau.rest.RestContext#getVarResolver()} method returns initialization-time variables only.
<li><l>Request-time variables</l>
<br>These are variables that are available during HTTP-requests and can be used on annotation such as {@link org.apache.juneau.rest.annotation.HtmlDoc @HtmlDoc}.
<br>{@link org.apache.juneau.rest.RestRequest#getVarResolverSession()} method returns initialization and request-time variables.
</ul>
<p>
The following is the default list of supported variables.
</p>
<h5 class='figure'><a href='#DefaultRestSvlVariables' id='DefaultRestSvlVariables'>Default REST SVL Variables:</a></h5>
<table class='styled w800'>
<tr>
<th>Module</th><th>Class</th><th>Pattern</th><th>Initialization<br>time</th><th>Request<br>time</th><th>Examples</th>
</tr>
<tr class='dark'>
<td rowspan='11' style='text-align:center;font-weight:bold;padding:20px;' class='code'>juneau-svl</td>
<td>{@link org.apache.juneau.svl.vars.EnvVariablesVar}</td>
<td class='code'>$E{key[,default]}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$E{PATH}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.SystemPropertiesVar}</td>
<td class='code'>$S{key[,default]}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$S{java.home}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.ArgsVar}</td>
<td class='code'>$A{key[,default]}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$A{foo,null}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.ManifestFileVar}</td>
<td class='code'>$MF{key[,default]}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$MF{Main-Class}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.IfVar}</td>
<td class='code'>$IF{arg,then[,else]}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$IF{$S{my.boolean.property},foo,bar}</td>
</tr>
<tr class='dark dd'>
<td>{@link org.apache.juneau.svl.vars.SwitchVar}</td>
<td class='code'>$SW{arg,p1:then1[,p2:then2...]}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$SW{$P{os.name},*win*:Windows,*:Something else}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.CoalesceVar}</td>
<td class='code'>$CO{arg1[,arg2...]}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$CO{$S{my.property},$E{my.property},n/a}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.PatternMatchVar}</td>
<td class='code'>$PM{arg,pattern}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$PM{$P{os.name},*win*}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.NotEmptyVar}</td>
<td class='code'>$NE{arg}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$NE{$S{foo}}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.UpperCaseVar}</td>
<td class='code'>$UC{arg}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$UC{$S{foo}}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.svl.vars.LowerCaseVar}</td>
<td class='code'>$LC{arg}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$LC{$S{foo}}</td>
</tr>
<tr class='light dd'>
<td rowspan='1' style='text-align:center;font-weight:bold;padding:20px;' class='code'>juneau-config</td>
<td>{@link org.apache.juneau.config.vars.ConfigVar}</td>
<td class='code'>$C{key[,default]}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$C{REST/staticFiles}</td>
</tr>
<tr class='dark'>
<td rowspan='14' style='text-align:center;font-weight:bold;padding:20px;' class='code'>juneau-rest-server</td>
<td>{@link org.apache.juneau.rest.vars.FileVar}</td>
<td class='code'>$F{path[,default]}}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$F{resources/MyAsideMessage.html, Oops not found!}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.ServletInitParamVar}</td>
<td class='code'>$I{name[,default]}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$I{my.param}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.LocalizationVar}</td>
<td class='code'>$L{key[,args...]}</td>
<td style='text-align:center;font-weight:bold'>no</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$L{MyMessage,foo,bar}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.RequestAttributeVar}</td>
<td class='code'>$RA{key1[,key2...]}</td>
<td style='text-align:center;font-weight:bold'>no</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$RA{attrName}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.RequestFormDataVar}</td>
<td class='code'>$RF{key1[,key2...]}</td>
<td style='text-align:center;font-weight:bold'>no</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$RF{paramName}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.RequestHeaderVar}</td>
<td class='code'>$RH{key1[,key2...]}</td>
<td style='text-align:center;font-weight:bold'>no</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$RH{Header-Name}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.RequestPathVar}</td>
<td class='code'>$RP{key1[,key2...]}</td>
<td style='text-align:center;font-weight:bold'>no</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$RP{pathVAr}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.RequestQueryVar}</td>
<td class='code'>$RQ{key1[,key2...]}</td>
<td style='text-align:center;font-weight:bold'>no</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$RQ{paramName}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.RequestVar}</td>
<td class='code'>$R{key1[,key2...]}</td>
<td style='text-align:center;font-weight:bold'>no</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$R{contextPath}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.RestInfoVar}</td>
<td class='code'>$RI{key}</td>
<td style='text-align:center;font-weight:bold'>no</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$RI{externalDocs}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.SerializedRequestAttrVar}</td>
<td class='code'>$SA{contentType,key[,default]}</td>
<td style='text-align:center;font-weight:bold'>no</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$SA{application/json,$RA{foo}}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.UrlVar}</td>
<td class='code'>$U{uri}></td>
<td style='text-align:center;font-weight:bold'>no</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$U{servlet:/foo}</td>
</tr>
<tr class='dark'>
<td>{@link org.apache.juneau.rest.vars.UrlEncodeVar}</td>
<td class='code'>$UE{uriPart}</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$U{servlet:/foo?bar=$UE{$RA{bar}}</td>
</tr>
<tr class='dark dd'>
<td>{@link org.apache.juneau.rest.vars.WidgetVar}</td>
<td class='code'>$W{name}</td>
<td style='text-align:center;font-weight:bold'>no</td>
<td style='text-align:center;font-weight:bold'>yes</td>
<td class='code'>$W{MenuItemWidget}</td>
</tr>
</table>
</div><!-- END: 6.24 - juneau-rest-server.SvlVariables -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.ConfigurationFiles' id='juneau-rest-server.ConfigurationFiles'>6.25 - Configuration Files</a></h3>
<div class='topic'><!-- START: 6.25 - juneau-rest-server.ConfigurationFiles -->
<p>
The Server API provides methods for associating configuration files with REST servlets so that
configuration properties can be defined in external files.
</p>
<p>
In recap, the Configuration API provides support for INI-style configuration files with embedded string variables:
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<cc>#--------------------------</cc>
<cc># Examples </cc>
<cc>#--------------------------</cc>
<cs>[MyProperties]</cs>
<ck>path</ck> = <cv>$E{PATH}</cv>
<ck>javaHome</ck> = <cv>$S{java.home}</cv>
<ck>customMessage</ck> = <cv>Java home is $C{MyProperties/javaHome} and the environment path is $C{MyProperties/path}.</cv>
</p>
<p>
These properties are then accessible through the {@link org.apache.juneau.config.Config} class.
</p>
<p class='bpcode w800'>
Config c = Config.<jsm>create</jsm>(<js>"myconfig.cfg"</js>).build();
String path = c.getString(<js>"MyProperties/path"</js>);
File javaHome = c.getObject(<js>"MyProperties/javaHome"</js>, File.<jk>class</jk>);
String customMessage = c.getString(<js>"MyProperties/customMessage"</js>);
</p>
<p>
Configuration files are associated with REST resources through the following:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#config() Rest(config)}
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Rest</ja>(
<jc>// Config file is located at ./config_dir/myconfig.cfg</jc>
config=<js>"config_dir/myconfig.cfg"</js>,
...
)
<jk>public class</jk> MyResource {...}
</p>
<p>
The annotation itself can contain string variables.
For example, the Microservice API {@link org.apache.juneau.rest.BasicRestServlet} class defines the
location of the config file as a system property <l>"juneau.configFile"</l>:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
<jc>// Config file location is defined as a system property</jc>
config=<js>"$S{juneau.configFile}"</js>,
...
)
<jk>public class</jk> MyResource {...}
</p>
<p>
Once a config file has been associated with a REST resource, it can be accessed through the
{@link org.apache.juneau.rest.RestContextBuilder#getConfig()} method.
</p>
<p>
A common usage is to use this method to initialize fields in your servlet.
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
<jc>// Config file is located at ./config_dir/myconfig.cfg</jc>
config=<js>"config_dir/myconfig.cfg"</js>,
...
)
<jk>public class</jk> MyResource {
<jk>private final</jk> String <jf>path</jf>;
<jk>private final</jk> File <jf>javaHome</jf>;
<jk>public</jk> MyResource(RestContextBuilder builder) {
Config c = builder.getConfig();
<jf>path</jf> = c.getString(<js>"MyProperties/path"</js>);
<jf>javaHome</jf> = c.getObject(File.<jk>class</jk>, <js>"MyProperties/javaHome"</js>);
}
</p>
<p>
Another common usage is to refer to config properties through <ck>$C</ck> variables in your annotations:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
<jc>// Get stylesheet from myconfig.cfg, but default to devops.css if it's not specified</jc>
htmldoc=<ja>@HtmlDoc</ja>(
stylesheet=<js>"$C{MyServlet/stylesheet,servlet:/styles/devops.css}"</js>,
)
...
)
<jk>public class</jk> MyResource {...}
</p>
<p>
It's even possible to reference request-level variables in your config file if you use
{@link org.apache.juneau.rest.RestRequest#getConfig()} to access the config file:
</p>
<p class='bpcode w800'>
<cc>#-------------------------------------</cc>
<cc># Contents of config_dir/myconfig.cfg </cc>
<cc>#-------------------------------------</cc>
<cs>[HelloWorldResource]</cs>
<ck>message</ck> = <cv>Hello $RQ{person}!</cv>
</p>
<p class='bpcode w800'>
<jd>/**
* Sample REST resource that prints out a simple "Hello world!" message.
*/</jd>
<ja>@Rest</ja>(
config=<js>"config_dir/myconfig.cfg"</js>,
...
)
<jk>public class</jk> HelloWorldResource <jk>extends</jk> BasicRestServlet {
<jd>/**
* GET request handler.
* Specify the GET parameter "?person=X" for a specialized message!
*/</jd>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>)
<jk>public</jk> String sayHello(RestRequest req) {
<jk>return</jk> req.getConfig().getString(<js>"HelloWorldResource/message"</js>);
}
}
</p>
<p>
You can even add resource bundles into the mix:
</p>
<p class='bpcode w800'>
<cc>#-------------------------------------</cc>
<cc># Contents of config_dir/myconfig.cfg </cc>
<cc>#-------------------------------------</cc>
<cs>[HelloWorldResource]</cs>
<ck>message</ck> = <cv>$L{localizedMessage,$RQ{person}}</cv>
</p>
<p class='bpcode w800'>
<cc>#-------------------------------------------</cc>
<cc># Contents of HelloWorldResource.properties </cc>
<cc>#-------------------------------------------</cc>
<ck>localizedMessage</ck> = <cv>Hello {0}!</cv>
</p>
<p class='bpcode w800'>
<jd>/**
* Sample REST resource that prints out a simple "Hello world!" message.
*/</jd>
<ja>@Rest</ja>(
messages=<js>"HelloWorldResources"</js>,
config=<js>"config_dir/myconfig.cfg"</js>,
...
)
<jk>public class</jk> HelloWorldResource <jk>extends</jk> BasicRestServlet {
<jd>/**
* GET request handler.
* Specify the GET parameter "?person=X" for a specialized message!
*/</jd>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>)
<jk>public</jk> String sayHello(RestRequest req) {
<jk>return</jk> req.getConfig().getString(<js>"HelloWorldResource/message"</js>);
}
}
</p>
<ul class='seealso'>
<li>{@doc juneau-config}
</ul>
</div><!-- END: 6.25 - juneau-rest-server.ConfigurationFiles -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.StaticFiles' id='juneau-rest-server.StaticFiles'>6.26 - Static files</a></h3>
<div class='topic'><!-- START: 6.26 - juneau-rest-server.StaticFiles -->
<p>
The {@link org.apache.juneau.rest.annotation.Rest#staticFiles @Rest(staticFiles)}
annotation is used to define paths and locations of statically-served files such as images or HTML
documents.
</p>
<p>
The value is a JSON map of paths to packages/directories located on either the classpath or working
directory.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jk>package</jk> com.foo.mypackage;
<ja>@Rest</ja>(
path=<js>"/myresource"</js>,
staticFiles={<js>"htdocs:docs"</js>}
)
<jk>public class</jk> MyResource <jk>extends</jk> BasicRestServlet {...}
</p>
<p>
Static files are found by calling {@link java.lang.Class#getResource(String)} up the class hierarchy.
If not found, then an attempt is made to find the class in the Java working directory.
</p>
<p>
In the example above, given a GET request to <l>/myresource/htdocs/foobar.html</l>, the servlet will
attempt to find the <l>foobar.html</l> file in the following ordered locations:
</p>
<ol>
<li><l>com.foo.mypackage.docs</l> package.
<li><l>[working-dir]/docs</l> directory.
</ol>
<ul class='notes'>
<li>
Mappings are cumulative from parent to child.
<br>Child resources can override mappings made on parent resources.
<li>
The media type on the response is determined by the
{@link org.apache.juneau.rest.RestContext#getMediaTypeForName(String)} method.
</ul>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_staticFiles}
</ul>
</div><!-- END: 6.26 - juneau-rest-server.StaticFiles -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.ClientVersioning' id='juneau-rest-server.ClientVersioning'>6.27 - Client Versioning</a></h3>
<div class='topic'><!-- START: 6.27 - juneau-rest-server.ClientVersioning -->
<p>
Client version headers are used to support backwards compatibility for breaking REST interface changes.
Using them, you're able to return different responses based on which client is making a request.
</p>
<p>
The APIs involved with defining client version headers are:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#clientVersionHeader() Rest(clientVersionHeader)}
<li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#clientVersionHeader(String)}
<li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#clientVersion() RestMethod(clientVersion)}
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
<ja>@Rest</ja>(clientVersionHeader=<js>"Client-Version"</js>)
<jk>public class</jk> MyResource {
<jc>// Call this method if Client-Version is at least 2.0.
// Note that this also matches 2.0.1.</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"2.0"</js>)
<jk>public</jk> Object method1() {
...
}
<jc>// Call this method if Client-Version is at least 1.1, but less than 2.0.</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"[1.1,2.0)"</js>)
<jk>public</jk> Object method2() {
...
}
<jc>// Call this method if Client-Version is less than 1.1.</jc>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"[0,1.1)"</js>)
<jk>public</jk> Object method3() {
...
}
</p>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_clientVersionHeader}
</ul>
</div><!-- END: 6.27 - juneau-rest-server.ClientVersioning -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestInfoProvider' id='juneau-rest-server.RestInfoProvider'>6.28 - RestInfoProvider</a></h3>
<div class='topic'><!-- START: 6.28 - juneau-rest-server.RestInfoProvider -->
<p>
The {@link org.apache.juneau.rest.RestInfoProvider} class is used to find the title
and description for your resource and also generate the Swagger documentation.
It can be overridden to provide your own custom Swagger documentation.
</p>
<p>
The methods on this interface are:
</p>
<ul class='javatree'>
<li class='jic'>{@link org.apache.juneau.rest.RestInfoProvider}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RestInfoProvider#getSwagger(RestRequest) getSwagger(RestRequest)}
<li class='jm'>{@link org.apache.juneau.rest.RestInfoProvider#getSiteName(RestRequest) getSiteName(RestRequest)}
<li class='jm'>{@link org.apache.juneau.rest.RestInfoProvider#getTitle(RestRequest) getTitle(RestRequest)}
<li class='jm'>{@link org.apache.juneau.rest.RestInfoProvider#getDescription(RestRequest) getDescription(RestRequest)}
<li class='jm'>{@link org.apache.juneau.rest.RestInfoProvider#getMethodSummary(Method,RestRequest) getMethodSummary(Method,RestRequest)}
<li class='jm'>{@link org.apache.juneau.rest.RestInfoProvider#getMethodDescription(Method,RestRequest) getMethodDescription(Method,RestRequest)}
</ul>
</ul>
<p>
The info provider in turn supplies the information returned by the following methods:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.RestRequest}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getSwagger() getSwagger()}
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getSiteName() getSiteName()}
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getResourceTitle() getResourceTitle()}
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getResourceDescription() getResourceDescription()}
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getMethodSummary() getMethodSummary()}
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getMethodDescription() getMethodDescription()}
</ul>
</ul>
<p>
Info providers are registered through the following property:
</p>
<ul class='javatree'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_infoProvider}
</ul>
<p>
While you can implement this interface from scratch, you may want to instead consider extending
from the <l>BasicRestInfoProvider</l> class described next.
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.RestInfoProvider.BasicRestInfoProvider' id='juneau-rest-server.RestInfoProvider.BasicRestInfoProvider'>6.28.1 - BasicRestInfoProvider</a></h4>
<div class='topic'><!-- START: 6.28.1 - juneau-rest-server.RestInfoProvider.BasicRestInfoProvider -->
<p>
The {@link org.apache.juneau.rest.BasicRestInfoProvider} class is the default implementation of the
{@link org.apache.juneau.rest.RestInfoProvider} interface.
</p>
<p>
It finds and collects information gathered from the following locations:
</p>
<ul>
<li>Localized JSON Swagger files in the classpath.
<li>Reflection.
<li>Annotations.
<li>Properties files.
</ul>
<p>
The class itself is designed to be extended if you wish to rely mostly on the default behavior, but tweak
certain aspects.
</p>
</div><!-- END: 6.28.1 - juneau-rest-server.RestInfoProvider.BasicRestInfoProvider -->
</div><!-- END: 6.28 - juneau-rest-server.RestInfoProvider -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Swagger' id='juneau-rest-server.Swagger'>6.29 - Swagger</a></h3>
<div class='topic'><!-- START: 6.29 - juneau-rest-server.Swagger -->
<p>
One of the most useful features of Juneau is the ability to generate Swagger-based OPTIONS pages for self-documenting designs
(i.e. REST interfaces that document themselves).
</p>
<p>
As described previously, the <c>PetStore</c> example provides an example of auto-generated Swagger JSON:
</p>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.1.png'>
<p>
Using {@link org.apache.juneau.dto.swagger.ui.SwaggerUI}, we're able to render that JSON as a Swagger user interface:
</p>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.2.png'>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Swagger.BasicRestServlet' id='juneau-rest-server.Swagger.BasicRestServlet'>6.29.1 - BasicRestServlet</a></h4>
<div class='topic'><!-- START: 6.29.1 - juneau-rest-server.Swagger.BasicRestServlet -->
<p>
Any subclass of {@link org.apache.juneau.rest.BasicRestServlet} gets an auto-generated Swagger UI when performing an <c>OPTIONS</c>
request with <c>Accept:text/html</c>.
</p>
<p>
The underlying mechanics are simple.
The {@link org.apache.juneau.rest.BasicRestServlet#getOptions(RestRequest)} method returns a {@link org.apache.juneau.dto.swagger.Swagger} bean
consisting of information gathered from annotations and other sources.
Then that bean is swapped for a {@link org.apache.juneau.dto.swagger.ui.SwaggerUI} bean when rendered as HTML.
</p>
<p>
Here's the class that defines the behavior:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
<jc>// Allow OPTIONS requests to be simulated using ?method=OPTIONS query parameter.</jc>
allowedMethodParams=<js>"OPTIONS"</js>,
...
)
<jk>public abstract class</jk> BasicRestServlet <jk>extends</jk> RestServlet <jk>implements</jk> BasicRestConfig {
<jd>/**
* [OPTIONS /*] - Show resource options.
*
* <ja>@param</ja> req The HTTP request.
* <ja>@return</ja> A bean containing the contents for the OPTIONS page.
*/</jd>
<ja>@RestMethod</ja>(name=<jsf>OPTIONS</jsf>, path=<js>"/*"</js>,
summary=<js>"Swagger documentation"</js>,
description=<js>"Swagger documentation for this resource."</js>,
htmldoc=<ja>@HtmlDoc</ja>(
<jc>// Override the nav links for the swagger page.</jc>
navlinks={
<js>"back: servlet:/"</js>,
<js>"json: servlet:/?method=OPTIONS&amp;Accept=text/json&amp;plainText=true"</js>
},
<jc>// Never show aside contents of page inherited from class.</jc>
aside=<js>"NONE"</js>
)
)
<ja>@JsonSchemaConfig</ja>(
<jc>// Add descriptions to the following types when not specified:</jc>
addDescriptionsTo=<js>"bean,collection,array,map,enum"</js>,
<jc>// Add x-example to the following types:</jc>
addExamplesTo=<js>"bean,collection,array,map"</js>,
<jc>// Don't generate schema information on the Swagger bean itself or HTML beans.</jc>
ignoreTypes=<js>"Swagger,org.apache.juneau.dto.html5.*"</js>,
<jc>// Use $ref references for bean definitions to reduce duplication in Swagger.</jc>
useBeanDefs=<js>"true"</js>
)
<ja>@BeanConfig</ja>(
<jc>// When parsing generated beans, ignore unknown properties that may only exist as getters and not setters.</jc>
ignoreUnknownBeanProperties=<js>"true"</js>,
<jc>// POJO swaps to apply to all serializers/parsers on this method.</jc>
pojoSwaps={
<jc>// Use the SwaggerUI swap when rendering Swagger beans.</jc>
<jc>// This is a per-media-type swap that only applies to text/html requests.</jc>
SwaggerUI.<jk>class</jk>
}
)
<jk>public</jk> Swagger getOptions(RestRequest req) {
<jc>// Localized Swagger for this resource is available through the RestRequest object.</jc>
<jk>return</jk> req.getSwagger();
}
}
</p>
<p>
Note that to have your resource create Swagger UI, you must either extend from {@link org.apache.juneau.rest.BasicRestServlet} or provide
your own <ja>@RestMethod</ja>-annotated method that returns a {@link org.apache.juneau.dto.swagger.Swagger} object and a {@link org.apache.juneau.dto.swagger.ui.SwaggerUI} swap.
</p>
</div><!-- END: 6.29.1 - juneau-rest-server.Swagger.BasicRestServlet -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Swagger.BasicSwaggerInfo' id='juneau-rest-server.Swagger.BasicSwaggerInfo'>6.29.2 - Basic Swagger Info</a></h4>
<div class='topic'><!-- START: 6.29.2 - juneau-rest-server.Swagger.BasicSwaggerInfo -->
<p>
Let's look at the various parts of the <c>Petstore</c> application Swagger UI to see how they are defined.
</p>
<p>
The top part of the page shows general information about the REST interface:
</p>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.3.png'>
<p>
The information is pulled from the {@link org.apache.juneau.rest.annotation.Rest#swagger() @Rest(swagger)} annotation.
</p>
<h5 class='figure'>org.apache.juneau.examples.rest.petstore.PetStoreResource</h5>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/petstore"</js>,
title=<js>"Petstore application"</js>,
...
swagger=@ResourceSwagger(<js>"$F{PetStoreResource.json}"</js>),
...
)
<jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena {...}
</p>
<p>
In this particular case, the Swagger is pulled in from a localized Swagger JSON file located in the
<c>org.apache.juneau.examples.rest.petstore</c> package using the {@link org.apache.juneau.rest.vars.FileVar $F} variable.
</p>
<h5 class='figure'>PetStoreResource.json</h5>
<p class='bpcode w800'>
{
<jok>"swagger"</jok>: <jov>"2.0"</jov>,
<jok>"info"</jok>: {
<jok>"version"</jok>: <jov>"1.0.0"</jov>,
<jok>"title"</jok>: <jov>"Swagger Petstore"</jov>,
<jok>"termsOfService"</jok>: <jov>"You are on your own."</jov>,
<jok>"contact"</jok>: {
<jok>"name"</jok>: <jov>"Juneau Development Team"</jov>,
<jok>"email"</jok>: <jov>"dev@juneau.apache.org"</jov>,
<jok>"url"</jok>: <jov>"http://juneau.apache.org"</jov>
},
<jok>"license"</jok>: {
<jok>"name"</jok>: <jov>"Apache 2.0"</jov>,
<jok>"url"</jok>: <jov>"http://www.apache.org/licenses/LICENSE-2.0.html"</jov>
}
},
<jok>"externalDocs"</jok>: {
<jok>"description"</jok>: <jov>"Find out more about Juneau"</jov>,
<jok>"url"</jok>: <jov>"http://juneau.apache.org"</jov>
},
...
}
</p>
<p>
Note that the {@link org.apache.juneau.rest.vars.FileVar $F} variable allows for request-locale-sensitive name matching so that you can provide
localized Swagger information.
</p>
<p>
The {@link org.apache.juneau.rest.vars.FileVar $F} variable simply expands to a string to fill the {@link org.apache.juneau.rest.annotation.ResourceSwagger#value() @ResourceSwagger(value)}
annotation.
You could equivalently embed JSON directly into your annotation like so:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/petstore"</js>,
title=<js>"Petstore application"</js>,
...
swagger=<ja>@ResourceSwagger</ja>(
<jc>// Raw Simplified JSON.</jc>
<jc>// Values are concatenated.
<js>"{"</js>,
<js>"swagger: '2.0',"</js>,
<js>"version: '1.0.0',"</js>,
...
<js>"}"</js>
),
...
)
<jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena {...}
</p>
<p>
However, a more typical (and less error-prone) scenario is to define all of your Swagger as annotations:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/petstore"</js>,
title=<js>"Petstore application"</js>,
...
swagger=<ja>@ResourceSwagger</ja>(
version=<js>"1.0.0"</js>,
title=<js>"Swagger Petstore"</js>,
termsOfService=<js>"You are on your own."</js>,
contact=<ja>@Contact</ja>(
name=<js>"Juneau Development Team"</js>,
email=<js>"dev@juneau.apache.org"</js>,
url=<js>"http://juneau.apache.org"</js>
),
license=<ja>@License</ja>(
name=<js>"Apache 2.0"</js>,
url=<js>"http://www.apache.org/licenses/LICENSE-2.0.html"</js>
),
externalDocs=<ja>@ExternalDocs</ja>(
description=<js>"Find out more about Juneau"</js>,
url=<js>"http://juneau.apache.org"</js>
)
),
...
)
<jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena {...}
</p>
<p>
All annotations support {@doc DefaultRestSvlVariables SVL variables}, so you could for example
pull localized strings from resource bundles using {@link org.apache.juneau.rest.vars.LocalizationVar $L} variables.
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/petstore"</js>,
title=<js>"Petstore application"</js>,
messages=<js>"nls/MyMessages"</js>,
...
swagger=<ja>@ResourceSwagger</ja>(
version=<js>"1.0.0"</js>,
title=<js>"$L{myTitle}"</js>,
termsOfService=<js>"$L{myTermsOfService}"</js>,
contact=<ja>@Contact</ja>(
name=<js>"$L{myTeam}"</js>,
email=<js>"dev@juneau.apache.org"</js>,
url=<js>"http://juneau.apache.org"</js>
),
license=<ja>@License</ja>(
name=<js>"Apache 2.0"</js>,
url=<js>"http://www.apache.org/licenses/LICENSE-2.0.html"</js>
),
externalDocs=<ja>@ExternalDocs</ja>(
description=<js>"$L{myExternalDocsDescription}"</js>,
url=<js>"http://juneau.apache.org"</js>
)
),
...
)
<jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena {...}
</p>
<p>
A third option is to define your Swagger information in your {@link org.apache.juneau.rest.annotation.Rest#messages @Rest(messages)} resource
bundle using predefined Swagger keywords:
</p>
<p class='bpcode w800'>
<mk>PetStoreResource.version</mk> = <mv>1.0.0</mv>
<mk>PetStoreResource.title</mk> = <mv>Swagger Petstore</mv>
<mk>PetStoreResource.termsOfService</mk> = <mv>You are on your own.</mv>
<mk>PetStoreResource.contact</mk> = <mv>{name:'Juneau Development Team', email:'dev@juneau.apache.org',...}</mv>
<mk>PetStoreResource.license</mk> = <mv>{name:'Apache 2.0',...}</mv>
<mk>PetStoreResource.externalDocs</mk> = <mv>{description:'Find out more about Juneau',...}</mv>
</p>
<p>
Information defined in multiple locations are merged into a single set of data.
When the same information is provided in multiple locations, the following order-of-precedence is used:
</p>
<ol>
<li>Java annotations
<li>Resource bundle
<li>Swagger JSON file
</ol>
</div><!-- END: 6.29.2 - juneau-rest-server.Swagger.BasicSwaggerInfo -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Swagger.Tags' id='juneau-rest-server.Swagger.Tags'>6.29.3 - Tags</a></h4>
<div class='topic'><!-- START: 6.29.3 - juneau-rest-server.Swagger.Tags -->
<p>
Tags allow you to group operations into general categories.
In the user interface, these can be expanded/collapsed by clicking on the tag sections.
In the example below, the <c>pet</c> and <c>store</c> tag sections are collapsed
and the <c>user</c> section is not:
</p>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.4.png'>
<p>
Tags are also defined in the <ja>@ResourceSwagger</ja> annotation
</p>
<h5 class='figure'>PetStoreResource.json</h5>
<p class='bpcode w800'>
<jok>"tags"</jok>: [
{
<jok>"name"</jok>: <jov>"pet"</jov>,
<jok>"description"</jok>: <jov>"Everything about your Pets"</jov>,
<jok>"externalDocs"</jok>: {
<jok>"description"</jok>: <jov>"Find out more"</jov>,
<jok>"url"</jok>: <jov>"http://juneau.apache.org"</jov>
}
},
{
<jok>"name"</jok>: <jov>"store"</jov>,
<jok>"description"</jok>: <jov>"Access to Petstore orders"</jov>
},
{
<jok>"name"</jok>: <jov>"user",
<jok>"description"</jok>: <jov>"Operations about user"</jov>,
<jok>"externalDocs"</jok>: {
<jok>"description"</jok>: <jov>"Find out more about our store"</jov>,
<jok>"url"</jok>: <jov>"http://juneau.apache.org"</jov>
}
}
],
</p>
<p>
The annotation-only approach is shown here:
</p>
<h5 class='figure'>org.apache.juneau.examples.rest.petstore.PetStoreResource</h5>
<p class='bpcode w800'>
swagger=<ja>@ResourceSwagger</ja>(
...
tags={
<ja>@Tag</ja>(
name=<js>"pet"</js>,
description=<js>"Everything about your Pets"</js>,
externalDocs=<ja>@ExternalDocs</ja>(
description=<js>"Find out more"</js>,
url=<js>"http://juneau.apache.org"</js>
)
),
<ja>@Tag</ja>(
name=<js>"store"</js>,
description=<js>"Access to Petstore orders"</js>
),
<ja>@Tag</ja>(
name=<js>"user"</js>,
description=<js>"Operations about user"</js>,
externalDocs=<ja>@ExternalDocs</ja>(
description=<js>"Find out more about our store"</js>,
url=<js>"http://juneau.apache.org"</js>
)
)
}
),
</p>
<p>
Tags are associated with operations using the {@link org.apache.juneau.rest.annotation.MethodSwagger#tags() @MethodSwagger(tags)} annotation:
</p>
<h5 class='figure'>GET /user operation</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(
name=<jsf>GET</jsf>,
path=<js>"/user"</js>,
summary=<js>"Petstore users"</js>,
swagger=<ja>@MethodSwagger</ja>(
tags=<js>"user"</js>
)
)
<jk>public</jk> Collection&lt;User&gt; getUsers() <jk>throws</jk> NotAcceptable {...}
</p>
<p>
Operations can be mapped to multiple tags.
</p>
<p>
Tags are optional.
Operations not mapped to tags are listed in the UI before tagged operations.
</p>
<p>
For example, the <c>getTopPage()</c> method in <c>PetStoreResource</c> is not tagged,
as well as the <c>getOptions()</c> method inherited from <c>BaseRestServlet</c>, so these
show up at the top of the page:
</p>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.5.png'>
</div><!-- END: 6.29.3 - juneau-rest-server.Swagger.Tags -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Swagger.Operations' id='juneau-rest-server.Swagger.Operations'>6.29.4 - Operations</a></h4>
<div class='topic'><!-- START: 6.29.4 - juneau-rest-server.Swagger.Operations -->
<p>
<ja>@RestMethod</ja>-annotated methods automatically get rendered as Swagger operations:
</p>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.Operations.1.png'>
<p>
The following shows the annotations defined on the <c>GET /pet</c> operation:
</p>
<h5 class='figure'>PetStoreResource.getPets()</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(
name=<jsf>GET</jsf>,
path=<js>"/pet"</js>,
summary=<js>"All pets in the store"</js>,
swagger=<ja>@MethodSwagger</ja>(
tags=<js>"pet"</js>,
...
),
...
)
<jk>public</jk> Collection&lt;Pet&gt; getPets() <jk>throws</jk> NotAcceptable {
<jk>return</jk> <jsf>store</jsf>.getPets();
}
</p>
<p>
Methods marked as deprecated will show up as deprecated in the Swagger UI:
</p>
<h5 class='figure'>PetStoreResource.findPetsByTag()</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(
name=<jsf>GET</jsf>,
path=<js>"/pet/findByTags"</js>,
summary=<js>"Finds Pets by tags"</js>,
...
)
<ja>@Deprecated</ja>
<jk>public</jk> Collection&lt;Pet&gt; findPetsByTags(...) {
...
}
</p>
</div><!-- END: 6.29.4 - juneau-rest-server.Swagger.Operations -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Swagger.Parameters' id='juneau-rest-server.Swagger.Parameters'>6.29.5 - Parameters</a></h4>
<div class='topic'><!-- START: 6.29.5 - juneau-rest-server.Swagger.Parameters -->
<p>
Expanding operations shows you a list of parameters:
</p>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.Operations.2.png'>
<p>
Parameter information can be defined in a couple of ways. The typical way is through annotations on parameters
being passed to your <ja>@RestMethod</ja>-annotated method, like so:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(
...
)
<jk>public</jk> Collection&lt;Pet&gt; getPets(
<ja>@Query</ja>(
name=<js>"s"</js>,
description={
<js>"Search."</js>,
<js>"Key/value pairs representing column names and search tokens."</js>,
<js>"'*' and '?' can be used as meta-characters in string fields."</js>,
<js>"'&gt;', '&gt;=', '&lt;', and '&lt;=' can be used as limits on numeric and date fields."</js>,
<js>"Date fields can be matched with partial dates (e.g. '2018' to match any date in the year 2018)."</js>
},
type=<js>"array"</js>,
collectionFormat=<js>"csv"</js>,
example=<js>"Bill*,birthDate>2000"</js>
)
String[] s,
<ja>@Query</ja>(
name=<js>"v"</js>,
description={
<js>"View."</js>,
<js>"Column names to display."</js>
},
type=<js>"array"</js>,
collectionFormat=<js>"csv"</js>,
example=<js>"name,birthDate"</js>
)
String[] v,
...
) <jk>throws</jk> NotAcceptable {
...
}
</p>
<p>
<b>Note:</b> The <c>type</c> and <c>collectionFormat</c> values above are optional and auto-detected based on the
parameter class type if omitted. They're included here for clarity.
The examples will be explained in the next section.
</p>
<p>
Another option is to specify your parameter information in the <c>parameters</c> annotation as free-form Simple JSON.
In the case of the <c>PetStoreResource.getPets()</c> method, we pull this information from a static field
defined in the {@link org.apache.juneau.rest.converters.Queryable} class:
</p>
<h5 class='figure'>PetStoreResource.getPets()</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(
name=<jsf>GET</jsf>,
path=<js>"/pet"</js>,
summary=<js>"All pets in the store"</js>,
swagger=<ja>@MethodSwagger</ja>(
tags=<js>"pet"</js>,
parameters={
Queryable.<jsf>SWAGGER_PARAMS</jsf>
}
),
...
converters={Queryable.<jk>class</jk>}
)
<jk>public</jk> Collection&lt;Pet&gt; getPets() <jk>throws</jk> NotAcceptable {
<jk>return</jk> <jf>store</jf>.getPets();
}
</p>
<h5 class='figure'>Queryable</h5>
<p class='bpcode w800'>
<jk>public class</jk> Queryable <jk>implements</jk> RestConverter {
<jk>public static final</jk> String <jsf>SWAGGER_PARAMS</jsf>=<js>""</js>
+ <js>"{"</js>
+ <js>"in:'query',"</js>
+ <js>"name:'s',"</js>
+ <js>"description:'"</js>
+ <js>"Search.\n"</js>
+ <js>"Key/value pairs representing column names and search tokens.\n"</js>
+ <js>"\\'*\\' and \\'?\\' can be used as meta-characters in string fields.\n"</js>
+ <js>"\\'&gt;\\', \\'&gt;=\\', \\'&lt;\\', and \\'&lt;=\\' can be used as limits on numeric and date fields.\n"</js>
+ <js>"Date fields can be matched with partial dates (e.g. \\'2018\\' to match any date in the year 2018)."</js>
+ <js>"',"</js>
+ <js>"type:'array',"</js>
+ <js>"collectionFormat:'csv',"</js>
+ <js>"x-examples:{example:'?s=Bill*,birthDate>2000'}"</js>
+ <js>"},"</js>
+ <js>"{"</js>
+ <js>"in:'query',"</js>
+ <js>"name:'v',"</js>
+ <js>"description:'"</js>
+ <js>"View.\n"</js>
+ <js>"Column names to display."</js>
+ <js>"',"</js>
+ <js>"type:'array',"</js>
+ <js>"collectionFormat:'csv',"</js>
+ <js>"x-examples:{example:'?v=name,birthDate'}"</js>
+ <js>"},"</js>
...
;
}
</p>
<p>
This information could have also been defined in the Swagger JSON for the resource as well.
</p>
<p>
The parameter section contains information about the request body as well for PUT and POST methods, as shown here:
</p>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.Parameters.2.png'>
<p>
The definition of this method is shown here:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(
summary=<js>"Add a new pet to the store"</js>,
swagger=<ja>@MethodSwagger</ja>(
tags=<js>"pet"</js>
)
)
<jk>public</jk> Ok postPet(
<ja>@Body</ja>(description=<js>"Pet object to add to the store"</js>) PetCreate pet
) <jk>throws</jk> IdConflict, NotAcceptable, UnsupportedMediaType {
<jf>store</jf>.create(pet);
<jk>return</jk> <jsf>OK</jsf>;
}
</p>
<p>
Note that the schema information on the body parameter is automatically detected if not provided.
</p>
</div><!-- END: 6.29.5 - juneau-rest-server.Swagger.Parameters -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Swagger.ParameterExamples' id='juneau-rest-server.Swagger.ParameterExamples'>6.29.6 - Parameter Examples</a></h4>
<div class='topic'><!-- START: 6.29.6 - juneau-rest-server.Swagger.ParameterExamples -->
<p>
The <c>model</c> select box in the parameters can be expanded to show examples:
</p>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.Parameters.1.png'>
<p>
The examples for query/form-data/path/header parameters can be defined using the <c>example</c> attribute on your annotated parameters as shown here:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(
...
)
<jk>public</jk> Collection&lt;Pet&gt; getPets(
<ja>@Query</ja>(
name=<js>"s"</js>,
description={
<js>"Search."</js>,
<js>"Key/value pairs representing column names and search tokens."</js>,
<js>"'*' and '?' can be used as meta-characters in string fields."</js>,
<js>"'&gt;', '&gt;=', '&lt;', and '&lt;=' can be used as limits on numeric and date fields."</js>,
<js>"Date fields can be matched with partial dates (e.g. '2018' to match any date in the year 2018)."</js>
},
type=<js>"array"</js>,
collectionFormat=<js>"csv"</js>,
example=<js>"Bill*,birthDate>2000"</js>
)
...
) <jk>throws</jk> NotAcceptable {
...
}
</p>
<p>
This value gets converted to an <c>x-examples</c> attribute in your parameter information:
</p>
<p class='bpcode w800'>
{
<jok>"swagger"</jok>: <jov>"2.0"</jov>,
<jok>"paths"</jok>: {
<jok>"/pet"</jok>: {
<jok>"get"</jok>: {
<jok>"operationId"</jok>: <jov>"getPets"</jov>,
<jok>"summary"</jok>: <jov>"All pets in the store"</jov>,
<jok>"parameters"</jok>: [
{
<jok>"in"</jok>: <jov>"query"</jov>,
<jok>"name"</jok>: <jov>"s"</jov>,
...
<jok>"x-examples"</jok>: {
<jok>"example"</jok>: <jov>"?s=Bill*,birthDate>2000"</jov>
}
},
...
</p>
<p>
Examples for request bodies includes all supported <c>Content-Type</c> values:
</p>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.Parameters.3.png'>
<p>
These are based on the parsers registered on your servlet or method.
</p>
<p>
Selecting any of the content types shows you a representative example for the POJO:
</p>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.Parameters.4.png'>
<p>
There are several options for defining examples for request bodies:
</p>
<ul class='spaced-list'>
<li>
{@link org.apache.juneau.http.annotation.Body#example() @Body(example)} annotation.
<li>
{@link org.apache.juneau.http.annotation.Body#examples() @Body(examples)} annotation.
<li>
Defining an <js>"x-examples"</js> field in the inherited Swagger JSON body field (classpath file or <c><ja>@ResourceSwagger</ja>(value)</c>/<c><ja>@MethodSwagger</ja>(value)</c>).
<li>
Defining an <js>"x-examples"</js> field in the Swagger Schema Object for the body (including referenced <js>"$ref"</js> schemas).
<li>
Allowing Juneau to auto-generate a code example.
</ul>
<p>
When using {@link org.apache.juneau.http.annotation.Body#example() @Body(example)}, you specify a Simple JSON representation of your POJO.
The Swagger generator will then convert that JSON into a POJO using the registered serializers on the REST method to produce examples for all
supported language types.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// A JSON representation of a PetCreate object.</jc>
<ja>@Body</ja>(
example=<js>"{name:'Doggie',price:9.99,species:'Dog',tags:['friendly','cute']}"</js>
)
</p>
<p>
The {@link org.apache.juneau.http.annotation.Body#examples() @Body(examples)} annotation allows you to specify raw output values per media type.
This field allows you to override the behavior and show examples for only specified media types or different examples for different media types.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// A JSON representation of a PetCreate object.</jc>
<ja>@Body</ja>(
examples={
<js>"'application/json':'{name:\\'Doggie\\',species:\\'Dog\\'}',"</js>,
<js>"'text/uon':'(name:Doggie,species=Dog)'"</js>
}
)
</p>
<p>
The Swagger generator uses these to create an <c>x-examples</c> entry in your generated Swagger:
</p>
<p class='bpcode w800'>
<jok>"/pet"</jok>: {
<jok>"post"</jok>: {
<jok>"operationId"</jok>: <jov>"postPet"</jov>,
<jok>"summary"</jok>: <jov>"Add a new pet to the store"</jov>,
<jok>"parameters"</jok>: [
{
<jok>"in"</jok>: <jov>"body"</jov>,
<jok>"description"</jok>: <jov>"Pet object to add to the store"</jov>,
<jok>"required"</jok>: <jov>true</jov>,
<jok>"schema"</jok>: {
<jok>"$ref"</jok>: <jov>"#/definitions/PetCreate"</jov>
},
<jok>"x-examples"</jok>: {
<jok>"application/json"</jok>: <jov>"{\n\t\"name\": \"Doggie\",\n\t\"species\": \"Dog\",\n\t\"price\": 9.99,\n\t\"tags\": [\n..."</jov>,
<jok>"application/json+simple"</jok>: <jov>"{\n\tname: 'Doggie',\n\tspecies: 'Dog',\n\tprice: 9.99,\n\ttags: [\n\t\t'friendly..."</jov>,
<jok>"text/xml"</jok>: <jov>"&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n&lt;object&gt;\n\t&lt;name&gt;Doggie&lt;/name&amp;..."</jov>,
<jok>"text/html+stripped"</jok>: <jov>"&lt;table&gt;\n\t&lt;tr&gt;\n\t\t&lt;td&gt;name&lt;/td&gt;\n\t\t&lt;td&gt;Doggie&lt;/t..."</jov>,
<jok>"text/uon"</jok>: <jov>"(\n\tname=Doggie,\n\tspecies=Dog,\n\tprice=9.99,\n\ttags=@(\n\t\tfriendly,\n\t\tcute\n\t)\n)"</jov>,
<jok>"application/x-www-form-urlencoded"</jok>: <jov>"name=Doggie\n&amp;species=Dog\n&amp;price=9.99\n&amp;tags=@(\n\tfriendly,\n\tcute\n)"</jov>,
<jok>"text/openapi"</jok>: <jov>"(\n\tname=Doggie,\n\tspecies=Dog,\n\tprice=9.99,\n\ttags=@(\n\t\tfriendly,\n\t\tcute\n\t)\n)"</jov>,
<jok>"octal/msgpack"</jok>: <jov>"84 A4 6E 61 6D 65 A6 44 6F 67 67 69 65 A7 73 70 65 63 69 65 73 A3 44 6F 67 A5 70 72 69 63 6..."</jov>,
<jok>"text/plain"</jok>: <jov>"{name:'Doggie',species:'Dog',price:9.99,tags:['friendly','cute']}"</jov>,
<jok>"text/xml+rdf"</jok>: <jov>"&lt;rdf:RDF\n xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n xmlns:j=\"ht..."</jov>,
<jok>"text/turtle"</jok>: <jov>"@prefix jp: &lt;http://www.apache.org/juneaubp/&gt; .\n@prefix j: &lt;http://www.a..."</jov>,
<jok>"text/n-triple"</jok>: <jov>"_:A59722791X3aX165d321a2b4X3aXX2dX7fca &lt;http://www.apache.org/juneaubp/name&gt; \"Doggie..."</jov>,
<jok>"text/n3"</jok>: <jov>"@prefix jp: &lt;http://www.apache.org/juneaubp/&gt; .\n@prefix j: &lt;http://www.apach..."</jov>
}
}
],
</p>
<p>
Another option is to define these directly in your resource Swagger JSON file, or via {@link org.apache.juneau.rest.annotation.Rest#swagger() @Rest(swagger)}/{@link org.apache.juneau.rest.annotation.RestMethod#swagger() @RestMethod(swagger)}.
</p>
<p>
Juneau also supports auto-generation of JSON-Schema directly from POJO classes.
By default, the generated swagger uses to the {@link org.apache.juneau.jsonschema.JsonSchemaGenerator#JSONSCHEMA_addExamplesTo JSONSCHEMA_addExamplesTo}
setting to automatically add examples to beans, collections, arrays, and maps:
</p>
<p class='bpcode w800'>
<jk>public abstract class</jk> BasicRestServlet <jk>extends</jk> RestServlet <jk>implements</jk> BasicRestConfig {
<ja>@RestMethod</ja>(name=<jsf>OPTIONS</jsf>, path=<js>"/*"</js>,
...
)
<ja>@JsonSchemaConfig</ja>(
<jc>// Add x-example to the following types:</jc>
addExamplesTo=<js>"bean,collection,array,map"</js>,
...
)
<jk>public</jk> Swagger getOptions(RestRequest req) {...}
</p>
<p>
Examples can be defined via static methods, fields, and annotations on the classes themselves.
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Annotation on class.</jc>
<ja>@Example</ja>(<js>"{name:'Doggie',price:9.99,species:'Dog',tags:['friendly','cute']}"</js>)
<jk>public class</jk> PetCreate {
...
}
</p>
<p class='bpcode w800'>
<jc>// Annotation on static method.</jc>
<jk>public class</jk> PetCreate {
<ja>@Example</ja>
<jk>public static</jk> PetCreate <jsm>sample</jsm>() {
<jk>return new</jk> PetCreate(<js>"Doggie"</js>, 9.99f, <js>"Dog"</js>, <jk>new</jk> String[] {<js>"friendly"</js>,<js>"cute"</js>});
}
}
</p>
<p class='bpcode w800'>
<jc>// Static method with specific name 'example'.</jc>
<jk>public class</jk> PetCreate {
<jk>public static</jk> PetCreate <jsm>example</jsm>() {
<jk>return new</jk> PetCreate(<js>"Doggie"</js>, 9.99f, <js>"Dog"</js>, <jk>new</jk> String[] {<js>"friendly"</js>,<js>"cute"</js>});
}
}
</p>
<p class='bpcode w800'>
<jc>// Static field.</jc>
<jk>public class</jk> PetCreate {
<ja>@Example</ja>
<jk>public static</jk> PetCreate <jsf>EXAMPLE</jsf> = <jk>new</jk> PetCreate(<js>"Doggie"</js>, 9.99f, <js>"Dog"</js>, <jk>new</jk> String[] {<js>"friendly"</js>,<js>"cute"</js>});
}
</p>
<p>
Examples can also be specified via generic properties as well using the {@link org.apache.juneau.BeanContext#BEAN_examples} property or {@link org.apache.juneau.annotation.BeanConfig#examples() @BeanConfig(examples)} annotation at either the class or method level.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Examples defined at class level.</jc>
<ja>@Rest</ja>(...)
<ja>@BeanConfig</ja>(
examples=<js>"{PetCreate: {name:'Doggie',price:9.99,species:'Dog',tags:['friendly','cute']}}"</js>
)
</p>
<ul class='seealso'>
<li class='ja'>{@link org.apache.juneau.annotation.Example}
<li class='jc'>{@link org.apache.juneau.BeanContext}
<ul>
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_examples BEAN_examples}
</ul>
<li class='jc'>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator}
<ul>
<li class='jf'>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator#JSONSCHEMA_addExamplesTo JSONSCHEMA_addExamplesTo}
<li class='jf'>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator#JSONSCHEMA_allowNestedExamples JSONSCHEMA_allowNestedExamples}
</ul>
</ul>
</div><!-- END: 6.29.6 - juneau-rest-server.Swagger.ParameterExamples -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Swagger.Responses' id='juneau-rest-server.Swagger.Responses'>6.29.7 - Responses</a></h4>
<div class='topic'><!-- START: 6.29.7 - juneau-rest-server.Swagger.Responses -->
<p>
Under the input parameters are listed the possible responses for the resource:
</p>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.Operations.3.png'>
<p>
The <c>200</c> response is determined by the return type on the method, in this case a collection of <c>Pet</c> objects:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(
name=<jsf>GET</jsf>,
path=<js>"/pet"</js>,
summary=<js>"All pets in the store"</js>,
...
)
<jk>public</jk> Collection&lt;Pet&gt; getPets() <jk>throws</jk> NotAcceptable {
<jk>return</jk> <jf>store</jf>.getPets();
}
</p>
<p>
Note that additional responses can be specified by throwing exceptions annotated with the {@link org.apache.juneau.http.annotation.Response @Response} annotation such
as this one:
</p>
<p class='bpcode w800'>
<ja>@Response</ja>(code=406, description=<js>"Not Acceptable"</js>)
<jk>public class</jk> NotAcceptable <jk>extends</jk> RestException {...}
</p>
<p>
Like input parameters, the Swagger for responses can be define in multiple locations such as:
</p>
<ul>
<li>{@link org.apache.juneau.http.annotation.Response @Response} annotated classes, methods, and parameters.
<li>{@link org.apache.juneau.rest.annotation.Rest#swagger() @Rest(swagger)} / {@link org.apache.juneau.rest.annotation.RestMethod#swagger() @RestMethod(swagger)} annotations.
</ul>
<ul class='seealso'>
<li class='link'>{@doc juneau-rest-server.HttpPartAnnotations.Response}
<li class='link'>{@doc juneau-rest-server.HttpPartAnnotations.ResponseHeader}
<li class='link'>{@doc juneau-rest-server.HttpPartAnnotations.ResponseStatus}
</ul>
</div><!-- END: 6.29.7 - juneau-rest-server.Swagger.Responses -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Swagger.ResponseExamples' id='juneau-rest-server.Swagger.ResponseExamples'>6.29.8 - Response Examples</a></h4>
<div class='topic'><!-- START: 6.29.8 - juneau-rest-server.Swagger.ResponseExamples -->
<p>
The <c>model</c> select box in the responses can be expanded to show examples:
</p>
<h5 class='figure'>PetStoreResource.getPet()</h5>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.ResponseExamples.1.png'>
<p>
Examples are provided for any supported <c>Accept</c> type based on the serializers defined on your
servlet/method.
</p>
<h5 class='figure'>application/json+simple</h5>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.ResponseExamples.2.png'>
<h5 class='figure'>text/uon</h5>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.ResponseExamples.3.png'>
<p>
Examples are pulled from the <c>examples</c> attribute in the response object of the generated Swagger JSON:
</p>
<p class='bpcode w800'>
<jok>"/pet/{petId}"</jok>: {
<jok>"get"</jok>: {
<jok>"operationId"</jok>: <jov>"getPet"</jov>,
<jok>"summary"</jok>: <jov>"Find pet by ID"</jov>,
<jok>"description"</jok>: <jov>"Returns a single pet"</jov>,
<jok>"responses"</jok>: {
<jok>"200"</jok>: {
<jok>"description"</jok>: <jov>"OK"</jov>,
<jok>"schema"</jok>: {
<jok>"$ref"</jok>: <jov>"#/definitions/Pet"</jov>
},
<jok>"examples"</jok>: {
<jok>"text/html+stripped"</jok>: <jov>"&lt;table&gt;\n\t&lt;tr&gt;\n\t\t&lt;td&gt;id&lt;/td&gt;\n\t\t&lt;td&gt;\t\t\t&lt;a href=\"..."</jov>,
<jok>"text/html+schema"</jok>: <jov>"&lt;html&gt;\n\t&lt;head&gt;\n\t\t&lt;link rel='icon' href='$U{servlet:/htdocs/cat.png}'/&gt;..."</jov>,
<jok>"application/json"</jok>: <jov>"{\n\t\"id\": 123,\n\t\"species\": {\n\t\t\"name\": \"Dog\",\n\t\t\"id\": 123\n\t},\n\t\"name\..."</jov>,
<jok>"application/json+simple"</jok>: <jov>"{\n\tid: 123,\n\tspecies: {\n\t\tname: 'Dog',\n\t\tid: 123\n\t},\n\tname: 'Doggie',\n\..."</jov>,
<jok>"application/json+schema"</jok>: <jov>"{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"id\": {\n\t\t\t\"type\": \"inte..."</jov>,
<jok>"text/xml"</jok>: <jov>"&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n&lt;Pet&gt;\n\t&lt;id&gt;123&lt;/id&gt;\n\t&lt;spec..."</jov>,
<jok>"text/xml+schema"</jok>: <jov>"&lt;schema xmlns=\"http://www.w3.org/2001/XMLSchema\" targetNamespace=\"http://www.apache.org/..."</jov>,
<jok>"text/uon"</jok>: <jov>"(\n\tid=123,\n\tspecies=(\n\t\tname=Dog,\n\t\tid=123\n\t),\n\tname=Doggie,\n\ttags=@(\n\t\t(\n\t\t\tn..."</jov>,
<jok>"application/x-www-form-urlencoded"</jok>: <jov>"id=123\n&amp;species=(\n\tname=Dog,\n\tid=123\n)\n&amp;name=Doggie\n&amp;tags=@(\n\t(\n\..."</jov>,
<jok>"text/openapi"</jok>: <jov>"(\n\tid=123,\n\tspecies=(\n\t\tname=Dog,\n\t\tid=123\n\t),\n\tname=Doggie,\n\ttags=@(\n\t\t(\n\t\..."</jov>,
<jok>"octal/msgpack"</jok>: <jov>"86 A2 69 64 7B A7 73 70 65 63 69 65 73 82 A4 6E 61 6D 65 A3 44 6F 67 A2 69 64 7B A4 6E 61 6D 65 ..."</jov>,
<jok>"text/xml+soap"</jok>: <jov>"&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n&lt;Envelope soap=\"http://www.w3.org/2003/05/..."</jov>,
<jok>"text/plain"</jok>: <jov>"{id:123,species:{name:'Dog',id:123},name:'Doggie',tags:[{name:'MyTag',id:123}],price:0.0,status:'AV..."</jov>,
<jok>"text/xml+rdf"</jok>: <jov>"&lt;rdf:RDF\n xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n xmlns:j=\"http://..."</jov>,
<jok>"text/xml+rdf+abbrev"</jok>: <jov>"&lt;rdf:RDF\n xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n xmlns:j=\"..."</jov>,
<jok>"text/turtle"</jok>: <jov>"@prefix jp: &lt;http://www.apache.org/juneaubp/&gt; .\n@prefix j: &lt;http://www.apache..."</jov>,
<jok>"text/n-triple"</jok>: <jov>"_:A720f0f4fX3aX165d4974933X3aXX2dX7f93 &lt;http://www.apache.org/juneaubp/name&gt; \"Dog\" .\n_:..."</jov>,
<jok>"text/n3"</jok>: <jov>"@prefix jp: &lt;http://www.apache.org/juneaubp/&gt; .\n@prefix j: &lt;http://www.apache.org..."</jov>
</p>
<p>
There are several options for defining examples for response bodies:
</p>
<ul class='spaced-list'>
<li>
{@link org.apache.juneau.http.annotation.Response#example() @Response(example)} annotation.
<li>
{@link org.apache.juneau.http.annotation.Response#examples() @Response(examples)} annotation.
<li>
Defining an <js>"examples"</js> field in the inherited Swagger JSON response object (classpath file or <c><ja>@ResourceSwagger</ja>(value)</c>/<c><ja>@MethodSwagger</ja>(value)</c>).
<li>
Defining an <js>"examples"</js> field in the Swagger Schema Object for the response object (including referenced <js>"$ref"</js> schemas).
<li>
Allowing Juneau to auto-generate a code example.
</ul>
<p>
The {@link org.apache.juneau.http.annotation.Response#example @Response(example)} annotation can be used on either your <ja>@RestMethod</ja>-annotated
method or return class to define the example of the body.
</p>
<p class='bpcode w800'>
<jc>// A JSON representation of a Pet object.</jc>
<ja>@Response</ja>(
example=<js>"{name:'Doggie',price:9.99,species:'Dog',tags:['friendly','cute']}"</js>
)
</p>
<p>
This is a Simple JSON representation of the body that is converted to a POJO and then serialized to all the registered serializers on the REST method to produce examples for all
supported language types.
These values are then used to automatically populate the <c>examples</c> field.
</p>
<p>
Direct per-media-type examples can also be defined using the {@link org.apache.juneau.http.annotation.Response#examples @Response(examples)} annotation:
</p>
<p class='bpcode w800'>
<jc>// A JSON representation of a PetCreate object.</jc>
<ja>@Response</ja>(
examples={
<js>"'application/json':'{name:\\'Doggie\\',species:\\'Dog\\'}',"</js>,
<js>"'text/uon':'(name:Doggie,species=Dog)'"</js>
}
)
</p>
<p>
Juneau also supports auto-generation of JSON-Schema directly from POJO classes.
By default, the generated swagger uses to the {@link org.apache.juneau.jsonschema.JsonSchemaGenerator#JSONSCHEMA_addExamplesTo JSONSCHEMA_addExamplesTo}
setting to automatically add examples to beans, collections, arrays, and maps:
</p>
<p>
In particular, examples can be defined via static methods, fields, and annotations on the classes themselves.
</p>
<p class='bpcode w800'>
<jc>// Annotation on class.</jc>
<ja>@Example</ja>(<js>"{name:'Doggie',price:9.99,species:'Dog',tags:['friendly','cute']}"</js>)
<jk>public class</jk> PetCreate {
...
}
</p>
<p class='bpcode w800'>
<jc>// Annotation on static method.</jc>
<jk>public class</jk> PetCreate {
<ja>@Example</ja>
<jk>public static</jk> PetCreate <jsm>sample</jsm>() {
<jk>return new</jk> PetCreate(<js>"Doggie"</js>, 9.99f, <js>"Dog"</js>, <jk>new</jk> String[] {<js>"friendly"</js>,<js>"cute"</js>});
}
}
</p>
<p class='bpcode w800'>
<jc>// Static method with specific name 'example'.</jc>
<jk>public class</jk> PetCreate {
<jk>public static</jk> PetCreate <jsm>example</jsm>() {
<jk>return new</jk> PetCreate(<js>"Doggie"</js>, 9.99f, <js>"Dog"</js>, <jk>new</jk> String[] {<js>"friendly"</js>,<js>"cute"</js>});
}
}
</p>
<p class='bpcode w800'>
<jc>// Static field.</jc>
<jk>public class</jk> PetCreate {
<ja>@Example</ja>
<jk>public static</jk> PetCreate <jsf>EXAMPLE</jsf> = <jk>new</jk> PetCreate(<js>"Doggie"</js>, 9.99f, <js>"Dog"</js>, <jk>new</jk> String[] {<js>"friendly"</js>,<js>"cute"</js>});
}
</p>
<p>
Examples can also be specified via generic properties as well using the {@link org.apache.juneau.BeanContext#BEAN_examples} property
or {@link org.apache.juneau.annotation.BeanConfig#examples @BeanConfig(examples)} annotation at either the class or method level.
</p>
<p class='bpcode w800'>
<jc>// Examples defined at class level.</jc>
<ja>@Rest</ja>(...)
<ja>@BeanConfig</ja>(
examples=<js>"{PetCreate: {name:'Doggie',price:9.99,species:'Dog',tags:['friendly','cute']}}"</js>
)
</p>
<p>
Response headers are also rendered in the Swagger UI:
</p>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.ResponseExamples.4.png'>
<p>
These can be auto-generated from {@link org.apache.juneau.http.annotation.ResponseHeader @ResponseHeader} annotations defined on either
method parameters or type classes.
The example above shows one of each:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(
name=<jsf>GET</jsf>,
path=<js>"/user/login"</js>,
summary=<js>"Logs user into the system"</js>,
swagger=<ja>@MethodSwagger</ja>(
tags=<js>"user"</js>
)
)
<jk>public</jk> Ok login(
<ja>@Query</ja>(
name=<js>"username"</js>,
description=<js>"The username for login"</js>,
required=<jk>true</jk>,
example=<js>"myuser"</js>
)
String username,
<ja>@Query</ja>(
name=<js>"password"</js>,
description=<js>"The password for login in clear text"</js>,
required=<jk>true</jk>,
example=<js>"abc123"</js>
)
String password,
<ja>@ResponseHeader</ja>(
name=<js>"X-Rate-Limit"</js>,
type=<js>"integer"</js>,
format=<js>"int32"</js>,
description=<js>"Calls per hour allowed by the user."</js>,
example=<js>"123"</js>
)
Value&lt;Integer&gt; rateLimit,
Value&lt;ExpiresAfter&gt; expiresAfter,
RestRequest req,
RestResponse res
) <jk>throws</jk> InvalidLogin, NotAcceptable {
<jk>if</jk> (! <jf>store</jf>.isValid(username, password))
<jk>throw new</jk> InvalidLogin();
Date d = <jk>new</jk> Date(System.<jsm>currentTimeMillis</jsm>() + 30 * 60 * 1000);
req.getSession().setAttribute(<js>"login-expires"</js>, d);
rateLimit.set(1000);
expiresAfter.set(<jk>new</jk> ExpiresAfter(d));
<jk>return</jk> <jsf>OK</jsf>;
}
</p>
<p class='bpcode w800'>
<ja>@ResponseHeader</ja>(
name=<js>"X-Expires-After"</js>,
type=<js>"string"</js>,
format=<js>"date-time"</js>,
description=<js>"Date in UTC when token expires"</js>,
example=<js>"2012-10-21"</js>
)
<jk>public static class</jk> ExpiresAfter {
<jk>private final</jk> Calendar <jf>c</jf>;
<jk>public</jk> ExpiresAfter(Date d) {
<jk>this</jk>.<jf>c</jf> = <jk>new</jk> GregorianCalendar();
<jf>c</jf>.setTime(d);
}
<jk>public</jk> Calendar toCalendar() {
<jk>return</jk> <jf>c</jf>;
}
}
</p>
</div><!-- END: 6.29.8 - juneau-rest-server.Swagger.ResponseExamples -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Swagger.Models' id='juneau-rest-server.Swagger.Models'>6.29.9 - Models</a></h4>
<div class='topic'><!-- START: 6.29.9 - juneau-rest-server.Swagger.Models -->
<p>
The {@link org.apache.juneau.jsonschema.JsonSchemaGenerator#JSONSCHEMA_useBeanDefs} setting can be used to reduce the size of your
generated Swagger JSON files by creating model definitions for beans and referencing those definitions through <c>$ref</c> attributes.
</p>
<p>
By default, this flag is enabled when extending from {@link org.apache.juneau.rest.BasicRestServlet}:
</p>
<p class='bpcode w800'>
<jk>public abstract class</jk> BasicRestServlet <jk>extends</jk> RestServlet <jk>implements</jk> BasicRestConfig {
<ja>@RestMethod</ja>(name=<jsf>OPTIONS</jsf>, path=<js>"/*"</js>,
...
flags={
<jc>// Use $ref references for bean definitions to reduce duplication in Swagger.</jc>
<jsf>JSONSCHEMA_useBeanDefs</jsf>
}
)
<jk>public</jk> Swagger getOptions(RestRequest req) {...}
</p>
<p>
In the Swagger UI, this causes bean definitions to show up in the Models section at the bottom of the page:
</p>
<h5 class='figure'>Models section</h5>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.Models.1.png'>
<h5 class='figure'>Models section with Order bean expanded</h5>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.Models.2.png'>
<p>
In the generated Swagger JSON, embedded schema information for beans will be replaced with references such as the one shown below for the <c>Order</c> bean:
</p>
<p class='bpcode w800'>
{
<jok>"swagger"</jok>: <jov>"2.0"</jov>,
<jok>"paths"</jok>: {
<jok>"/store/order"</jok>: {
<jok>"get"</jok>: {
<jok>"operationId"</jok>: <jov>"getOrders"</jov>,
<jok>"summary"</jok>: <jov>"Petstore orders"</jov>,
<jok>"responses"</jok>: {
<jok>"200"</jok>: {
<jok>"description"</jok>: <jov>"OK"</jov>,
<jok>"schema"</jok>: {
<jok>"description"</jok>: <jov>"java.util.Collection&lt;org.apache.juneau.examples.rest.petstore.Order&gt;"</jov>,
<jok>"type"</jok>: <jov>"array"</jov>,
<jok>"items"</jok>: {
<jok>"$ref"</jok>: <jov>"#/definitions/Order"</jov>
}
},
...
...
...
...
...
},
<jok>"definitions"</jok>: {
<jok>"Order"</jok>: {
<jok>"type"</jok>: <jov>"object"</jov>,
<jok>"properties"</jok>: {
<jok>"id"</jok>: {
<jok>"type"</jok>: <jov>"integer"</jov>,
<jok>"format"</jok>: <jov>"int64"</jov>
},
<jok>"petId": {
<jok>"type"</jok>: <jov>"integer"</jov>,
<jok>"format"</jok>: <jov>"int64"</jov>
},
<jok>"shipDate"</jok>: {
<jok>"type"</jok>: <jov>"string"</jov>
},
<jok>"status"</jok>: {
<jok>"type"</jok>: <jov>"string"</jov>,
<jok>"enum"</jok>: [
<jov>"PLACED"</jov>,
<jov>"APPROVED"</jov>,
<jov>"DELIVERED"</jov>
]
}
},
<jok>"description"</jok>: <jov>"org.apache.juneau.examples.rest.petstore.Order"</jov>,
<jok>"example"</jok>: {
<jok>"id"</jok>: <jov>123</jov>,
<jok>"petId"</jok>: <jov>456</jov>,
<jok>"shipDate"</jok>: <jov>"2012-12-21"</jov>,
<jok>"status"</jok>: <jov>"APPROVED"</jov>
}
},
...
}
</p>
<p>
Note that this does not affect how the information is rendered for that bean in the Swagger UI:
</p>
<img class='bordered w900' src='doc-files/juneau-rest-server.Swagger.Models.3.png'>
</div><!-- END: 6.29.9 - juneau-rest-server.Swagger.Models -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Swagger.Stylesheet' id='juneau-rest-server.Swagger.Stylesheet'>6.29.10 - SwaggerUI.css</a></h4>
<div class='topic'><!-- START: 6.29.10 - juneau-rest-server.Swagger.Stylesheet -->
<p>
The look-and-feel of the Swagger UI is controlled via a single CSS file: <c>SwaggerUI.css</c>.
</p>
<p>
In the microservice template, this file is located in the <c>files/htdocs/styles</c> directory.
It's a simple straightforward file consisting of less than 350 lines.
This file can be modified to change the look-and-feel of your Swagger UI.
</p>
</div><!-- END: 6.29.10 - juneau-rest-server.Swagger.Stylesheet -->
</div><!-- END: 6.29 - juneau-rest-server.Swagger -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HtmlDocAnnotation' id='juneau-rest-server.HtmlDocAnnotation'>6.30 - @HtmlDocConfig</a></h3>
<div class='topic'><!-- START: 6.30 - juneau-rest-server.HtmlDocAnnotation -->
<p>
The {@link org.apache.juneau.html.annotation.HtmlDocConfig @HtmlDocConfig} annotation is used to customize the HTML
view of your serialized POJOs.
It's used in the following locations:
</p>
<ul>
<li>{@link org.apache.juneau.rest.annotation.Rest @Rest}-annotated classes.
<li>{@link org.apache.juneau.rest.annotation.RestMethod @RestMethod}-annotated methods.
</ul>
<p>
The annotation itself is just a convenience for setting configuration properties set
on the {@link org.apache.juneau.html.HtmlDocSerializer} class.
For example, the following two pieces of code are equivalent:
</p>
<p class='bpcode w800'>
<jc>// Title defined via property.</jc>
<ja>@Rest</ja>(
properties={
<ja>@Property</ja>(name=<jsf>HTMLDOC_title</jsf>, value=<js>"My Resource Page"</js>)
}
)
<jc>// Title defined via @HtmlDoc annotation.</jc>
<ja>@Rest</ja>()
<ja>@HtmlDocConfig</ja>(
title=<js>"My Resource Page"</js>
)
</p>
<p>
The purpose of these annotation is to populate the HTML document view which by default consists of the following
structure:
</p>
<p class='bpcode w800'>
<xt>&lt;html&gt;
&lt;head&gt;
&lt;style <xa>type</xa>=<xs>'text/css'</xs>&gt;
<xv>CSS styles and links to stylesheets</xv>
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;header&gt;
<xv>Page header</xv>
&lt;/header&gt;
&lt;nav&gt;
<xv>Navigation links</xv>
&lt;/nav&gt;
&lt;aside&gt;
<xv>Side-bar text</xv>
&lt;/aside&gt;
&lt;article&gt;
<xv>Contents of serialized object</xv>
&lt;/article&gt;
&lt;footer&gt;
<xv>Footer message</xv>
&lt;/footer&gt;
&lt;/body&gt;
&lt;/html&gt;</xt>
</p>
<p>
The outline above is controlled by the {@link org.apache.juneau.html.HtmlDocTemplate} interface
which can be overridden via the {@link org.apache.juneau.rest.annotation.HtmlDoc#template @HtmlDoc(template)} annotation.
</p>
<p>
The <l>HelloWorldResource</l> class was an example of the <l>@HtmlDoc</l> annotation in use:
</p>
<p class='bpcode w800'>
<jd>/**
* Sample REST resource that prints out a simple "Hello world!" message.
*/</jd>
<ja>@Rest</ja>(
path=<js>"/helloWorld"</js>
)
<ja>@HtmlDocConfig</ja>(
navlinks={
<js>"up: request:/.."</js>,
<js>"options: servlet:/?method=OPTIONS"</js>
},
aside={
<js>"&lt;div style='max-width:400px' class='text'&gt;"</js>,
<js>" &lt;p&gt;This page shows a resource that simply response with a 'Hello world!' message&lt;/p&gt;"</js>,
<js>" &lt;p&gt;The POJO serialized is a simple String.&lt;/p&gt;"</js>,
<js>"&lt;/div&gt;"</js>
}
)
<jk>public class</jk> HelloWorldResource <jk>extends</jk> BasicRestServlet {...}
</p>
<p>
SVL variables can be used in any of these annotations:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/helloWorld"</js>,
<jc>// Register a config file.</jc>
config=<js>"MyConfig.cfg"</js>
)
<ja>@HtmlDocConfig</ja>(
navlinks={
<js>"up: request:/.."</js>,
<js>"options: servlet:/?method=OPTIONS"</js>,
<jc>// Add a nav link to view the source code for this class.</jc>
<js>"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"</js>
},
aside={
<jc>// Localize our messages.</jc>
<js>"&lt;div style='max-width:400px' class='text'&gt;"</js>,
<js>" &lt;p&gt;$L{localizedMessage1}&lt;/p&gt;"</js>,
<js>" &lt;p&gt;$L{localizedMessage2}&lt;/p&gt;"</js>,
<js>"&lt;/div&gt;"</js>
}
)
<jk>public class</jk> HelloWorldResource <jk>extends</jk> BasicRestServlet {...}
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HtmlDocAnnotation.UIvsDI' id='juneau-rest-server.HtmlDocAnnotation.UIvsDI'>6.30.1 - User Interfaces (UI) vs. Developer Interfaces (DI)</a></h4>
<div class='topic'><!-- START: 6.30.1 - juneau-rest-server.HtmlDocAnnotation.UIvsDI -->
<p>
An important distinction needs to be made about the HTML representations produced by the REST
API. These should not be considered User Interfaces, but rather Developer Interfaces.
</p>
<p>
UIs should hide the end-user from the underlying architecture.
The audience generally consists of non-technical people not interested in how the UI works.
</p>
<p>
DIs, on the other hand, should NOT hide the end-user from the underlying architecture.
Instead, it's a thin veneer over the REST interface with the following goals:
</p>
<ul class='spaced-list'>
<li>Make it easy for the developer to explore and understand the REST API.
<li>Make it easy for the developer to debug the REST API using simple tools (hopefully just a browser).
</ul>
<p>
As a result, the following guidelines are recommended:
</p>
<ul class='spaced-list'>
<li>
Use titles/descriptions/asides to describe why the REST interface exists.
A developer knowing little about it should be able to access it with a browser and quickly
understand what it is and how to use it.
<li>
Don't hide the raw data!
The HTML view should simply be considered an easier-to-read representation of the data normally
rendered in JSON or some other format.
<li>
Limit your use of Javascript!
You can use it sparingly if you want to implement something simple like a pull-down menu to
simplify some debug task, but remember that your audience cares more about interacting with your
service programmatically using REST.
Remember that the HTML is just icing on the cake.
<li>
Don't use it to implement a Web 2.0 interface!
If you want a Web 2.0 UI, implement it separately ON TOP OF this REST interface.
The architecture is flexible enough that you could in theory pull in and use jQuery, React,
Angular, or any number of sophisticated Javascript UI frameworks. Resist the urge to do so.
</ul>
</div><!-- END: 6.30.1 - juneau-rest-server.HtmlDocAnnotation.UIvsDI -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HtmlDocAnnotation.Widgets' id='juneau-rest-server.HtmlDocAnnotation.Widgets'>6.30.2 - Widgets</a></h4>
<div class='topic'><!-- START: 6.30.2 - juneau-rest-server.HtmlDocAnnotation.Widgets -->
<p>
The {@link org.apache.juneau.rest.widget.Widget} class allows you to add arbitrary HTML, CSS, and Javascript
to HTML pages.
<br>They are registered in the following locations:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.rest.annotation.HtmlDoc#widgets() HtmlDoc(widgets)}
<li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#widgets(Class...)}
<li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#widgets(Widget...)}
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_widgets}
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(
widgets={
MyWidget.<jk>class</jk>
}
htmldoc=<ja>@HtmlDoc</ja>(
navlinks={
<js>"$W{MyWidget}"</js>
},
aside={
<js>"Check out this widget: $W{MyWidget}"</js>
}
)
)
</p>
<p>
The <l>Widget</l> class is composed of the following methods:
</p>
<ul class='javatree'>
<li class='jac'>{@link org.apache.juneau.rest.widget.Widget}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.widget.Widget#getHtml(RestRequest,RestResponse) getHtml(RestRequest,RestResponse)}
<li class='jm'>{@link org.apache.juneau.rest.widget.Widget#getStyle(RestRequest,RestResponse) getStyle(RestRequest,RestResponse)}
<li class='jm'>{@link org.apache.juneau.rest.widget.Widget#getScript(RestRequest,RestResponse) getScript(RestRequest,RestResponse)}
</ul>
</ul>
<p>
The HTML content returned by the {@link org.apache.juneau.rest.widget.Widget#getHtml(RestRequest,RestResponse) getHtml(RestRequest,RestResponse)}
method is added wherever the <js>"$W{...}"</js> variable is used.
</p>
<p>
The CSS returned by {@link org.apache.juneau.rest.widget.Widget#getScript(RestRequest,RestResponse) getScript(RestRequest,RestResponse)}
is added to the style section in the page header.
</p>
<p>
The Javascript returned by {@link org.apache.juneau.rest.widget.Widget#getScript(RestRequest,RestResponse) getScript(RestRequest,RestResponse)}
is added to the script section in the page header.
</p>
<p>
The following examples shows how to associate a widget with a REST method and then have it rendered in the links
and aside section of the page.
It shows an example of a widget that renders an image located in the <c>htdocs</c> static files
directory in your classpath (see {@link org.apache.juneau.rest.annotation.Rest#staticFiles() @Rest(staticFiles)}):
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyWidget <jk>extends</jk> Widget {
<ja>@Override</ja> <jc>/* Widget */</jc>
<jk>public</jk> String getHtml(RestRequest req) <jk>throws</jk> Exception {
UriResolver r = req.getUriResolver(); <jc>// API used for resolving URIs.</jc>
<jk>return</jk> <js>"&lt;img class='myimage' onclick='myalert(this)' src='"</js>+r.resolve(<js>"servlet:/htdocs/myimage.png"</js>)+<js>"'&gt;"</js>;
}
<ja>@Override</ja> <jc>/* Widget */</jc>
<jk>public</jk> String getScript(RestRequest req) <jk>throws</jk> Exception {
<jk>return</jk> <js>""</js>
+ <js>"\n function myalert(imageElement) {"</js>
+ <js>"\n alert('cool!');"</js>
+ <js>"\n }"</js>;
}
<ja>@Override</ja> <jc>/* Widget */</jc>
<jk>public</jk> String getStyle(RestRequest req) <jk>throws</jk> Exception {
<jk>return</jk> <js>""</js>
+ <js>"\n .myimage {"</js>
+ <js>"\n border: 10px solid red;"</js>
+ <js>"\n }"</js>;
}
}
</p>
<p>
The <l>Widget</l> class also defines the following two convenience methods for loading Javascript and CSS
files from the classpath or file system.
</p>
<ul class='javatree'>
<li class='jac'>{@link org.apache.juneau.rest.widget.Widget}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.widget.Widget#getClasspathResourceAsString(String) getClasspathResourceAsString(String)}
<li class='jm'>{@link org.apache.juneau.rest.widget.Widget#getClasspathResourceAsString(String,Locale) getClasspathResourceAsString(String,Locale)}
</ul>
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jk>public class</jk> MyWidget <jk>extends</jk> Widget {
...
<ja>@Override</ja> <jc>/* Widget */</jc>
<jk>public</jk> String getScript(RestRequest req) <jk>throws</jk> Exception {
<jk>return</jk> getClasspathResourceAsString(<js>"MyWidget.js"</js>);
}
<ja>@Override</ja> <jc>/* Widget */</jc>
<jk>public</jk> String getStyle(RestRequest req) <jk>throws</jk> Exception {
<jk>return</jk> getClasspathResourceAsString(<js>"MyWidget.css"</js>);
}
}
</p>
<ul class='seealso'>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_widgets}
</ul>
</div><!-- END: 6.30.2 - juneau-rest-server.HtmlDocAnnotation.Widgets -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets' id='juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets'>6.30.3 - Predefined Widgets</a></h4>
<div class='topic'><!-- START: 6.30.3 - juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets -->
<p>
The {@link org.apache.juneau.rest.widget} package contains predefined reusable widgets.
</p>
<ul class='javatree'>
<li class='jp'>{@link org.apache.juneau.rest.widget}
<ul>
<li class='jac'>{@link org.apache.juneau.rest.widget.Widget}
<ul>
<li class='jac'>{@link org.apache.juneau.rest.widget.MenuItemWidget}
<ul>
<li class='jc'>{@link org.apache.juneau.rest.widget.ContentTypeMenuItem}
<li class='jc'>{@link org.apache.juneau.rest.widget.QueryMenuItem}
<li class='jc'>{@link org.apache.juneau.rest.widget.ThemeMenuItem}
</ul>
<li class='jc'>{@link org.apache.juneau.rest.widget.PoweredByJuneau}
</ul>
<li class='jc'>{@link org.apache.juneau.rest.widget.Tooltip}
</ul>
</ul>
<h5 class='topic'>MenuItemWidget</h5>
<p>
{@link org.apache.juneau.rest.widget.MenuItemWidget} is an abstract class for rendering menu items with drop-downs.
It defines some simple CSS and Javascript for enabling drop-down menus in the nav section of the page (although
nothing keeps you from using it in an arbitrary location in the page).
</p>
<p>
The script specifies a <js>"menuClick(element)"</js> function that toggles the visibility of the next sibling of the element.
</p>
<p>
Subclasses implement the following two methods:
</p>
<ul class='javatree'>
<li class='jac'>{@link org.apache.juneau.rest.widget.MenuItemWidget}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.widget.MenuItemWidget#getLabel(RestRequest,RestResponse) getLabel(RestRequest,RestResponse)} - The menu item label.
<li class='jm'>{@link org.apache.juneau.rest.widget.MenuItemWidget#getContent(RestRequest,RestResponse) getContent(RestRequest,RestResponse)} - The menu item content.
</ul>
</ul>
<p>
For example, to render a link that brings up a simple dialog in a div tag:
</p>
<p class='bpcode w800'>
<ja>@Override</ja>
<jk>public</jk> String getLabel() {
<jk>return</jk> <js>"my-menu-item"</js>;
};
<ja>@Override</ja>
<jk>public</jk> Div getLabel() {
<jk>return</jk> Html5Builder.<jsm>div</jsm>(<js>"Surprise!"</js>).style(<js>"color:red"</js>);
};
</p>
<p>
The HTML content returned by the {@link org.apache.juneau.rest.widget.MenuItemWidget#getHtml(RestRequest,RestResponse) getHtml(RestRequest,RestResponse)} method is added where the <js>"$W{...}"</js> is referenced in the page.
</p>
<h5 class='topic'>ContentTypeMenuItem</h5>
<p>
{@link org.apache.juneau.rest.widget.ContentTypeMenuItem} is a predefined Widget that returns back a list of hyperlinks for rendering the contents of a page in a variety of content types.
</p>
<p>
The variable it resolves is <js>"$W{ContentTypeMenuItem}"</js>.
</p>
<p>
An example of this widget can be found in the <c>PetStoreResource</c> in the examples that provides a drop-down menu item for rendering all other supported content types in plain text:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(
name=<jsf>GET</jsf>,
path=<js>"/"</js>,
widgets={
ContentTypeMenuItem.<jk>class</jk>,
},
htmldoc=<ja>@HtmlDoc</ja>(
navlinks={
<js>"up: ..."</js>,
<js>"options: ..."</js>,
<js>"$W{QueryMenuItem}"</js>,
<js>"$W{ContentTypeMenuItem}"</js>,
<js>"$W{ThemeMenuItem}"</js>,
<js>"source: ..."</js>
}
)
)
<jk>public</jk> Collection&lt;Pet&gt; getPets() {
</p>
<p>
It renders the following popup-box:
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets.1.png'>
<h5 class='topic'>QueryMenuItem</h5>
<p>
{@link org.apache.juneau.rest.widget.QueryMenuItem} is a predefined Widget that returns a menu-item drop-down form for entering search/view/sort arguments.
</p>
<p>
The variable it resolves is <js>"$W{QueryMenuItem}"</js>.
</p>
<p>
This widget is designed to be used in conjunction with the {@link org.apache.juneau.rest.converters.Queryable} converter, although implementations
can process the query parameters themselves if they wish to do so by using the {@link org.apache.juneau.rest.RequestQuery#getSearchArgs()}
method to retrieve the arguments and process the data themselves.
</p>
<p>
An example of this widget can be found in the <c>PetStoreResource</c> in the examples that provides
search/view/sort capabilities against the collection of POJOs:
<p class='bpcode w800'>
<ja>@RestMethod</ja>(
name=<jsf>GET</jsf>,
path=<js>"/"</js>,
widgets={
QueryMenuItem.<jk>class</jk>,
},
htmldoc=<ja>@HtmlDoc</ja>(
navlinks={
<js>"up: ..."</js>,
<js>"options: ..."</js>,
<js>"$W{QueryMenuItem}"</js>,
<js>"$W{ContentTypeMenuItem}"</js>,
<js>"$W{ThemeMenuItem}"</js>,
<js>"source: ..."</js>
}
),
converters=Queryable.<jk>class</jk>
)
<jk>public</jk> Collection&lt;Pet&gt; getPets() {
</p>
<p>
It renders the following popup-box:
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets.2.png'>
<p>
Tooltips are provided by hovering over the field names.
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets.3.png'>
<p>
When submitted, the form submits a GET request against the current URI with special GET search API query parameters.
(e.g. <js>"?s=column1=Foo*&amp;v=column1,column2&amp;o=column1,column2-&amp;p=100&amp;l=100"</js>).
The {@link org.apache.juneau.rest.converters.Queryable} class knows how to perform these filters against collections of POJOs.
</p>
<h5 class='topic'>ThemeMenuItem</h5>
<p>
{@link org.apache.juneau.rest.widget.ThemeMenuItem} is a predefined Widget that returns back a list of hyperlinks for rendering the contents of a page in the various default styles.
</p>
<p>
The variable it resolves is <js>"$W{ThemeMenuItem}"</js>.
</p>
<p>
An example of this widget can be found in the <c>PetStoreResource</c> in the examples that provides
a drop-down menu item for rendering all other supported content types in plain text:
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(
name=<jsf>GET</jsf>,
path=<js>"/"</js>,
widgets={
ThemeMenuItem.<jk>class</jk>,
},
htmldoc=<ja>@HtmlDoc</ja>(
navlinks={
<js>"up: ..."</js>,
<js>"options: ..."</js>,
<js>"$W{QueryMenuItem}"</js>,
<js>"$W{ContentTypeMenuItem}"</js>,
<js>"$W{ThemeMenuItem}"</js>,
<js>"source: ..."</js>
}
)
)
<jk>public</jk> Collection&lt;Pet&gt; getPets() {
</p>
<h5 class='topic'>PoweredByJuneau</h5>
<p>
{@link org.apache.juneau.rest.widget.PoweredByJuneau} is a predefined Widget that places a powered-by-Juneau message on a page.
</p>
<p>
The variable it resolves is <js>"$W{PoweredByJuneau}"</js>.
</p>
<p>
It produces a simple Apache Juneau icon floating on the right.
Typically it's used in the footer of the page, as shown below in the <c>AddressBookResource</c> from the examples:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/addressBook"</js>,
widgets={
PoweredByJuneau.<jk>class</jk>
},
htmldoc=<ja>@HtmlDoc</ja>(
footer=<js>"$W{PoweredByJuneau}"</js>
)
</p>
<p>
It renders the following image:
</p>
<img class='bordered' src='doc-files/juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets.4.png'>
<h5 class='topic'>Tooltip</h5>
<p>
{@link org.apache.juneau.rest.widget.Tooltip} is a predefined template for adding tooltips to HTML5 bean constructs, typically in menu item widgets.
</p>
<p>
The following examples shows how tooltips can be added to a menu item widget.
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyFormMenuItem <jk>extends</jk> MenuItemWidget {
<ja>@Override</ja>
<jk>public</jk> String getLabel(RestRequest req) <jk>throws</jk> Exception {
<jk>return</jk> <js>"myform"</js>;
}
<ja>@Override</ja>
<jk>public</jk> Object getContent(RestRequest req) <jk>throws</jk> Exception {
<jk>return</jk> div(
<jsm>form</jsm>().id(<js>"form"</js>).action(<js>"servlet:/form"</js>).method(<jsf>POST</jsf>).children(
<jsm>table</jsm>(
<jsm>tr</jsm>(
<jsm>th</jsm>(<js>"Field 1:"</js>),
<jsm>td</jsm>(<jsm>input</jsm>().name(<js>"field1"</js>).type(<js>"text"</js>)),
<jsm>td</jsm>(<jk>new</jk> Tooltip(<js>"(?)"</js>, <js>"This is field #1!"</js>, br(), <js>"(e.g. '"</js>, code(<js>"Foo"</js>), <js>"')"</js>))
),
<jsm>tr</jsm>(
<jsm>th</jsm>(<js>"Field 2:"</js>),
<jsm>td</jsm>(<jsm>input</jsm>().name(<js>"field2"</js>).type(<js>"text"</js>)),
<jsm>td</jsm>(<jk>new</jk> Tooltip(<js>"(?)"</js>, <js>"This is field #2!"</js>, br(), <js>"(e.g. '"</js>, code(<js>"Bar"</js>), <js>"')"</js>))
)
)
)
);
}
}
</p>
</div><!-- END: 6.30.3 - juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HtmlDocAnnotation.UiCustomization' id='juneau-rest-server.HtmlDocAnnotation.UiCustomization'>6.30.4 - UI Customization</a></h4>
<div class='topic'><!-- START: 6.30.4 - juneau-rest-server.HtmlDocAnnotation.UiCustomization -->
<p>
The HTML views of POJOs can somewhat be considered a rudimentary User Interface.
In reality, a better term for them would be a Developer Interface as they're meant to be used
primarily by developers and not end users.
Despite that distinction, it is possible to 'brand' the HTML page to whatever you desire.
</p>
<p>
The sample root page below includes some default branding for Juneau and Apache:
</p>
<p class='bpcode w800'>
http://localhost:10000/helloWorld
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.UiCustomization.1.png'>
<p>
The Juneau REST framework does not provide specific branding support (i.e. there is no concept of a brand icon).
Instead, it just uses the existing open-ended API for defining branding via annotations on your REST classes.
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
...
<jc>// HTML-page specific settings</jc>
htmldoc=<ja>@HtmlDoc</ja>(
<jc>// Default page header contents.</jc>
header={
<js>"&lt;h1&gt;$R{resourceTitle}&lt;/h1&gt;"</js>, <jc>// Use @Rest(title)</jc>
<js>"&lt;h2&gt;$R{methodSummary,resourceDescription}&lt;/h2&gt;"</js>, <jc>// Use either @RestMethod(summary) or @Rest(description)</jc>
<js>"$C{REST/header}"</js> <jc>// Extra header HTML defined in external config file.</jc>
},
<jc>// Default stylesheet to use for the page.
// Can be overridden from external config file.
// Default is DevOps look-and-feel (aka Depression look-and-feel).</jc>
stylesheet=<js>"$C{REST/theme,servlet:/htdocs/themes/devops.css}"</js>,
<jc>// Default contents to add to the &lt;head&gt; section of the HTML page.
// Use it to add a favicon link to the page.</jc>
head={
<js>"&lt;link rel='icon' href='$U{$C{REST/favicon}}'/&gt;"</js>
},
<jc>// No default page footer contents.
// Can be overridden from external config file.</jc>
footer=<js>"$C{REST/footer}"</js>
),
<jc>// Optional external configuration file.</jc>
config=<js>"$S{juneau.configFile}"</js>,
<jc>// These are static files that are served up by the servlet under the specified sub-paths.
// For example, "/servletPath/htdocs/javadoc.css" resolves to the file "[servlet-package]/htdocs/javadoc.css"
// By default, we define static files through the external configuration file.</jc>
staticFiles=<js>"$C{REST/staticFiles}"</js>
)
<jk>public interface</jk> BasicRestConfig {}
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
...
htmldoc=<ja>@HtmlDoc</ja>(
htmldoc=<ja>@HtmlDoc</ja>(
<jc>// Basic page navigation links.</jc>
navlinks={
<js>"up: request:/.."</js>,
<js>"options: servlet:/?method=OPTIONS"</js>
}
)
),
...
)
<jk>public abstract class</jk> BasicRestServlet <jk>extends</jk> RestServlet <jk>implements</jk> BasicRestConfig {...}
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>
<jk>public abstract class</jk> BasicRestServletGroup <jk>extends</jk> BasicRestServlet {...}
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
htmldoc=<ja>@HtmlDoc</ja>(
widgets={
ContentTypeMenuItem.<jk>class</jk>,
ThemeMenuItem.<jk>class</jk>
},
navlinks={
<js>"options: ?method=OPTIONS"</js>,
<js>"$W{ContentTypeMenuItem}"</js>,
<js>"$W{ThemeMenuItem}"</js>,
<js>"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"</js>
},
aside={
<js>"&lt;div style='max-width:400px' class='text'&gt;"</js>,
<js>" &lt;p&gt;This is an example of a 'router' page that serves as a jumping-off point to child resources.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Resources can be nested arbitrarily deep through router pages.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Note the &lt;span class='link'&gt;options&lt;/span&gt; link provided that lets you see the generated swagger doc for this page.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Also note the &lt;span class='link'&gt;sources&lt;/span&gt; link on these pages to view the source code for the page.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;All content on pages in the UI are serialized POJOs. In this case, it's a serialized array of beans with 2 properties, 'name' and 'description'.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Other features (such as this aside) are added through annotations.&lt;/p&gt;"</js>,
<js>"&lt;/div&gt;"</js>
}
),
...
)
<jk>public class</jk> RootResources <jk>extends</jk> BasicRestServletGroup {...}
</p>
<p>
The default annotation values use {@link org.apache.juneau.config.vars.ConfigVar $C} variables to pull in values from an optional
external configuration file such as the one shown below:
</p>
<p class='bpcode w800'>
<cc>#=======================================================================================================================
# REST settings
#=======================================================================================================================</cc>
<cs>[REST]</cs>
<ck>staticFiles</ck> = <cv>htdocs:files/htdocs</cv>
<cc># Stylesheet to use for HTML views.</cc>
<ck>theme</ck> = <cv>servlet:/htdocs/themes/devops.css</cv>
<ck>headerIcon</ck> = <cv>servlet:/htdocs/images/juneau.png</cv>
<ck>headerLink</ck> = <cv>http://juneau.apache.org</cv>
<ck>footerIcon</ck> = <cv>servlet:/htdocs/images/asf.png</cv>
<ck>footerLink</ck> = <cv>http://www.apache.org</cv>
<ck>favicon</ck> = <cv>$C{REST/headerIcon}</cv>
<ck>header</ck> =
<cv>&lt;a href='$U{$C{REST/headerLink}}'&gt;</cv>
<cv>&lt;img src='$U{$C{REST/headerIcon}}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/&gt;</cv>
<cv>&lt;/a&gt;</cv>
<ck>footer</ck> =
<cv>&lt;a href='$U{$C{REST/footerLink}}'&gt;</cv>
<cv>&lt;img src='$U{$C{REST/footerIcon}}' style='float:right;padding-right:20px;height:32px'/&gt;</cv>
<cv>&lt;/a&gt;</cv>
</p>
<p>
The take-away here is that the "User Interface" is open-ended, lets you define pretty much anything you want through arbitrary HTML,
and allows you either hardcode your interface inside annotations or pull them in via string variables from other places such as
external config files.
</p>
<ul class='seealso'>
<li class='link'>{@doc juneau-microservice-jetty.UiCustomization}
</ul>
</div><!-- END: 6.30.4 - juneau-rest-server.HtmlDocAnnotation.UiCustomization -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HtmlDocAnnotation.Stylesheets' id='juneau-rest-server.HtmlDocAnnotation.Stylesheets'>6.30.5 - Stylesheets</a></h4>
<div class='topic'><!-- START: 6.30.5 - juneau-rest-server.HtmlDocAnnotation.Stylesheets -->
<p>
The sample root page renders in the default "devops" look-and-feel:
</p>
<p class='bpcode w800'>
http://localhost:10000
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.Stylesheets.0.png'>
<p>
The sample root page provides a dropdown widget to try out the other default look-and-feels:
</p>
<img class='bordered' src='doc-files/juneau-rest-server.Stylesheets.1.png'/>
<p>
For example, the "light" look-and-feel:
</p>
<p class='bpcode w800'>
http://localhost:10000/?stylesheet=styles%2Flight.css
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.Stylesheets.2.png'>
<p>
And the "dark" look-and-feel:
</p>
<p class='bpcode w800'>
http://localhost:10000/?stylesheet=styles%2Fdark.css
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.Stylesheets.3.png'>
<p>
The stylesheet URL is controlled by the {@link org.apache.juneau.html.annotation.HtmlDocConfig#stylesheet() @HtmlDocConfig(stylesheet)} annotation.
The {@link org.apache.juneau.rest.BasicRestServlet} class defines the stylesheet served up as a static file:
<p class='bpcode w800'>
<ja>@Rest</ja>(
htmldoc=<ja>@HtmlDoc</ja>(
stylesheet=<js>"$C{REST/stylesheet,servlet:/styles/devops.css}"</js>,
),
staticFiles={<js>"styles:styles"</js>}
)
<jk>public abstract class</jk> BasicRestServlet <jk>extends</jk> RestServlet {...}
</p>
<p>
The <js>"$C{REST/stylesheet,servlet:/styles/devops.css}"</js> variable says to use the URI defined
in your servlet's config file, if there is one, and to default to serving up the file
<c>org/apache/juneau/rest/styles/devops.css</c>.
</p>
<p>
To provide your own stylesheet, simply override the stylesheet attribute and point to a different
file:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
htmldoc=<ja>@HtmlDoc</ja>(
stylesheet=<js>"servlet:/my-styles/my-style.css}"</js>,
),
staticFiles={<js>"my-styles:my-styles"</js>}
)
<jk>public class</jk> MyResourceBaseClass <jk>extends</jk> BasicRestServlet {...}
</p>
<p>
You can try out different stylesheets by passing in a <c>stylesheet</c> attribute in the request
URL.
The example above show this in use.
</p>
<p>
In case you're curious about how the menu item works, it's defined via a widget:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
htmldoc=<ja>@HtmlDoc</ja>(
widgets={
PoweredByApache.<jk>class</jk>,
ContentTypeMenuItem.<jk>class</jk>,
StyleMenuItem.<jk>class</jk>
},
navlinks={
<js>"options: ?method=OPTIONS"</js>,
<js>"$W{ContentTypeMenuItem}"</js>,
<js>"$W{StyleMenuItem}"</js>,
<js>"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"</js>
},
)
<jk>public class</jk> RootResources <jk>extends</jk> BasicRestServletJenaGroup {...}
</p>
<p>
The <l>StyleMenuItem</l> is a widget that extends from {@link org.apache.juneau.rest.widget.MenuItemWidget}, a
specialized widget for creating pop-up menus.
In the case of <l>StyleMenuItem</l>, it's simply returning a list of links wrapped in a div tag:
</p>
<p class='bpcode w800'>
<jk>import static</jk> org.apache.juneau.dto.html5.HtmlBuilder.*;
<jk>public class</jk> StyleMenuItem <jk>extends</jk> MenuItemWidget {
<jk>private static final</jk> String[] <jsf>BUILT_IN_STYLES</jsf> = {<js>"devops"</js>, <js>"light"</js>, <js>"original"</js>, <js>"dark"</js>};
<ja>@Override</ja> <jc>/* Widget */</jc>
<jk>public</jk> String getLabel(RestRequest req) {
<jk>return</jk> <js>"styles"</js>;
}
<ja>@Override</ja> <jc>/* MenuItemWidget */</jc>
<jk>public</jk> Div getContent(RestRequest req) <jk>throws</jk> Exception {
Div div = <jsm>div</jsm>();
<jk>for</jk> (String s : <jsf>BUILT_IN_STYLES</jsf>) {
java.net.URI uri = req.getUri(<jk>true</jk>, <jk>new</jk> AMap&lt;String,String&gt;().append(<js>"stylesheet"</js>, <js>"styles/"</js>+s+<js>".css"</js>));
div.children(<jsm>a</jsm>(uri, s), <jsm>br</jsm>());
}
<jk>return</jk> div;
}
}
</p>
</div><!-- END: 6.30.5 - juneau-rest-server.HtmlDocAnnotation.Stylesheets -->
</div><!-- END: 6.30 - juneau-rest-server.HtmlDocAnnotation -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.DefaultHeaders' id='juneau-rest-server.DefaultHeaders'>6.31 - Default Headers</a></h3>
<div class='topic'><!-- START: 6.31 - juneau-rest-server.DefaultHeaders -->
<p>
The following annotations are provided for specifying default header values for requests and responses:
</p>
<ul class='javatree'>
<li class='ja'>
{@link org.apache.juneau.rest.annotation.Rest#reqHeaders() Rest(reqHeaders)}
<br>Defines default headers on request when the client doesn't specify them.
<li class='ja'>
{@link org.apache.juneau.rest.annotation.Rest#resHeaders() Rest(resHeaders)}
<br>Appends the specified headers if they weren't already set programmatically.
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Servlet with default headers</jc>
<ja>@Rest</ja>(
<jc>// Assume "text/json" Accept value when Accept not specified</jc>
reqHeaders={<js>"Accept: text/json"</js>},
<jc>// Add a version header attribute to all responses</jc>
resHeaders={<js>"X-Version: 1.0"</js>}
)
<jk>public</jk> MyRestServlet <jk>extends</jk> BasicRestServlet {
...
}
</p>
<p>
Default headers can also be specified programmatically by overriding the following methods:
</p>
<ul class='javatree'>
<li class='jac'>
{@link org.apache.juneau.rest.RestContextBuilder}
<ul>
<li class='jm'>
{@link org.apache.juneau.rest.RestContextBuilder#reqHeaders(String[])}
<li class='jm'>
{@link org.apache.juneau.rest.RestContextBuilder#resHeaders(String[])}
</ul>
</li>
</ul>
</div><!-- END: 6.31 - juneau-rest-server.DefaultHeaders -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.LoggingAndDebugging' id='juneau-rest-server.LoggingAndDebugging'>6.32 - Logging / Debugging</a></h3>
<div class='topic'><!-- START: 6.32 - juneau-rest-server.LoggingAndDebugging -->
<p>
The REST APIs provides support for fine-tuned control of logging for HTTP requests and responses.
</p>
<p>
The APIs involved are:
</p>
<ul class='javatree'>
<li class='ja'>
{@link org.apache.juneau.rest.annotation.Rest}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.annotation.Rest#logging() logging()} - Class-level logging configuration and rules.
<li class='jm'>{@link org.apache.juneau.rest.annotation.Rest#debug() debug()} - Enable debug mode.
</ul>
</li>
<li class='ja'>
{@link org.apache.juneau.rest.annotation.RestMethod}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.annotation.RestMethod#logging() logging()} - Class-level logging configuration.
<li class='jm'>{@link org.apache.juneau.rest.annotation.RestMethod#debug() debug()} - Enable debug mode.
</ul>
</li>
<li class='jc'>
{@link org.apache.juneau.rest.RestContext}
<ul>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_callLoggerConfig REST_callLoggerConfig} - Underlying configuration property for {@link org.apache.juneau.rest.annotation.Rest#logging() @Rest(logging)}.
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_debug REST_debug} - Underlying configuration property for {@link org.apache.juneau.rest.annotation.Rest#debug() @Rest(debug)}.
</ul>
</li>
<li class='ja'>
{@link org.apache.juneau.rest.annotation.Logging} - Annotation for {@link org.apache.juneau.rest.annotation.Rest#logging() @Rest(logging)} and {@link org.apache.juneau.rest.annotation.RestMethod#logging() @RestMethod(logging)}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.annotation.Logging#level() level()} - The logging level.
<li class='jm'>{@link org.apache.juneau.rest.annotation.Logging#rules() rules()} - The logging rules.
<li class='jm'>{@link org.apache.juneau.rest.annotation.Logging#useStackTraceHashing() useStackTraceHashing()} - Enables de-duplication of logged stack traces and replacement with hash IDs.
<li class='jm'>{@link org.apache.juneau.rest.annotation.Logging#stackTraceHashingTimeout() stackTraceHashingTimeout()} - Controls how frequently hashed stack traces are re-logged.
<li class='jm'>{@link org.apache.juneau.rest.annotation.Logging#disabled() disabled()} - Disables logging completely or per-request.
</ul>
</li>
<li class='ja'>
{@link org.apache.juneau.rest.annotation.LoggingRule} - Annotation for {@link org.apache.juneau.rest.annotation.Logging#rules() @Logging(rules)}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.annotation.LoggingRule#level() level()} - The logging level.
<li class='jm'>{@link org.apache.juneau.rest.annotation.LoggingRule#codes() codes()} - Status code patterns and ranges to match against.
<li class='jm'>{@link org.apache.juneau.rest.annotation.LoggingRule#exceptions() exceptions()} - Exception class names and patterns to match against.
<li class='jm'>{@link org.apache.juneau.rest.annotation.LoggingRule#debugOnly() debugOnly()} - Match only if debug is set on the request.
<li class='jm'>{@link org.apache.juneau.rest.annotation.LoggingRule#req() req()} - The level of request detail.
<li class='jm'>{@link org.apache.juneau.rest.annotation.LoggingRule#res() res()} - The level of response detail.
<li class='jm'>{@link org.apache.juneau.rest.annotation.LoggingRule#verbose() verbose()} - Shortcut for <jsf>LONG</jsf> request and response detail.
<li class='jm'>{@link org.apache.juneau.rest.annotation.LoggingRule#disabled() disabled()} - Disables logging completely or per-request.
</ul>
</li>
</ul>
<h5 class='topic'>Request/response details</h5>
<p>
The amount of detail on requests and responses is controlled via the {@link org.apache.juneau.rest.annotation.LoggingRule#req() @LoggingRule(req)}
and {@link org.apache.juneau.rest.annotation.LoggingRule#res() @LoggingRule(res)} annotations:
</p>
<ul>
<li><js>"short"</js> - Results in simple one-line log lines containing the HTTP method + url + response code.
<li><js>"medium"</js> - Also includes headers and body length information (if debug enabled).
<li><js>"large"</js> - Dumps the entire request/response bodies (if debug enabled).
</ul>
<p>
The following code shows the output produced using the <js>"short"</js> setting:
</p>
<p class='bpcode'>
<ja>@Rest</ja>(
logging=<ja>@Logging</ja>(
level=<js>"info"</js>,
rules={
<ja>@LoggingRule</ja>(codes<js>"500-"</js>, level=<js>"warning"</js>, req=<js>"short"</js>, res=<js>"short"</js>)
}
)
)
<jk>public static class</jk> MyRestClass {
<ja>@RestMethod</ja>(method=<js>"POST"</js>, path=<js>"foo"</js>)
<jk>public</jk> String myRestMethod(RestRequest req, RestResponse res) <jk>throws</jk> Exception {
res.setStatus(500);
res.setHeader(<js>"Foo"</js>, <js>"bar"</js>);
res.setException(<jk>new</jk> StringIndexOutOfBoundsException()); <jc>// Could also throw.</jc>
<jk>return</jk> req.getBody().asString();
}
}
<jk>static</jk> MockRest <jsf>MY_REST</jsf> = MockRest.<jsm>build</jsm>(MyRestClass.<jk>class</jk>, <jk>null</jk>);
<ja>@Test</ja>
<jk>public void</jk> test() <jk>throws</jk> Exception {
<jsf>MY_REST</jsf>.<jsm>post</jsm>(<js>"/foo?foo=bar"</js>, <js>"Foo"</js>).header(<js>"Foo"</js>, <js>"bar"</js>).execute().assertStatus(500);
}
</p>
<p>
The log output produced from the code above looks like this:
</p>
<p class='bpcode'>
WARNING: [500] HTTP POST /foo
java.lang.StringIndexOutOfBoundsException
at org.apache.juneau.rest.annotation.RestResourceLoggingTest$MyRestClass.myRestMethod(RestResourceLoggingTest.java:672)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
...
</p>
<p>
In comparison, using <js>"long"</js> formatting adds information about headers and body.
</p>
<p class='bpcode'>
<ja>@Rest</ja>(
debug=<js>"true"</js>, <jc>// Needed to capture request/response bodies for logging.</jc>
logging=<ja>@Logging</ja>(
level=<js>"info"</js>,
rules={
<ja>@LoggingRule</ja>(codes<js>"500-"</js>, level=<js>"warning"</js>, req=<js>"long"</js>, res=<js>"long"</js>)
}
)
)
</p>
<p>
Request/response bodies are only cached for logging if debugging is enabled via the <c class='snippet'>debug=<js>"true"</js></c> flag.
</p>
<p>
The log file now contains the following with shows the contents of the request and response bodies in both UTF-8
and spaced-hex:
<p>
<p class='bpcode'>
WARNING:
=== HTTP Request (incoming) ===================================================
[500] HTTP POST /foo?foo=bar
Request length: 3 bytes
Response code: 500
Response length: 3 bytes
Exec time: 20ms
---Request Headers---
Foo: bar
---Response Headers---
Foo: bar
Content-Type: text/plain
---Request Body UTF-8---
Foo
---Request Body Hex---
46 6F 6F
---Response Body UTF-8---
Foo
---Response Body Hex---
46 6F 6F
=== END ===================================================================
java.lang.StringIndexOutOfBoundsException
at org.apache.juneau.rest.annotation.RestResourceLoggingTest$MyRestClass.myRestMethod(RestResourceLoggingTest.java:672)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
...
</p>
<h5 class='topic'>Rule matching</h5>
<p>
Logging rules can match against status codes, exception class names, and the debug flag.
<br>The following shows various examples of logging rule matches.
</p>
<p class='bpcode'>
<ja>@Rest</ja>(
logging=<ja>@Logging</ja>(
rules={
<jc>// Individual status codes.</jc>
<ja>@LoggingRule</ja>(codes=<js>"300"</js>, ...)
<jc>// Ranges of status codes.</jc>
<ja>@LoggingRule</ja>(codes=<js>"400-499"</js>, ...)
<ja>@LoggingRule</ja>(codes=<js>">=500"</js>, ...)
<jc>// All codes.</jc>
<ja>@LoggingRule</ja>(codes=<js>"*"</js>, ...)
<jc>// Full class names of exceptions.</jc>
<ja>@LoggingRule</ja>(exceptions=<js>"java.lang.StringIndexOutOfBoundsException"</js>, ...)
<jc>// Exception class name patterns.</jc>
<ja>@LoggingRule</ja>(exceptions=<js>"String*Exception *Foo*Exception"</js>, ...)
<jc>// Match when debug enabled only.</jc>
<ja>@LoggingRule</ja>(codes=<js>"*"</js>, debugOnly=<js>"true"</js>, ...)
}
)
)
</p>
<p>
Rules are matched in the order listed on the annotation.
Rules on methods are matched before rules on classes.
Rules on child methods/classes are matched before rules on parent classes.
</p>
<h5 class='topic'>Debug mode</h5>
<p>
The debug mode setting allows HTTP request/response bodies to be cached in memory for logging purposes:
</p>
<p class='bpcode'>
<ja>@Rest</ja>(
debug=<js>"true"</js>
)
</p>
<p>
The possible values for the debug setting are (case-insensitive):
</p>
<ul>
<li><js>"true"</js> - Debug mode enabled.
<li><js>"false"</js> (default) - Debug mode disabled.
<li><js>"per-request"</js> - Debug mode is enabled only on requests containing an <c class='snippet'>X-Debug: true</c> header.
</ul>
<p>
Note that caching HTTP bodies in memory can produce significant performance penalties, so use the setting wisely.
<br>In particular, do not leave this setting enabled on production instances since it can easily lead to
denial-of-service attacks.
</p>
<p>
Servlet code can check the debug setting via the {@link org.apache.juneau.rest.RestRequest#isDebug()} method allowing it to be used
for custom purposes.
</p>
<p>
Debug mode can also be enabled on a request by calling the {@link org.apache.juneau.rest.RestRequest#setDebug(Boolean)} or
{@link org.apache.juneau.rest.RestResponse#setDebug(Boolean)} methods. Note however that you must be sure not to have already consumed
the request or started writing the response before calling this method.
</p>
<h5 class='topic'>No-trace (disabled) mode</h5>
<p>
The {@link org.apache.juneau.rest.annotation.Logging#disabled() @Logging(disabled)} and {@link org.apache.juneau.rest.annotation.LoggingRule#disabled() @LoggingRule(disabled)} annotations
can be used to disable logging entirely or on a per-request basis:
</p>
<p class='bpcode'>
<ja>@Rest</ja>(
logging=<ja>@Logging</ja>(
disabled=<js>"true"</js>
rules={
<ja>@LoggingRule</ja>(
codes<js>"500-"</js>,
disabled=<js>"false"</js>
)
}
)
)
</p>
<p>
The possible values for the disabled setting are (case-insensitive):
</p>
<ul>
<li><js>"true"</js> - Logging disabled.
<li><js>"false"</js> (default) - Logging not disabled.
<li><js>"per-request"</js> - Logging is disabled only on requests containing a <c class='snippet'>X-NoTrace: true</c> header.
</ul>
<p>
Disabled logging is particularly useful when running testcases that are expected to throw exceptions or cause
other errors and you don't want these errors logged.
</p>
<p>
Disabled logging can also be set on a request by calling the {@link org.apache.juneau.rest.RestRequest#setNoTrace(Boolean)} or
{@link org.apache.juneau.rest.RestResponse#setNoTrace(Boolean)} methods.
</p>
<h5 class='topic'>Stacktrace hashing</h5>
<p>
The {@link org.apache.juneau.rest.annotation.Logging#useStackTraceHashing() @Logging(useStackTraceHashing)} setting can be used to eliminate duplicate stacktraces
in your log file by logging them once and then logging identifying hash IDs.
</p>
<p>
In the example below, we're causing two exceptions but only logging the first one:
</p>
<p class='bpcode'>
<ja>@Rest</ja>(
logging=<ja>@Logging</ja>(
useStackTraceHashing=<js>"true"</js>,
rules={
<ja>@LoggingRule</ja>(codes<js>">=500"</js>, level=<js>"warning"</js>, req=<js>"short"</js>, res=<js>"short"</js>)
}
)
)
<jk>public static class</jk> MyRestClass {
<ja>@RestMethod</ja>(method=<js>"POST"</js>, path=<js>"foo"</js>)
<jk>public</jk> String myRestMethod(RestRequest req, RestResponse res) <jk>throws</jk> Exception {
res.setHeader(<js>"Foo"</js>, <js>"bar"</js>);
// Equivalent to throwing an exception.
res.setStatus(500);
res.setException(<jk>new</jk> StringIndexOutOfBoundsException());
<jk>return</jk> req.getBody().asString();
}
}
<jk>static</jk> MockRest <jsf>MY_REST</jsf> = MockRest.<jsm>build</jsm>(MyRestClass.<jk>class</jk>, <jk>null</jk>);
<ja>@Test</ja>
<jk>public void</jk> test() <jk>throws</jk> Exception {
<jsf>MY_REST</jsf>.<jsm>post</jsm>(<js>"/foo?foo=bar"</js>, <js>"Foo"</js>).header(<js>"Foo"</js>, <js>"bar"</js>).execute().assertStatus(500);
<jsf>MY_REST</jsf>.<jsm>post</jsm>(<js>"/foo?foo=bar"</js>, <js>"Foo"</js>).header(<js>"Foo"</js>, <js>"bar"</js>).execute().assertStatus(500);
}
</p>
<p>
The log file will show a 4 byte hash ID <js>"9b85cc96"</js> and count <js>".1"</js> as shown below:
</p>
<p class='bpcode'>
Jul 11, 2019 3:38:48 PM org.apache.juneau.rest.BasicRestCallLogger log
WARNING: [500,9b85cc96.1] HTTP POST /foo
java.lang.StringIndexOutOfBoundsException
at org.apache.juneau.rest.annotation.RestResourceLoggingTest$MyRestClass.myRestMethod(RestResourceLoggingTest.java:671)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
...
WARNING: [500,9b85cc96.2] HTTP POST /foo
</p>
<p>
The {@link org.apache.juneau.rest.annotation.Logging#stackTraceHashingTimeout() @Logging(stackTraceHashingTimeout)} setting can be used to periodically log the stacktrace
to the log file again.
</p>
</div><!-- END: 6.32 - juneau-rest-server.LoggingAndDebugging -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HttpStatusCodes' id='juneau-rest-server.HttpStatusCodes'>6.33 - HTTP Status Codes</a></h3>
<div class='topic'><!-- START: 6.33 - juneau-rest-server.HttpStatusCodes -->
<p>
By default, a 200 (OK) status is automatically set as the HTTP status when a Java method executes
successfully.
</p>
<p>
Other status codes can be generated by throwing a {@link org.apache.juneau.rest.RestException} with a
specific HTTP status code, or calling {@link javax.servlet.http.HttpServletResponse#setStatus(int)}.
</p>
<p>
Non-OK (200) status codes are automatically triggered by the following conditions:
</p>
<table class='styled w800'>
<tr>
<th><l>Code</l></th>
<th><l>Description</l></th>
<th><l>When triggered</l></th>
</tr>
<tr>
<td><l>401</l></td>
<td>Unauthorized</td>
<td>A {@link org.apache.juneau.rest.RestGuard guard} prevented the method from being executed</td>
</tr>
<tr>
<td><l>404</l></td>
<td>Not Found</td>
<td>No matching path patterns were found on any method</td>
</tr>
<tr>
<td><l>405</l></td>
<td>Method Not Implemented</td>
<td>A path pattern matched, but no Java methods were found for the HTTP method</td>
</tr>
<tr>
<td><l>406</l></td>
<td>Not Acceptable</td>
<td>
A path pattern matched, but no Java methods were found with a matching serializer for the
<l>Accept</l> on the request
</td>
</tr>
<tr>
<td><l>412</l></td>
<td>Precondition Failed</td>
<td>
A path pattern matched, but no Java methods were found that were not rejected by
{@link org.apache.juneau.rest.RestMatcher matchers}
</td>
</tr>
<tr>
<td><l>415</l></td>
<td>Unsupported Media Type</td>
<td>
A path pattern matched, but no Java methods were found with a matching parser for the
<l>Content-Type</l> on the request
</td>
</tr>
<tr>
<td><l>500</l></td>
<td>Internal Server Error</td>
<td>The Java method threw an exception other than {@link org.apache.juneau.rest.RestException}</td>
</tr>
</table>
</div><!-- END: 6.33 - juneau-rest-server.HttpStatusCodes -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.OverloadingHttpMethods' id='juneau-rest-server.OverloadingHttpMethods'>6.34 - Overloading HTTP Methods</a></h3>
<div class='topic'><!-- START: 6.34 - juneau-rest-server.OverloadingHttpMethods -->
<p>
Through the use of the built-in <l>"method"</l> GET parameter, you can implement requests beyond the basic
REST http method types.
</p>
<p>
For example, the URL <l>"/sample/foo?method=BAR"</l> will cause the following method to be invoked...
</p>
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<js>"BAR"</js>)
<jk>public void</jk> doBar(RestRequest req, RestResponse res) {
<jc>// Handle BAR requests</jc>
}
</p>
<p>
To support overloaded methods, the {@link org.apache.juneau.rest.annotation.Rest#allowedMethodParams() @Rest(allowedMethodParams)}
setting must be enabled on your servlet.
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
<jc>// Allow &amp;method parameter on BAR requests</jc>
allowedMethodParams=<js>"BAR"</js>
)
</p>
</div><!-- END: 6.34 - juneau-rest-server.OverloadingHttpMethods -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.BuiltInParameters' id='juneau-rest-server.BuiltInParameters'>6.35 - Built-in Parameters</a></h3>
<div class='topic'><!-- START: 6.35 - juneau-rest-server.BuiltInParameters -->
<p>
The following URL parameters have special meaning and can be passed in through the URL of the request:
</p>
<table class='styled w800'>
<tr>
<th><l>GET Parameter</l></th>
<th><l>Description</l></th>
</tr>
<tr>
<td class='code'>&amp;plainText=true</td>
<td>
Response will always be <l>Content-Type: text/plain</l> and the returned text will be human-readable
({@link org.apache.juneau.serializer.WriterSerializer#WSERIALIZER_useWhitespace WSERIALIZER_useWhitespace} enabled).
<br>Useful for debugging.
</td>
</tr>
<tr>
<td class='code'>&amp;debug=true</td>
<td>
Request body content will be dumped to log file.
</td>
</tr>
<tr>
<td class='code'>&amp;noTrace=true</td>
<td>
If an error occurs, don't log the stack trace to the log file.
<br>Useful for automated JUnit testcases testing error states to prevent the log file from filling
up with useless stack traces.
</td>
</tr>
<tr>
<td class='code'>&amp;method=X</td>
<td>
Overload the HTTP method as a GET parameter (e.g <l>"POST"</l>).
<br>Must be enabled via {@link org.apache.juneau.rest.annotation.Rest#allowedMethodParams() @Rest(allowedMethodParams)} setting.
</td>
</tr>
<tr>
<td class='code'>&amp;Header-Name=headerValue</td>
<td>
Specify a header value as a GET parameter.
<br>Must be enabled via {@link org.apache.juneau.rest.annotation.Rest#allowedHeaderParams() @Rest(allowedHeaderParams)} setting.
</td>
</tr>
<tr>
<td class='code'>&amp;body=X</td>
<td>
Pass in the HTTP body content on PUT and POST methods as a UON-encoded GET parameter.
<br>Must be enabled via {@link org.apache.juneau.rest.annotation.Rest#allowBodyParam() @Rest(allowBodyParam)} setting.
</td>
</tr>
<tr>
<td class='code'>&amp;x-response-headers=X</td>
<td>
Pass-through headers to the response.
<br>Must be a UON-encoded map of key-value pairs.
</td>
</tr>
</table>
</div><!-- END: 6.35 - juneau-rest-server.BuiltInParameters -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.CustomSerializersAndParsers' id='juneau-rest-server.CustomSerializersAndParsers'>6.36 - Custom Serializers and Parsers</a></h3>
<div class='topic'><!-- START: 6.36 - juneau-rest-server.CustomSerializersAndParsers -->
<p>
A very easy-to-use API is provided for defining your own serializers and parsers at both the servlet and
method levels.
</p>
<p>
The following examples show a custom serializer and parser defined at the method level.
It's the <l>PhotosResource</l> class pulled from the Samples project.
It shows an example of defining a serializer and parser to handle images.
</p>
<p class='bpcode w800'>
<jd>/**
* Sample resource that allows images to be uploaded and retrieved.
*/</jd>
<ja>@Rest</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>(
navlinks={
<js>"options: ?method=OPTIONS"</js>
}
)
)
<jk>public class</jk> PhotosResource <jk>extends</jk> BasicRestServlet {
<jc>// Our cache of photos</jc>
<jk>private</jk> Map&lt;Integer,Photo&gt; photos = <jk>new</jk> TreeMap&lt;Integer,Photo&gt;();
<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=<jsf>GET</jsf>, 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=<jsf>GET</jsf>, path=<js>"/{id}"</js>, serializers=ImageSerializer.<jk>class</jk>)
<jk>public</jk> BufferedImage getPhoto(RestRequest req, <ja>@Path</ja>(<js>"id"</js>) 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=<jsf>PUT</jsf>, path=<js>"/{id}"</js>, parsers=ImageParser.<jk>class</jk>)
<jk>public</jk> String addPhoto(RestRequest req, <ja>@Path</ja>(<js>"id"</js>) <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=<jsf>POST</jsf>, 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=<jsf>DELETE</jsf>, path=<js>"/{id}"</js>)
<jk>public</jk> String deletePhoto(RestRequest req, <ja>@Path</ja>(<js>"id"</js>) <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=<jsf>OPTIONS</jsf>, 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> <jc>/* Serializer */</jc>
<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> <jc>/* Parser */</jc>
<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><!-- END: 6.36 - juneau-rest-server.CustomSerializersAndParsers -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.UsingWithOsgi' id='juneau-rest-server.UsingWithOsgi'>6.37 - Using with OSGi</a></h3>
<div class='topic'><!-- START: 6.37 - juneau-rest-server.UsingWithOsgi -->
<p>
Since REST servlets are basically just <l>HttpServlets</l>, incorporating them into an OSGi environment
is pretty straightforward.
</p>
<p>
The following code shows how to register your REST servlets in an OSGi <l>Activator</l>:
</p>
<p class='bpcode w800'>
<jk>package</jk> org.apache.juneau.examples.rest;
<jk>import</jk> org.osgi.framework.*;
<jk>import</jk> org.osgi.service.http.*;
<jk>import</jk> org.osgi.util.tracker.*;
<jk>import</jk> org.apache.juneau.rest.samples.*;
<jd>/**
* Activator class used when running samples as a bundle in an OSGi environment.
*/</jd>
<jk>public class</jk> Activator <jk>implements</jk> BundleActivator, ServiceTrackerCustomizer {
<jk>private</jk> ServiceTracker <jf>httpServiceTracker</jf>;
<jk>private</jk> BundleContext <jf>context</jf>;
<ja>@Override</ja> <jc>/* BundleActivator */</jc>
<jk>public void</jk> start(BundleContext context) <jk>throws</jk> Exception {
<jk>this</jk>.<jf>context</jf> = context;
<jf>httpServiceTracker</jf> = <jk>new</jk> ServiceTracker(context, HttpService.<jk>class</jk>.getName(), <jk>this</jk>);
<jf>httpServiceTracker</jf>.open();
}
<ja>@Override</ja> <jc>/* BundleActivator */</jc>
<jk>public void</jk> stop(BundleContext context) <jk>throws</jk> Exception {
<jf>httpServiceTracker</jf>.close();
}
<ja>@Override</ja> <jc>/* ServiceTrackerCustomizer */</jc>
<jk>public</jk> Object addingService(ServiceReference reference) {
Object service = <jf>context</jf>.getService(reference);
<jk>if</jk> (service <jk>instanceof</jk> HttpService) {
HttpService s = (HttpService)service;
<jk>try</jk> {
s.registerServlet(<js>"/sample"</js>, <jk>new</jk> MyRestServlet(), <jk>null</jk>, <jk>null</jk>);
} <jk>catch</jk> (Exception e) {
<jk>throw new</jk> RuntimeException(e);
}
}
<jk>return</jk> service;
}
<ja>@Override</ja> <jc>/* ServiceTrackerCustomizer */</jc>
<jk>public void</jk> modifiedService(ServiceReference reference, Object service) {
}
<ja>@Override</ja> <jc>/* ServiceTrackerCustomizer */</jc>
<jk>public void</jk> removedService(ServiceReference reference, Object service) {
}
}
</p>
</div><!-- END: 6.37 - juneau-rest-server.UsingWithOsgi -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.Injection' id='juneau-rest-server.Injection'>6.38 - Using with Spring and Injection frameworks</a></h3>
<div class='topic'><!-- START: 6.38 - juneau-rest-server.Injection -->
<p>
The Juneau REST server API is compatible with dependency injection frameworks such as Spring.
</p>
<p>
The important class is the {@link org.apache.juneau.rest.RestResourceResolver} class which is used
to resolve child servlet/resource implementation classes inside parent contexts.
In other words, it's used for resolving {@link org.apache.juneau.rest.annotation.Rest#children() @Rest(children)} instances.
</p>
<p>
The general approach starts with defining a resolver that uses the Spring application context for resolution:
</p>
<p class='bpcode w800'>
<jk>public class</jk> SpringRestResourceResolver <jk>extends</jk> RestResourceResolverSimple {
<jk>private final</jk> ApplicationContext <jf>appContext</jf>;
<jk>public</jk> SpringRestResourceResolver(ApplicationContext appContext) {
<jk>this</jk>.<jf>appContext</jf> = appContext;
}
<jk>@Override</jk> <jc>/* RestResourceResolverSimple */</jc>
<jk>public</jk> Object resolve(Class&lt;?&gt; resourceType, RestContextBuilder builder) <jk>throws</jk> Exception {
Object resource = <jf>appContext.</jf>getBean(type);
<jc>// If Spring can't resolve it, use default resolution (just look for no-arg constructor).</jc>
<jk>if</jk> (resource == <jk>null</jk>) {
resource = <jk>super</jk>.resolve(resourceType, builder);
}
<jk>return</jk> resource;
}
}
</p>
<p>
Next, define the Spring configuration to return our resolver:
</p>
<p class='bpcode w800'>
<ja>@Configuration</ja>
<jk>public abstract class</jk> MySpringConfiguration {
<ja>@Autowired</ja>
<jk>private static</jk> ApplicationContext <jsf>appContext</jsf>;
<jk>public static</jk> ApplicationContext getAppContext(){
<jk>return</jk> <jsf>appContext</jsf>;
}
<jk>public static void</jk> setAppContext(ApplicationContext appContext){
MySpringConfiguration.<jsf>appContext</jsf> = appContext;
}
<ja>@Bean</ja>
<jk>public</jk> RestResourceResolver restResourceResolver(ApplicationContext appContext) {
<jk>return new</jk> SpringRestResourceResolver(appContext);
}
}
</p>
<p>
Finally, define your <c>Root</c> resource with a constructor that takes in our rest resource resolver and
sets it on the config object during initialization.
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
children={
...
}
)
<jk>public class</jk> Root <jk>extends</jk> BasicRestServletGroup {
<jk>private final</jk> RestResourceResolver <jf>resolver</jf>;
<ja>@Inject</ja>
<jk>public</jk> Root(RestResourceResolver resolver) {
<jk>this</jk>.<jf>resolver</jf> = resolver;
}
<ja>@RestHook</ja>(<jsf>INIT</jsf>)
<jk>public void</jk> initSpring(RestContextBuilder builder) <jk>throws</jk> Exception {
builder.setResourceResolver(<jf>resolver</jf>);
}
}
</p>
<p>
After that, just define constructors on your child resources to take in Spring beans:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/child"</js>
)
<jk>public class</jk> MyChildResource <jk>extends</jk> BasicRestServlet {
<jk>private final</jk> Bean1 <jf>bean1</jf>;
<jk>private final</jk> Bean2 <jf>bean2</jf>;
<jk>private final</jk> Bean3 <jf>bean3</jf>;
<ja>@Inject</ja>
<jk>public</jk> MyChildResource(Bean1 bean1, Bean2 bean2, Bean3 bean3) {
<jk>this</jk>.<jf>bean1</jf> = bean1;
<jk>this</jk>.<jf>bean2</jf> = bean2;
<jk>this</jk>.<jf>bean3</jf> = bean3;
}
</p>
</div><!-- END: 6.38 - juneau-rest-server.Injection -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.HTTP2' id='juneau-rest-server.HTTP2'>6.39 - Using HTTP/2 features</a></h3>
<div class='topic'><!-- START: 6.39 - juneau-rest-server.HTTP2 -->
<p>
Juneau is built as a veneer on top of the Servlet API, allowing you to use low-level Servlet APIs
whenever needed.
This allows you to take advantage of the newest HTTP/2 features implemented in the new Servlet 4.0
specification.
</p>
</div><!-- END: 6.39 - juneau-rest-server.HTTP2 -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server.OtherNotes' id='juneau-rest-server.OtherNotes'>6.40 - Other Notes</a></h3>
<div class='topic'><!-- START: 6.40 - juneau-rest-server.OtherNotes -->
<ul class='spaced-list'>
<li>
Subclasses can use either {@link javax.servlet.http.HttpServlet#init(ServletConfig)}
or {@link javax.servlet.http.HttpServlet#init()} for initialization just like any other servlet.
<li>
The <l>X-Response-Headers</l> header can be used to pass through header values into the response.
The value should be a URL-encoded map of key-value pairs.
For example, to add a <l>"Refresh: 1"</l> header to the response to auto-refresh a page, the following
parameter can be specified: <l>"/sample?X-Response-Headers={Refresh=1}"</l>
</ul>
</div><!-- END: 6.40 - juneau-rest-server.OtherNotes -->
</div><!-- END: 6 - juneau-rest-server -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server-jaxrs' id='juneau-rest-server-jaxrs'>7 - juneau-rest-server-jaxrs</a></h2>
<div class='topic'><!-- START: 7 - juneau-rest-server-jaxrs -->
<h5 class='figure'>Maven Dependency</h5>
<p class='bpcode w500'>
<xt>&lt;dependency&gt;</xt>
<xt>&lt;groupId&gt;</xt>org.apache.juneau<xt>&lt;/groupId&gt;</xt>
<xt>&lt;artifactId&gt;</xt>juneau-rest-server-jaxrs<xt>&lt;/artifactId&gt;</xt>
<xt>&lt;version&gt;</xt>{@property juneauVersion}<xt>&lt;/version&gt;</xt>
<xt>&lt;/dependency&gt;</xt>
</p>
<h5 class='figure'>Java Library</h5>
<p class='bpcode w500'>
juneau-rest-server-jaxrs-{@property juneauVersion}.jar
</p>
<h5 class='figure'>OSGi Module</h5>
<p class='bpcode w500'>
org.apache.juneau.rest.server_{@property juneauVersion}.jar
</p>
<p>
The <c>juneau-rest-server-jaxrs</c> library provides an implementation of a <c>MessageBodyReader</c>
and <c>MessageBodyWriter</c> to allow any of the Juneau serializers and parsers to be used in a
JAX/RS environment.
</p>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server-jaxrs.BaseProvider' id='juneau-rest-server-jaxrs.BaseProvider'>7.1 - Juneau JAX-RS Provider</a></h3>
<div class='topic'><!-- START: 7.1 - juneau-rest-server-jaxrs.BaseProvider -->
<p>
The Juneau framework contains the <l>juneau-rest-server-jaxrs</l> bundle for performing simple
integration of Juneau serializers and parsers in JAX-RS compliant environments.
</p>
<p>
It should be noted that although some of the functionality of the Juneau Server API is provided through the JAX-RS
integration components, it is not nearly as flexible as using the {@link org.apache.juneau.rest.RestServlet} class directly.
</p>
<p>
What you can do with the Juneau JAX-RS provider classes:
</p>
<ul class='spaced-list'>
<li>
Use existing Juneau serializers and parsers for converting streams to POJOs and vis-versa.
<li>
Use annotations to specify filters and properties using the {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod}
and {@link org.apache.juneau.rest.jaxrs.JuneauProvider} annotations.
</ul>
<p>
What you can't do with the Juneau JAX-RS provider classes:
</p>
<ul class='spaced-list'>
<li>
Specify or override serializers/parsers at the Java class and method levels.
<br>JAX-RS does not provide the capability to use different providers for the same media types
at the class or method levels.
<li>
Specify or override filters and properties at the Java class level.
<li>
Default stylesheets for the {@link org.apache.juneau.html.HtmlDocSerializer} class.
<br>It will produce HTML, but it won't contain any styles applied.
<li>
The ability to specify HTTP method, headers, and content using GET parameters.
<br>These make debugging REST interfaces using only a browser possible.
<li>
Class or method level encoding.
<li>
Class or method level guards.
<li>
Class or method level converters.
</ul>
<p>
The Juneau JAX-RS provider API consists of the following classes:
</p>
<ul class='javatree'>
<li class='jc'>
{@link org.apache.juneau.rest.jaxrs.BaseProvider} - The base provider class that implements the JAX-RS
<c>MessageBodyReader</c> and <c>MessageBodyWriter</c> interfaces.
<li class='jc'>
{@link org.apache.juneau.rest.jaxrs.JuneauProvider} - Annotation that is applied to subclasses of <c>BaseProvider</c>
to specify the serializers/parsers associated with a provider, and optionally filters and properties to
apply to those serializers and parsers.
<li class='jc'>
{@link org.apache.juneau.rest.jaxrs.BasicProvider} - A default provider that provides the same level
of media type support as the {@link org.apache.juneau.rest.BasicRestServlet} class.
</ul>
<p>
For the most part, when using these components, you'll either use the existing <l>BasicProvider</l>,
or define your own by subclassing <l>BaseProvider</l>.
</p>
</div><!-- END: 7.1 - juneau-rest-server-jaxrs.BaseProvider -->
</div><!-- END: 7 - juneau-rest-server-jaxrs -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server-springboot' id='juneau-rest-server-springboot'>8 - juneau-rest-server-springboot</a></h2>
<div class='topic'><!-- START: 8 - juneau-rest-server-springboot -->
<h5 class='figure'>Maven Dependency</h5>
<p class='bpcode w500'>
<xt>&lt;dependency&gt;</xt>
<xt>&lt;groupId&gt;</xt>org.apache.juneau<xt>&lt;/groupId&gt;</xt>
<xt>&lt;artifactId&gt;</xt>juneau-rest-server-springboot<xt>&lt;/artifactId&gt;</xt>
<xt>&lt;version&gt;</xt>{@property juneauVersion}<xt>&lt;/version&gt;</xt>
<xt>&lt;/dependency&gt;</xt>
</p>
<h5 class='figure'>Java Library</h5>
<p class='bpcode w500'>
juneau-rest-server-springboot-{@property juneauVersion}.jar
</p>
<h5 class='figure'>OSGi Module</h5>
<p class='bpcode w500'>
org.apache.juneau.rest.server.springboot_{@property juneauVersion}.jar
</p>
<p>
The <c>juneau-rest-server-springboot</c> library provides classes to make it easy to integrate
Juneau REST resources with Spring and Spring Boot.
</p>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server-springboot.Overview' id='juneau-rest-server-springboot.Overview'>8.1 - Overview</a></h3>
<div class='topic'><!-- START: 8.1 - juneau-rest-server-springboot.Overview -->
<p>
The Juneau integration component for Spring Boot consists of the following classes:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.rest.springboot.annotation.JuneauRestRoot}
<li class='jc'>{@link org.apache.juneau.rest.springboot.JuneauRestInitializer}
<li class='jc'>{@link org.apache.juneau.rest.springboot.SpringRestResourceResolver}
</ul>
<p>
A typical Spring Boot application can use the {@link org.apache.juneau.rest.springboot.JuneauRestInitializer} to find
and register Juneau REST servlets via the {@link org.apache.juneau.rest.springboot.annotation.JuneauRestRoot} annotation.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@SpringBootApplication</ja>
<ja>@Controller</ja>
<jk>public class</jk> App {
<jk>public static void</jk> main(String[] args) {
<jk>new</jk> SpringApplicationBuilder(App.<jk>class</jk>)
.initializers(<jk>new</jk> JuneauRestInitializer(App.<jk>class</jk>))
.run(args);
}
<jd>/** Our root resource */</jd>
<ja>@Bean @JuneauRestRoot</ja>
<jk>public</jk> RootResource getRootResource() {
<jk>return new</jk> RootResource(); <jc>// A subclass of RestServlet.</jc>
}
}
</p>
<p>
The initializer will search for Spring beans annotated with the <ja>@JuneauRestRoot</ja> annotation identifying it
as a top-level servlet to be deployed in the Spring Boot web container.
</p>
<p>
Another option is to use the <ja>@JuneauRestRoot</ja> annotation on your Spring Boot source class like so:
</p>
<p class='bpcode w800'>
<ja>@SpringBootApplication</ja>
<ja>@Controller</ja>
<ja>@JuneauRestRoot</ja>(servlets=RootResource.<jk>class</jk>)
<jk>public class</jk> App {
<jk>public static void</jk> main(String[] args) {
<jk>new</jk> SpringApplicationBuilder(App.<jk>class</jk>)
.initializers(<jk>new</jk> JuneauRestInitializer(App.<jk>class</jk>))
.run(args);
}
}
</p>
<p>
The root servlets are given an instance of {@link org.apache.juneau.rest.springboot.SpringRestResourceResolver} which allows
for child resources to be defined as injectable Spring beans.
</p>
<p>
The {@doc juneau-examples-rest-springboot} section describes how the Examples REST application is deployed
using Spring Boot and quickly deployable as an online application using Heroku.
</p>
</div><!-- END: 8.1 - juneau-rest-server-springboot.Overview -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-server-springboot.ChildResources' id='juneau-rest-server-springboot.ChildResources'>8.2 - Child Resources</a></h3>
<div class='topic'><!-- START: 8.2 - juneau-rest-server-springboot.ChildResources -->
<p>
When using the <ja>@JuneauRestRoot</ja> annotation, servlet are given an instance of {@link org.apache.juneau.rest.springboot.SpringRestResourceResolver}.
The resource resolver gets passed down through the children hierarchy, allowing child resources to be defined as injectable Spring beans.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Configuration</ja>
<jk>public class</jk> AppConfiguration {
<ja>@Bean @JuneauRestRoot</ja>
<jk>public</jk> RootResource getRootResource() {
<jk>return new</jk> RootResource();
}
<ja>@Bean</ja>
<jk>public</jk> ChildResource getChildResource() {
<jk>return new</jk> ChildResource();
}
<ja>@Bean</ja>
<jk>public</jk> GrandChildResource getGrandChildResource() {
<jk>return new</jk> GrandChildResource();
}
}
</p>
<p>
The root resource class must extend from <c>HttpServlet</c> so that it can be registered as a normal
servlet using the Spring Boot architecture. The {@link org.apache.juneau.rest.BasicRestServletGroup} class is our router class
that extends from <c>HttpServlet</c>:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/root"</js>,
children={
ChildResource.<jk>class</jk>
}
)
<jk>public class</jk> RootResource <jk>extends</jk> BasicRestServletGroup {
<jc>// No code needed.</jc>
}
</p>
<p>
Because Spring Boot will automatically register any beans that extend from <c>HttpServlet</c>, we
DON'T want the child classes to extend from <c>HttpServlet</c>. Instead, we extend from
{@link org.apache.juneau.rest.BasicRestGroup} and {@link org.apache.juneau.rest.BasicRest} instead:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/child"</js>,
children={
GrandChildResource.<jk>class</jk>
}
)
<jk>public class</jk> ChildResource <jk>extends</jk> BasicRestGroup {
<jc>// No code needed.</jc>
}
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/grandchild"</js>
)
<jk>public class</jk> GrandChildResource <jk>extends</jk> BasicRest {
<jc>// Injectable bean</jc>
}
</p>
</div><!-- END: 8.2 - juneau-rest-server-springboot.ChildResources -->
</div><!-- END: 8 - juneau-rest-server-springboot -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client' id='juneau-rest-client'>9 - juneau-rest-client</a></h2>
<div class='topic'><!-- START: 9 - juneau-rest-client -->
<h5 class='figure'>Maven Dependency</h5>
<p class='bpcode w500'>
<xt>&lt;dependency&gt;</xt>
<xt>&lt;groupId&gt;</xt>org.apache.juneau<xt>&lt;/groupId&gt;</xt>
<xt>&lt;artifactId&gt;</xt>juneau-rest-client<xt>&lt;/artifactId&gt;</xt>
<xt>&lt;version&gt;</xt>{@property juneauVersion}<xt>&lt;/version&gt;</xt>
<xt>&lt;/dependency&gt;</xt>
</p>
<h5 class='figure'>Java Library</h5>
<p class='bpcode w500'>
juneau-rest-client-{@property juneauVersion}.jar
</p>
<h5 class='figure'>OSGi Module</h5>
<p class='bpcode w500'>
org.apache.juneau.rest.client_{@property juneauVersion}.jar
</p>
<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='bpcode w800'>
<jc>// Create a reusable JSON client.</jc>
<jk>try</jk> (RestClient client = RestClient.<jsm>create</jsm>().json().build()) {
<jc>// The address of the root resource.</jc>
String url = <js>"http://localhost:10000/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>);
}
<jk>try</jk> (RestClient client = RestClient.<jsm>create</jsm>().serializer(XmlSerializer.<jk>class</jk>).parser(XmlSerializer.<jk>class</jk>).build()) {
<jc>// Add a person to the address book.
// Use XML as the transport medium.</jc>
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>
Juneau provides an HTTP client API that makes it extremely simple to connect to remote REST interfaces and
seemlessly send and receive serialized POJOs in requests and responses.
</p>
<h5 class='topic'>Features</h5>
<ul class='spaced-list'>
<li>
Converts POJOs directly to HTTP request message bodies using {@link org.apache.juneau.serializer.Serializer}
classes.
<li>
Converts HTTP response message bodies directly to POJOs using {@link org.apache.juneau.parser.Parser}
classes.
<li>
Serializes and parses HTTP request and response parts (query/form-data parameters, headers, path variables)
using OpenAPI marshalling and validation.
<li>
Exposes the full functionality of the Apache HttpClient API by exposing all methods defined on the
{@link org.apache.http.impl.client.HttpClientBuilder} class.
</ul>
<p>
The client API is designed to work as a thin layer on top of the proven Apache HttpClient API.
By leveraging the HttpClient library, details such as SSL certificate negotiation, proxies, encoding, etc...
are all handled in Apache code.
</p>
<p>
The Juneau client API prereq's Apache HttpClient 4.5+.
At a minimum, the following jars are required:
</p>
<ul>
<li><c>httpclient-4.5.jar</c>
<li><c>httpcore-4.4.1.jar</c>
<li><c>httpmime-4.5.jar</c>
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Examples below use the Juneau Address Book resource example</jc>
<jc>// Create a reusable client with JSON support</jc>
<jk>try</jk> (RestClient client = RestClient.<jsm>create</jsm>().json().build()) {
<jc>// GET request, ignoring output</jc>
<jk>try</jk> {
<jk>int</jk> rc = client.doGet(<js>"http://localhost:10000/addressBook"</js>).run();
<jc>// Succeeded!</jc>
} <jk>catch</jk> (RestCallException e) {
<jc>// Failed!</jc>
System.<jsf>err</jsf>.println(
String.<jsm>format</jsm>(<js>"status=%s, message=%s"</js>, e.getResponseStatus(), e.getResponseMessage())
);
}
<jc>// Remaining examples ignore thrown exceptions.</jc>
<jc>// GET request, secure, ignoring output</jc>
client.doGet(<js>"https://localhost:9443/sample/addressBook"</js>).run();
<jc>// GET request, getting output as a String. No POJO parsing is performed.
// Note that when calling one of the getX() methods, you don't need to call connect() or disconnect(), since
// it's automatically called for you.</jc>
String output = client.doGet(<js>"http://localhost:10000/addressBook"</js>)
.getResponseAsString();
<jc>// GET request, getting output as a Reader</jc>
Reader r = client.doGet(<js>"http://localhost:10000/addressBook"</js>)
.getReader();
<jc>// GET request, getting output as an untyped map</jc>
<jc>// Input must be an object (e.g. "{...}")</jc>
ObjectMap m = client.doGet(<js>"http://localhost:10000/addressBook/0"</js>)
.getResponse(ObjectMap.<jk>class</jk>);
<jc>// GET request, getting output as an untyped list</jc>
<jc>// Input must be an array (e.g. "[...]")</jc>
ObjectList l = client.doGet(<js>"http://localhost:10000/addressBook"</js>)
.getResponse(ObjectList.<jk>class</jk>);
<jc>// GET request, getting output as a parsed bean</jc>
<jc>// Input must be an object (e.g. "{...}")</jc>
<jc>// Note that you don't have to do any casting!</jc>
Person p = client.doGet(<js>"http://localhost:10000/addressBook/0"</js>)
.getResponse(Person.<jk>class</jk>);
<jc>// GET request, getting output as a parsed bean</jc>
<jc>// Input must be an array of objects (e.g. "[{...},{...}]")</jc>
Person[] pa = client.doGet(<js>"http://localhost:10000/addressBook"</js>)
.getResponse(Person[].<jk>class</jk>);
<jc>// Same as above, except as a List&lt;Person&gt;</jc>
List&lt;Person&gt; pl = client.doGet(<js>"http://localhost:10000/addressBook"</js>)
.getResponse(List.<jk>class</jk>, Person.<jk>class</jk>);
<jc>// GET request, getting output as a parsed string</jc>
<jc>// Input must be a string (e.g. "&lt;string&gt;foo&lt;/string&gt;" or "'foo'")</jc>
String name = client.doGet(<js>"http://localhost:10000/addressBook/0/name"</js>)
.getResponse(String.<jk>class</jk>);
<jc>// GET request, getting output as a parsed number</jc>
<jc>// Input must be a number (e.g. "&lt;number&gt;123&lt;/number&gt;" or "123")</jc>
<jk>int</jk> age = client.doGet(<js>"http://localhost:10000/addressBook/0/age"</js>)
.getResponse(Integer.<jk>class</jk>);
<jc>// GET request, getting output as a parsed boolean</jc>
<jc>// Input must be a boolean (e.g. "&lt;boolean&gt;true&lt;/boolean&gt;" or "true")</jc>
<jk>boolean</jk> isCurrent = client.doGet(<js>"http://localhost:10000/addressBook/0/addresses/0/isCurrent"</js>)
.getResponse(Boolean.<jk>class</jk>);
}
<jc>// GET request, getting a filtered object</jc>
<jk>try</jk> (RestClient client = RestClient.<jsm>create</jsm>().pojoSwaps(TemporalCalendarSwap.IsoInstant.<jk>class</jk>).build()) {
Calendar birthDate = client.doGet(<js>"http://localhost:10000/addressBook/0/birthDate"</js>)
.getResponse(GregorianCalendar.<jk>class</jk>);
<jc>// PUT request on regular field</jc>
String newName = <js>"John Smith"</js>;
<jk>int</jk> rc = client.doPut(<js>"http://localhost:10000/addressBook/0/name"</js>, newName).run();
<jc>// PUT request on filtered field</jc>
Calendar newBirthDate = <jk>new</jk> GregorianCalendar(1, 2, 3, 4, 5, 6);
rc = client.doPut(<js>"http://localhost:10000/addressBook/0/birthDate"</js>, newBirthDate).run();
<jc>// POST of a new entry to a list</jc>
Address newAddress = <jk>new</jk> Address(<js>"101 Main St"</js>, <js>"Anywhere"</js>, <js>"NY"</js>, 12121, <jk>false</jk>);
rc = client.doPost(<js>"http://localhost:10000/addressBook/0/addresses"</js>, newAddress).run();
}
</p>
<ul class='notes'>
<li>
The {@link org.apache.juneau.rest.client.RestClient} class exposes all the builder methods on the Apache
HttpClient {@link org.apache.http.impl.client.HttpClientBuilder} class.
<br>Use these methods to provide any customized HTTP client behavior.
</ul>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies' id='juneau-rest-client.RestProxies'>9.1 - REST Proxies</a></h3>
<div class='topic'><!-- START: 9.1 - juneau-rest-client.RestProxies -->
<p>
The <c>juneau-rest-client</c> library 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>
Remote resources are instantiated using one of the following methods:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.client.RestClient}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.client.RestClient#getRemote(Class) getRemote(Class)}
<li class='jm'>{@link org.apache.juneau.rest.client.RestClient#getRemote(Class,Object) getRemote(Class,Object)}
<li class='jm'>{@link org.apache.juneau.rest.client.RestClient#getRemote(Class,Object,Serializer,Parser) getRemote(Class,Object,Serializer,Parser)}
</ul>
</ul>
<p>
Annotations are used on the interface and interface methods to specify how to convert input and output to HTTP headers, query parameters, form
post parameters, or request/response bodies.
</p>
<ul class='javatree'>
<li class='jp'>{@link org.apache.juneau.http.remote}
<ul>
<li class='ja'>{@link org.apache.juneau.http.remote.Remote}
<li class='ja'>{@link org.apache.juneau.http.remote.RemoteMethod}
</ul>
<li class='jp'>{@link org.apache.juneau.http.annotation}
<ul>
<li class='ja'>{@link org.apache.juneau.http.annotation.Body}
<li class='ja'>{@link org.apache.juneau.http.annotation.Header}
<li class='ja'>{@link org.apache.juneau.http.annotation.FormData}
<li class='ja'>{@link org.apache.juneau.http.annotation.Query}
<li class='ja'>{@link org.apache.juneau.http.annotation.Path}
<li class='ja'>{@link org.apache.juneau.http.annotation.Request}
<li class='ja'>{@link org.apache.juneau.http.annotation.Response}
</ul>
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Remote</ja>(path=<js>"/petstore"</js>)
<jk>public interface</jk> PetStore {
<ja>@RemoteMethod</ja>(httpMethod=<jsf>POST</jsf>, path=<js>"/pets"</js>)
String addPet(
<ja>@Body</ja> CreatePet pet,
<ja>@Header</ja>(<js>"E-Tag"</js>) UUID etag,
<ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> debug
);
}
</p>
<p class='bpcode w800'>
<jc>// Use a RestClient with default Simple JSON support.</jc>
<jk>try</jk> (RestClient client = RestClient.<jsm>create</jsm>().simpleJson().build()) {
PetStore store = client.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
CreatePet pet = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99);
String response = store.createPet(pet, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>);
}
</p>
<p>
The call above translates to the following REST call:
</p>
<p class='bpcode w800'>
POST http://localhost:10000/petstore/pets?debug=true HTTP/1.1
Accept: application/json
Content-Type: application/json
E-Tag: 475588d4-0b27-4f56-9296-cc683251d314
{
name: 'Fluffy',
price: 9.99
}
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies.Remote' id='juneau-rest-client.RestProxies.Remote'>9.1.1 - @Remote</a></h4>
<div class='topic'><!-- START: 9.1.1 - juneau-rest-client.RestProxies.Remote -->
<p>
The {@link org.apache.juneau.http.remote.Remote @Remote} annotation is used on your interface class
to identify it as a REST proxy interface.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.remote.Remote}
<ul>
<li class='jf'>{@link org.apache.juneau.http.remote.Remote#path path}
</ul>
</ul>
<p>
The <ja>@Remote</ja> annotation is optional, but often included for code readability.
</p>
<h5 class='topic'>@Remote(path)</h5>
<p>
The {@link org.apache.juneau.http.remote.Remote#path @Remote(path)} annotation is used to define the
HTTP path of the REST service.
</p>
<p>
The path can be an absolute path to your REST service.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Remote</ja>(path=<js>"http://localhost:10000/petstore"</js>)
<jk>public interface</jk> PetStore {...}
</p>
<p class='bpcode w800'>
PetStore p = client.getRemote(PetStore.<jk>class</jk>);
</p>
<p>
When a relative path is specified, it's relative to the root-url defined on the <c>RestClient</c> used to instantiate the interface.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Remote</ja>(path=<js>"/petstore"</js>)
<jk>public interface</jk> PetStore {...}
</p>
<p class='bpcode w800'>
RestClient client = RestClient.<jsm>create</jsm>().json().rootUrl(<js>"http://localhost:10000"</js>).build();
PetStore p = client.getRemote(PetStore.<jk>class</jk>);
</p>
<p>
When no path is specified, the root-url defined on the <c>RestClient</c> is used.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Remote</ja>
<jk>public interface</jk> PetStore {...}
</p>
<p class='bpcode w800'>
RestClient client = RestClient.<jsm>create</jsm>().json().rootUrl(<js>"http://localhost:10000/petstore"</js>).build();
PetStore p = client.getRemote(PetStore.<jk>class</jk>);
</p>
</div><!-- END: 9.1.1 - juneau-rest-client.RestProxies.Remote -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies.RemoteMethod' id='juneau-rest-client.RestProxies.RemoteMethod'>9.1.2 - @RemoteMethod</a></h4>
<div class='topic'><!-- START: 9.1.2 - juneau-rest-client.RestProxies.RemoteMethod -->
<p>
The {@link org.apache.juneau.http.remote.RemoteMethod @RemoteMethod} annotation is applied to methods
of <ja>@Remote</ja>-annotated interfaces to identify REST endpoints.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.remote.RemoteMethod}
<ul>
<li class='jf'>{@link org.apache.juneau.http.remote.RemoteMethod#method method}
<li class='jf'>{@link org.apache.juneau.http.remote.RemoteMethod#path path}
<li class='jf'>{@link org.apache.juneau.http.remote.RemoteMethod#returns returns}
</ul>
</ul>
<h5 class='topic'>@RemoteMethod(method/path)</h5>
<p>
The HTTP method and path are mapped to a Java method using the <c>method</c> and <c>path</c> annotations.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Remote</ja>
<jk>public interface</jk> PetStore {
<jc>// GET /pets/{petId}</jc>
<ja>@RemoteMethod</ja>(method=<js>"GET"</js>, path=<js>"/pets/{petId}"</js>)
Pet getPet(<ja>@Path</ja>(<js>"petId"</js>) <jk>int</jk> id);
}
</p>
<p>
The Java method name can be anything.
</p>
<h5 class='topic'>Inferred method/path</h5>
<p>
In such cases, <c>method</c> and <c>path</c> annotations are optional if you follow certain naming
conventions on your method that identify the method and path.
</p>
<p>
For example, the <c>getPet</c> method below defaults to <c>GET /pet</c>:
</p>
<p class='bpcode w800'>
<ja>@Remote</ja>
<jk>public interface</jk> PetStore {
<jc>// GET /pet</jc>
<ja>@RemoteMethod</ja>
Pet getPet(...);
}
</p>
<p>
In such cases, the <ja>@RemoteMethod</ja> annotation is optional.
</p>
<p>
Method names matching the following pattern are assumed to be implying the HTTP method name:
</p>
<p class='bpcode w800'>
(get|put|post|delete|options|head|connect|trace|patch).*
</p>
<p class='bpcode w800'>
do(?i)(get|put|post|delete|options|head|connect|trace|patch)
</p>
<h5 class='figure'>Examples:</h5>
<table class='styled w500'>
<tr>
<th>Java method name</th>
<th>Inferred HTTP method</th>
<th>Inferred HTTP path</th>
</tr>
<tr>
<td class='code'>getPet()</td>
<td class='code'>GET</td>
<td class='code'>/pet</td>
</tr>
<tr>
<td class='code'>get()</td>
<td class='code'>GET</td>
<td class='code'>/</td>
</tr>
<tr>
<td class='code'>postPet()</td>
<td class='code'>POST</td>
<td class='code'>/pet</td>
</tr>
<tr>
<td class='code'>fooPet()</td>
<td class='code'>[default]</td>
<td class='code'>/fooPet</td>
</tr>
<tr>
<td class='code'>doGet()</td>
<td class='code'>GET</td>
<td class='code'>/</td>
</tr>
<tr>
<td class='code'>doGET()</td>
<td class='code'>GET</td>
<td class='code'>/</td>
</tr>
<tr>
<td class='code'>doFoo()</td>
<td class='code'>[default]</td>
<td class='code'>/doFoo</td>
</tr>
</table>
<h5 class='topic'>@RemoteMethod(returns)</h5>
<p>
The return type of the Java methods of 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 {@doc PojoCategories parsable} POJO
- The body of the response will be converted to the POJO using the parser defined on the
<c>RestClient</c> based on the <c>Content-Type</c> of the response.
<li>
Any {@link org.apache.juneau.http.annotation.Response @Response}-annotated type. (described later)
<li>
<c>HttpResponse</c>
- Returns the raw <c>HttpResponse</c> returned by the inner <c>HttpClient</c>.
<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>
<p>
If you're only interested in the HTTP status code of the response, you can use the {@link org.apache.juneau.http.remote.RemoteMethod#returns() returns}
annotation with a value of {@link org.apache.juneau.http.remote.RemoteReturn#STATUS STATUS}:
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Remote</ja>
<jk>public interface</jk> PetStore {
<jc>// POST /pets</jc>
<jc>// Returns HTTP status code.</jc>
<ja>@RemoteMethod</ja>(returns=<jsf>STATUS</jsf>)
<jk>int</jk> postPets(...);
}
</p>
<p>
If your <c>RestClient</c> does not have a parser associated with it, then the value is converted directly from a String using
the rules defined in {@doc PojosConveribleToStrings}.
</p>
</div><!-- END: 9.1.2 - juneau-rest-client.RestProxies.RemoteMethod -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies.Body' id='juneau-rest-client.RestProxies.Body'>9.1.3 - @Body</a></h4>
<div class='topic'><!-- START: 9.1.3 - juneau-rest-client.RestProxies.Body -->
<p>
The {@link org.apache.juneau.http.annotation.Body @Body} annotation can be applied to arguments of <ja>@RemoteMethod</ja>-annotated methods
to denote that they are the HTTP body of the request.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Body}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.Body#required() required} - Input validation. Body must be present.
<li class='jf'>{@link org.apache.juneau.http.annotation.Body#schema() schema} - Swagger schema.
</ul>
</ul>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Used on parameter</jc>
<ja>@Remote</ja>(path=<js>"/petstore"</js>)
<jk>public interface</jk> PetStore {
<ja>@RemoteMethod</ja>(path=<js>"/pets"</js>)
String addPet(<ja>@Body</ja> Pet pet);
}
</p>
<p class='bpcode w800'>
<jc>// Used on class</jc>
<ja>@Remote</ja>(path=<js>"/petstore"</js>)
<jk>public interface</jk> PetStore {
<ja>@RemoteMethod</ja>(path=<js>"/pets"</js>)
String addPet(Pet pet);
}
<ja>@Body</ja>
<jk>public class</jk> Pet {...}
</p>
<p>
The argument can be any of the following types:
</p>
<ul class='spaced-list'>
<li>
Any serializable POJO - Converted to output using the {@link org.apache.juneau.serializer.Serializer} registered with the <c>RestClient</c>.
<br><c>Content-Type</c> is set to that of the <c>Serializer</c>.
<li>
{@link java.io.Reader} - Raw contents of {@code Reader} will be serialized to remote resource.
<br><c>Content-Type</c> is set to <js>"text/plain"</js>.
<li>
{@link java.io.InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
<br><c>Content-Type</c> is set to <js>"application/octet-stream"</js>.
<li>
<c>NameValuePairs</c> - Converted to a URL-encoded FORM post.
<br><c>Content-Type</c> is set to <js>"aplication/x-www-form-urlencoded"</js>.
<li>
<c>HttpEntity</c> - Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
</ul>
<p>
OpenAPI schema based serialization can be used by using the {@link org.apache.juneau.oapi.OpenApiSerializer} class.
</p>
<p class='bpcode w800'>
<ja>@RemoteMethod</ja>(path=<js>"/comma-delimited-pipe-delimited-ints"</js>)
String addCommaDelimitedPipeDelimitedInts(
<ja>@Body</ja>(
serializer=OpenApiSerializer.<jk>class</jk>,
schema=<ja>@Schema</ja>(
type=<js>"array"</js>,
collectionFormat=<js>"pipes"</js>,
items=<ja>@Items</ja>(
type=<js>"array"</js>
items=<ja>@SubItems</ja>(
type=<js>"int32"</js>,
<jc>// Auto-validates on client side!</jc>
minimum=<js>"0"</js>,
maximum=<js>"64"</js>
)
)
)
)
<jk>int</jk>[][] input
);
</p>
<p>
See {@doc juneau-marshall.OpenApiDetails.Serializers} for information about supported data types in OpenAPI serialization.
</p>
<p>
If your <c>RestClient</c> class does not have a serializer associated with it, the body will automatically be serialized to a
string using the rules defined in {@doc PojosConveribleToStrings}.
</p>
</div><!-- END: 9.1.3 - juneau-rest-client.RestProxies.Body -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies.FormData' id='juneau-rest-client.RestProxies.FormData'>9.1.4 - @FormData</a></h4>
<div class='topic'><!-- START: 9.1.4 - juneau-rest-client.RestProxies.FormData -->
<p>
The {@link org.apache.juneau.http.annotation.FormData @FormData} annotation can be applied to arguments of <ja>@RemoteMethod</ja>-annotated methods
to denote that they are form-data parameters on the request.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.FormData}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#_default() _default} - Default value if not present.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#_enum() _enum} - Input validation. Must match one of the values.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#allowEmptyValue() allowEmptyValue} - Input validation. Allow empty value.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#collectionFormat() collectionFormat} - How collections of items are formatted.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#exclusiveMaximum() exclusiveMaximum} - Input validation. Whether maximum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#exclusiveMinimum() exclusiveMinimum} - Input validation. Whether minimum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#format() format} - The schema type format.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#items() items} - The schema of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#maximum() maximum} - Input validation. Maximum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#maxItems() maxItems} - Input validation. Maximum number of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#maxLength() maxLength} - Input validation. Maximum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#minimum() minimum} - Input validation. Minimum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#minItems() minItems} - Input validation. Minimum number of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#minLength() minLength} - Input validation. Minimum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#multipleOf() multipleOf} - Input validation. Number must be a multiple of.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#name() name} - Form data entry name.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#pattern() pattern}- Input validation. Must match regular expression.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#required() required}- Input validation. Form data entry must be present.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#serializer() serializer}- Override the part serializer.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#skipIfEmpty() skipIfEmpty}- Don't add if value is null or empty.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#type() type} - The schema type.
<li class='jf'>{@link org.apache.juneau.http.annotation.FormData#uniqueItems() uniqueItems} - Input validation. Collections must contain unique items only.
</ul>
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Remote</ja>(path=<js>"/myproxy"</js>)
<jk>public interface</jk> MyProxy {
<jc>// Explicit names specified for form data parameters.</jc>
<ja>@RemoteMethod</ja>
String postParameters(
<ja>@FormData</ja>(<js>"foo"</js>)</ja> String foo,
<ja>@FormData</ja>(<js>"bar"</js>)</ja> MyPojo pojo
);
<jc>// Multiple values pulled from a NameValuePairs object.</jc>
<jc>// Name "*" is inferred.</jc>
<ja>@RemoteMethod</ja>
String postNameValuePairs(<ja>@FormData</ja> NameValuePairs nameValuePairs);
<jc>// Multiple values pulled from a Map.</jc>
<ja>@RemoteMethod</ja>
String postMap(<ja>@FormData</ja> Map&lt;String,Object&gt; map);
<jc>// Multiple values pulled from a bean.</jc>
<ja>@RemoteMethod</ja>
String postBean(<ja>@FormData</ja> MyBean bean);
<jc>// An entire form-data HTTP body as a String.</jc>
<ja>@RemoteMethod</ja>
String postString(<ja>@FormData</ja> String string);
<jc>// An entire form-data HTTP body as a Reader.</jc>
<ja>@RemoteMethod</ja>
String postReader(<ja>@FormData</ja> Reader reader);
}
</p>
<p>
Single-part arguments (i.e. those with name != <js>"*"</js>) can be any of the following types:
</p>
<ul class='spaced-list'>
<li>
Any serializable POJO - Converted to a string using the {@link org.apache.juneau.httppart.HttpPartSerializer} registered with the
<c>RestClient</c> ({@link org.apache.juneau.oapi.OpenApiSerializer} by default) or associated via the {@link org.apache.juneau.http.annotation.FormData#serializer() @FormData(serializer)} annotation.
</ul>
<p>
Multi-part arguments (i.e. those with name == <js>"*"</js> or empty) can be any of the following types:
</p>
<ul class='spaced-list'>
<li>
{@link java.io.Reader} - Raw contents of {@code Reader} will be serialized to remote resource.
<li>
{@link java.io.InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
<li>
<c>NameValuePairs</c> - Converted to a URL-encoded FORM post.
<li>
<c>Map</c> - Converted to key-value pairs.
<br>Values serialized using the registered {@link org.apache.juneau.httppart.HttpPartSerializer} ({@link org.apache.juneau.oapi.OpenApiSerializer} by default).
<li>
Bean - Converted to key-value pairs.
<br>Values serialized using the registered {@link org.apache.juneau.httppart.HttpPartSerializer} ({@link org.apache.juneau.oapi.OpenApiSerializer} by default).
<li>
<c>CharSequence</c> - Used directly as am <js>"application/x-www-form-urlencoded"</js> entity.
</ul>
<p>
See the link below for information about supported data types in OpenAPI serialization.
</p>
<ul class='seealso'>
<li class='link'>{@doc juneau-marshall.OpenApiDetails.Serializers}
</ul>
</div><!-- END: 9.1.4 - juneau-rest-client.RestProxies.FormData -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies.Query' id='juneau-rest-client.RestProxies.Query'>9.1.5 - @Query</a></h4>
<div class='topic'><!-- START: 9.1.5 - juneau-rest-client.RestProxies.Query -->
<p>
The {@link org.apache.juneau.http.annotation.Query @Query} annotation can be applied to arguments of <ja>@RemoteMethod</ja>-annotated methods
to denote that they are query parameters on the request.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Query}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#_default() _default} - Default value if not present.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#_enum() _enum} - Input validation. Must match one of the values.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#allowEmptyValue() allowEmptyValue} - Input validation. Allow empty value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#collectionFormat() collectionFormat} - How collections of items are formatted.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#exclusiveMaximum() exclusiveMaximum} - Input validation. Whether maximum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#exclusiveMinimum() exclusiveMinimum} - Input validation. Whether minimum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#format() format} - The schema type format.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#items() items} - The schema of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#maximum() maximum} - Input validation. Maximum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#maxItems() maxItems} - Input validation. Maximum number of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#maxLength() maxLength} - Input validation. Maximum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#minimum() minimum} - Input validation. Minimum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#minItems() minItems} - Input validation. Minimum number of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#minLength() minLength} - Input validation. Minimum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#multipleOf() multipleOf} - Input validation. Number must be a multiple of.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#name() name} - Query parameter name.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#pattern() pattern} - Input validation. Must match regular expression.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#required() required} - Input validation. Query parameter must be present.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#serializer() serializer} - Override the part serializer.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#skipIfEmpty() skipIfEmpty}- Don't add if value is null or empty.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#type() type} - The schema type.
<li class='jf'>{@link org.apache.juneau.http.annotation.Query#uniqueItems() uniqueItems} - Input validation. Collections must contain unique items only.
</ul>
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Remote</ja>(path=<js>"/myproxy"</js>)
<jk>public interface</jk> MyProxy {
<jc>// Explicit names specified for query parameters.</jc>
<ja>@RemoteMethod</ja>
String parameters(
<ja>@Query</ja>(<js>"foo"</js>)</ja> String foo,
<ja>@Query</ja>(<js>"bar"</js>)</ja> MyPojo pojo);
<jc>// Multiple values pulled from a NameValuePairs object.</jc>
<jc>// Same as @Query("*").</jc>
<ja>@RemoteMethod</ja>
String nameValuePairs(<ja>@Query</ja> NameValuePairs nameValuePairs);
<jc>// Multiple values pulled from a Map.</jc>
<jc>// Same as @Query("*").</jc>
<ja>@RemoteMethod</ja>
String map(<ja>@Query</ja> Map&lt;String,Object&gt; map);
<jc>// Multiple values pulled from a bean.</jc>
<jc>// Same as @Query("*").</jc>
<ja>@RemoteMethod</ja>
String bean(<ja>@Query</ja> MyBean myBean);
<jc>// An entire query string as a String.</jc>
<jc>// Same as @Query("*").</jc>
<ja>@RemoteMethod</ja>
String string(<ja>@Query</ja> String string);
<jc>// An entire query string as a Reader.</jc>
<jc>// Same as @Query("*").</jc>
<ja>@RemoteMethod</ja>
String reader(<ja>@Query</ja> Reader reader);
}
</p>
<p>
Single-part arguments (i.e. those with name != <js>"*"</js>) can be any of the following types:
</p>
<ul class='spaced-list'>
<li>
Any serializable POJO - Converted to a string using the {@link org.apache.juneau.httppart.HttpPartSerializer} registered with the
<c>RestClient</c> ({@link org.apache.juneau.oapi.OpenApiSerializer} by default) or associated via the {@link org.apache.juneau.http.annotation.Query#serializer() @Query(serializer)} annotation.
</ul>
<p>
Multi-part arguments (i.e. those with name == <js>"*"</js> or empty) can be any of the following types:
</p>
<ul class='spaced-list'>
<li>
{@link java.io.Reader} - Raw contents of {@code Reader} will be serialized directly a query string.
<li>
<c>NameValuePairs</c> - Serialized as individual query parameters.
<li>
<c>Map</c> - Converted to key-value pairs.
<br>Values serialized using the registered {@link org.apache.juneau.httppart.HttpPartSerializer} ({@link org.apache.juneau.oapi.OpenApiSerializer} by default).
<li>
Bean - Converted to key-value pairs.
<br>Values serialized using the registered {@link org.apache.juneau.httppart.HttpPartSerializer} ({@link org.apache.juneau.oapi.OpenApiSerializer} by default).
<li>
<c>CharSequence</c> - Serialized directly a query string.
</ul>
<p>
See the link below for information about supported data types in OpenAPI serialization.
</p>
<ul class='seealso'>
<li class='link'>{@doc juneau-marshall.OpenApiDetails.Serializers}
</ul>
</div><!-- END: 9.1.5 - juneau-rest-client.RestProxies.Query -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies.Header' id='juneau-rest-client.RestProxies.Header'>9.1.6 - @Header</a></h4>
<div class='topic'><!-- START: 9.1.6 - juneau-rest-client.RestProxies.Header -->
<p>
The {@link org.apache.juneau.http.annotation.Header @Header} annotation can be applied to arguments of <ja>@RemoteMethod</ja>-annotated methods
to denote that they are header parameters on the request.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Header}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#_default() _default} - Default value if not present.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#_enum() _enum} - Input validation. Must match one of the values.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#allowEmptyValue() allowEmptyValue} - Input validation. Allow empty value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#collectionFormat() collectionFormat} - How collections of items are formatted.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#exclusiveMaximum() exclusiveMaximum} - Input validation. Whether maximum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#exclusiveMinimum() exclusiveMinimum} - Input validation. Whether minimum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#format() format} - The schema type format.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#items() items} - The schema of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#maximum() maximum} - Input validation. Maximum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#maxItems() maxItems} - Input validation. Maximum number of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#maxLength() maxLength} - Input validation. Maximum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#minimum() minimum} - Input validation. Minimum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#minItems() minItems} - Input validation. Minimum number of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#minLength() minLength} - Input validation. Minimum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#multipleOf() multipleOf} - Input validation. Number must be a multiple of.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#name() name} - Header name.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#pattern() pattern} - Input validation. Must match regular expression.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#required() required} - Input validation. Header must be present.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#serializer() serializer} - Override the part serializer.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#skipIfEmpty() skipIfEmpty} - Don't add if value is null or empty.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#type() type} - The schema type.
<li class='jf'>{@link org.apache.juneau.http.annotation.Header#uniqueItems() uniqueItems} - Input validation. Collections must contain unique items only.
</ul>
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Remote</ja>(path=<js>"/myproxy"</js>)
<jk>public interface</jk> MyProxy {
<jc>// Explicit names specified for HTTP headers.</jc>
<jc>// pojo will be converted to UON notation (unless plain-text parts enabled).</jc>
<ja>@RemoteMethod</ja>(path=<js>"/mymethod1"</js>)
String myProxyMethod1(<ja>@Header</ja>(<js>"Foo"</js>)</ja> String foo,
<ja>@Header</ja>(<js>"Bar"</js>)</ja> MyPojo pojo);
<jc>// Multiple values pulled from a NameValuePairs object.</jc>
<jc>// Same as @Header("*").</jc>
<ja>@RemoteMethod</ja>(path=<js>"/mymethod2"</js>)
String myProxyMethod2(<ja>@Header</ja> NameValuePairs nameValuePairs);
<jc>// Multiple values pulled from a Map.</jc>
<jc>// Same as @Header("*").</jc>
<ja>@RemoteMethod</ja>(path=<js>"/mymethod3"</js>)
String myProxyMethod3(<ja>@Header</ja> Map&lt;String,Object&gt; map);
<jc>// Multiple values pulled from a bean.</jc>
<jc>// Same as @Header("*").</jc>
<ja>@RemoteMethod</ja>(path=<js>"/mymethod4"</js>)
String myProxyMethod4(<ja>@Header</ja> MyBean myBean);
}
</p>
<p>
Single-part arguments (i.e. those with name != <js>"*"</js>) can be any of the following types:
</p>
<ul class='spaced-list'>
<li>
Any serializable POJO - Converted to a string using the {@link org.apache.juneau.httppart.HttpPartSerializer} registered with the
<c>RestClient</c> ({@link org.apache.juneau.oapi.OpenApiSerializer} by default) or associated via the {@link org.apache.juneau.http.annotation.Header#serializer() @Header(serializer)} annotation.
</ul>
<p>
Multi-part arguments (i.e. those with name == <js>"*"</js> or empty) can be any of the following types:
</p>
<ul class='spaced-list'>
<li>
<c>NameValuePairs</c> - Serialized as individual headers.
<li>
<c>Map</c> - Converted to key-value pairs.
<br>Values serialized using the registered {@link org.apache.juneau.httppart.HttpPartSerializer} ({@link org.apache.juneau.oapi.OpenApiSerializer} by default).
<li>
Bean - Converted to key-value pairs.
<br>Values serialized using the registered {@link org.apache.juneau.httppart.HttpPartSerializer} ({@link org.apache.juneau.oapi.OpenApiSerializer} by default).
</ul>
<p>
See the link below for information about supported data types in OpenAPI serialization.
</p>
<ul class='seealso'>
<li class='link'>{@doc juneau-marshall.OpenApiDetails.Serializers}
</ul>
</div><!-- END: 9.1.6 - juneau-rest-client.RestProxies.Header -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies.Path' id='juneau-rest-client.RestProxies.Path'>9.1.7 - @Path</a></h4>
<div class='topic'><!-- START: 9.1.7 - juneau-rest-client.RestProxies.Path -->
<p>
The {@link org.apache.juneau.http.annotation.Path @Path} annotation can be applied to arguments of <ja>@RemoteMethod</ja>-annotated methods
to denote that they are path parameters on the request.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Path}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#_enum() _enum} - Input validation. Must match one of the values.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#allowEmptyValue() allowEmptyValue} - Input validation. Allow empty value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#collectionFormat() collectionFormat} - How collections of items are formatted.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#exclusiveMaximum() exclusiveMaximum} - Input validation. Whether maximum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#exclusiveMinimum() exclusiveMinimum} - Input validation. Whether minimum is exclusive.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#format() format} - The schema type format.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#items() items} - The schema of items in a collection.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#maximum() maximum} - Input validation. Maximum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#maxLength() maxLength} - Input validation. Maximum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#minimum() minimum} - Input validation. Minimum numeric value.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#minLength() minLength} - Input validation. Minimum length of a string.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#multipleOf() multipleOf} - Input validation. Number must be a multiple of.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#name() name} - Path variable name.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#pattern() pattern} - Input validation. Must match regular expression.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#serializer() serializer} - Override the part serializer.
<li class='jf'>{@link org.apache.juneau.http.annotation.Path#type() type} - The schema type.
</ul>
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Remote</ja>(path=<js>"/myproxy"</js>)
<jk>public interface</jk> MyProxy {
<jc>// Explicit names specified for path parameters.</jc>
<jc>// pojo will be converted to UON notation (unless plain-text parts enabled).</jc>
<ja>@RemoteMethod</ja>(path=<js>"/mymethod1/{foo}/{bar}"</js>)
String myProxyMethod1(<ja>@Path</ja>(<js>"foo"</js>)</ja> String foo, <ja>@Path</ja>(<js>"bar"</js>)</ja> MyPojo pojo);
<jc>// Multiple values pulled from a NameValuePairs object.</jc>
<jc>// Same as @Path("*").</jc>
<ja>@RemoteMethod</ja>(path=<js>"/mymethod2/{foo}/{bar}/{baz}"</js>)
String myProxyMethod2(<ja>@Path</ja> NameValuePairs nameValuePairs);
<jc>// Multiple values pulled from a Map.</jc>
<jc>// Same as @Path("*").</jc>
<ja>@RemoteMethod</ja>(path=<js>"/mymethod3/{foo}/{bar}/{baz}"</js>)
String myProxyMethod3(<ja>@Path</ja> Map&lt;String,Object&gt; map);
<jc>// Multiple values pulled from a bean.</jc>
<jc>// Same as @Path("*").</jc>
<ja>@RemoteMethod</ja>(path=<js>"/mymethod4/{foo}/{bar}/{baz}"</js>)
String myProxyMethod4(<ja>@Path</ja> MyBean myBean);
}
</p>
<p>
Single-part arguments (i.e. those with name != <js>"*"</js>) can be any of the following types:
</p>
<ul class='spaced-list'>
<li>
Any serializable POJO - Converted to a string using the {@link org.apache.juneau.httppart.HttpPartSerializer} registered with the
<c>RestClient</c> ({@link org.apache.juneau.oapi.OpenApiSerializer} by default) or associated via the {@link org.apache.juneau.http.annotation.Path#serializer() @Path(serializer)} annotation.
</ul>
<p>
Multi-part arguments (i.e. those with name == <js>"*"</js> or empty) can be any of the following types:
</p>
<ul class='spaced-list'>
<li>
<c>NameValuePairs</c> - Serialized as individual query parameters.
<li>
<c>Map</c> - Converted to key-value pairs.
<br>Values serialized using the registered {@link org.apache.juneau.httppart.HttpPartSerializer} ({@link org.apache.juneau.oapi.OpenApiSerializer} by default).
<li>
Bean - Converted to key-value pairs.
<br>Values serialized using the registered {@link org.apache.juneau.httppart.HttpPartSerializer} ({@link org.apache.juneau.oapi.OpenApiSerializer} by default).
</ul>
<p>
See the link below for information about supported data types in OpenAPI serialization.
</p>
<ul class='seealso'>
<li class='link'>{@doc juneau-marshall.OpenApiDetails.Serializers}
</ul>
</div><!-- END: 9.1.7 - juneau-rest-client.RestProxies.Path -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies.Request' id='juneau-rest-client.RestProxies.Request'>9.1.8 - @Request</a></h4>
<div class='topic'><!-- START: 9.1.8 - juneau-rest-client.RestProxies.Request -->
<p>
The {@link org.apache.juneau.http.annotation.Request @Request} annotation can be applied to a type of a <ja>@RemoteMethod</ja>-annotated method
to identify it as a bean for setting HTTP parts through a bean-like interface.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Request}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.Request#partSerializer() partSerializer} - Override the part serializer.
</ul>
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Remote</ja>(path=<js>"/petstore"</js>)
<jk>public interface</jk> PetStore {
<ja>@RemoteMethod</ja>
String postPet(CreatePetRequest bean);
}
</p>
<p class='bpcode w800'>
<ja>@Request</ja>
<jk>public class</jk> CreatePetRequest {
<jk>private</jk> CreatePet <jf>pet</jf>;
<jk>public</jk> CreatePetRequest(String name, <jk>float</jk> price) {
<jk>this</jk>.<jf>pet</jf> = <jk>new</jk> CreatePet(name, price);
}
<ja>@Body</ja>
<jk>public</jk> CreatePet getBody() {
<jk>return</jk> <jk>this</jk>.<jf>pet</jf>;
}
<ja>@Query</ja>
<jk>public</jk> Map&lt;String,Object&gt; getQueryParams() {
<jk>return new</jk> ObjectMap().append(<js>"debug"</js>, <jk>true</jk>);
}
<ja>@Header</ja>(<js>"E-Tag"</js>)
<jk>public static</jk> UUID <jsm>getUUID</jsm>() {
<jk>return</jk> UUID.<jsm>generatedUUID</jsm>();
}
}
</p>
<p class='bpcode w800'>
PetStore store = restClient.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
CreatePetRequest requestBean = <jk>new</jk> CreatePetRequest(<js>"Fluffy"</js>, 9.99);
String response = store.postPet(requestBean);
</p>
<p>
The <ja>@Request</ja> annotation can be applied to either the class or argument.
</p>
<p>
The annotated methods must be no-arg and public.
They can be named anything.
</p>
<p>
Any of the following annotations can be used on the methods:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Body}
<li class='ja'>{@link org.apache.juneau.http.annotation.Header}
<li class='ja'>{@link org.apache.juneau.http.annotation.FormData}
<li class='ja'>{@link org.apache.juneau.http.annotation.Query}
<li class='ja'>{@link org.apache.juneau.http.annotation.Path}
</ul>
<p>
The behavior and functionality of all of the annotations are the same as if they were used on method arguments directly.
This means full support for OpenAPI serialization and validation.
</p>
<p>
Annotations on methods are inherited from parent classes and interfaces.
For example, the request bean above could have defined annotations in an interface to keep them clear from the implementation:
</p>
<p class='bpcode w800'>
<ja>@Request</ja>
<jk>public interface</jk> CreatePetRequest {
<ja>@Body</ja>
CreatePet getBody();
<ja>@Query</ja>
Map&lt;String,Object&gt; getQueryParams();
<ja>@Header</ja>(<js>"E-Tag"</js>)
UUID getUUID();
}
</p>
<p class='bpcode w800'>
<jk>public class</jk> CreatePetRequestImpl <jk>implements</jk> CreatePetRequest {
<jk>public</jk> CreatePetRequestImpl(String name, <jk>float</jk> price) {...}
<ja>@Override</ja>
<jk>public</jk> CreatePet getBody() {
<jk>return</jk> <jk>this</jk>.<jf>pet</jf>;
}
<ja>@Override</ja>
<jk>public</jk> Map&lt;String,Object&gt; getQueryParams() {
<jk>return new</jk> ObjectMap().append(<js>"debug"</js>, <jk>true</jk>);
}
<ja>@Override</ja>
<jk>public</jk> UUID getUUID() {
<jk>return</jk> UUID.<jsm>generateUUID</jsm>();
}
}
</p>
</div><!-- END: 9.1.8 - juneau-rest-client.RestProxies.Request -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies.Response' id='juneau-rest-client.RestProxies.Response'>9.1.9 - @Response</a></h4>
<div class='topic'><!-- START: 9.1.9 - juneau-rest-client.RestProxies.Response -->
<p>
The {@link org.apache.juneau.http.annotation.Response @Response} annotation can be applied to types returned by <ja>@RemoteMethod</ja>-annotated methods.
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Response}
<ul>
<li class='jf'>{@link org.apache.juneau.http.annotation.Response#partParser() partParser} - Override the part parser.
</ul>
</ul>
<p>
The <ja>@Response</ja> annotation can be used to define interfaces for retrieving response parts using a bean-like proxy.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<ja>@Remote</ja>
<jk>public interface</jk> PetStore {
<ja>@RemoteMethod</ja>
CreatePetResponse postPet(...);
}
</p>
<p class='bpcode w800'>
<ja>@Response</ja>
<jk>public interface</jk> CreatePetResponse {
<ja>@ResponseBody</ja>
Pet getBody();
<ja>@ResponseHeader</ja>(<js>"E-Tag"</js>)
UUID getUUID();
<ja>@ResponseStatus</ja>
int getStatus();
}
</p>
<p class='bpcode w800'>
PetStore store = restClient.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
CreatePetResponse response = store.postPet(...);
Pet pet = response.getBody();
UUID uuid = response.getUUID();
<jk>int</jk> status = response.getStatus();
</p>
<p>
The annotated methods must be no-arg.
They can be named anything.
</p>
<p>
Any of the following annotations can be used on the methods:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseBody}
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseHeader}
<li class='ja'>{@link org.apache.juneau.http.annotation.ResponseStatus}
</ul>
<p>
The behavior and functionality of all of the annotations are the same as if they were used on method arguments directly. This means full support for OpenAPI serialization and validation.
</p>
</div><!-- END: 9.1.9 - juneau-rest-client.RestProxies.Response -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies.DualPurposeInterfaces' id='juneau-rest-client.RestProxies.DualPurposeInterfaces'>9.1.10 - Dual-purpose (end-to-end) interfaces</a></h4>
<div class='topic'><!-- START: 9.1.10 - juneau-rest-client.RestProxies.DualPurposeInterfaces -->
<p>
A common coding practice is to use the same Java interface to define both your server and client side REST interfaces.
The advantage to this approach is that changes that you make to your REST interface can be reflected in both places
at the same time, reducing the chances for compatibility mistakes.
</p>
<p>
What makes this possible is that method-level annotations such as <ja>@RestMethod</ja> and parameter-level annotations
such as <ja>@Query</ja> are inherited from parent classes.
This normally isn't possible, but the framework will spider up the parent hierarchy of classes to find method and parameter level
annotations defined on overridden methods.
</p>
<p>
The general approach is to define your {@link org.apache.juneau.http.remote.Remote @Remote}-annotated interface first.
The following example is pulled from the PetStore app:
</p>
<p class='bpcode w800'>
<ja>@Remote</ja>(path=<js>"/petstore"</js>)
<jk>public interface</jk> PetStore {
<ja>@RemoteMethod</ja>(method=<jsf>GET</jsf>, path=<js>"/pet"</js>)
<jk>public</jk> Collection&lt;Pet&gt; getPets() <jk>throws</jk> NotAcceptable;
<ja>@RemoteMethod</ja>(method=<jsf>DELETE</jsf>, path=<js>"/pet/{petId}"</js>)
<jk>public</jk> Ok deletePet(
<ja>@Header</ja>(
name=<js>"api_key"</js>,
description=<js>"Security API key"</js>,
required=<jk>true</jk>,
example=<js>"foobar"</js>
)
String apiKey,
<ja>@Path</ja>(
name=<js>"petId"</js>,
description=<js>"Pet id to delete"</js>,
example=<js>"123"</js>
)
<jk>long</jk> petId
) <jk>throws</jk> IdNotFound, NotAcceptable;
...
</p>
<p>
Next you define the implementation of your interface as a normal Juneau REST resource:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/petstore"</js>,
title=<js>"Petstore application"</js>,
...
)
<jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestJena <jk>implements</jk> PetStore {
...
<ja>@Override</ja> <jc>/* PetStore */</jc>
<ja>@RestMethod</ja>(
name=<jsm>GET</jsm>,
path=<js>"/pet"</js>,
summary=<js>"All pets in the store"</js>,
...
)
<jk>public</jk> Collection&lt;Pet&gt; getPets() <jk>throws</jk> NotAcceptable {
<jk>return</jk> <jsf>store</jsf>.getPets();
}
<ja>@Override</ja> <jc>/* PetStore */</jc>
<ja>@RestMethod</ja>(
name=<jsf>DELETE</jsf>,
path=<js>"/pet/{petId}"</js>,
summary=<js>"Deletes a pet"</js>,
...
)
<jk>public</jk> Ok deletePet(String apiKey, long petId) <jk>throws</jk> IdNotFound, NotAcceptable {
<jsf>store</jsf>.removePet(petId);
<jk>return</jk> <jsf>OK</jsf>;
}
</p>
<p>
Then use the interface as a remote resource like so:
</p>
<p class='bpcode w800'>
<jk>try</jk> (RestClient rc = RestClient.<jsm>create</jsm>().json().rootUrl(<js>"http://localhost:10000"</js>).build()) {
PetStore ps = rc.getRemote(PetStore.<jk>class</jk>);
<jk>for</jk> (Pet x : ps.getPets()) {
ps.deletePet(<js>"my-special-key"</js>, x.getId());
System.<jsf>err</jsf>.println(<js>"Deleted pet: id="</js> + x.getId());
}
}
</p>
<p>
In the example above, we chose to add the <ja>@RestMethod</ja> annotation to the implementation class.
However, they could have been added to the interface instead.
</p>
<p>
Note how we didn't need to use the <ja>@Header</ja> and <ja>@Path</ja> annotations in our implementation since
the annotations were inherited from the interface.
</p>
</div><!-- END: 9.1.10 - juneau-rest-client.RestProxies.DualPurposeInterfaces -->
</div><!-- END: 9.1 - juneau-rest-client.RestProxies -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.SSL' id='juneau-rest-client.SSL'>9.2 - SSL Support</a></h3>
<div class='topic'><!-- START: 9.2 - juneau-rest-client.SSL -->
<p>
The simplest way to enable SSL support in the client is to use the
{@link org.apache.juneau.rest.client.RestClientBuilder#enableLaxSSL()} method.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Create a client that ignores self-signed or otherwise invalid certificates.</jc>
RestClient rc = RestClient.<jsm>create</jsm>().enableLaxSSL().build();
</p>
<p>
A more typical scenario using default cert and hostname verification is shown here:
</p>
<p class='bpcode w800'>
RestClient rc = RestClient.create().enableSSL().sslProtocols(<js>"TLSv1.2"</js>).build();
</p>
<p>
The following convenience methods are provided in the builder class for specifying SSL parameters:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.client.RestClientBuilder}
<ul>
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#sslProtocols(String...) sslProtocols(String...)}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#cipherSuites(String...) cipherSuites(String...)}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#hostnameVerifier(HostnameVerifier) hostnameVerifier(HostnameVerifier)}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#keyManagers(KeyManager...) keyManagers(KeyManager...)}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#trustManagers(TrustManager...)}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#secureRandom(SecureRandom)}
</ul>
</ul>
<p>
SSL support can also be enabled by passing in your own connection manager using {@link org.apache.juneau.rest.client.RestClientBuilder#httpClientConnectionManager(HttpClientConnectionManager)}.
</p>
</div><!-- END: 9.2 - juneau-rest-client.SSL -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.Authentication' id='juneau-rest-client.Authentication'>9.3 - Authentication</a></h3>
<div class='topic'><!-- START: 9.3 - juneau-rest-client.Authentication -->
<p>
The Juneau REST client itself does not implement any support for authentication.
Instead, it delegates it to the underlying Apache HTTP Client interface.
</p>
<p>
The following sections show how some common authentication mechanisms can be set up using HTTP Client APIs.
</p>
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.Authentication.BASIC' id='juneau-rest-client.Authentication.BASIC'>9.3.1 - BASIC Authentication</a></h4>
<div class='topic'><!-- START: 9.3.1 - juneau-rest-client.Authentication.BASIC -->
<p>
The {@link org.apache.juneau.rest.client.RestClientBuilder#basicAuth(String,int,String,String)} method
can be used to quickly enable BASIC authentication support.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Create a client that performs BASIC authentication using the specified user/pw.</jc>
RestClient restClient = RestClient.<jsm>create</jsm>()
.basicAuth(<jsf>HOST</jsf>, <jsf>PORT</jsf>, <jsf>USER</jsf>, <jsf>PW</jsf>)
.build();
</p>
<p>
This is functionally equivalent to the following:
</p>
<p class='bpcode w800'>
RestClientBuilder builder = RestClient.<jsm>create</jsm>();
AuthScope scope = <jk>new</jk> AuthScope(<jsf>HOST</jsf>, <jsf>PORT</jsf>);
Credentials up = <jk>new</jk> UsernamePasswordCredentials(<jsf>USER</jsf>, <jsf>PW</jsf>);
CredentialsProvider p = <jk>new</jk> BasicCredentialsProvider();
p.setCredentials(scope, up);
builder.setDefaultCredentialsProvider(p);
</p>
</div><!-- END: 9.3.1 - juneau-rest-client.Authentication.BASIC -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.Authentication.FORM' id='juneau-rest-client.Authentication.FORM'>9.3.2 - FORM-based Authentication</a></h4>
<div class='topic'><!-- START: 9.3.2 - juneau-rest-client.Authentication.FORM -->
<p>
The {@link org.apache.juneau.rest.client.RestClientBuilder} class does not itself provide FORM-based
authentication since there is no standard way of providing such support.
Typically, to perform FORM-based or other types of authentication, you'll want to create your own
subclass of {@link org.apache.juneau.rest.client.RestClientBuilder} and override the
{@link org.apache.juneau.rest.client.RestClientBuilder#createHttpClient()} method to provide an
authenticated client.
</p>
<p>
The following example shows how the <c>JazzRestClient</c> class provides FORM-based
authentication support.
</p>
<p class='bpcode w800'>
<jd>/**
* Constructor.
*/</jd>
<jk>public</jk> JazzRestClientBuilder(URI jazzUri, String user, String pw) <jk>throws</jk> IOException {
...
}
<jd>/**
* Override the createHttpClient() method to return an authenticated client.
*/</jd>
<ja>@Override</ja> <jc>/* RestClientBuilder */</jc>
<jk>protected</jk> CloseableHttpClient createHttpClient() <jk>throws</jk> Exception {
CloseableHttpClient client = <jk>super</jk>.createHttpClient();
formBasedAuthenticate(client);
visitAuthenticatedURL(client);
<jk>return</jk> client;
}
<jc>/*
* Performs form-based authentication against the Jazz server.
*/</jc>
<jk>private void</jk> formBasedAuthenticate(HttpClient client) <jk>throws</jk> IOException {
URI uri2 = <jf>jazzUri</jf>.resolve(<js>"j_security_check"</js>);
HttpPost request = <jk>new</jk> HttpPost(uri2);
request.setConfig(RequestConfig.<jsm>custom</jsm>().setRedirectsEnabled(<jk>false</jk>).build());
<jc>// Charset must explicitly be set to UTF-8 to handle user/pw with non-ascii characters.</jc>
request.addHeader(<js>"Content-Type"</js>, <js>"application/x-www-form-urlencoded; charset=utf-8"</js>);
NameValuePairs params = <jk>new</jk> NameValuePairs()
.append(<jk>new</jk> BasicNameValuePair(<js>"j_username""</js>, <jf>user</jf>))
.append(<jk>new</jk> BasicNameValuePair(<js>"j_password"</js>, <jf>pw</jf>));
request.setEntity(<jk>new</jk> UrlEncodedFormEntity(params));
HttpResponse response = client.execute(request);
<jk>try</jk> {
<jk>int</jk> rc = response.getStatusLine().getStatusCode();
Header authMsg = response.getFirstHeader(<js>"X-com-ibm-team-repository-web-auth-msg"</js>);
<jk>if</jk> (authMsg != <jk>null</jk>)
<jk>throw new</jk> IOException(authMsg.getValue());
<jc>// The form auth request should always respond with a 200 ok or 302 redirect code</jc>
<jk>if</jk> (rc == <jsf>SC_MOVED_TEMPORARILY</jsf>) {
<jk>if</jk> (response.getFirstHeader(<js>"Location"</js>).getValue().matches(<js>"^.*/auth/authfailed.*$"</js>))
<jk>throw new</jk> IOException(<js>"Invalid credentials."</js>);
} <jk>else if</jk> (rc != <jsf>SC_OK</jsf>) {
<jk>throw new</jk> IOException(<js>"Unexpected HTTP status: "</js> + rc);
}
} <jk>finally</jk> {
EntityUtils.<jsm>consume</jsm>(response.getEntity());
}
}
<jc>/*
* This is needed for Tomcat because it responds with SC_BAD_REQUEST when the j_security_check URL is visited before an
* authenticated URL has been visited. This same URL must also be visited after authenticating with j_security_check
* otherwise tomcat will not consider the session authenticated
*/</jc>
<jk>private int</jk> visitAuthenticatedURL(HttpClient httpClient) <jk>throws</jk> IOException {
HttpGet authenticatedURL = <jk>new</jk> HttpGet(<jf>jazzUri</jf>.resolve(<js>"authenticated/identity"</js>));
HttpResponse response = httpClient.execute(authenticatedURL);
<jk>try</jk> {
<jk>return</jk> response.getStatusLine().getStatusCode();
} <jk>finally</jk> {
EntityUtils.<jsm>consume</jsm>(response.getEntity());
}
}
</p>
</div><!-- END: 9.3.2 - juneau-rest-client.Authentication.FORM -->
<!-- ==================================================================================================== -->
<h4 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.Authentication.OIDC' id='juneau-rest-client.Authentication.OIDC'>9.3.3 - OIDC Authentication</a></h4>
<div class='topic'><!-- START: 9.3.3 - juneau-rest-client.Authentication.OIDC -->
<p>
The following example shows how the <c>JazzRestClient</c> class provides OIDC authentication
support.
</p>
<p class='bpcode w800'>
<jd>/**
* Constructor.
*/</jd>
<jk>public</jk> JazzRestClientBuilder(URI jazzUri, String user, String pw) <jk>throws</jk> IOException {
...
}
<jd>/**
* Override the createHttpClient() method to return an authenticated client.
*/</jd>
<ja>@Override</ja> <jc>/* RestClientBuilder */</jc>
<jk>protected</jk> CloseableHttpClient createHttpClient() <jk>throws</jk> Exception {
CloseableHttpClient client = <jk>super</jk>.createHttpClient();
oidcAuthenticate(client);
<jk>return</jk> client;
}
<jk>private void</jk> oidcAuthenticate(HttpClient client) <jk>throws</jk> IOException {
HttpGet request = <jk>new</jk> HttpGet(<jf>jazzUri</jf>);
request.setConfig(RequestConfig.<jsm>custom</jsm>().setRedirectsEnabled(<jk>false</jk>).build());
<jc>// Charset must explicitly be set to UTF-8 to handle user/pw with non-ascii characters.</jc>
request.addHeader(<js>"Content-Type"</js>, <js>"application/x-www-form-urlencoded; charset=utf-8"</js>);
HttpResponse response = client.execute(request);
<jk>try</jk> {
<jk>int</jk> code = response.getStatusLine().getStatusCode();
<jc>// Already authenticated</jc>
<jk>if</jk> (code == <jsf>SC_OK</jsf>)
<jk>return</jk>;
<jk>if</jk> (code != <jsf>SC_UNAUTHORIZED</jsf>)
<jk>throw new</jk> RestCallException(<js>"Unexpected response during OIDC authentication: "</js>
+ response.getStatusLine());
<jc>// x-jsa-authorization-redirect</jc>
String redirectUri = getHeader(response, <js>"X-JSA-AUTHORIZATION-REDIRECT"</js>);
<jk>if</jk> (redirectUri == <jk>null</jk>)
<jk>throw new</jk> RestCallException(<js>"Expected a redirect URI during OIDC authentication: "</js>
+ response.getStatusLine());
<jc>// Handle Bearer Challenge</jc>
HttpGet method = <jk>new</jk> HttpGet(redirectUri + <js>"&amp;prompt=none"</js>);
addDefaultOidcHeaders(method);
response = client.execute(method);
code = response.getStatusLine().getStatusCode();
<jk>if</jk> (code != <jsf>SC_OK</jsf>)
<jk>throw new</jk> RestCallException(<js>"Unexpected response during OIDC authentication phase 2: "</js>
+ response.getStatusLine());
String loginRequired = getHeader(response, <js>"X-JSA-LOGIN-REQUIRED"</js>);
<jk>if</jk> (! <js>"true"</js>.equals(loginRequired))
<jk>throw new</jk> RestCallException(<js>"X-JSA-LOGIN-REQUIRED header not found on response during OIDC authentication phase 2: "</js>
+ response.getStatusLine());
method = <jk>new</jk> HttpGet(redirectUri + <js>"&amp;prompt=none"</js>);
addDefaultOidcHeaders(method);
response = client.execute(method);
code = response.getStatusLine().getStatusCode();
<jk>if</jk> (code != <jsf>SC_OK</jsf>)
<jk>throw new</jk> RestCallException(<js>"Unexpected response during OIDC authentication phase 3: "</js>
+ response.getStatusLine());
<jc>// Handle JAS Challenge</jc>
method = <jk>new</jk> HttpGet(redirectUri);
addDefaultOidcHeaders(method);
response = client.execute(method);
code = response.getStatusLine().getStatusCode();
<jk>if</jk> (code != <jsf>SC_OK</jsf>)
<jk>throw new</jk> RestCallException(<js>"Unexpected response during OIDC authentication phase 4: "</js>
+ response.getStatusLine());
<jf>cookie</jf> = getHeader(response, <js>"Set-Cookie"</js>);
Header[] defaultHeaders = <jk>new</jk> Header[] {
<jk>new</jk> BasicHeader(<js>"User-Agent"</js>, <js>"Jazz Native Client"</js>),
<jk>new</jk> BasicHeader(<js>"X-com-ibm-team-configuration-versions"</js>,
<js>"com.ibm.team.rtc=6.0.0,com.ibm.team.jazz.foundation=6.0"</js>),
<jk>new</jk> BasicHeader(<js>"Accept"</js>, <js>"text/json"</js>),
<jk>new</jk> BasicHeader(<js>"Authorization"</js>, <js>"Basic "</js>
+ StringUtils.<jsm>base64EncodeToString</jsm>(<jf>user</jf> + <js>":"</js> + <jf>pw</jf>)),
<jk>new</jk> BasicHeader(<js>"Cookie"</js>, cookie)
};
setDefaultHeaders(Arrays.<jsm>asList</jsm>(defaultHeaders));
} <jk>finally</jk> {
EntityUtils.<jsm>consume</jsm>(response.getEntity());
}
}
<jk>private void</jk> addDefaultOidcHeaders(HttpRequestBase method) {
method.addHeader(<js>"User-Agent"</js>, <js>"Jazz Native Client"</js>);
method.addHeader(<js>"X-com-ibm-team-configuration-versions"</js>,
<js>"com.ibm.team.rtc=6.0.0,com.ibm.team.jazz.foundation=6.0"</js>);
method.addHeader(<js>"Accept"</js>, <js>"text/json"</js>);
<jk>if</jk> (<jf>cookie</jf> != <jk>null</jk>) {
method.addHeader(<js>"Authorization"</js>, <js>"Basic "</js>
+ StringUtils.<jsm>base64EncodeToString</jsm>(<jf>user</jf> + <js>":"</js> + <jf>pw</jf>));
method.addHeader(<js>"Cookie"</js>, cookie);
}
}
</p>
</div><!-- END: 9.3.3 - juneau-rest-client.Authentication.OIDC -->
</div><!-- END: 9.3 - juneau-rest-client.Authentication -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.ResponsePatterns' id='juneau-rest-client.ResponsePatterns'>9.4 - Using Response Patterns</a></h3>
<div class='topic'><!-- START: 9.4 - juneau-rest-client.ResponsePatterns -->
<p>
One issue with REST (and HTTP in general) is that the HTTP response code must be set as a header before the
body of the request is sent.
This can be problematic when REST calls invoke long-running processes, pipes
the results through the connection, and then fails after an HTTP 200 has already been sent.
</p>
<p>
One common solution is to serialize some text at the end to indicate whether the long-running process
succeeded (e.g. <js>"FAILED"</js> or <js>"SUCCEEDED"</js>).
</p>
<p>
The {@link org.apache.juneau.rest.client.RestClient} class has convenience methods for scanning the
response without interfering with the other methods used for retrieving output.
</p>
<p>
The following example shows how the {@link org.apache.juneau.rest.client.RestCall#successPattern(String)}
method can be used to look for a SUCCESS message in the output:
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Throw a RestCallException if SUCCESS is not found in the output.</jc>
restClient.doPost(<jsf>URL</jsf>)
.successPattern(<js>"SUCCESS"</js>)
.run();
</p>
<p>
The {@link org.apache.juneau.rest.client.RestCall#failurePattern(String)} method does the opposite.
It throws an exception if a failure message is detected.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Throw a RestCallException if FAILURE or ERROR is found in the output.</jc>
restClient.doPost(<jsf>URL</jsf>)
.failurePattern(<js>"FAILURE|ERROR"</js>)
.run();
</p>
<p>
These convenience methods are specialized methods that use the
{@link org.apache.juneau.rest.client.RestCall#responsePattern(ResponsePattern)} method which uses regular
expression matching against the response body.
This method can be used to search for arbitrary patterns in the response body.
</p>
<p>
The following example shows how to use a response pattern finder to find and capture patterns for
<js>"x=number"</js> and <js>"y=string"</js> from a response body.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jk>final</jk> List&lt;Number&gt; xList = <jk>new</jk> ArrayList&lt;Number&gt;();
<jk>final</jk> List&lt;String&gt; yList = <jk>new</jk> ArrayList&lt;String&gt;();
String responseText = restClient.doGet(<jsf>URL</jsf>)
.responsePattern(
<jk>new</jk> ResponsePattern(<js>"x=(\\d+)"</js>) {
<ja>@Override</ja>
<jk>public void</jk> onMatch(RestCall restCall, Matcher m) <jk>throws</jk> RestCallException {
xList.add(Integer.<jsm>parseInt</jsm>(m.group(1)));
}
<ja>@Override</ja>
<jk>public void</jk> onNoMatch(RestCall restCall) <jk>throws</jk> RestCallException {
<jk>throw new</jk> RestCallException(<js>"No X's found!"</js>);
}
}
)
.responsePattern(
<jk>new</jk> ResponsePattern(<js>"y=(\\S+)"</js>) {
<ja>@Override</ja>
<jk>public void</jk> onMatch(RestCall restCall, Matcher m) <jk>throws</jk> RestCallException {
yList.add(m.group(1));
}
<ja>@Override</ja>
<jk>public void</jk> onNoMatch(RestCall restCall) <jk>throws</jk> RestCallException {
<jk>throw new</jk> RestCallException(<js>"No Y's found!"</js>);
}
}
)
.getResponseAsString();
</p>
<p>
Using response patterns does not affect the functionality of any of the other methods
used to retrieve the response such as {@link org.apache.juneau.rest.client.RestCall#getResponseAsString()}
or {@link org.apache.juneau.rest.client.RestCall#getResponse(Class)}.
HOWEVER, if you want to retrieve the entire text of the response from inside the match methods,
use {@link org.apache.juneau.rest.client.RestCall#getCapturedResponse()} since this method will not absorb
the response for those other methods.
</p>
</div><!-- END: 9.4 - juneau-rest-client.ResponsePatterns -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.PipingOutput' id='juneau-rest-client.PipingOutput'>9.5 - Piping Response Output</a></h3>
<div class='topic'><!-- START: 9.5 - juneau-rest-client.PipingOutput -->
<p>
The {@link org.apache.juneau.rest.client.RestCall} class provides various convenience <c>pipeTo()</c>
methods to pipe output to output streams and writers.
</p>
<p>
If you want to pipe output without any intermediate buffering, you can use the
{@link org.apache.juneau.rest.client.RestCall#byLines()} method.
This will cause the output to be piped and flushed after every line.
This can be useful if you want to display the results in real-time from a long running process producing
output on a REST call.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Pipe output from REST call to System.out in real-time.</jc>
restClient.doPost(<jsf>URL</jsf>).byLines().pipeTo(<jk>new</jk> PrintWriter(System.<jk>out</jk>)).run();
</p>
</div><!-- END: 9.5 - juneau-rest-client.PipingOutput -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.Debugging' id='juneau-rest-client.Debugging'>9.6 - Debugging</a></h3>
<div class='topic'><!-- START: 9.6 - juneau-rest-client.Debugging -->
<p>
Use the {@link org.apache.juneau.rest.client.RestClientBuilder#debug()} method to enable logging for HTTP requests
made from the client.
</p>
<p>
Under-the-covers, this is simply a shortcut for adding the {@link org.apache.juneau.rest.client.RestCallLogger#DEFAULT}
interceptor to the client.
This causes the following output to be generated by the Java <c>org.apache.juneau.rest.client</c>
logger at <jsf>WARNING</jsf> level:
</p>
<p class='bpcode w800 console'>
=== HTTP Call (outgoing) =======================================================
=== REQUEST ===
POST http://localhost:10000/testUrl HTTP/1.1
---request headers---
Debug: true
No-Trace: true
Accept: application/json
---request entity---
Content-Type: application/json
---request content---
{"foo":"bar","baz":123}
=== RESPONSE ===
HTTP/1.1 200 OK
---response headers---
Content-Type: application/json;charset=utf-8
Content-Length: 21
Server: Jetty(8.1.0.v20120127)
---response content---
{"message":"OK then"}
=== END ========================================================================
</p>
<p>
This setting also causes a <c>Debug: true</c> header value to trigger logging of the request on the
server side as well.
</p>
<p class='bpcode w800 console'>
=== HTTP Request (incoming) ====================================================
HTTP POST /testUrl
---Headers---
Host: localhost:10000
Transfer-Encoding: chunked
Accept: application/json
Content-Type: application/json
User-Agent: Apache-HttpClient/4.5 (Java/1.6.0_65)
Connection: keep-alive
Debug: true
Accept-Encoding: gzip,deflate
---Default Servlet Headers---
---Body---
{"foo":"bar","baz":123}
=== END ========================================================================
</p>
</div><!-- END: 9.6 - juneau-rest-client.Debugging -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.Logging' id='juneau-rest-client.Logging'>9.7 - Logging</a></h3>
<div class='topic'><!-- START: 9.7 - juneau-rest-client.Logging -->
<p>
Use the {@link org.apache.juneau.rest.client.RestClientBuilder#logTo(Level,Logger)} and
{@link org.apache.juneau.rest.client.RestCall#logTo(Level,Logger)} methods to log HTTP calls.
These methods will cause the HTTP request and response headers and body to be logged to the specified logger.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Log the HTTP request/response to the specified logger.</jc>
<jk>int</jk> rc = restClient.doGet(<jsf>URL</jsf>).logTo(<jsf>INFO</jsf>, getLogger()).run();
</p>
<p>
The method call is ignored if the logger level is below the specified level.
</p>
<p>
Customized logging can be handled by sub-classing the {@link org.apache.juneau.rest.client.RestCallLogger}
class and using the {@link org.apache.juneau.rest.client.RestCall#interceptor(RestCallInterceptor)} method.
</p>
</div><!-- END: 9.7 - juneau-rest-client.Logging -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.Interceptors' id='juneau-rest-client.Interceptors'>9.8 - Interceptors</a></h3>
<div class='topic'><!-- START: 9.8 - juneau-rest-client.Interceptors -->
<p>
The {@link org.apache.juneau.rest.client.RestClientBuilder#interceptors(RestCallInterceptor...)} and
{@link org.apache.juneau.rest.client.RestCall#interceptor(RestCallInterceptor)} methods can be used to
intercept responses during specific connection lifecycle events.
</p>
<p>
The {@link org.apache.juneau.rest.client.RestCallLogger} class is an example of an interceptor that uses
the various lifecycle methods to log HTTP requests.
</p>
<p class='bpcode w800'>
<jd>/**
* Specialized interceptor for logging calls to a log file.
*/</jd>
<jk>public class</jk> RestCallLogger <jk>extends</jk> RestCallInterceptor {
<jk>private</jk> Level <jf>level</jf>;
<jk>private</jk> Logger <jf>log</jf>;
<jd>/**
* Constructor.
*
* <ja>@param</ja> level The log level to log messages at.
* <ja>@param</ja> log The logger to log to.
*/</jd>
<jk>protected</jk> RestCallLogger(Level level, Logger log) {
<jk>this</jk>.<jf>level</jf> = level;
<jk>this</jk>.<jf>log</jf> = log;
}
<ja>@Override</ja> <jc>/* RestCallInterceptor */</jc>
<jk>public void</jk> onInit(RestCall restCall) {
<jk>if</jk> (<jf>log</jf>.isLoggable(<jf>level</jf>))
restCall.captureResponse();
}
<ja>@Override</ja> <jc>/* RestCallInterceptor */</jc>
<jk>public void</jk> onConnect(RestCall restCall, <jk>int</jk> statusCode, HttpRequest req, HttpResponse res) {
<jc>// Do nothing.</jc>
}
<ja>@Override</ja> <jc>/* RestCallInterceptor */</jc>
<jk>public void</jk> onRetry(RestCall restCall, <jk>int</jk> statusCode, HttpRequest req, HttpResponse res) {
<jk>if</jk> (<jf>log</jf>.isLoggable(<jf>level</jf>))
<jf>log</jf>.log(level, MessageFormat.<jsm>format</jsm>(<js>"Call to {0} returned {1}. Will retry."</js>, req.getRequestLine().getUri(), statusCode));
}
<ja>@Override</ja> <jc>/* RestCallInterceptor */</jc>
<jk>public void</jk> onClose(RestCall restCall) <jk>throws</jk> RestCallException {
<jk>try</jk> {
<jk>if</jk> (<jf>log</jf>.isLoggable(<jf>level</jf>)) {
String output = restCall.getCapturedResponse();
StringBuilder sb = <jk>new</jk> StringBuilder();
HttpUriRequest req = restCall.getRequest();
HttpResponse res = restCall.getResponse();
<jk>if</jk> (req != <jk>null</jk>) {
sb.append(<js>"\n=== HTTP Call (outgoing) ========================================================="</js>);
sb.append(<js>"\n=== REQUEST ===\n"</js>).append(req);
sb.append(<js>"\n---request headers---"</js>);
<jk>for</jk> (Header h : req.getAllHeaders())
sb.append(<js>"\n"</js>).append(h);
<jk>if</jk> (req <jk>instanceof</jk> HttpEntityEnclosingRequestBase) {
sb.append(<js>"\n---request entity---"</js>);
HttpEntityEnclosingRequestBase req2 = (HttpEntityEnclosingRequestBase)req;
HttpEntity e = req2.getEntity();
<jk>if</jk> (e == <jk>null</jk>)
sb.append(<js>"\nEntity is null"</js>);
<jk>else</jk> {
<jk>if</jk> (e.getContentType() != <jk>null</jk>)
sb.append(<js>"\n"</js>).append(e.getContentType());
<jk>if</jk> (e.getContentEncoding() != <jk>null</jk>)
sb.append(<js>"\n"</js>).append(e.getContentEncoding());
<jk>if</jk> (e.isRepeatable()) {
<jk>try</jk> {
sb.append(<js>"\n---request content---\n"</js>).append(EntityUtils.<jsm>toString</jsm>(e));
} <jk>catch</jk> (Exception ex) {
<jk>throw new</jk> RuntimeException(ex);
}
}
}
}
}
<jk>if</jk> (res != <jk>null</jk>) {
sb.append(<js>"\n=== RESPONSE ===\n"</js>).append(res.getStatusLine());
sb.append(<js>"\n---response headers---"</js>);
<jk>for</jk> (Header h : res.getAllHeaders())
sb.append(<js>"\n"</js>).append(h);
sb.append(<js>"\n---response content---\n"</js>).append(output);
sb.append(<js>"\n=== END ========================================================================"</js>);
}
<jf>log</jf>.log(<jf>level</jf>, sb.toString());
}
} <jk>catch</jk> (IOException e) {
<jf>log</jf>.log(Level.<jsf>SEVERE</jsf>, e.getLocalizedMessage(), e);
}
}
}
</p>
</div><!-- END: 9.8 - juneau-rest-client.Interceptors -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-client.Other' id='juneau-rest-client.Other'>9.9 - Other Useful Methods</a></h3>
<div class='topic'><!-- START: 9.9 - juneau-rest-client.Other -->
<p>
The {@link org.apache.juneau.rest.client.RestClientBuilder#rootUrl(Object)} method can be used to specify a
root URL on all requests so that you don't have to use absolute paths on individual calls.
</p>
<p class='bpcode w800'>
<jc>// Create a rest client with a root URL</jc>
RestClient rc = RestClient.<jsm>create</jsm>().rootUrl(<js>"http://localhost:9080/foobar"</js>).build();
String r = rc.doGet(<js>"/baz"</js>).getResponseAsString(); <jc>// Gets "http://localhost:9080/foobar/baz"</jc>
</p>
<p>
The {@link org.apache.juneau.rest.client.RestClientBuilder#set(String,Object)} method can be used to
set serializer and parser properties.
For example, if you're parsing a response into POJOs and you want to ignore fields that aren't on the
POJOs, you can use the {@link org.apache.juneau.BeanContext#BEAN_ignoreUnknownBeanProperties} property.
</p>
<p class='bpcode w800'>
<jc>// Create a rest client that ignores unknown fields in the response</jc>
RestClient rc = RestClient.<jsm>create</jsm>()
.set(<jsf>BEAN_ignoreUnknownBeanProperties</jsf>, <jk>true</jk>)
<jc>// or .ignoreUnknownBeanProperties(true)</jc>
.build();
MyPojo myPojo = rc.doGet(<jsf>URL</jsf>).getResponse(MyPojo.<jk>class</jk>);
</p>
<p>
The {@link org.apache.juneau.rest.client.RestCall#retryable(int,long,RetryOn)} method can be used to
automatically retry requests on failures.
This can be particularly useful if you're attempting to connect to a REST resource that may be in the
process of still initializing.
</p>
<p class='bpcode w800'>
<jc>// Create a rest call that retries every 10 seconds for up to 30 minutes as long as a connection fails
// or a 400+ is received.</jc>
restClient.doGet(<jsf>URL</jsf>)
.retryable(180, 10000, RetryOn.<jsf>DEFAULT</jsf>)
.run();
</p>
</div><!-- END: 9.9 - juneau-rest-client.Other -->
</div><!-- END: 9 - juneau-rest-client -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-mock' id='juneau-rest-mock'>10 - juneau-rest-mock</a></h2>
<div class='topic'><!-- START: 10 - juneau-rest-mock -->
<h5 class='figure'>Maven Dependency</h5>
<p class='bpcode w500'>
<xt>&lt;dependency&gt;</xt>
<xt>&lt;groupId&gt;</xt>org.apache.juneau<xt>&lt;/groupId&gt;</xt>
<xt>&lt;artifactId&gt;</xt>juneau-rest-mock<xt>&lt;/artifactId&gt;</xt>
<xt>&lt;version&gt;</xt>{@property juneauVersion}<xt>&lt;/version&gt;</xt>
<xt>&lt;/dependency&gt;</xt>
</p>
<h5 class='figure'>Java Library</h5>
<p class='bpcode w500'>
juneau-rest-mock-{@property juneauVersion}.jar
</p>
<h5 class='figure'>OSGi Module</h5>
<p class='bpcode w500'>
org.apache.juneau.rest.mock_{@property juneauVersion}.jar
</p>
<p>
The <c>juneau-rest-mock</c> module contains convenience APIs for performing serverless unit
testing of your REST APIs.
Each of the APIs provide the ability to fully test your server and client REST interfaces without the
need for a running servlet container.
</p>
<p>
The API consists of the following classes:
</p>
<ul class='javatree'>
<li class='jp'>{@link org.apache.juneau.rest.mock2}
<ul>
<li class='jc'>{@link org.apache.juneau.rest.mock2.MockRest} - API for unit testing {@link org.apache.juneau.rest.annotation.Rest @Rest}-annotated classes.
<li class='jc'>{@link org.apache.juneau.rest.mock2.MockRemote} - API for unit testing {@link org.apache.juneau.http.remote.Remote @Remote}-annotated classes.
</ul>
</ul>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-mock.MockRest' id='juneau-rest-mock.MockRest'>10.1 - MockRest</a></h3>
<div class='topic'><!-- START: 10.1 - juneau-rest-mock.MockRest -->
<p>
The {@link org.apache.juneau.rest.mock2.MockRest} class is used for performing serverless unit testing of {@link org.apache.juneau.rest.annotation.Rest @Rest}-annotated
classes. These include both parent resource classes that extend from {@link org.apache.juneau.rest.RestServlet} and child resources that do not.
</p>
<p>
The API consists of the following classes:
</p>
<ul class='javatree'>
<li class='jp'>{@link org.apache.juneau.rest.mock2}
<ul>
<li class='jc'>{@link org.apache.juneau.rest.mock2.MockRest}
<br>The API for instantiating mocks of REST resource classes.
<li class='jc'>{@link org.apache.juneau.rest.mock2.MockServletRequest}
<br>An implementation of {@link javax.servlet.http.HttpServletRequest} with additional convenience methods for building requests.
<li class='jc'>{@link org.apache.juneau.rest.mock2.MockServletResponse}
<br>An implementation of {@link javax.servlet.http.HttpServletRequest} with additional convenience methods for testing responses.
</ul>
</ul>
<p>
The following shows a simple example of invoking a PUT method on a simple REST interface and asserting
the correct status code and response body:
</p>
<p class='bpcode w800'>
<jk>public class</jk> MockTest {
<jc>// Our REST resource to test.</jc>
<ja>@Rest</ja>(
serializers=SimpleJsonSerializer.<jk>class</jk>,
parsers=JsonParser.<jk>class</jk>
)
<jk>public static class</jk> EchoRest {
<ja>@RestMethod</ja>(
name=<jsf>PUT</jsf>,
path=<js>"/echo"</js>
)
<jk>public</jk> String echo(<ja>@Body</ja> String body) {
<jk>return</jk> body;
}
}
<jc>// Our JUnit test.</jc>
<ja>@Test</ja>
<jk>public void</jk> testEcho() <jk>throws</jk> Exception {
MockRest mr = MockRest.<jsm>build</jsm>(EchoRest.<jk>class</jk>);
mr
.put(<js>"/echo"</js>, <js>"'foo'"</js>)
.execute()
.assertStatus(200)
.assertBody(<js>"'foo'"</js>);
}
}
</p>
<p>
Breaking apart the fluent method call above will help you understand how this works.
</p>
<p class='bpcode w800'>
<ja>@Test</ja>
<jk>public void</jk> testEcho() <jk>throws</jk> Exception {
<jc>// Instantiate our mock.</jc>
MockRest mr = MockRest.<jsm>build</jsm>(EchoRest.<jk>class</jk>);
<jc>// Create a request.</jc>
MockServletRequest req = mr.put(<js>"/echo"</js>, <js>"'foo'"</js>);
<jc>// Execute it (by calling RestCallHandler.service(...) and then returning the response object).</jc>
MockServletResponse res = req.execute();
<jc>// Run assertion tests on the results.</jc>
res.assertStatus(200);
res.assertBody(<js>"'foo'"</js>);
}
</p>
<p>
The concept of the design is simple. The {@link org.apache.juneau.rest.mock2.MockRest} class is used to create instances of {@link org.apache.juneau.rest.mock2.MockServletRequest}
and {@link org.apache.juneau.rest.mock2.MockServletResponse} which are passed directly to the call handler on the resource class {@link org.apache.juneau.rest.RestCallHandler#service(HttpServletRequest,HttpServletResponse)}.
In effect, you're fully testing your REST API as if it were running in a live servlet container, yet not
actually having to run in a servlet container.
</p>
<p>
The <c>create(Object)</c> method can take in either <c>Class</c> objects or pre-instantiated beans.
The latter is particularly useful for testing Spring beans.
</p>
<hr>
<p>
By default, the {@link org.apache.juneau.rest.mock2.MockRest} class specifies the following request headers:
</p>
<p class='bpcode w800'>
Accept: application/json+simple
Content-Type: application/json
</p>
<p>
The reason for using <js>"application/json+simple"</js> as the default is that it significantly simplifies
testing by allowing you to compare response content with simple Java strings without having to escape lots
of quotes:
</p>
<p class='bpcode w800'>
<jc>// Using Simple JSON</jc>
mr.assertBody(<js>"{foo:'bar':baz:123}"</js>);
<jc>// Using normal JSON</jc>
mr.assertBody(<js>"{\"foo\":\"bar\",\"baz\":123}"</js>);
</p>
<p>
Other media types headers can be specified via any of the following methods:
</p>
<ul class='javatree'>
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRest#build(Object,Marshall) build(Object,Marshall)} - Use media types defined on a marshall.
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRest#build(Object,Serializer,Parser) build(Object,Serializer,Parser)} - Use media types defined on a serializer and parser.
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRest.Builder#accept(String) accept(String)} - Explicitly set the <c>Accept</c> header.
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRest.Builder#contentType(String) contentType(String)} - Explicitly set the <c>Content-Type</c> header.
</ul>
<p>
Various other convenience methods for common media types are also provided.
</p>
<p>
The following examples are functionally equivalent for specifying XML serialization:
</p>
<p class='bpcode w800'>
MockRest mr;
mr = MockRest.<jsm>build</jsm>(EchoRest.<jk>class</jk>, Xml.<jsf>DEFAULT</jsf>);
mr = MockRest.<jsm>build</jsm>(EchoRest.<jk>class</jk>, XmlSerializer.<jsf>DEFAULT</jsf>, XmlParser.<jsf>DEFAULT</jsf>);
mr = MockRest.<jsm>create</jsm>(EchoRest.<jk>class</jk>).marshall(Xml.<jsf>DEFAULT</jsf>).build();
mr = MockRest.<jsm>create</jsm>(EchoRest.<jk>class</jk>).serializer(XmlSerializer.<jsf>DEFAULT</jsf>).parser(XmlParser.<jsf>DEFAULT</jsf>).build();
mr = MockRest.<jsm>create</jsm>(EchoRest.<jk>class</jk>).accept(<js>"text/xml"</js>).contentType(<js>"text/xml"</js>).build();
mr = MockRest.<jsm>create</jsm>(EchoRest.<jk>class</jk>).xml().build();
</p>
<hr>
<p>
The {@link org.apache.juneau.rest.mock2.MockRest} class provides the following methods for creating requests:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.mock2.MockRest}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRest#request(String,String) request(String,String)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRest#request(String,String,Object) request(String,String,Object)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRest#get(String) get(String)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRest#put(String,Object) put(String,Object)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRest#post(String,Object) post(String,Object)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRest#delete(String) delete(String)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRest#patch(String,Object) patch(String,Object)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRest#options(String) options(String)}
</ul>
</ul>
<p>
For HTTP methods that pass a request body (i.e. <c>PUT</c>,<c>POST</c><c>PATCH</c>), the body object can be any of the following types:
</p>
<ul>
<li><c><jk>byte</jk>[]</c>
<li>{@link java.io.Reader}
<li>{@link java.io.InputStream}
<li>{@link java.lang.CharSequence}
</ul>
<p>
All other body object types are converted to strings using the <c>toString()</c> method.
</p>
<p>
A common tactic is to override a bean's <c>toString()</c> method to return Simple JSON so that
instances can be passed to the methods above.
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyBean {
...
<ja>@Override</ja>
<jk>public</jk> String toString() {
SimpleJson.<jsf>DEFAULT</jsf>.toString(<jk>this</jk>);
}
}
</p>
<p>
The {@link org.apache.juneau.rest.mock2.MockServletRequest} class provides default implementations for all the methods defined
on the {@link javax.servlet.http.HttpServletRequest} in addition to many convenience methods.
</p>
<p>
The following fluent convenience methods are provided for setting common <c>Accept</c> and <c>Content-Type</c> headers.
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.mock2.MockServletRequest}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#json() json()}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#xml() xml()}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#html() html()}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#plainText() plainText()}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#msgpack() msgpack()}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#uon() uon()}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#urlEnc() urlEnc()}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#yaml() yaml()}
</ul>
</ul>
<p>
The following fluent convenience methods are provided for building up your request.
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.mock2.MockServletRequest}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#header(String,Object) header(String,Object)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#query(String,Object) query(String,Object}}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#formData(String,Object) formData(String,Object)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#attribute(String,Object) attribute(String,Object)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#body(Object) body(Object)}
</ul>
</ul>
<p>
Fluent setters are provided for all common request headers:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.mock2.MockServletRequest}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#accept(Object) accept(Object)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#acceptCharset(Object) acceptCharset(Object)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#acceptEncoding(Object) acceptEncoding(Object)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletRequest#acceptLanguage(Object) acceptLanguage(Object)}
<li class='jm'>...
</ul>
</ul>
<p>
The {@link org.apache.juneau.rest.mock2.MockServletResponse} class provides default implementations for all the methods defined
on the {@link javax.servlet.http.HttpServletResponse} in addition to many convenience methods.
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.mock2.MockServletResponse}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletResponse#getBody() getBody()}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletResponse#getBodyAsString() getBodyAsString()}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletResponse#assertStatus(int) assertStatus(int)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletResponse#assertBody(String) assertBody(String)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletResponse#assertBodyContains(String...) assertBodyContains(String...)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletResponse#assertBodyMatches(String) assertBodyMatches(String)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletResponse#assertBodyMatchesRE(String) assertBodyMatchesRE(String)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletResponse#assertHeader(String,String) assertHeader(String,String)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockServletResponse#assertHeaderContains(String,String...) assertHeaderContains(String,String...)}
</ul>
</ul>
<hr>
<p>
The {@link org.apache.juneau.rest.mock2.MockRest} class has a debug mode that will cause your HTTP requests and responses to
be sent to the console:
</p>
<p class='bpcode w800'>
MockRest mr = MockRest
.<jsm>create</jsm>(MyRest.<jk>class</jk>)
.debug()
.simpleJson()
.build();
</p>
</div><!-- END: 10.1 - juneau-rest-mock.MockRest -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-rest-mock.MockRemote' id='juneau-rest-mock.MockRemote'>10.2 - MockRemote</a></h3>
<div class='topic'><!-- START: 10.2 - juneau-rest-mock.MockRemote -->
<p>
The {@link org.apache.juneau.rest.mock2.MockRemote} class is used for serverless unit testing of {@link org.apache.juneau.http.remote.Remote @Remote}-annotated
classes.
</p>
<p>
The {@link org.apache.juneau.rest.mock2.MockRemote} API requires a {@link org.apache.juneau.rest.annotation.Rest @Rest}-annotated class to be used as
an underlying mocked resource to process the request and return a response.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// Our remote resource to test.</jc>
<ja>@Remote</ja>
<jk>public interface</jk> MyRemoteInterface {
<ja>@RemoteMethod</ja>(httpMethod=<js>"GET"</js>, path=<js>"/echoQuery"</js>)
<jk>public int</jk> echoQuery(<ja>@Query</ja>(name=<js>"id"</js>) <jk>int</jk> id);
}
<jc>// Our mocked-up REST interface to test against.</jc>
<ja>@Rest</ja>
<jk>public class</jk> MyRest {
<ja>@RestMethod</ja>(name=GET, path=<js>"/echoQuery"</js>)
<jk>public int</jk> echoQuery(<ja>@Query</ja>(<js>"id"</js>) String id) {
<jk>return</jk> id;
}
}
<ja>@Test</ja>
<jk>public void</jk> testProxy() {
MyRemoteInterface mri = MockRemote.build(MyRemoteInterface.<jk>class</jk>, MyRest.<jk>class</jk>);
<jsm>assertEquals</jsm>(123, mri.echoQuery(123));
}
</p>
<p>
It looks simple, but there's a lot going on here.
</p>
<p>
Remote resource interfaces are normally created through the {@link org.apache.juneau.rest.client.RestClient#getRemote(Class)} method.
The {@link org.apache.juneau.rest.mock2.MockRemote} will create a {@link org.apache.juneau.rest.client.RestClient} using a specialized <c>HttpClientConnectionManager</c>
designed to transform client-side <c>HttpRequest</c>/<c>HttpResponse</c> objects into server-side
{@link org.apache.juneau.rest.mock2.MockServletRequest}/{@link org.apache.juneau.rest.mock2.MockServletResponse} objects and then pass those to the {@link org.apache.juneau.rest.mock2.MockRest}
object described in the previous section.
</p>
<p>
All aspects of the client and server side code are tested, yet no servlet container is required. The actual
over-the-wire serialization is the only aspect being bypassed.
</p>
<hr>
<p>
By default, the {@link org.apache.juneau.rest.mock2.MockRemote} class uses JSON marshalling.
This can be overridden via any of the following methods:
</p>
<ul class='javatree'>
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRemote#build(Class,Object,Marshall)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRemote#build(Class,Object,Serializer,Parser)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRemote#create(Class,Object,Marshall)}
<li class='jm'>{@link org.apache.juneau.rest.mock2.MockRemote#create(Class,Object,Serializer,Parser)}
</ul>
<hr>
<p>
The {@link org.apache.juneau.rest.mock2.MockRemote} class has a debug mode that will cause your HTTP requests and responses to
be sent to the console on both the client and server sides:
</p>
<p class='bpcode w800'>
<ja>@Test</ja>
<jk>public void</jk> testProxy() {
MyRemoteInterface mri = MockRemote
.create(MyRemoteInterface.<jk>class</jk>, MyRest.<jk>class</jk>)
.debug()
.build();
<jsm>assertEquals</jsm>(123, mri.echoQuery(123));
}
</p>
</div><!-- END: 10.2 - juneau-rest-mock.MockRemote -->
</div><!-- END: 10 - juneau-rest-mock -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-core' id='juneau-microservice-core'>11 - juneau-microservice-core</a></h2>
<div class='topic'><!-- START: 11 - juneau-microservice-core -->
<div class='warn'>
The Juneau Microservice libraries are likely to be removed in Juneau 9.0 due to the popularity of the Spring Boot
framework for creating microservices and the ability for Juneau to be used within Spring Boot.
</div>
<h5 class='figure'>Maven Dependency</h5>
<p class='bpcode w500'>
<xt>&lt;dependency&gt;</xt>
<xt>&lt;groupId&gt;</xt>org.apache.juneau<xt>&lt;/groupId&gt;</xt>
<xt>&lt;artifactId&gt;</xt>juneau-microservice-core<xt>&lt;/artifactId&gt;</xt>
<xt>&lt;version&gt;</xt>{@property juneauVersion}<xt>&lt;/version&gt;</xt>
<xt>&lt;/dependency&gt;</xt>
</p>
<h5 class='figure'>Java Library</h5>
<p class='bpcode w500'>
juneau-microservice-core-{@property juneauVersion}.jar
</p>
<h5 class='figure'>OSGi Module</h5>
<p class='bpcode w500'>
org.apache.juneau.microservice.core_{@property juneauVersion}.jar
</p>
<p>
Juneau Microservice is an API for creating stand-alone executable jars with automatic support for
Juneau configurations and console commands.
</p>
<p>
Features include:
</p>
<ul class='spaced-list'>
<li>
A builder-based API for defining and starting microservices.
<li>
An extensible API that allows you to hook into various lifecycle events.
<li>
Simple-to-use APIs for accessing manifest file entries, command-line arguments, and external configuration
file properties.
</ul>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-core.Overview' id='juneau-microservice-core.Overview'>11.1 - Microservice Overview</a></h3>
<div class='topic'><!-- START: 11.1 - juneau-microservice-core.Overview -->
<p>
The Microservice API consists of a base class for defining executable microservices.
</p>
<p>
Features include:
</p>
<ul class='spaced-list'>
<li>
A builder-based API for defining and starting microservices.
<li>
An extensible API that allows you to hook into various lifecycle events.
<li>
Simple-to-use APIs for accessing manifest file entries, command-line arguments, and external configuration
file properties.
</ul>
<p>
The Microservice API consists of the following packages and classes:
</p>
<ul class='javatree'>
<li class='jp'>{@link org.apache.juneau.microservice}
<ul>
<li class='jc'>{@link org.apache.juneau.microservice.Microservice} - The base microservice class.
<li class='jc'>{@link org.apache.juneau.microservice.MicroserviceBuilder} - Builder for the microservice class.
<li class='jic'>{@link org.apache.juneau.microservice.MicroserviceListener} - Interface for hooking into lifecyle events of the microservice.
<ul>
<li class='jc'>{@link org.apache.juneau.microservice.BasicMicroserviceListener} - Adapter for MicroserviceListener class.
</ul>
</ul>
<li class='jp'>{@link org.apache.juneau.microservice.console}
<ul>
<li class='jac'>{@link org.apache.juneau.microservice.console.ConsoleCommand} - Abstract class for defining console commands.
</ul>
</ul>
<p>
By itself the Microservice API doesn't provided much functionality, but it does provide the basis for the {@doc juneau-microservice-jetty Jetty Microservice} described later.
</p>
<p>
The most-basic creation of a microservice from an entry-point method is shown below:
</p>
<p class='bpcode w800'>
<jk>public class</jk> App {
<jk>public static void</jk> main(String[] args) {
Microservice
.<jsm>create</jsm>() <jc>// Create builder.</jc>
.args(args) <jc>// Pass in args.</jc>
.build() <jc>// Create microservice.</jc>
.start() <jc>// Start microservice.</jc>
;
}
}
</p>
</div><!-- END: 11.1 - juneau-microservice-core.Overview -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-core.LifecycleMethods' id='juneau-microservice-core.LifecycleMethods'>11.2 - Lifecycle Methods</a></h3>
<div class='topic'><!-- START: 11.2 - juneau-microservice-core.LifecycleMethods -->
<p>
The lifecycle methods of the {@link org.apache.juneau.microservice.Microservice} class consists of the following:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.microservice.Microservice}
<ul>
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#start() start()}
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#startConsole() startConsole()}
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#join() join()}
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#stop() stop()}
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#stopConsole() stopConsole()}
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#exit() exit()}
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#kill() kill()}
</ul>
</ul>
<p>
A typical implementation of an app with lifecycle methods might look like the following:
</p>
<p class='bpcode w800'>
<jk>public class</jk> App {
<jk>private static final</jk> Microservice <jsf>MICROSERVICE</jsf>;
<jk>public static void</jk> main(String[] args) {
<jsf>MICROSERVICE</jsf> = Microservice
.<jsm>create</jsm>() <jc>// Create builder.</jc>
.args(args) <jc>// Pass in args.</jc>
.build() <jc>// Create microservice.</jc>
.start() <jc>// Start microservice.</jc>
.startConsole() <jc>// Start console.</jc>
.join() <jc>// Join thread.</jc>
;
}
<jk>public static void</jk> restart() {
<jsf>MICROSERVICE</jsf>.stop().start();
}
<jk>public static void</jk> exit() {
<jsf>MICROSERVICE</jsf>.exit();
}
}
</p>
<p>
If your application consists of a single microservice, you can use the {@link org.apache.juneau.microservice.Microservice#getInstance()} method
from anywhere in your code:
</p>
<p class='bpcode w800'>
<jk>public class</jk> App {
<jk>public static void</jk> main(String[] args) {
Microservice
.<jsm>create</jsm>() <jc>// Create builder.</jc>
.args(args) <jc>// Pass in args.</jc>
.build() <jc>// Create microservice.</jc>
.start() <jc>// Start microservice.</jc>
.startConsole() <jc>// Start console.</jc>
.join() <jc>// Join thread.</jc>
;
}
<jk>public static void</jk> restart() {
Microservice.<jsm>getInstance</jsm>().stop().start();
}
<jk>public static void</jk> exit() {
Microservice.<jsm>getInstance</jsm>().exit();
}
}
</p>
<p>
The {@link org.apache.juneau.microservice.Microservice#startConsole()} and {@link org.apache.juneau.microservice.Microservice#stopConsole()} control
the lifecycle of the console commands.
Typically you'll want to control these separately from the app so that you can easily restart your application
from the console without affecting the console itself.
</p>
<p>
The lifecycle methods on the {@link org.apache.juneau.microservice.Microservice} class are purposely left non-final so that
subclasses can override them to provide customized behavior.
</p>
</div><!-- END: 11.2 - juneau-microservice-core.LifecycleMethods -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-core.Args' id='juneau-microservice-core.Args'>11.3 - Args</a></h3>
<div class='topic'><!-- START: 11.3 - juneau-microservice-core.Args -->
<p>
Command-line arguments can be associated with a microservice using the {@link org.apache.juneau.microservice.MicroserviceBuilder#args(String...)} method.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jk>public static void</jk> main(String[] args) {
Microservice
.<jsm>create</jsm>() <jc>// Create builder.</jc>
.args(args) <jc>// Pass in args.</jc>
.build() <jc>// Create microservice.</jc>
.start() <jc>// Start microservice.</jc>
.join() <jc>// Join thread.</jc>
;
}
</p>
<p>
When specified, the arguments can be retrieved using the {@link org.apache.juneau.microservice.Microservice#getArgs()} method which provides
an API for easily accessing command-line arguments using common notation:
</p>
<p class='bpcode w800'>
Args a = Microservice.<jsm>getInstance</jsm>().getArgs();
<jc>// One main argument</jc>
<jc>// a1</jc>
String a1 = a.getArg(0); <jc>// "a1"</jc>
String a2 = a.getArg(1); <jc>// null</jc>
<jc>// Two main arguments</jc>
<jc>// a1 a2</jc>
String a1 = a.getArg(0); <jc>// "a1"</jc>
String a2 = a.getArg(1); <jc>// "a2"</jc>
<jc>// One main argument and one optional argument with no value</jc>
<jc>// a1 -a2</jc>
String a1 = a.getArg(0);
<jk>boolean</jk> hasA2 = a.hasArg(<js>"a2"</js>); <jc>// true</jc>
<jk>boolean</jk> hasA3 = a.hasArg(<js>"a3"</js>); <jc>// false</jc>
<jc>// One main argument and one optional argument with one value</jc>
<jc>// a1 -a2 v2</jc>
String a1 = a.getArg(0);
String a2 = a.getArg(<js>"a2"</js>); <jc>// "v2"</jc>
String a3 = a.getArg(<js>"a3"</js>); <jc>// null</jc>
<jc>// One main argument and one optional argument with two values</jc>
<jc>// a1 -a2 v2a v2b</jc>
String a1 = a.getArg(0);
List&lt;String&gt; a2 = a.getArgs(<js>"a2"</js>); <jc>// Contains ["v2a","v2b"]</jc>
List&lt;String&gt; a3 = a.getArgs(<js>"a3"</js>); <jc>// Empty list</jc>
<jc>// Same as previous, except specify optional argument name multiple times</jc>
<jc>// a1 -a2 v2a -a2 v2b</jc>
String a1 = a.getArg(0);
List&lt;String&gt; a2 = a.getArgs(<js>"a2"</js>); <jc>// Contains ["v2a","v2b"]</jc>
</p>
<p>
Specifying the command-line arguments also makes them available through {@link org.apache.juneau.svl.vars.ArgsVar $A} SVL variables.
These can be used in the configuration file and throughout various Juneau annotations.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jc>// $A used in variable resolver.</jc>
VarResolver vr = Microservice.<jsm>getInstance</jsm>().getVarResolver();
System.<jsf>out</jsf>.println(vr.resolve(<js>"Arg #1 is set to $A{1}"</js>));
</p>
<p class='bpcode w800'>
<jc>// $A used in annotation.</jc>
<ja>@Rest</ja>(
title=<js>"$A{title}"</js>,
...
)
</p>
</div><!-- END: 11.3 - juneau-microservice-core.Args -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-core.Manifest' id='juneau-microservice-core.Manifest'>11.4 - Manifest</a></h3>
<div class='topic'><!-- START: 11.4 - juneau-microservice-core.Manifest -->
<p>
The {@link org.apache.juneau.microservice.MicroserviceBuilder#manifest(Object)} method can be used to specify the contents or location of of the main
manifest file of the executable jar.
</p>
<p>
If you do not specify the location/contents of the manifest file, the microservice will attempt to resolve it through the following methods:
</p>
<ol class='spaced-list'>
<li>
Looking on the file system for a file at <js>"META-INF/MANIFEST.MF"</js>.
This is primarily to allow for running microservices from within eclipse workspaces where the manifest file
is located in the project root.
<li>
Using the class loader for this class to find the file at the URL <js>"META-INF/MANIFEST.MF"</js>.
</ol>
<p>
If you do manually specify the manifest file, you can pass in any of the following types:
</p>
<ul>
<li>{@link org.apache.juneau.utils.ManifestFile} - A pre-parsed manifest file.
<li>{@link java.util.jar.Manifest} - A pre-parsed manifest file.
<li>{@link java.io.Reader} - Containing the raw contents of the manifest.
<li>{@link java.io.InputStream} - Containing the raw contents of the manifest.
<li>{@link java.io.File} - File containing the raw contents of the manifest.
<li>{@link java.lang.String} - Path to file containing the raw contents of the manifest.
<li>{@link java.lang.Class} - Finds and loads the manifest file of the jar file that the specified class is contained within.
</ul>
<p>
The manifest file can be retrieved using the the {@link org.apache.juneau.microservice.Microservice#getManifest()} method which
provides an API for accessing manifest file entries.
This method returns an instance of {@link org.apache.juneau.utils.ManifestFile} which extends from {@link org.apache.juneau.ObjectMap} allowing
you to retrieve entries as any data types supported by that class.
</p>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
ManifestFile mf = Microservice.<jsm>getInstance</jsm>().getManifest();
String mainClass = mf.getString(<js>"Main-Class"</js>);
<jk>int</jk> myInt = mf.getInt(<js>"My-Int"</js>, 123);
<jk>boolean</jk> myBoolean = mf.getBoolean(<js>"My-Boolean"</js>);
</p>
<p>
The manifest is also used for the {@link org.apache.juneau.svl.vars.ManifestFileVar $MF} SVL variable.
</p>
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// $MF used in variable resolver.</jc>
VarResolver vr = Microservice.<jsm>getInstance</jsm>().getVarResolver();
System.<jsf>out</jsf>.println(vr.resolve(<js>"The main class is $MF{Main-Class}"</js>));
</p>
<p class='bpcode w800'>
<jc>// $MF used in annotation.</jc>
<ja>@Rest</ja>(
title=<js>"$MF{Application-Title}"</js>,
...
)
</p>
</div><!-- END: 11.4 - juneau-microservice-core.Manifest -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-core.Config' id='juneau-microservice-core.Config'>11.5 - Config</a></h3>
<div class='topic'><!-- START: 11.5 - juneau-microservice-core.Config -->
<p>
The following methods can be used to define the configuration for your microservice using the powerful Config API:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.microservice.MicroserviceBuilder}
<ul>
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceBuilder#config(Config) config(Config)}
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceBuilder#configName(String) configName(String)}
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceBuilder#configStore(ConfigStore) configStore(ConfigStore)}
</ul>
</ul>
<p>
If you do not specify any of this information, we attempt to resolve it through the following methods:
</p>
<ol class='spaced-list'>
<li>
Resolve file first in working directory, then in classpath, using the following names:
<ol>
<li>
The <js>"configFile"</js> argument in the command line arguments passed in through the constructor.
<li>
The value of the <c>Main-Config</c> entry in the manifest file.
<li>
A config file in the same location and with the same name as the executable jar file.
(e.g. <js>"java -jar myjar.jar"</js> will look for <js>"myjar.cfg"</js>).
</ol>
<li>
Resolve any <js>"*.cfg"</js> file that can be found in the working directory.
<li>
Resolve any of the following files in the classpath:
<ol>
<li><c>juneau.cfg</c>
<li><c>default.cfg</c>
<li><c>application.cfg</c>
<li><c>app.cfg</c>
<li><c>settings.cfg</c>
</ol>
</ol>
<p>
If no configuration file is found, and empty in-memory configuration is used.
</p>
<p>
The {@link org.apache.juneau.microservice.MicroserviceBuilder#configName(String) configName(String)} method allows you to explicitly specify the name
of the external configuration file location for your microservice.
</p>
<p class='bpcode w800'>
Microservice
.<jsm>create</jsm>()
.config(<js>"my-files/MyMicroservice.cfg"</js>)
.build()
.start()
;
</p>
<p>
By default, we try to find the file on the file system and then the classpath.
If located on the file system, then the configuration is writeable and the microservice can automatically
listen for and react to changes in the configuration file on the file system.
If located on the classpath, then the configuration can still react to modifications made to it through
the Config API, but the changes cannot be persisted since the location prevents the file from being modified.
</p>
<p>
The {@link org.apache.juneau.microservice.MicroserviceBuilder#configStore(ConfigStore) configStore(ConfigStore)} method can be used to explicitly
specify a configuration store.
This can include your own custom configuration store, such as one that's implemented in a relational database.
</p>
<p class='bpcode w800'>
Microservice
.<jsm>create</jsm>()
.configStore(<jk>new</jk> MyConfigSqlStore())
.configName(<js>"MyConfig"</js>)
.build()
.start()
;
</p>
<p>
The {@link org.apache.juneau.microservice.MicroserviceBuilder#config(Config) config(Config)} method can be used to explicitly specify a {@link org.apache.juneau.config.Config}
file as the microservice configuration. When this method is used, the above two methods are bypassed entirely.
</p>
<p class='bpcode w800'>
Config config = <jsm>getMyOwnConfig</jsm>();
Microservice
.<jsm>create</jsm>()
.config(config)
.build()
.start()
;
</p>
<p>
Once the configuration is resolved, it is made as the system default configuration available through the {@link org.apache.juneau.config.Config#getSystemDefault()}.
This in turn allows it to be used by REST resources that reference the system default configuration via the <js>"SYSTEM_DEFAULT"</js> such as those
implementing the {@link org.apache.juneau.rest.BasicRestConfig} interface.
<p>
<h5 class='figure'>BasicRestConfig.java</h5>
<p class='bpcode w800'>
<ja>@Rest</ja>(
config=<js>"$S{juneau.configFile,SYSTEM_DEFAULT}"</js>
...
)
</p>
<p>
The {@link org.apache.juneau.microservice.Microservice#getConfig()} method can be used to get access to the configuration.
</p>
<p class='bpcode w800'>
Config c = Microservice.<jsm>getInstance</jsm>().getConfig();
File logDir = c.getObject(<js>"Logging/logDir"</js>, File.<jk>class</jk>);
boolean append = c.getBoolean(<js>"Logging/append"</js>);
String format = c.getString(<js>"Logging/format"</js>, <js>"[{date} {level}] {msg}%n"</js>);
long limit = c.getLong(<js>"Logging/limit"</js>);
Map&lt;String,Level&gt; levels = c.getObject(<js>"Logging/levels"</js>, Map.<jk>class</jk>, String.<jk>class</jk>, Level.<jk>class</jk>);
</p>
<p>
Changes to the configuration file can trigger notifications that can be used to restart your microservice or make various other
on-the-fly changes.
This can be accomplished by either overriding the {@link org.apache.juneau.microservice.Microservice#onConfigChange(ConfigEvents)} or implementing
a listener and using the {@link org.apache.juneau.microservice.MicroserviceListener#onConfigChange(Microservice,ConfigEvents)} methods.
These will be described in detail later.
</p>
<ul class='seealso'>
<li class='link'>{@doc juneau-config}
</ul>
</div><!-- END: 11.5 - juneau-microservice-core.Config -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-core.SystemProperties' id='juneau-microservice-core.SystemProperties'>11.6 - System properties</a></h3>
<div class='topic'><!-- START: 11.6 - juneau-microservice-core.SystemProperties -->
<p>
As a convenience, the <c>SystemProperties</c> section of your configuration file can be used to define system
properties to set during initialization of your microservice:
</p>
<p class='bpcode w800'>
<cc>#=======================================================================================================================
# System properties
#-----------------------------------------------------------------------------------------------------------------------
# These are arbitrary system properties that are set during startup.
#=======================================================================================================================</cc>
<cs>[SystemProperties]</cs>
<cc># Configure Jetty for StdErrLog Logging
# org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog</cc>
<cc># Configure Jetty to log using java-util logging</cc>
<ck>org.eclipse.jetty.util.log.class</ck> = <cv>org.apache.juneau.microservice.jetty.JettyLogger</cv>
<cc># Jetty logging level
# Possible values: ALL, DEBUG, INFO, WARN, OFF</cc>
<ck>org.eclipse.jetty.LEVEL</ck> = <cv>WARN</cv>
<ck>derby.stream.error.file</ck> = <cv>$C{Logging/logDir}/derby-errors.log</cv>
</p>
</div><!-- END: 11.6 - juneau-microservice-core.SystemProperties -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-core.VarResolver' id='juneau-microservice-core.VarResolver'>11.7 - VarResolver</a></h3>
<div class='topic'><!-- START: 11.7 - juneau-microservice-core.VarResolver -->
<p>
The Microservice API incorporates the {@doc juneau-marshall.SimpleVariableLanguage Simple Variable Language} API.
</p>
<p>
The variable resolver can be augmented through the following methods:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.microservice.MicroserviceBuilder}
<ul>
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceBuilder#vars(Class...) vars(Class...)}
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceBuilder#varContext(String, Object) varContext(String,Object)}
</ul>
</ul>
<p>
A typical usage pattern is shown below:
</p>
<p class='bpcode w800'>
<jc>// $A used in variable resolver.</jc>
VarResolver vr = Microservice.<jsm>getInstance</jsm>().getVarResolver();
System.<jsf>out</jsf>.println(vr.resolve(<js>"Main class is set to $MF{Main-Class, unknown}"</js>));
</p>
<p>
The variable resolver becomes much more powerful when used in REST resource annotations which will be
described latter in {@doc juneau-microservice-jetty}
</p>
<p>
By default, support for the following variables are provided:
</p>
<ul>
<li><c>$S{key[,default]}</c> - {@link org.apache.juneau.svl.vars.SystemPropertiesVar}
<li><c>$E{key[,default]}</c> - {@link org.apache.juneau.svl.vars.EnvVariablesVar}
<li><c>$A{key[,default]}</c> - {@link org.apache.juneau.svl.vars.ArgsVar}
<li><c>$C{key[,default]}</c> - {@link org.apache.juneau.config.vars.ConfigVar}
<li><c>$MF{key[,default]}</c> - {@link org.apache.juneau.svl.vars.ManifestFileVar}
<li><c>$IF{arg,then[,else]}</c> - {@link org.apache.juneau.svl.vars.IfVar}
<li><c>$SW{arg,pattern1:then1[,pattern2:then2...]}</c> - {@link org.apache.juneau.svl.vars.SwitchVar}
<li><c>$CO{arg[,arg2...]}</c> - {@link org.apache.juneau.svl.vars.CoalesceVar}
<li><c>$PM{arg,pattern}</c> - {@link org.apache.juneau.svl.vars.PatternMatchVar}
<li><c>$UC{arg}</c> - {@link org.apache.juneau.svl.vars.UpperCaseVar}
<li><c>$LC{arg}</c> - {@link org.apache.juneau.svl.vars.LowerCaseVar}
<li><c>$NE{arg}</c> - {@link org.apache.juneau.svl.vars.NotEmptyVar}
</ul>
</div><!-- END: 11.7 - juneau-microservice-core.VarResolver -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-core.ConsoleCommands' id='juneau-microservice-core.ConsoleCommands'>11.8 - Console Commands</a></h3>
<div class='topic'><!-- START: 11.8 - juneau-microservice-core.ConsoleCommands -->
<p>
The Microservice API provides support for simple console commands.
</p>
<p class='bpcode w800'>
<jk>public static void</jk> main(String[] args) {
Microservice
.<jsm>create</jsm>()
.args(args)
.build()
.start()
.startConsole() <jc>// Start console.</jc>
.join()
;
}
</p>
<p>
When started, the console renders the following output:
</p>
<p class='bpcode w800 console'>
Running class 'Microservice' using config file 'my-microservice.cfg'.
List of available commands:
exit -- Shut down service
restart -- Restarts service
help -- Commands help
>
</p>
<p>
The builder methods for controlling the console are as follows:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.microservice.MicroserviceBuilder}
<ul>
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceBuilder#consoleEnabled(boolean) consoleEnabled(boolean)}
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceBuilder#consoleCommands(ConsoleCommand...) consoleCommands(ConsoleCommand...)}
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceBuilder#consoleCommands(Class...) consoleCommands(Class...)}
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceBuilder#console(Scanner,PrintWriter) console(Scanner,PrintWriter)}
</ul>
</ul>
<p>
By default, the supported commands are pulled from the configuration file:
</p>
<p class='bpcode w800'>
<cc>#=======================================================================================================================
# Console settings
#=======================================================================================================================</cc>
<cs>[Console]</cs>
<ck>enabled = <cv>true</cv>
<cc># List of available console commands.
# These are classes that implements ConsoleCommand that allow you to submit commands to the microservice via
# the console.
# When listed here, the implementations must provide a no-arg constructor.
# They can also be provided dynamically by overriding the Microservice.createConsoleCommands() method.</cc>
<ck>commands</ck> =
<cv>org.apache.juneau.microservice.console.ExitCommand,
org.apache.juneau.microservice.console.RestartCommand,
org.apache.juneau.microservice.console.HelpCommand</cv>
</p>
<p>
New commands can be added by adding them to the configuration file, or programmatically using the {@link org.apache.juneau.microservice.MicroserviceBuilder#consoleCommands(ConsoleCommand...) consoleCommands(ConsoleCommand...)}
builder method.
</p>
<p>
The API for defining console commands is shown below:
</p>
<ul class='javatree'>
<li class='jac'>{@link org.apache.juneau.microservice.console.ConsoleCommand}
<ul>
<li class='jm'>{@link org.apache.juneau.microservice.console.ConsoleCommand#execute(Scanner,PrintWriter,Args) execute(Scanner,PrintWriter,Args)}
<li class='jm'>{@link org.apache.juneau.microservice.console.ConsoleCommand#getDescription() getDescription()}
<li class='jm'>{@link org.apache.juneau.microservice.console.ConsoleCommand#getExamples() getExamples()}
<li class='jm'>{@link org.apache.juneau.microservice.console.ConsoleCommand#getInfo() getInfo()}
<li class='jm'>{@link org.apache.juneau.microservice.console.ConsoleCommand#getName() getName()}
<li class='jm'>{@link org.apache.juneau.microservice.console.ConsoleCommand#getSynopsis() getSynopsis()}
</ul>
</ul>
<p>
By default, the console input and output are taken from {@link java.lang.System.in} and {@link java.lang.System.out}.
These can be overridden using the {@link org.apache.juneau.microservice.MicroserviceBuilder#console(Scanner,PrintWriter) console(Scanner,PrintWriter)} method.
</p>
</div><!-- END: 11.8 - juneau-microservice-core.ConsoleCommands -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-core.Logging' id='juneau-microservice-core.Logging'>11.9 - Logging</a></h3>
<div class='topic'><!-- START: 11.9 - juneau-microservice-core.Logging -->
<p>
The Microservice API provides build-in but configurable and overridable support for logging.
</p>
<p>
The method for configuring logging is as follows:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.microservice.MicroserviceBuilder}
<ul>
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceBuilder#logConfig(LogConfig) logConfig(LogConfig)}
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceBuilder#logger(Logger) logger(Logger)}
</ul>
</ul>
<p>
If not specified, the logging configuration is pulled in from the configuration file:
</p>
<p class='bpcode w800'>
<jc>#=======================================================================================================================
# Logger settings
#-----------------------------------------------------------------------------------------------------------------------
# See FileHandler Java class for details.
#=======================================================================================================================</jc>
<cs>[Logging]</cs>
<jc># The directory where to create the log file.
# Default is "."</jc>
<ck>logDir</ck> = <cv>logs</cv>
<jc># The name of the log file to create for the main logger.
# The logDir and logFile make up the pattern that's passed to the FileHandler
# constructor.
# If value is not specified, then logging to a file will not be set up.</jc>
<ck>logFile</ck> = <cv>microservice.%g.log</cv>
<jc># Whether to append to the existing log file or create a new one.</jc>
<ck>append</ck> = <cv>false</cv>
<jc># The SimpleDateFormat format to use for dates.</jc>
<ck>dateFormat</ck> = <cv>yyyy.MM.dd hh:mm:ss</cv>
<jc># The log message format.
# The value can contain any of the following variables:
# {date} - The date, formatted per dateFormat.
# {class} - The class name.
# {method} - The method name.
# {logger} - The logger name.
# {level} - The log level name.
# {msg} - The log message.
# {threadid} - The thread ID.
# {exception} - The localized exception message.</jc>
<ck>format</ck> = <cv>[{date} {level}] {msg}%n</cv>
<jc># The maximum log file size.
# Suffixes available for numbers.
# See Config.getInt(String,int) for details.</jc>
<ck>limit</ck> = <cv>1M</cv>
<jc># Max number of log files.</jc>
<ck>count</ck> = <cv>5</cv>
<jc># Default log levels.
# Format is lax-JSON.
# Keys are logger names.
# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)</jc>
<ck>levels</ck> =
<cv>{
'': 'WARNING',
org.apache.juneau: 'WARNING',
org.eclipse.jetty: 'WARNING'
}</cv>
<jc># Only print unique stack traces once and then refer to them by a simple 8 character hash identifier.
# Useful for preventing log files from filling up with duplicate stack traces.</jc>
<ck>useStackTraceHashes</ck> = <cv>true</cv>
<jc># The default level for the console logger.
# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)</jc>
<ck>consoleLevel</ck> = <cv>WARNING</cv>
<jc># The default level for the file logger.
# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)</jc>
<ck>fileLevel</ck> = <cv>INFO</cv>
</p>
<p>
The logging configuration can also be defined programmatically through the following API:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.microservice.LogConfig}
<ul>
<li class='jm'>{@link org.apache.juneau.microservice.LogConfig#create() create()}
<li class='jm'>{@link org.apache.juneau.microservice.LogConfig#append() append()}
<li class='jm'>{@link org.apache.juneau.microservice.LogConfig#consoleLevel(Level) consoleLevel(Level)}
<li class='jm'>{@link org.apache.juneau.microservice.LogConfig#count(int) count(int)}
<li class='jm'>{@link org.apache.juneau.microservice.LogConfig#fileLevel(Level) fileLevel(Level)}
<li class='jm'>{@link org.apache.juneau.microservice.LogConfig#formatter(Formatter) formatter(Formatter)}
<li class='jm'>{@link org.apache.juneau.microservice.LogConfig#level(String,Level) level(String,Level)}
<li class='jm'>{@link org.apache.juneau.microservice.LogConfig#levels(Map) levels(Map)}
<li class='jm'>{@link org.apache.juneau.microservice.LogConfig#limit(int) limit(int)}
<li class='jm'>{@link org.apache.juneau.microservice.LogConfig#logDir(String) logDir(String)}
<li class='jm'>{@link org.apache.juneau.microservice.LogConfig#logFile(String) logFile(String)}
</ul>
</ul>
<h5 class='figure'>Example:</h5>
<p class='bpcode w800'>
<jk>public static void</jk> main(String[] args) {
LogConfig logConfig = LogConfig
.<jsm>create</jsm>()
.append(<jk>true</jk>)
.consoleLevel(<jsf>FINE</jsf>)
.level(<js>"org.mylogger"</js>, <jsf>FINER</jsf>)
.logDir(<js>"my-log-files"</js>);
Microservice
.<jsm>create</jsm>()
.args(args)
.logConfig(logConfig)
.build()
.start()
.join()
;
}
</p>
<p>
If you wish to bypass the default logging configuration entirely, you can pass in your own logger via
the {@link org.apache.juneau.microservice.MicroserviceBuilder#logger(Logger)} method.
</p>
<p>
In addition to configuring the built-in Java logging framework, the following convenience methods are also
provided on the {@link org.apache.juneau.microservice.Microservice} class for logging.
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.microservice.Microservice}
<ul>
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#getLogger() getLogger()}
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#out(MessageBundle,String,Object...) out(MessageBundle,String,Object...)}
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#err(MessageBundle,String,Object...) err(MessageBundle,String,Object...)}
</ul>
</ul>
</div><!-- END: 11.9 - juneau-microservice-core.Logging -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-core.Listeners' id='juneau-microservice-core.Listeners'>11.10 - Listeners</a></h3>
<div class='topic'><!-- START: 11.10 - juneau-microservice-core.Listeners -->
<p>
As mentioned previously, the lifecycle methods for the {@link org.apache.juneau.microservice.Microservice} class are explicitly
defined as non-final so that they can be overridden by subclasses.
</p>
<p>
In addition to this support, an interface for defining event listeners for your microservice:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.microservice.MicroserviceBuilder}
<ul>
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceBuilder#listener(MicroserviceListener) listener(MicroserviceListener)}
</ul>
<li class='jic'>{@link org.apache.juneau.microservice.MicroserviceListener}
<ul>
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceListener#onStart(Microservice) onStart(Microservice)}
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceListener#onStop(Microservice) onStop(Microservice)}
<li class='jm'>{@link org.apache.juneau.microservice.MicroserviceListener#onConfigChange(Microservice,ConfigEvents) onConfigChange(Microservice,ConfigEvents)}
</ul>
<li class='jac'>{@link org.apache.juneau.microservice.BasicMicroserviceListener}
</ul>
<p>
This listener API can be used for listening for and reacting to configuration changes on the file system.
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyMicroserviceListener <jk>extends</jk> BasicMicroserviceListener {
<ja>@Override</ja> <jc>/* MicroserviceListener */</jc>
<jk>public void</jk> onConfigChange(Microservice microservice, ConfigEvents events) {
<jc>// Restart the microservice if anything was modified in one of our sections</jc>
<jk>if</jk> (events.isSectionChanged(<js>"MySection"</js>))
microservice.stop().start();
}
}
</p>
<p>
Note that the {@link org.apache.juneau.microservice.Microservice#onConfigChange(ConfigEvents)} method can also be overridden
to react to configuration changes as well:
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyMicroservice <jk>extends</jk> Microservice {
<ja>@Override</ja> <jc>/* MicroserviceListener */</jc>
<jk>public void</jk> onConfigChange(ConfigEvents events) {
<jc>// Restart the microservice if anything was modified in one of our sections</jc>
<jk>if</jk> (events.isSectionChanged(<js>"MySection"</js>))
<jk>this</jk>.stop().start();
}
}
</p>
</div><!-- END: 11.10 - juneau-microservice-core.Listeners -->
</div><!-- END: 11 - juneau-microservice-core -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-jetty' id='juneau-microservice-jetty'>12 - juneau-microservice-jetty</a></h2>
<div class='topic'><!-- START: 12 - juneau-microservice-jetty -->
<div class='warn'>
The Juneau Microservice libraries are likely to be removed in Juneau 9.0 due to the popularity of the Spring Boot
framework for creating microservices and the ability for Juneau to be used within Spring Boot.
</div>
<h5 class='figure'>Maven Dependency</h5>
<p class='bpcode w500'>
<xt>&lt;dependency&gt;</xt>
<xt>&lt;groupId&gt;</xt>org.apache.juneau<xt>&lt;/groupId&gt;</xt>
<xt>&lt;artifactId&gt;</xt>juneau-microservice-jetty<xt>&lt;/artifactId&gt;</xt>
<xt>&lt;version&gt;</xt>{@property juneauVersion}<xt>&lt;/version&gt;</xt>
<xt>&lt;/dependency&gt;</xt>
</p>
<h5 class='figure'>Java Library</h5>
<p class='bpcode w500'>
juneau-microservice-jetty-{@property juneauVersion}.jar
</p>
<h5 class='figure'>OSGi Module</h5>
<p class='bpcode w500'>
org.apache.juneau.microservice.jetty_{@property juneauVersion}.jar
</p>
<p>
Juneau Microservice Jetty is an API for creating stand-alone executable jars that can be used to
start lightweight configurable REST interfaces with all the power of the Juneau REST server and client APIs.
</p>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-jetty.Overview' id='juneau-microservice-jetty.Overview'>12.1 - Overview</a></h3>
<div class='topic'><!-- START: 12.1 - juneau-microservice-jetty.Overview -->
<p>
The Jetty Microservice API consists of a combination of the Juneau Core, Server, and Client APIs and an embedded
Eclipse Jetty Servlet Container.
</p>
<p>
The API builds upon the {@doc juneau-microservice-core Core Microservice} classes to produce easy-to-create and
easy-to-use microservices in a standard Java 1.8+ environment.
</p>
<p>
The <c>juneau-microservice-jetty</c> library consists of the following classes:
</p>
<ul class='javatree'>
<li class='jp'>{@link org.apache.juneau.microservice.jetty}
<ul>
<li class='jc'>{@link org.apache.juneau.microservice.jetty.JettyMicroservice} - The Jetty microservice class.
<li class='jc'>{@link org.apache.juneau.microservice.jetty.JettyMicroserviceBuilder} - Builder for the microservice class.
<li class='jic'>{@link org.apache.juneau.microservice.jetty.JettyMicroserviceListener} - Interface for hooking into lifecyle events of the microservice.
<ul>
<li class='jc'>{@link org.apache.juneau.microservice.jetty.BasicJettyMicroserviceListener} - Adapter for JettyMicroserviceListener class.
</ul>
<li class='jic'>{@link org.apache.juneau.microservice.jetty.JettyServerFactory} - Interface for defining custom Jetty servers.
<ul>
<li class='jc'>{@link org.apache.juneau.microservice.jetty.BasicJettyServerFactory} - Adapter for JettyServerFactory class.
</ul>
</ul>
</ul>
<p>
The most-basic creation of a Jetty microservice from an entry-point method is shown below:
</p>
<p class='bpcode w800'>
<jk>public class</jk> App {
<jk>public static void</jk> main(String[] args) {
JettyMicroservice
.<jsm>create</jsm>() <jc>// Create builder.</jc>
.args(args) <jc>// Pass in args.</jc>
.servlets(RootResource.<jk>class</jk>) <jc>// A Juneau RestServlet class.</jc>
.build() <jc>// Create microservice.</jc>
.start() <jc>// Start microservice.</jc>
;
}
}
</p>
</div><!-- END: 12.1 - juneau-microservice-jetty.Overview -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-jetty.LifecycleMethods' id='juneau-microservice-jetty.LifecycleMethods'>12.2 - Lifecycle Methods</a></h3>
<div class='topic'><!-- START: 12.2 - juneau-microservice-jetty.LifecycleMethods -->
<p>
To review, the {@link org.apache.juneau.microservice.Microservice} class contains the following lifecycle methods:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.microservice.Microservice}
<ul>
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#start() start()}
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#startConsole() startConsole()}
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#join() join()}
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#stop() stop()}
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#stopConsole() stopConsole()}
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#exit() exit()}
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#kill() kill()}
</ul>
</ul>
<p>
The {@link org.apache.juneau.microservice.jetty.JettyMicroservice} class which extends from {@link org.apache.juneau.microservice.Microservice}
provides the following additional lifecycle methods:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.microservice.jetty.JettyMicroservice}
<ul>
<li class='jm'>{@link org.apache.juneau.microservice.jetty.JettyMicroservice#createServer() createServer()}
<li class='jm'>{@link org.apache.juneau.microservice.jetty.JettyMicroservice#startServer() startServer()}
<li class='jm'>{@link org.apache.juneau.microservice.jetty.JettyMicroservice#destroyServer() destroyServer()}
</ul>
</ul>
<p>
The additional lifecycle methods are typically not called directly, but are exposed to allow subclasses to
provide customized behavior for these events.
For this reason, these methods are left as non-final so that they can be overridden.
</p>
<p>
A typical implementation of an app with lifecycle methods might look like the following:
</p>
<p class='bpcode w800'>
<jk>public class</jk> App {
<jk>private static final</jk> JettyMicroservice <jsf>MICROSERVICE</jsf>;
<jk>public static void</jk> main(String[] args) {
<jsf>MICROSERVICE</jsf> = JettyMicroservice
.<jsm>create</jsm>() <jc>// Create builder.</jc>
.args(args) <jc>// Pass in args.</jc>
.servlets(RootResource.<jk>class</jk>) <jc>// A Juneau RestServlet class.</jc>
.build() <jc>// Create microservice.</jc>
.start() <jc>// Start microservice.</jc>
.startConsole() <jc>// Start console.</jc>
.join() <jc>// Join thread.</jc>
;
}
<jk>public static void</jk> restart() {
<jsf>MICROSERVICE</jsf>.stop().start();
}
<jk>public static void</jk> exit() {
<jsf>MICROSERVICE</jsf>.exit();
}
}
</p>
<p>
Similar to {@link org.apache.juneau.microservice.Microservice#getInstance()}, the {@link org.apache.juneau.microservice.jetty.JettyMicroservice#getInstance()}
also allows easy access to the microservice:
</p>
<p class='bpcode w800'>
<jk>public class</jk> App {
<jk>public static void</jk> main(String[] args) {
JettyMicroservice
.<jsm>create</jsm>() <jc>// Create builder.</jc>
.args(args) <jc>// Pass in args.</jc>
.servlets(RootResource.<jk>class</jk>) <jc>// A Juneau RestServlet class.</jc>
.build() <jc>// Create microservice.</jc>
.start() <jc>// Start microservice.</jc>
.startConsole() <jc>// Start console.</jc>
.join() <jc>// Join thread.</jc>
;
}
<jk>public static void</jk> restart() {
JettyMicroservice.<jsm>getInstance</jsm>().stop().start();
}
<jk>public static void</jk> exit() {
JettyMicroservice.<jsm>getInstance</jsm>().exit();
}
}
</p>
</div><!-- END: 12.2 - juneau-microservice-jetty.LifecycleMethods -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-jetty.ResourceClasses' id='juneau-microservice-jetty.ResourceClasses'>12.3 - Resource Classes</a></h3>
<div class='topic'><!-- START: 12.3 - juneau-microservice-jetty.ResourceClasses -->
<p>
This section describes how to define a top-level REST resource page and deploy it in our microservice.
The example is a router page that serves as a jumping off page to child resources.
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/*"</js>,
title=<js>"My Microservice"</js>,
description=<js>"Top-level resources page"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
navlinks={
<js>"options: servlet:/?method=OPTIONS"</js>
}
),
children={
HelloWorldResource.<jk>class</jk>,
ConfigResource.<jk>class</jk>,
LogsResource.<jk>class</jk>
}
)
<jk>public class</jk> RootResources <jk>extends</jk> BasicRestServletJenaGroup {
<jc>// No code! </jc>
}
</p>
<p>
When deployed, it looks like this in a browser:
</p>
<p class='bpcode w800'>
http://localhost:10000
</p>
<img class='bordered w800' src='doc-files/juneau-microservice-jetty.Running.1.png'>
<ul class='spaced-list'>
<li>
The </l>title</l> and <l>description</l> annotations define the titles on the page.
<br>These can be globalized using <l>$L{...}</l> variables, or by defining specially-named properties in the
properties file for the resource.
<li>
In this case, the <l>path</l> annotation defines the context root of your application since it was
not specified in the manifest or config file.
<br>Therefore, this resource is mapped to <l>http://localhost:10000</l>.
<li>
The <l>children</l> annotation make up the list of child resources.
<br>These child resources can be anything that extends from <l>Servlet</l>, although usually
they will be subclasses of {@link org.apache.juneau.rest.BasicRestServlet} or other resource groups.
</ul>
<p>
If you click the <l>helloWorld</l> link in your application, you'll get a simple hello world message:
</p>
<p class='bpcode w800'>
http://localhost:10000/helloWorld
</p>
<img class='bordered w800' src='doc-files/juneau-microservice-jetty.ResourceClasses.1.png'>
<p>
...which is generated by this class...
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
path=<js>"/helloWorld"</js>,
title=<js>"Hello World example"</js>,
description=<js>"Simplest possible REST resource"</js>
)
<jk>public class</jk> HelloWorldResource <jk>extends</jk> BasicRestServlet {
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>)
<jk>public</jk> String sayHello() {
<jk>return</jk> <js>"Hello world!"</js>;
}
}
</p>
<p>
The most-common case for deploying the top-level resource is to use the {@link org.apache.juneau.microservice.jetty.JettyMicroserviceBuilder#servlet(Class)} method:
</p>
<p class='bpcode w800'>
<jk>public class</jk> App {
<jk>public static void</jk> main(String[] args) {
JettyMicroservice
.<jsm>create</jsm>()
.args(args)
.servlet(RootResources.<jk>class</jk>) <jc>// Our root resource.</jc>
.build()
.start()
;
}
}
</p>
<p>
However, there are multiple ways of deploying top-level resources:
</p>
<ul class='spaced-list'>
<li>
{@link org.apache.juneau.microservice.jetty.JettyMicroserviceBuilder#servlet(Class)} - Using the builder. Several methods provided.
<li>
{@link org.apache.juneau.microservice.jetty.JettyMicroservice#addServlet(Servlet,String)} - After the Jetty container has been started.
<li>
As a configuration variable <js>"Jetty/servlets"</js>.
<p class='bcode w800'>
<cc>#=======================================================================================================================
# Jetty settings
#=======================================================================================================================</cc>
<cs>[Jetty]</cs>
<cc># Subclasses of RestServlet</cc>
<ck>servlets</ck> = <cv>org.apache.juneau.examples.rest.RootResources</cv>
</p>
<li>
As a configuration variable <js>"Jetty/servletMap"</js>.
<p class='bcode w800'>
<cc>#=======================================================================================================================
# Jetty settings
#=======================================================================================================================</cc>
<cs>[Jetty]</cs>
<cc># Any servlets and their path specs</cc>
<ck>servletMap</ck> =
<cv>{
'/*': 'org.apache.juneau.examples.rest.RootResources'
}</cv>
</cv>
<li>
Directly in the <c>jetty.xml</c> file.
<p class='bcode w800'>
<xt>&lt;Configure</xt> <xa>id</xa>=<xs>"ExampleServer"</xs> <xa>class</xa>=<xs>"org.eclipse.jetty.server.Server"</xs><xt>&gt;</xt>
...
<xt>&lt;New</xt> <xa>id</xa>=<xs>"context"</xs> <xa>class</xa>=<xs>"org.eclipse.jetty.servlet.ServletContextHandler"</xs><xt>&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"contextPath"</xs><xt>&gt;/&lt;/Set&gt;</xt>
<xt>&lt;Call</xt> <xa>name</xa>=<xs>"addServlet"</xs><xt>&gt;</xt>
<xt>&lt;Arg&gt;</xt>org.apache.juneau.rest.test.Root<xt>&lt;/Arg&gt;</xt>
<xt>&lt;Arg&gt;</xt>/*<xt>&lt;/Arg&gt;</xt>
<xt>&lt;/Call&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"sessionHandler"</xs><xt>&gt;</xt>
<xt>&lt;New</xt> <xa>class</xa>=<xs>"org.eclipse.jetty.server.session.SessionHandler"</xs> <xt>/&gt;</xt>
<xt>&lt;/Set&gt;</xt>
<xt>&lt;/New&gt;</xt>
...
</p>
</ul>
</div><!-- END: 12.3 - juneau-microservice-jetty.ResourceClasses -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-jetty.PredefinedResourceClasses' id='juneau-microservice-jetty.PredefinedResourceClasses'>12.4 - Predefined Resource Classes</a></h3>
<div class='topic'><!-- START: 12.4 - juneau-microservice-jetty.PredefinedResourceClasses -->
<p>
The following predefined resource classes are also provided for easy inclusion into your microservice:
</p>
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.microservice.resources.ConfigResource}
- View and modify the external INI config file.
<li class='jc'>{@link org.apache.juneau.microservice.resources.DirectoryResource}
- View and modify file system directories.
<li class='jc'>{@link org.apache.juneau.microservice.resources.LogsResource}
- View and control generated log files.
<li class='jc'>{@link org.apache.juneau.microservice.resources.SampleRootResource}
- A sample root resource class to get started from.
<li class='jc'>{@link org.apache.juneau.microservice.resources.ShutdownResource}
- Shutdown and/or restart the JVM.
</ul>
</div><!-- END: 12.4 - juneau-microservice-jetty.PredefinedResourceClasses -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-jetty.Config' id='juneau-microservice-jetty.Config'>12.5 - Config</a></h3>
<div class='topic'><!-- START: 12.5 - juneau-microservice-jetty.Config -->
<p>
In {@doc juneau-microservice-core.Config}, we described how to associate a configuration file with your
microservice.
In this section we describe how that configuration can be used to customize the behavior or your REST resource
classes.
</p>
<p>
The most common usage for the configuration file is to reference values using the {@link org.apache.juneau.config.vars.ConfigVar $C} variable in annotations.
For example, the {@link org.apache.juneau.rest.BasicRestConfig} interface that defines the annotations that control the look-and-feel of
classes that extend from {@link org.apache.juneau.rest.BasicRestServlet} use several <c>$C</c> variables to externalize values:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
...
<jc>// HTML-page specific settings</jc>
htmldoc=<ja>@HtmlDoc</ja>(
<jc>// Default page header contents.</jc>
header={
<js>"&lt;h1&gt;$R{resourceTitle}&lt;/h1&gt;"</js>, <jc>// Use @Rest(title)</jc>
<js>"&lt;h2&gt;$R{methodSummary,resourceDescription}&lt;/h2&gt;"</js>, <jc>// Use either @RestMethod(summary) or @Rest(description)</jc>
<js>"$C{REST/header}"</js> <jc>// Extra header HTML defined in external config file.</jc>
},
<jc>// Default stylesheet to use for the page.
// Can be overridden from external config file.
// Default is DevOps look-and-feel (aka Depression look-and-feel).</jc>
stylesheet=<js>"$C{REST/theme,servlet:/htdocs/themes/devops.css}"</js>,
<jc>// Default contents to add to the &lt;head&gt; section of the HTML page.
// Use it to add a favicon link to the page.</jc>
head={
<js>"&lt;link rel='icon' href='$U{$C{REST/favicon}}'/&gt;"</js>
},
<jc>// No default page footer contents.
// Can be overridden from external config file.</jc>
footer=<js>"$C{REST/footer}"</js>,
...
),
<jc>// These are static files that are served up by the servlet under the specified sub-paths.
// For example, "/servletPath/htdocs/javadoc.css" resolves to the file "[servlet-package]/htdocs/javadoc.css"
// By default, we define static files through the external configuration file.</jc>
staticFiles=<js>"$C{REST/staticFiles}"</js>
)
<jk>public interface</jk> BasicRestConfig {}
</p>
<p>
These values in turn are pulled from the external configuration file shown below.
Note that the configuration file can also contain <c>$C</c> variables.
</p>
<p class='bpcode w800'>
<cc>#=======================================================================================================================
# REST settings
#=======================================================================================================================</cc>
<cs>[REST]</cs>
<cc># Mappings to folders containing static files.</cc>
<cc># Can be in the working directory or in the classpath.</cc>
<ck>staticFiles</ck> = <cv>htdocs:files/htdocs</cv>
<cc># Stylesheet to use for HTML views.</cc>
<ck>theme</ck> = <cv>servlet:/htdocs/themes/devops.css</cv>
<ck>headerIcon</ck> = <cv>servlet:/htdocs/images/juneau.png</cv>
<ck>headerLink</ck> = <cv>http://juneau.apache.org</cv>
<ck>footerIcon</ck> = <cv>servlet:/htdocs/images/asf.png</cv>
<ck>footerLink</ck> = <cv>http://www.apache.org</cv>
<ck>favicon</ck> = <cv>$C{REST/headerIcon}</cv>
<ck>header</ck> =
<cv>&lt;a href='$U{$C{REST/headerLink}}'&gt;</cv>
<cv>&lt;img src='$U{$C{REST/headerIcon}}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/&gt;</cv>
<cv>&lt;/a&gt;</cv>
<ck>footer</ck> =
<cv>&lt;a href='$U{$C{REST/footerLink}}'&gt;</cv>
<cv>&lt;img src='$U{$C{REST/footerIcon}}' style='float:right;padding-right:20px;height:32px'/&gt;</cv>
<cv>&lt;/a&gt;</cv>
</p>
<p>
Configuration files can also be accessed programmatically.
There are 3 primary ways of getting access to the config file:
</p>
<ul class='javatree'>
<li class='jm'>{@link org.apache.juneau.microservice.Microservice#getConfig()}
<p>Any {@doc DefaultRestSvlVariables initialization-time variables} can be used.</p>
<li class='jm'>{@link org.apache.juneau.rest.RestContext#getConfig()}
<p>Any {@doc DefaultRestSvlVariables initialization-time variables} can be used.</p>
<h5 class='figure'>Example usage:</h5>
<p class='bcode w800'>
<cc>#----------------------------------</cc>
<cc># Configuration for MyHelloResource </cc>
<cc>#----------------------------------</cc>
<cs>[MyHelloResource]</cs>
<ck>greeting</ck> = <cv>Hello world!</cv>
</p>
<p class='bcode w800'>
<cc>#---------------------------------</cc>
<cc># Contents of MyHelloResource.java </cc>
<cc>#---------------------------------</cc>
<ja>@Rest</ja>(...)
<jk>public class</jk> MyHelloResource <jk>extends</jk> BasicRestServlet {
<jk>private</jk> String <jf>greeting</jf>;
<jc>// Or access config file in servlet init method.</jc>
<ja>@Override</ja> <jc>/* Servlet */</jc>
<jk>public void</jk> init() {
Config c = getContext().getConfig();
<jk>this</jk>.<jf>greeting</jf> = c.getString(<js>"MyHelloResource/greeting"</js>);
}
}
</p>
<p>
Additional user-defined variables at the servlet level can be defined by adding a
{@link org.apache.juneau.rest.annotation.HookEvent#INIT} hook method
and using the {@link org.apache.juneau.rest.RestContextBuilder#vars(Class...)} method.
</p>
<li class='jm'>
{@link org.apache.juneau.rest.RestRequest#getConfig()}
- An instance method to access it from inside a REST method.
<p>Any {@doc DefaultRestSvlVariables initialization-time or request-time variables} can be used.</p>
<h5 class='figure'>Example usage:</h5>
<p class='bcode w800'>
<cc>#----------------------------------</cc>
<cc># Configuration for MyHelloResource</cc>
<cc>#----------------------------------</cc>
<cs>[MyHelloResource]</cs>
<ck>greeting</ck> = <cv>Hello $RP{person}!</cv> <cc>// $RP is RequestPathVar</cc>
<ck>localizedGreeting</ck> = <cv>$L{HelloMessage,$RP{person}}</cv> <cc>// $L is LocalizationVar with args</cc>
</p>
<p class='bcode w800'>
<cc>#---------------------------------</cc>
<cc># Contents of MyHelloResource.java </cc>
<cc>#---------------------------------</cc>
<ja>@Rest</ja>(
path=<js>"/hello"</js>,
messages=<js>"nls/Messages"</js>,
...
)
<jk>public class</jk> MyHelloResource <jk>extends</jk> BasicRestServlet {
<jd>/** Standard hello message. */</jd>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/{person}"</js>)
<jk>public</jk> String sayHello(RestRequest req) {
<jk>return</jk> req.getConfig().getString(<js>"MyHelloResource/greeting"</js>);
}
<jd>/** Hello message in users language. */</jd>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/localized/{person}"</js>)
<jk>public</jk> String sayLocalizedHello(RestRequest req) {
<jk>return</jk> req.getConfig().getString(<js>"MyHelloResource/localizedGreeting"</js>);
}
}
</p>
<p class='bcode w800'>
<cc>#---------------------------------------</cc>
<cc># Contents of nls/Messages_en.properties </cc>
<cc>#---------------------------------------</cc>
<ck>MyHelloResource.HelloMessage</ck> = <cv>Hello {0}!</cv>
</p>
<p>
Additional user-defined variables can be defined at this level by overriding the
{@link org.apache.juneau.rest.RestContextBuilder#vars(Class...)} method.
</p>
</ul>
<p>
That <l>sayLocalizedHello()</l> example might need some explanation since there's a lot going on there.
Here's what happens when an HTTP call is made to <l>GET /hello/localized/Bob</l>:
</p>
<ol class='spaced-list'>
<li>
The HTTP call matches the <l>/hello</l> path on the <l>MyHelloResource</l> class.
<li>
The HTTP call matches the <l>/localized/{person}</l> path on the <l>sayLocalizedHello()</l> method.
<li>
The request attribute <l>person</l> gets assigned the value <l>"Bob"</l>.
<li>
The call to <l>req.getConfig().getString("MyHelloResource/localizedGreeting")</l>
finds the value <l>"$L{HelloMessage,$RP{person}}"</l>.
<li>
The arguments in the <l>$L{}</l> variable get resolved, resulting in <l>"$L{HelloMessage,Bob}"</l>.
<li>
The <l>$L{}</l> variable gets resolved to the message <l>"Hello {0}!"</l> in the localized properties
file of the servlet based on the <l>Accept-Language</l> header on the request.
<li>
The arguments get replaced in the message resulting in <l>"Hello Bob!"</l>.
<li>
The resulting message <l>"Hello Bob!"</l> is returned as a POJO to be serialized to whatever content
type was specified on the <l>Accept</l> header on the request.
</ol>
<p>
This particular example is needlessly complex, but it gives an idea of how variables can be used
recursively to produce sophisticated results
</p>
<ul class='seealso'>
<li class='link'>{@doc juneau-config}
</ul>
</div><!-- END: 12.5 - juneau-microservice-jetty.Config -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-jetty.JettyXml' id='juneau-microservice-jetty.JettyXml'>12.6 - Jetty.xml file</a></h3>
<div class='topic'><!-- START: 12.6 - juneau-microservice-jetty.JettyXml -->
<p>
The Jetty microservice comes with a bare-bones <c>jetty.xml</c> file which can be modified to suite any needs.
</p>
<p>
The <c>jetty.xml</c> can be located in either the <js>"."</js> or <js>"files"</js> working directory or classpath.
It can also be specified in any of the following ways:
</p>
<ul class='spaced-list'>
<li>
Using the {@link org.apache.juneau.microservice.jetty.JettyMicroserviceBuilder#jettyXml(Object,boolean)} method to specify the location or contents
of the file.
<li>
Specifying the location using a <c>Jetty-Config</c> value in the <c>MANIFEST.MF</c> file.
<p class='bcode w800'>
<mk>Jetty-Config:</mk> <mv>files/jetty.xml</mv>
</p>
<li>
Specifying the location using the <js>"Jetty/jettyXml"</js> configuration value.
<p class='bcode w800'>
<cc>#=======================================================================================================================
# Jetty settings
#=======================================================================================================================</cc>
<cs>[Jetty]</cs>
<cc># Path of the jetty.xml file used to configure the Jetty server.</cc>
<ck>config</ck> = <cv>files/jetty.xml</cv>
</p>
</ul>
<p>
SVL variables in the <c>jetty.xml</c> file are automatically resolved by the microservice.
This allows you to reference values in your configuration file from the <c>jetty.xml</c> file.
</p>
<p>
The HTTP port used is controlled via the following:
</p>
<ul class='spaced-list'>
<li>
The {@link org.apache.juneau.microservice.jetty.JettyMicroserviceBuilder#ports(int...)} method.
<p class='bcode w800'>
JettyMicroservice
.<jsm>create</jsm>()
.args(args)
.servlets(RootResource.<jk>class</jk>)
.port(1000,2000,0,0,0) <jc>// Try port 1000, then 2000, then 3 random ports.</jc>
.build()
.start()
</p>
<li>
The <js>"Jetty/ports"</js> configuration property.
<p class='bcode w800'>
<cc>#=======================================================================================================================
# Jetty settings
#=======================================================================================================================</cc>
<cs>[Jetty]</cs>
<cc># Port to use for the jetty server.
# You can specify multiple ports. The first available will be used. '0' indicates to try a random port.
<ck>port</ck> = <cv>1000,2000,0,0,0</cv>
</p>
</ul>
<p>
The first available port is then made available through the system property <js>"availablePort"</js> so that it
can be referenced in our <c>jetty.xml</c> file.
</p>
<p class='bpcode w800'>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"connectors"</xs><xt>&gt;</xt>
<xt>&lt;Array</xt> <xa>type</xa>=<xs>"org.eclipse.jetty.server.Connector"</xs><xt>&gt;</xt>
<xt>&lt;Item&gt;</xt>
<xt>&lt;New</xt> <xa>class</xa>=<xs>"org.eclipse.jetty.server.ServerConnector"</xs><xt>&gt;</xt>
<xt>&lt;Arg&gt;</xt>
<xt>&lt;Ref</xt> <xa>refid</xa>=<xs>"ExampleServer"</xs> <xt>/&gt;</xt>
<xt>&lt;/Arg&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"port"</xs><xt>&gt;</xt>$S{availablePort,8080}<xt>&lt;/Set&gt;</xt>
<xt>&lt;/New&gt;</xt>
<xt>&lt;/Item&gt;</xt>
<xt>&lt;/Array&gt;</xt>
<xt>&lt;/Set&gt;</xt>
</p>
<p>
The {@link org.apache.juneau.microservice.jetty.JettyMicroserviceBuilder#jettyServerFactory(JettyServerFactory)} method is also provided
to use your own customized Jetty server.
</p>
</div><!-- END: 12.6 - juneau-microservice-jetty.JettyXml -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-jetty.UiCustomization' id='juneau-microservice-jetty.UiCustomization'>12.7 - UI Customization</a></h3>
<div class='topic'><!-- START: 12.7 - juneau-microservice-jetty.UiCustomization -->
<p>
The Microservice project contains a <c>files/htdocs</c> folder with predefined stylesheets and
images.
</p>
<img style='width:200px' src='doc-files/juneau-microservice-jetty.UiCustomization.1.png'>
<p>
These files can be used to tailor the look-and-feel of your microservice.
</p>
<p class='bpcode w800'>
http://localhost:10000/helloWorld
</p>
<img class='bordered w800' src='doc-files/juneau-rest-server.UiCustomization.1.png'>
<p>
The REST configuration section of your microservice configuration file can be used to tailor the header and footer on the pages:
</p>
<p class='bpcode w800'>
<cc>#=======================================================================================================================
# REST settings
#=======================================================================================================================</cc>
<cs>[REST]</cs>
<ck>staticFiles</ck> = <cv>htdocs:files/htdocs</cv>
<cc># Stylesheet to use for HTML views.</cc>
<ck>theme</ck> = <cv>servlet:/htdocs/themes/devops.css</cv>
<ck>headerIcon</ck> = <cv>servlet:/htdocs/images/juneau.png</cv>
<ck>headerLink</ck> = <cv>http://juneau.apache.org</cv>
<ck>footerIcon</ck> = <cv>servlet:/htdocs/images/asf.png</cv>
<ck>footerLink</ck> = <cv>http://www.apache.org</cv>
<ck>favicon</ck> = <cv>$C{REST/headerIcon}</cv>
<ck>header</ck> =
<cv>&lt;a href='$U{$C{REST/headerLink}}'&gt;</cv>
<cv>&lt;img src='$U{$C{REST/headerIcon}}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/&gt;</cv>
<cv>&lt;/a&gt;</cv>
<ck>footer</ck> =
<cv>&lt;a href='$U{$C{REST/footerLink}}'&gt;</cv>
<cv>&lt;img src='$U{$C{REST/footerIcon}}' style='float:right;padding-right:20px;height:32px'/&gt;</cv>
<cv>&lt;/a&gt;</cv>
</p>
<p>
The {@link org.apache.juneau.rest.BasicRestConfig} interface (which defines the default settings for {@link org.apache.juneau.rest.BasicRestServlet}
pulls in this information using {@link org.apache.juneau.config.vars.ConfigVar $C} and {@link org.apache.juneau.rest.vars.UrlVar $U} variables:
</p>
<p class='bpcode w800'>
<ja>@Rest</ja>(
...
<jc>// HTML-page specific settings</jc>
htmldoc=<ja>@HtmlDoc</ja>(
<jc>// Default page header contents.</jc>
header={
<js>"&lt;h1&gt;$R{resourceTitle}&lt;/h1&gt;"</js>, <jc>// Use @Rest(title)</jc>
<js>"&lt;h2&gt;$R{methodSummary,resourceDescription}&lt;/h2&gt;"</js>, <jc>// Use either @RestMethod(summary) or @Rest(description)</jc>
<js>"$C{REST/header}"</js> <jc>// Extra header HTML defined in external config file.</jc>
},
<jc>// Default stylesheet to use for the page.
// Can be overridden from external config file.
// Default is DevOps look-and-feel (aka Depression look-and-feel).</jc>
stylesheet=<js>"$C{REST/theme,servlet:/htdocs/themes/devops.css}"</js>,
<jc>// Default contents to add to the &lt;head&gt; section of the HTML page.
// Use it to add a favicon link to the page.</jc>
head={
<js>"&lt;link rel='icon' href='$U{$C{REST/favicon}}'/&gt;"</js>
},
<jc>// No default page footer contents.
// Can be overridden from external config file.</jc>
footer=<js>"$C{REST/footer}"</js>
),
<jc>// Optional external configuration file.</jc>
config=<js>"$S{juneau.configFile}"</js>,
<jc>// These are static files that are served up by the servlet under the specified sub-paths.
// For example, "/servletPath/htdocs/javadoc.css" resolves to the file "[servlet-package]/htdocs/javadoc.css"
// By default, we define static files through the external configuration file.</jc>
staticFiles=<js>"$C{REST/staticFiles}"</js>
)
<jk>public interface</jk> BasicRestConfig {}
</p>
<p>
Note that the <c>files/htdocs</c> directory is mapped to <js>"servlet:/htdocs"</js> using the <c>staticFiles</c>
setting. This allows those files to be served up through the servlet through the URL <js>"/[servlet-path]/htdocs"</js>
</p>
<p>
The theme files are externally accessible and can be modified to produce any look-and-feel you desire.
The microservice still works without the files directory. An embedded <c>devops.css</c> is included in the jar as a default spreadsheet.
</p>
<p>
If you're testing out changes in the theme stylesheets, you may want to set the following system property that prevents caching of those files so
that you don't need to restart the microservice each time a change is made:
</p>
<p class='bpcode w800'>
<cc>#=======================================================================================================================
# System properties
#-----------------------------------------------------------------------------------------------------------------------
# These are arbitrary system properties that are set during startup.
#=======================================================================================================================</cc>
<cs>[SystemProperties]</cs>
<cc># Disable classpath resource caching.
# Useful if you're attached using a debugger and you're modifying classpath resources while running.</cc>
<ck>RestContext.useClasspathResourceCaching.b</ck> = <cv>false</cv>
</p>
</div><!-- END: 12.7 - juneau-microservice-jetty.UiCustomization -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-microservice-jetty.Extending' id='juneau-microservice-jetty.Extending'>12.8 - Extending JettyMicroservice</a></h3>
<div class='topic'><!-- START: 12.8 - juneau-microservice-jetty.Extending -->
<p>
This example shows how the {@link org.apache.juneau.microservice.jetty.JettyMicroservice} class
can be extended to implement lifecycle listener methods or override existing methods.
We'll create a new class <l>com.foo.MyJettyMicroservice</l>.
</p>
<p class='bpcode w800'>
<jd>/**
* Sample subclass of a JettyMicroservice that provides customized behavior.
*/</jd>
<jk>public class</jk> MyJettyMicroservice <jk>extends</jk> JettyMicroservice {
<jk>public static void</jk> main(String[] args) <jk>throws</jk> Exception {
JettyMicroserviceBuilder builder = JettyMicroservice.<jsm>create</jsm>();
<jk>new</jk> MyJettyMicroservice(builder).start().join();
}
<jk>public</jk> MyJettyMicroservice(JettyMicroserviceBuilder builder) <jk>throws</jk> Exception {
<jk>super</jk>(builder);
}
<jc>// Customized code here.</jc>
</p>
<p>
Optionally, you can extend the {@link org.apache.juneau.microservice.jetty.JettyMicroserviceBuilder} class as well:
</p>
<p class='bpcode w800'>
<jk>public class</jk> MyJettyMicroserviceBuilder <jk>extends</jk> JettyMicroserviceBuilder {
<jk>int</jk> <jf>extraField</jf>;
<jd>/**
* Constructor (required).
*/</jd>
<jk>protected</jk> MyJettyMicroserviceBuilder() {}
<jd>/**
* Copy constructor (required).
*
* <ja>@param</ja> copyFrom The builder to copy settings from.
*/</jd>
<jk>protected</jk> MyJettyMicroserviceBuilder(MyJettyMicroserviceBuilder copyFrom) {
<jk>super</jk>(copyFrom);
}
<jc>// Additional setters</jc>
<jk>public</jk> MyJettyMicroserviceBuilder extraField(<jk>int</jk> extraField) {
<jk>this</jk>.<jf>extraField</jf> = extraField;
<jk>return this</jk>;
}
<jc>// Overridden methods</jc>
<ja>@Override</ja> <jc>/* JettyMicroserviceBuilder */</jc>
<jk>public</jk> MyJettyMicroserviceBuilder copy() {
<jk>return new</jk> MyJettyMicroserviceBuilder(<jk>this</jk>);
}
<ja>@Override</ja> <jc>/* JettyMicroserviceBuilder */</jc>
<jk>public</jk> MyJettyMicroserviceBuilder ports(<jk>int</jk>...ports) {
<jk>super</jk>.ports(ports);
<jk>return this</jk>;
}
<ja>@Override</ja> <jc>/* JettyMicroserviceBuilder */</jc>
<jk>public</jk> MyJettyMicroserviceBuilder servlet(Class&lt;? <jk>extends</jk> RestServlet&gt; c) <jk>throws</jk> InstantiationException, IllegalAccessException {
<jk>super</jk>.servlet(c);
<jk>return this</jk>;
}
...
}
</p>
</div><!-- END: 12.8 - juneau-microservice-jetty.Extending -->
</div><!-- END: 12 - juneau-microservice-jetty -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#my-jetty-microservice' id='my-jetty-microservice'>13 - my-jetty-microservice</a></h2>
<div class='topic'><!-- START: 13 - my-jetty-microservice -->
<div class='warn'>
The Juneau Microservice libraries are likely to be removed in Juneau 9.0 due to the popularity of the Spring Boot
framework for creating microservices and the ability for Juneau to be used within Spring Boot.
</div>
<h5 class='figure'>Starter Project Zip</h5>
<p class='bpcode w500'>
my-jetty-microservice-{@property juneauVersion}.zip
</p>
<p>
The <l>my-jetty-microservice.zip</l> file is a predefined starter Eclipse project for developing
REST microservices using the {@doc juneau-microservice-jetty juneau-microservice-jetty} package.
</p>
<p>
It includes a combination of the Juneau Core, Server, and Client APIs and all libraries needed to execute in a Java 1.8+ environment.
</p>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#my-jetty-microservice.Installing' id='my-jetty-microservice.Installing'>13.1 - Installing in Eclipse</a></h3>
<div class='topic'><!-- START: 13.1 - my-jetty-microservice.Installing -->
<p>
Follow these instructions to create a new template project in Eclipse.
</p>
<ol class='spaced-list'>
<li>
Download the <c>my-jetty-microservice-{@property juneauVersion}.zip</c> file from the downloads page
(located in the binaries) and import it into your workspace as an existing project:
<br><br>
<img class='bordered' src='doc-files/my-jetty-microservice.Installing.1.png' style='width:524px'>
<li>
Select the archive file and import the project:
<br><br>
<img class='bordered' src='doc-files/my-jetty-microservice.Installing.2.png' style='width:549px'>
<li>
In your workspace, you should now see the following project:
<br><br>
<img class='bordered' src='doc-files/my-jetty-microservice.Installing.3.png' style='width:400px'>
</ol>
<p>
The important elements in this project are:
</p>
<ul class='spaced-list'>
<li>
<l>App.java</l> - The entry point.
<br>This class creates and starts our microservice:
<br><br>
<p class='bcode w800'>
<jk>public class</jk> App {
<jk>public static void</jk> main(String[] args) <jk>throws</jk> Exception {
JettyMicroservice
.<jsm>create</jsm>()
.args(args)
.servlet(RootResources.<jk>class</jk>)
.build()
.start()
.startConsole()
.join();
}
}
</p>
<li>
<l>RootResources.java</l> - The top-level REST resource.
<br>This class routes HTTP requests to child resources:
<br><br>
<p class='bcode w800'>
<ja>@Rest</ja>(
path=<js>"/"</js>,
title=<js>"My Microservice"</js>,
description=<js>"Top-level resources page"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
widgets={
ContentTypeMenuItem.<jk>class</jk>,
StyleMenuItem.<jk>class</jk>
},
navlinks={
<js>"options: servlet:/?method=OPTIONS"</js>
}
),
children={
HelloWorldResource.<jk>class</jk>,
ConfigResource.<jk>class</jk>,
LogsResource.<jk>class</jk>
}
)
<jk>public class</jk> RootResources <jk>extends</jk> BasicRestServletJenaGroup {
<jc>// No code</jc>
}
</p>
<li>
<l>my-jetty-microservice.cfg</l> - The external configuration file.
<br>Contains various useful settings.
<br>Can be used for your own resource configurations.
<br><br>
<p class='bcode w800'>
<cc>#=======================================================================================================================
# Basic configuration file for REST microservices
# Subprojects can use this as a starting point.
#=======================================================================================================================</cc>
<cc>#=======================================================================================================================
# Jetty settings
#=======================================================================================================================</cc>
<cs>[Jetty]</cs>
<cc># Path of the jetty.xml file used to configure the Jetty server.</cc>
<ck>config</ck> = <cv>jetty.xml</cv>
<cc># Resolve Juneau variables in the jetty.xml file.</cc>
<ck>resolveVars</ck> = <cv>true</cv>
<cc># Port to use for the jetty server.
# You can specify multiple ports. The first available will be used. '0' indicates to try a random port.
# The resulting available port gets set as the system property "availablePort" which can be referenced in the
# jetty.xml file as "$S{availablePort}" (assuming resolveVars is enabled).</cc>
<ck>port</ck> = <cv>10000,0,0,0</cv>
<cc># Optionally specify your servlets here:
#servlets = org.apache.juneau.microservice.sample.RootResources</cc>
<cc>#=======================================================================================================================
# REST settings
#=======================================================================================================================</cc>
<cs>[REST]</cs>
<cc># Comma-delimited list of key-value pairs that represent locations of static files that can be served up by your @Rest-annotated
# classes. These are static files that are served up by the servlet under the specified sub-paths.
# For example, given the following setting...
# staticFiles = htdocs:my-docs,styles/my-styles
# ...the URI "/servletPath/htdocs/javadoc.css" resolves to the path "/my-docs/javadoc.css".
# This path can be relative to the working directory, classpath root, or package of your resource class.
# Used by the BasicRestConfig interface that defines the following value:
# staticFiles="$C{REST/staticFiles}"</cc>
<ck>staticFiles</ck> = htdocs:htdocs
<cc># Stylesheet to use for HTML views.
# Used by the BasicRestConfig interface that defines the following value:
# stylesheet="$C{REST/theme,servlet:/htdocs/themes/devops.css}"</cc>
<ck>theme</ck> = <cv>servlet:/htdocs/themes/devops.css</cv>
<cc># Various look-and-feel settings used in the BasicRestConfig interface.</cc>
<ck>headerIcon</ck> = <cv>servlet:/htdocs/images/juneau.png</cv>
<ck>headerLink</ck> = <cv>http://juneau.apache.org</cv>
<ck>footerIcon</ck> = <cv>servlet:/htdocs/images/asf.png</cv>
<ck>footerLink</ck> = <cv>http://www.apache.org</cv>
<ck>favicon</ck> = <cv>$C{REST/headerIcon}</cv>
<ck>header</ck> =
<cv>&lt;a href='$U{$C{REST/headerLink}}'&gt;
&lt;img src='$U{$C{REST/headerIcon}}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/&gt;
&lt;/a&gt;</cv>
<ck>footer</ck> =
<cv>&lt;a href='$U{$C{REST/footerLink}}'&gt;
&lt;img src='$U{$C{REST/footerIcon}}' style='float:right;padding-right:20px;height:32px'/&gt;
&lt;/a&gt;</cv>
<cc>#=======================================================================================================================
# Console settings
#=======================================================================================================================</cc>
<cs>[Console]</cs>
<ck>enabled</ck> = <cv>true</cv>
<cc># List of available console commands.
# These are classes that implements ConsoleCommand that allow you to submit commands to the microservice via
# the console.
# When listed here, the implementations must provide a no-arg constructor.
# They can also be provided dynamically by overriding the Microservice.createConsoleCommands() method.</cc>
<ck>commands</ck> =
<cv>org.apache.juneau.microservice.console.ExitCommand,
org.apache.juneau.microservice.console.RestartCommand,
org.apache.juneau.microservice.console.HelpCommand,
org.apache.juneau.microservice.console.ConfigCommand</cv>
<cc>#=======================================================================================================================
# Logger settings
#-----------------------------------------------------------------------------------------------------------------------
# See FileHandler Java class for details.
#=======================================================================================================================</cc>
<cs>[Logging]</cs>
...
<cc>#=======================================================================================================================
# System properties
#-----------------------------------------------------------------------------------------------------------------------
# These are arbitrary system properties that are set during startup.
#=======================================================================================================================</cc>
<cs>[SystemProperties]</cs>
<cc># Configure Jetty for StdErrLog Logging
# org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog</cc>
<cc># Configure Jetty to log using java-util logging</cc>
<ck>org.eclipse.jetty.util.log.class</ck> = <cv>org.apache.juneau.microservice.jetty.JettyLogger</cv>
<cc># Jetty logging level
# Possible values: ALL, DEBUG, INFO, WARN, OFF</cc>
<ck>org.eclipse.jetty.LEVEL</ck> = <cv>WARN
<ck>derby.stream.error.file</ck> = <cv>$C{Logging/logDir}/derby-errors.log</cv>
</p>
<li>
<l>jetty.xml</l> - The Jetty configuration file.
<br>A bare-bones config file that can be extended to use any Jetty features.
<br><br>
<p class='bcode w800'>
<xt>&lt;Configure</xt> <xa>id</xa>=<xs>"ExampleServer"</xs> <xa>class</xa>=<xs>"org.eclipse.jetty.server.Server"</xs>&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"connectors"</xs><xt>&gt;</xt>
<xt>&lt;Array</xt> <xa>type</xa>=<xs>"org.eclipse.jetty.server.Connector"</xs><xt>&gt;</xt>
<xt>&lt;Item&gt;</xt>
<xt>&lt;New</xt> <xa>class</xa>=<xs>"org.eclipse.jetty.server.ServerConnector"</xs><xt>&gt;</xt>
<xt>&lt;Arg&gt;</xt>
<xt>&lt;Ref</xt> <xa>refid</xa>=<xs>"ExampleServer"</xs><xt>/&gt;</xt>
<xt>&lt;/Arg&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"port"</xs><xt>&gt;</xt>$S{availablePort,8080}<xt>&lt;/Set&gt;</xt>
<xt>&lt;/New&gt;</xt>
<xt>&lt;/Item&gt;</xt>
<xt>&lt;/Array&gt;</xt>
<xt>&lt;/Set&gt;</xt>
<xt>&lt;New</xt> <xa>id</xa>=<xs>"context"</xs> <xa>class</xa>=<xs>"org.eclipse.jetty.servlet.ServletContextHandler"</xs><xt>&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"contextPath"</xs><xt>&gt;/&lt;/Set&gt;</xt>
<xc>&lt;!-- Optionally specify your servlets here --&gt;
&lt;!--Call name="addServlet"&gt;
&lt;Arg&gt;org.apache.juneau.microservice.sample.RootResources&lt;/Arg&gt;
&lt;Arg&gt;/*&lt;/Arg&gt;
&lt;/Call--&gt;</xc>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"sessionHandler"</xs><xt>&gt;</xt>
<xt>&lt;New</xt> <xa>class</xa>=<xs>"org.eclipse.jetty.server.session.SessionHandler"</xs><xt>/&gt;</xt>
<xt>&lt;/Set&gt;</xt>
<xt>&lt;/New&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"handler"</xs><xt>&gt;</xt>
<xt>&lt;New</xt> <xa>class</xa>=<xs>"org.eclipse.jetty.server.handler.HandlerCollection"</xs><xt>&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"handlers"</xs><xt>&gt;</xt>
<xt>&lt;Array</xt> <xa>type</xa>=<xs>"org.eclipse.jetty.server.Handler"</xs><xt>&gt;</xt>
<xt>&lt;Item&gt;</xt>
<xt>&lt;Ref</xt> <xa>refid</xa>=<xs>"context"</xs><xt>/&gt;</xt>
<xt>&lt;/Item&gt;</xt>
<xt>&lt;Item&gt;</xt>
<xt>&lt;New</xt> <xa>class</xa>=<xs>"org.eclipse.jetty.server.handler.DefaultHandler"</xs><xt>/&gt;</xt>
<xt>&lt;/Item&gt;</xt>
<xt>&lt;/Array&gt;</xt>
<xt>&lt;/Set&gt;</xt>
<xt>&lt;/New&gt;</xt>
<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"requestLog"</xs><xt>&gt;</xt>
<xt>&lt;New</xt> <xa>id</xa>=<xs>"RequestLogImpl"</xs> <xa>class</xa>=<xs>"org.eclipse.jetty.server.NCSARequestLog"</xs><xt>&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"filename"</xs><xt>&gt;&lt;Property</xt> <xa>name</xa>=<xs>"jetty.logs"</xs> <xa>default</xa>=<xs>"$C{Logging/logDir,logs}"</xs><xt>/&gt;</xt>/jetty-requests.log<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"filenameDateFormat</xs><xt>"&gt;</xt>yyyy_MM_dd<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"LogTimeZone"</xs><xt>&gt;</xt>GMT<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"retainDays"</xs><xt>&gt;</xt>90<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"append"</xs><xt>&gt;</xt>false<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"LogLatency"</xs><xt>&gt;</xt>true<xt>&lt;/Set&gt;</xt>
<xt>&lt;/New&gt;</xt>
<xt>&lt;/Set&gt;</xt>
<xt>&lt;Get</xt> <xa>name</xa>=<xs>"ThreadPool"</xs><xt>&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"minThreads"</xs> <xa>type</xa>=<xs>"int"</xs><xt>&gt;</xt>10<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"maxThreads"</xs> <xa>type</xa>=<xs>"int"</xs><xt>&gt;</xt>100<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"idleTimeout"</xs> <xa>type</xa>=<xs>"int"</xs><xt>&gt;</xt>60000<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"detailedDump"</xs><xt>&gt;</xt>true<xt>&lt;/Set&gt;</xt>
<xt>&lt;/Get&gt;</xt>
<xt>&lt;/Configure&gt;</xt>
</p>
</ul>
<p>
At this point, you're ready to start the microservice from your workspace.
</p>
</div><!-- END: 13.1 - my-jetty-microservice.Installing -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#my-jetty-microservice.Running' id='my-jetty-microservice.Running'>13.2 - Running in Eclipse</a></h3>
<div class='topic'><!-- START: 13.2 - my-jetty-microservice.Running -->
<p>
The <l>my-jetty-microservice.launch</l> file is already provided to allow you to quickly start
your new microservice.
</p>
<p>
Go to <b>Run -&gt; Run Configurations -&gt; Java Application -&gt; my-jetty-microservice</b> and click <b>Run</b>.
In your console view, you should see the following output:
</p>
<p class='bpcode w800 console'>
Running class 'JettyMicroservice' using config file 'my-jetty-microservice.cfg'.
Server started on port 10000
List of available commands:
exit -- Shut down service
restart -- Restarts service
help -- Commands help
>
</p>
<p>
Now open your browser and point to <l>http://localhost:10000</l>.
You should see the following:
</p>
<p class='bpcode w400'>
http://localhost:10000
</p>
<img class='bordered w400' src='doc-files/my-jetty-microservice.Running.1.png'>
<p>
You can enter the command <c>exit</c> to shut it down.
</p>
</div><!-- END: 13.2 - my-jetty-microservice.Running -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#my-jetty-microservice.Building' id='my-jetty-microservice.Building'>13.3 - Building and Running from Command-Line</a></h3>
<div class='topic'><!-- START: 13.3 - my-jetty-microservice.Building -->
<p>
The <l>pom.xml</l> file is a basic Maven build script for creating your microservice
as an executable uber-jar.
</p>
<p>
The easiest way to build your microservice is to run the following from the project root.
</p>
<p class='bpcode w800'>
mvn clean install
</p>
<p>
Your <c>target</c> directory should now contain the following files:
</p>
<ul>
<li><c>my-jetty-microservice-1.0.jar</c>
<li><c>my-jetty-microservice.cfg</c>
</ul>
<p>
To start from a command line, run the following command from inside your <c>target</c> directory:
</p>
<p class='bpcode w800'>
java -jar my-jetty-microservice-1.0.jar
</p>
<p>
You should see the following console output:
</p>
<p class='bpcode w800 console'>
Running class 'JettyMicroservice' using config file 'my-jetty-microservice.cfg'.
Server started on port 10000
List of available commands:
exit -- Shut down service
restart -- Restarts service
help -- Commands help
>
</p>
<p>
If you get this error message: <code class='snippet'>java.net.BindException: Address already in use</code>,
then this microservice is already running elsewhere and so it cannot bind to port 10000.
</p>
</div><!-- END: 13.3 - my-jetty-microservice.Building -->
</div><!-- END: 13 - my-jetty-microservice -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#my-springboot-microservice' id='my-springboot-microservice'>14 - my-springboot-microservice</a></h2>
<div class='topic'><!-- START: 14 - my-springboot-microservice -->
<h5 class='figure'>Starter Project Zip</h5>
<p class='bpcode w500'>
my-springboot-microservice-{@property juneauVersion}.zip
</p>
<p>
The <l>my-springboot-microservice.zip</l> file is a predefined starter Eclipse project for developing
REST microservices using the {@doc juneau-rest-server-springboot juneau-rest-server-springboot} package with Spring Boot.
</p>
<p>
It includes a combination of the Juneau Core, Server, and Client APIs and all libraries needed to execute in a Java 1.8+ environment.
</p>
<p>
One significant difference is that we are not using the Juneau {@link org.apache.juneau.microservice.Microservice} API for our
application but instead using the existing Spring Boot API.
</p>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#my-springboot-microservice.Installing' id='my-springboot-microservice.Installing'>14.1 - Installing in Eclipse</a></h3>
<div class='topic'><!-- START: 14.1 - my-springboot-microservice.Installing -->
<p>
Follow these instructions to create a new template project in Eclipse.
</p>
<ol class='spaced-list'>
<li>
Download the <c>my-springboot-microservice-{@property juneauVersion}.zip</c> file from the downloads page
(located in the binaries) and import it into your workspace as an existing project:
<br><br>
<img class='bordered' src='doc-files/my-springboot-microservice.Installing.1.png' style='width:524px'>
<li>
Select the archive file and import the project:
<br><br>
<img class='bordered' src='doc-files/my-springboot-microservice.Installing.2.png' style='width:549px'>
<li>
In your workspace, you should now see the following project:
<br><br>
<img class='bordered' src='doc-files/my-springboot-microservice.Installing.3.png' style='width:400px'>
</ol>
<p>
The important elements in this project are:
</p>
<ul class='spaced-list'>
<li>
<l>App.java</l> - The entry point.
<br>This class creates and starts our microservice.
<br>Note that we're using the existing Spring Boot application logic for the microservice and we're retrieving
our root resource as a spring bean.
<br>Only the top-level resource needs to be annotated with {@link org.apache.juneau.rest.springboot.annotation.JuneauRestRoot @JuneauRestRoot}
<br><br>
<p class='bcode w800'>
<ja>@SpringBootApplication</ja>
<ja>@Controller</ja>
<jk>public class</jk> App {
<jk>public static void</jk> main(String[] args) {
<jk>new</jk> SpringApplicationBuilder(App.<jk>class</jk>)
.initializers(<jk>new</jk> JuneauRestInitializer(App.<jk>class</jk>))
.run(args);
}
<ja>@Bean @JuneauRestRoot</ja>
<jk>public</jk> RootResources getRootResources() {
<jk>return new</jk> RootResources();
}
}
</p>
<li>
<l>RootResources.java</l> - The top-level REST resource.
<br>This class routes HTTP requests to child resources.
<br>This is identical to the Jetty example.
<br><br>
<p class='bcode w800'>
<ja>@Rest</ja>(
path=<js>"/"</js>,
title=<js>"My Microservice"</js>,
description=<js>"Top-level resources page"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
widgets={
ContentTypeMenuItem.<jk>class</jk>,
StyleMenuItem.<jk>class</jk>
},
navlinks={
<js>"options: servlet:/?method=OPTIONS"</js>
}
),
children={
HelloWorldResource.<jk>class</jk>,
ConfigResource.<jk>class</jk>,
LogsResource.<jk>class</jk>
}
)
<jk>public class</jk> RootResources <jk>extends</jk> BasicRestServletJenaGroup {
<jc>// No code</jc>
}
</p>
<li>
<l>juneau.cfg</l> - The configuration file.
<br>Contains various useful settings.
<br>Can be used for your own resource configurations.
<br>Note that the Jetty configuration is not present.
<br>Also it's located in the classpath so that our microservice can be built as a single executable jar.
<br><br>
<p class='bcode w800'>
<cc>#=======================================================================================================================
# Basic configuration file for REST microservices
# Subprojects can use this as a starting point.
#=======================================================================================================================</cc>
<cc>#=======================================================================================================================
# REST settings
#=======================================================================================================================</cc>
<cs>[REST]</cs>
<cc># Comma-delimited list of key-value pairs that represent locations of static files that can be served up by your @Rest-annotated
# classes. These are static files that are served up by the servlet under the specified sub-paths.
# For example, given the following setting...
# staticFiles = htdocs:my-docs,styles/my-styles
# ...the URI "/servletPath/htdocs/javadoc.css" resolves to the path "/my-docs/javadoc.css".
# This path can be relative to the working directory, classpath root, or package of your resource class.
# Used by the BasicRestConfig interface that defines the following value:
# staticFiles="$C{REST/staticFiles}"</cc>
<ck>staticFiles</ck> = htdocs:htdocs
<cc># Stylesheet to use for HTML views.
# Used by the BasicRestConfig interface that defines the following value:
# stylesheet="$C{REST/theme,servlet:/htdocs/themes/devops.css}"</cc>
<ck>theme</ck> = <cv>servlet:/htdocs/themes/devops.css</cv>
<cc># Various look-and-feel settings used in the BasicRestConfig interface.</cc>
<ck>headerIcon</ck> = <cv>servlet:/htdocs/images/juneau.png</cv>
<ck>headerLink</ck> = <cv>http://juneau.apache.org</cv>
<ck>footerIcon</ck> = <cv>servlet:/htdocs/images/asf.png</cv>
<ck>footerLink</ck> = <cv>http://www.apache.org</cv>
<ck>favicon</ck> = <cv>$C{REST/headerIcon}</cv>
<ck>header</ck> =
<cv>&lt;a href='$U{$C{REST/headerLink}}'&gt;
&lt;img src='$U{$C{REST/headerIcon}}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/&gt;
&lt;/a&gt;</cv>
<ck>footer</ck> =
<cv>&lt;a href='$U{$C{REST/footerLink}}'&gt;
&lt;img src='$U{$C{REST/footerIcon}}' style='float:right;padding-right:20px;height:32px'/&gt;
&lt;/a&gt;</cv>
</p>
</ul>
<p>
At this point, you're ready to start the microservice from your workspace.
</p>
</div><!-- END: 14.1 - my-springboot-microservice.Installing -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#my-springboot-microservice.Running' id='my-springboot-microservice.Running'>14.2 - Running in Eclipse</a></h3>
<div class='topic'><!-- START: 14.2 - my-springboot-microservice.Running -->
<p>
The <l>my-springboot-microservice.launch</l> file is already provided to allow you to quickly start
your new microservice.
</p>
<p>
Go to <b>Run -&gt; Run Configurations -&gt; Java Application -&gt; my-springboot-microservice</b> and click <b>Run</b>.
In your console view, you should see the following output:
</p>
<p class='bpcode w800'>
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.1.RELEASE)
...
INFO: Tomcat started on port(s): 8080 (http) with context path ''
Dec 21, 2012 12:30:00 AM org.springframework.boot.StartupInfoLogger logStarted
INFO: Started App in 1.999 seconds (JVM running for 2.999)
</p>
<p>
Now open your browser and point to <l>http://localhost:5000</l>.
You should see the following:
</p>
<p class='bpcode w400'>
http://localhost:5000
</p>
<img class='bordered w400' src='doc-files/my-springboot-microservice.Running.1.png'>
</div><!-- END: 14.2 - my-springboot-microservice.Running -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#my-springboot-microservice.Building' id='my-springboot-microservice.Building'>14.3 - Building and Running from Command-Line</a></h3>
<div class='topic'><!-- START: 14.3 - my-springboot-microservice.Building -->
<p>
The <l>pom.xml</l> file is a basic Maven build script for creating your microservice
as an executable uber-jar.
</p>
<p>
The easiest way to build your microservice is to run the following from the project root.
</p>
<p class='bpcode w800'>
mvn clean install
</p>
<p>
Your <c>target</c> directory should now contain the following files:
</p>
<ul>
<li><c>my-springboot-microservice-1.0.jar</c>
</ul>
<p>
To start from a command line, run the following command from inside your <c>target</c> directory:
</p>
<p class='bpcode w800'>
java -jar my-springboot-microservice-1.0.jar
</p>
<p>
You should see the following console output:
</p>
<p class='bpcode w800 console'>
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.1.RELEASE)
...
INFO: Tomcat started on port(s): 8080 (http) with context path ''
Dec 21, 2012 12:30:00 AM org.springframework.boot.StartupInfoLogger logStarted
INFO: Started App in 1.999 seconds (JVM running for 2.999)
</p>
</div><!-- END: 14.3 - my-springboot-microservice.Building -->
</div><!-- END: 14 - my-springboot-microservice -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-core' id='juneau-examples-core'>15 - juneau-examples-core</a></h2>
<div class='topic'><!-- START: 15 - juneau-examples-core -->
<h5 class='figure'>Archive File</h5>
<p class='bpcode w500'>
juneau-examples-core-{@property juneauVersion}.zip
</p>
<p>
The <c>juneau-examples-core</c> project contains various code examples for using the core APIs.
</p>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-core.Installing' id='juneau-examples-core.Installing'>15.1 - Installing in Eclipse</a></h3>
<div class='topic'><!-- START: 15.1 - juneau-examples-core.Installing -->
<p>
Follow these instructions to import the Juneau project into Eclipse.
</p>
<ol class='spaced-list'>
<li>
Download the <c>juneau-examples-core-{@property juneauVersion}.zip</c> file from the downloads page
(located in the binaries) and import it into your workspace as an existing project:
<br><br>
<img class='bordered' src='doc-files/juneau-examples-core.Installing.1.png' style='width:524px'>
<li>
Select the archive file and import the project:
<br><br>
<img class='bordered' src='doc-files/juneau-examples-core.Installing.2.png' style='width:549px'>
<li>
In your workspace, you should now see the following project:
<br><br>
<img class='bordered' src='doc-files/juneau-examples-core.Installing.3.png' style='width:400px'>
</ol>
</div><!-- END: 15.1 - juneau-examples-core.Installing -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-core.Examples' id='juneau-examples-core.Examples'>15.2 - Examples</a></h3>
<div class='topic'><!-- START: 15.2 - juneau-examples-core.Examples -->
<p>
The following shows the core examples provided:
</p>
<ul class='javatree'>
<li class='jp'>{@link org.apache.juneau.examples.core.json}
<ul>
<li class='jc'>{@link org.apache.juneau.examples.core.json.JsonSimpleExample} - JsonSerializer and JsonParser usage on serialize and deserialize simple Pojo bean.
<li class='jc'>{@link org.apache.juneau.examples.core.json.JsonComplexExample} - JsonSerializer and JsonParser usage on serialize and deserialize complex Pojo bean.
<li class='jc'>{@link org.apache.juneau.examples.core.json.JsonConfigurationExample} - Json Serializers configured using properties defined in JsonSerializer class.
</ul>
<li class='jp'>{@link org.apache.juneau.examples.core.xml}
<ul>
<li class='jc'>{@link org.apache.juneau.examples.core.xml.XmlSimpleExample} - XmlSerializer and XmlParser usage on serialize and deserialize simple Pojo bean.
<li class='jc'>{@link org.apache.juneau.examples.core.xml.XmlComplexExample} - XmlSerializer and XmlParser usage on serialize and deserialize complex Pojo bean.
<li class='jc'>{@link org.apache.juneau.examples.core.xml.XmlConfigurationExample} - XmlSerializers configured using properties defined in XmlSerializer class.
</ul>
<li class='jp'>{@link org.apache.juneau.examples.core.dto}
<ul>
<li class='jc'>{@link org.apache.juneau.examples.core.dto.DtoExample} - Usage of core dto module.
</ul>
<li class='jp'>{@link org.apache.juneau.examples.core.rdf}
<ul>
<li class='jc'>{@link org.apache.juneau.examples.core.rdf.RdfExample} - RdfXmlSerializer usage on serialize simple Pojo bean.
<li class='jc'>{@link org.apache.juneau.examples.core.rdf.RdfComplexExample} - RdfXmlSerializer usage on serialize complex Pojo bean.
</ul>
<li class='jp'>{@link org.apache.juneau.examples.core.html}
<ul>
<li class='jc'>{@link org.apache.juneau.examples.core.html.HtmlSimpleExample} - HtmlSerializer usage on serialize and deserialize simple Pojo bean.
<li class='jc'>{@link org.apache.juneau.examples.core.html.HtmlComplexExample} - HtmlSerializer usage on serialize and deserialize complex Pojo bean.
</ul>
<li class='jp'>{@link org.apache.juneau.examples.core.uon}
<ul>
<li class='jc'>{@link org.apache.juneau.examples.core.uon.UONExample} - UonSerializer usage on serialize and deserialize simple Pojo bean.
<li class='jc'>{@link org.apache.juneau.examples.core.uon.UONComplexExample} - UonSerializer usage on serialize and deserialize complex Pojo bean.
</ul>
<li class='jp'>{@link org.apache.juneau.examples.core.svl}
<ul>
<li class='jc'>{@link org.apache.juneau.examples.core.svl.SvlExample} - Usage of Svl module in juneau.
</ul>
</ul>
</div><!-- END: 15.2 - juneau-examples-core.Examples -->
</div><!-- END: 15 - juneau-examples-core -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest' id='juneau-examples-rest'>16 - juneau-examples-rest</a></h2>
<div class='topic'><!-- START: 16 - juneau-examples-rest -->
<h5 class='figure'>Maven Dependency</h5>
<p class='bpcode w500'>
<xt>&lt;dependency&gt;</xt>
<xt>&lt;groupId&gt;</xt>org.apache.juneau<xt>&lt;/groupId&gt;</xt>
<xt>&lt;artifactId&gt;</xt>juneau-examples-rest<xt>&lt;/artifactId&gt;</xt>
<xt>&lt;version&gt;</xt>{@property juneauVersion}<xt>&lt;/version&gt;</xt>
<xt>&lt;/dependency&gt;</xt>
</p>
<h5 class='figure'>Java Library</h5>
<p class='bpcode w500'>
juneau-examples-rest-{@property juneauVersion}.jar
</p>
<h5 class='figure'>OSGi Module</h5>
<p class='bpcode w500'>
org.apache.juneau.examples.rest_{@property juneauVersion}.jar
</p>
<p>
The <c>juneau-examples-rest</c> project includes various examples of REST resources written
using Juneau.
</p>
<p>
Note: These examples can be deployed as buildable Eclipse projects using Jetty or Spring Boot using instructions
in the following sections:
</p>
<ul class='spaced-list'>
<li>{@doc juneau-examples-rest-jetty}
<li>{@doc juneau-examples-rest-springboot}
</ul>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest.RootResources' id='juneau-examples-rest.RootResources'>16.1 - RootResources</a></h3>
<div class='topic'><!-- START: 16.1 - juneau-examples-rest.RootResources -->
<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='javatree'>
<li class='jac'>
{@link org.apache.juneau.rest.RestServlet} - Contains all the REST servlet logic.
<ul>
<li class='jac'>
{@link org.apache.juneau.rest.BasicRestServlet} - Defines default serializers and parsers, and OPTIONs page logic.
<ul>
<li class='jac'>
{@link org.apache.juneau.rest.BasicRestServletGroup} - Specialized subclass for grouping other resources.
<ul>
<li class='jac'>
{@link org.apache.juneau.rest.BasicRestServletJenaGroup} - Group resource with added RDF support.
<ul>
<li class='jc'>
<c>RootResources</c>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>
Pointing a browser to the resource shows the following:
</p>
<p class='bpcode w800'>
http://localhost:10000
</p>
<img class='bordered w800' src='doc-files/juneau-examples-rest.RootResources.1.png'>
<p>
The <l>RootResources</l> class can also be defined as a servlet in a <l>web.xml</l> file:
</p>
<p class='bpcode w800'>
<xt>&lt;web-app</xt> <xa>version</xa>=<xs>'3.0'</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.examples.rest.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>
<h5 class='figure'>RootResources.java</h5>
<p class='bpcode w800'>
<jd>/**
* Sample REST resource showing how to implement a "router" resource page.
*/</jd>
<ja>@Rest</ja>(
path=<js>"/"</js>,
title=<js>"Root resources"</js>,
description=<js>"Example of a router resource page."</js>,
htmldoc=<ja>@HtmlDoc</ja>(
widgets={
ContentTypeMenuItem.<jk>class</jk>,
StyleMenuItem.<jk>class</jk>
},
navlinks={
<js>"options: ?method=OPTIONS"</js>,
<js>"$W{ContentTypeMenuItem}"</js>,
<js>"$W{StyleMenuItem}"</js>,
<js>"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"</js>
},
aside={
<js>"&lt;div style='max-width:400px' class='text'&gt;"</js>,
<js>" &lt;p&gt;This is an example of a 'router' page that serves as a jumping-off point to child resources.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Resources can be nested arbitrarily deep through router pages.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Note the &lt;span class='link'&gt;options&lt;/span&gt; link provided that lets you see the generated swagger doc for this page.&lt;/p&gt;"</js>,
<js><js>" &lt;p&gt;Also note the &lt;span class='link'&gt;sources&lt;/span&gt; link on these pages to view the source code for the page.&lt;/p&gt;"</js>,
" &lt;p&gt;All content on pages in the UI are serialized POJOs. In this case, it's a serialized array of beans with 2 properties, 'name' and 'description'.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Other features (such as this aside) are added through annotations.&lt;/p&gt;"</js>,
<js>"&lt;/div&gt;"</js>
}
),
children={
HelloWorldResource.<jk>class</jk>,
PetStoreResource.<jk>class</jk>,
DtoExamples.<jk>class</jk>,
ConfigResource.<jk>class</jk>,
LogsResource.<jk>class</jk>,
DebugResource.<jk>class</jk>,
ShutdownResource.<jk>class</jk>
}
)
<ja>@SerializerConfig</ja>(
<jc>// For testing purposes, we want to use single quotes in all the serializers so it's easier to do simple
// String comparisons.</jc>
quoteChar=<js>"'"</js>
)
<jk>public class</jk> RootResources <jk>extends</jk> BasicRestServletJenaGroup {
<jc>// No code!</jc>
}
</p>
<p>
The <l>children</l> annotation defines the child resources of this router resource.
These are resources whose paths are direct descendants to the parent resource.
</p>
<p>
Child resources must be annotated with the {@link org.apache.juneau.rest.annotation.Rest#path() @Rest(path)} annotation to
identify the subpath of the child.
Children CAN extend from {@link org.apache.juneau.rest.BasicRestServlet} but it is not a requirement.
</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>
<p>
Let's step back and describe what's going on here:
</p>
<p>
During servlet initialization of the <l>RootResources</l> object, the toolkit looks for the
<l>@Rest(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>@Rest(path)</l> annotation on the child class.
</p>
<p>
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).
</p>
</div><!-- END: 16.1 - juneau-examples-rest.RootResources -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest.HelloWorldResource' id='juneau-examples-rest.HelloWorldResource'>16.2 - HelloWorldResource</a></h3>
<div class='topic'><!-- START: 16.2 - juneau-examples-rest.HelloWorldResource -->
<p>
The <l>HelloWorldResource</l> class is a simple resource that prints a "Hello world!" message.
</p>
<h5 class='figure'>HelloWorldResource.java</h5>
<p class='bpcode w800'>
<jd>/**
* Sample REST resource that prints out a simple "Hello world!" message.
*/</jd>
<ja>@Rest</ja>(
title=<js>"Hello World"</js>,
description=<js>"An example of the simplest-possible resource"</js>,
path=<js>"/helloWorld"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
aside={
<js>"&lt;div style='max-width:400px' class='text'&gt;"</js>,
<js>" &lt;p&gt;This page shows a resource that simply response with a 'Hello world!' message&lt;/p&gt;"</js>,
<js>" &lt;p&gt;The POJO serialized is a simple String.&lt;/p&gt;"</js>,
<js>"&lt;/div&gt;"</js>
}
)
)
<jk>public class</jk> HelloWorldResource <jk>implements</jk> BasicRestConfig {
<jd>/** GET request handler */</jd>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>, summary=<js>"Responds with \"Hello world!\""</js>)
<jk>public</jk> String sayHello() {
<jk>return</jk> <js>"Hello world!"</js>;
}
}
</p>
<p>
Notice that in this case we're not extending from {@link org.apache.juneau.rest.RestServlet}.
We are however implementing {@link org.apache.juneau.rest.BasicRestConfig} which is a no-op
interface that defines a default <ja>@Rest</ja> annotation with all the serializers, parsers,
and configuration defined on the {@link org.apache.juneau.rest.BasicRestServlet} class.
</p>
<p>
The only difference between implementing <l>BasicRestConfig</l> and extending from <l>BasicRestServlet</l>
is that the latter provides the following additional features:
</p>
<ul class='spaced-list'>
<li>A default OPTIONS method.
<li>It can be deployed like any servlet.
</ul>
<p>
All other examples in this project extend from <l>BasicRestServlet</l> so that they provide automatic OPTIONS page support.
</p>
<p>
Pointing a browser to the resource shows the following:
</p>
<p class='bpcode w800'>
http://localhost:10000/helloWorld
</p>
<img class='bordered w800' src='doc-files/juneau-examples-rest.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>
<p class='bpcode w800'>
http://localhost:10000/helloWorld?Accept=text/json&amp;plainText=true
</p>
<img class='bordered w800' src='doc-files/juneau-examples-rest.HelloWorldResource.2.png'>
</div><!-- END: 16.2 - juneau-examples-rest.HelloWorldResource -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest.DtoExamples' id='juneau-examples-rest.DtoExamples'>16.3 - DtoExamples</a></h3>
<div class='topic'><!-- START: 16.3 - juneau-examples-rest.DtoExamples -->
<p>
The <l>DtoExamples</l> resource is a resource group for demonstrating various DTO examples.
</p>
<p>
The <l>AtomFeedResource</l> class shows examples of the following:
</p>
<ul class='spaced-list'>
<li>
Using the {@doc org.apache.juneau.dto.atom#TOC ATOM Feed DTO} API.
</ul>
<p>
Pointing a browser to the resource shows the following:
</p>
<p class='bpcode w800'>
http://localhost:10000/atom
</p>
<img class='bordered w800' src='doc-files/juneau-examples-rest.AtomFeedResource.1.png'>
<p>
True ATOM feeds require using an <l>Accept:text/xml</l> header:
</p>
<p class='bpcode w800'>
http://localhost:10000/atom?Accept=text/xml&amp;plainText=true
</p>
<img class='bordered w800' src='doc-files/juneau-examples-rest.AtomFeedResource.2.png'>
<p>
Other languages, such as JSON are also supported:
</p>
<p class='bpcode w800'>
http://localhost:10000/atom?Accept=text/json&amp;plainText=true
</p>
<img class='bordered w800' src='doc-files/juneau-examples-rest.AtomFeedResource.3.png'>
<h5 class='figure'>AtomFeedResource.java</h5>
<p class='bpcode w800'>
<jd>/**
* Sample resource that shows how to generate ATOM feeds.
*/</jd>
<ja>@Rest</ja>(
path=<js>"/atom"</js>,
title=<js>"Sample ATOM feed resource"</js>,
description=<js>"Sample resource that shows how to render ATOM feeds"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
widgets={
ContentTypeMenuItem.<jk>class</jk>,
StyleMenuItem.<jk>class</jk>
},
navlinks={
<js>"up: request:/.."</js>,
<js>"options: servlet:/?method=OPTIONS"</js>,
<js>"$W{ContentTypeMenuItem}"</js>,
<js>"$W{StyleMenuItem}"</js>,
<js>"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"</js>
}
),
encoders=GzipEncoder.<jk>class</jk>
)
<ja>@SerializerConfig</ja>(quoteChar=<js>"'"</js>)
<ja>@RdfConfig</ja>(rdfxml_tab=<js>"5"</js>, addRootProperty=<js>"true"</js>)
<jk>public class</jk> AtomFeedResource <jk>extends</jk> BasicRestServletJena {
<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> =
<jsm>feed</jsm>(<js>"tag:juneau.sample.com,2013:1"</js>, <js>"Juneau ATOM specification"</js>, <js>"2013-05-08T12:29:29Z"</js>)
.subtitle(<jsm>text</jsm>(<js>"html"</js>).text(<js>"A &lt;em&gt;lot&lt;/em&gt; of effort went into making this effortless"</js>))
.links(
<jsm>link</jsm>(<js>"alternate"</js>, <js>"text/html"</js>, <js>"http://www.sample.com/"</js>).hreflang(<js>"en"</js>),
<jsm>link</jsm>(<js>"self"</js>, <js>"application/atom+xml"</js>, <js>"http://www.sample.com/feed.atom"</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>"2013-05-08T12:29:29Z"</js>)
.links(
<jsm>link</jsm>(<js>"alternate"</js>, <js>"text/html"</js>, <js>"http://www.sample.com/2012/05/08/juneau.atom"</js>),
<jsm>link</jsm>(<js>"enclosure"</js>, <js>"audio/mpeg"</js>, <js>"http://www.sample.com/audio/juneau_podcast.mp3"</js>).length(1337)
)
.published(<js>"2013-05-08T12:29:29Z"</js>)
.authors(
<jsm>person</jsm>(<js>"James Bognar"</js>).uri(<jk>new</jk> URI(<js>"http://www.sample.com/"</js>)).email(<js>"jamesbognar@apache.org"</js>)
)
.contributors(
<jsm>person</jsm>(<js>"Barry M. Caceres"</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;[Update: Juneau supports ATOM.]&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=<jsf>GET</jsf>, 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=<jsf>PUT</jsf>, path=<js>"/"</js>)
<jk>public</jk> Feed setFeed(<ja>@Body</ja> Feed feed) <jk>throws</jk> Exception {
<jk>this</jk>.<jf>feed</jf> = feed;
<jk>return</jk> feed;
}
}
</p>
<p>
The <l>JsonSchemaResource</l> class shows examples of the following:
</p>
<ul class='spaced-list'>
<li>
Using the {@link org.apache.juneau.dto.jsonschema JSON Schema DTO} API.
</ul>
<p>
The resource consists of a pre-initialized {@link org.apache.juneau.dto.jsonschema.JsonSchema} object.
Pointing a browser to the resource shows the following:
</p>
<p class='bpcode w800'>
http://localhost:10000/jsonSchema
</p>
<img class='bordered w800' src='doc-files/juneau-examples-rest.JsonSchemaResource.1.png'>
<p>
For true JSON-Schema, you need to specify the header <l>Accept: text/json</l>:
</p>
<p class='bpcode w800'>
http://localhost:10000/jsonSchema?Accept=text/json&amp;plainText=true
</p>
<img class='bordered w800' src='doc-files/juneau-examples-rest.JsonSchemaResource.2.png'>
<h5 class='figure'>JsonSchemaResource.java</h5>
<p class='bpcode w800'>
<jd>/**
* Sample resource that shows how to serialize JSON-Schema documents.
*/</jd>
<ja>@Rest</ja>(
path=<js>"/jsonSchema"</js>,
messages=<js>"nls/JsonSchemaResource"</js>,
title=<js>"Sample JSON-Schema document"</js>,
description=<js>"Sample resource that shows how to generate JSON-Schema documents"</js>,
htmldoc=<ja>@HtmlDoc</ja>(
widgets={
ContentTypeMenuItem.<jk>class</jk>,
StyleMenuItem.<jk>class</jk>
},
navlinks={
<js>"up: request:/.."</js>,
<js>"options: servlet:/?method=OPTIONS"</js>,
<js>"$W{ContentTypeMenuItem}"</js>,
<js>"$W{StyleMenuItem}"</js>,
<js>"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"</js>
},
aside={
<js>"&lt;div style='min-width:200px' class='text'&gt;"</js>,
<js>" &lt;p&gt;Shows how to produce JSON-Schema documents in a variety of languages using the JSON-Schema DTOs.&lt;/p&gt;"</js>,
<js>"&lt;/div&gt;"</js>
}
)
)
<jk>public class</jk> JsonSchemaResource <jk>extends</jk> BasicRestServletJena {
<jk>private static final long</jk> <jsf>serialVersionUID</jsf> = 1L;
<jk>private</jk> JsonSchema schema; <jc>// The schema document</jc>
<ja>@Override</ja> /* Servlet */
<jk>public void</jk> init() {
<jk>try</jk> {
<jf>schema</jf> = <jk>new</jk> JsonSchema()
.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> JsonSchemaProperty(<js>"firstName"</js>, JsonType.<jsf>STRING</jsf>),
<jk>new</jk> JsonSchemaProperty(<js>"lastName"</js>, JsonType.<jsf>STRING</jsf>),
<jk>new</jk> JsonSchemaProperty(<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=<jsf>GET</jsf>, path=<js>"/"</js>)
<jk>public</jk> JsonSchema 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=<jsf>PUT</jsf>, path=<js>"/"</js>)
<jk>public</jk> JsonSchema setSchema(<ja>@Body</ja> JsonSchema schema) <jk>throws</jk> Exception {
<jk>this</jk>.<jf>schema</jf> = schema;
<jk>return</jk> schema;
}
}
</p>
</div><!-- END: 16.3 - juneau-examples-rest.DtoExamples -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest.ConfigResource' id='juneau-examples-rest.ConfigResource'>16.4 - ConfigResource</a></h3>
<div class='topic'><!-- START: 16.4 - juneau-examples-rest.ConfigResource -->
<p>
The {@link org.apache.juneau.microservice.resources.ConfigResource} class is a predefined reusable resource.
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>
<p class='bpcode w800'>
http://localhost:10000/config
</p>
<img class='bordered w800' src='doc-files/juneau-examples-rest.ConfigResource.1.png'>
<p>
An edit page is provided for altering the raw config file:
</p>
<p class='bpcode w800'>
http://localhost:10000/config/edit
</p>
<img class='bordered w800' src='doc-files/juneau-examples-rest.ConfigResource.2.png'>
<p>
The {@link org.apache.juneau.config.Config} class is a serializable POJO, which makes the resource
relatively straightforward to implement.
</p>
<h5 class='figure'>ConfigResource.java</h5>
<p class='bpcode w800'>
<jd>/**
* Shows contents of the microservice configuration file.
*/</jd>
<ja>@Rest</ja>(
path=<js>"/config"</js>,
title=<js>"Configuration"</js>,
description=<js>"Contents of configuration file."</js>,
htmldoc=<ja>@HtmlDoc</ja>(
navlinks={
<js>"up: request:/.."</js>,
<js>"options: servlet:/?method=OPTIONS"</js>,
<js>"edit: servlet:/edit"</js>
}
)
)
<jk>public class</jk> ConfigResource <jk>extends</jk> BasicRestServlet {
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>, description=<js>"Show contents of config file."</js>)
<jk>public</jk> ObjectMap getConfig() <jk>throws</jk> Exception {
<jk>return</jk> getServletConfig().getConfig().asMap();
}
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/edit"</js>, description=<js>"Edit config file."</js>)
<jk>public</jk> Form getConfigEditForm(RestRequest req) <jk>throws</jk> Exception {
<jk>return</jk> <jsm>form</jsm>().id(<js>"form"</js>).action(<js>"servlet:/"</js>).method(<js>"POST"</js>).enctype(<js>"application/x-www-form-urlencoded"</js>).children(
<jsm>div</jsm>()._class(<js>"data"</js>).children(
<jsm>table</jsm>(
<jsm>tr</jsm>(<jsm>td</jsm>().style(<js>"text-align:right"</js>).children(<jsm>button</jsm>(<js>"submit"</js>,<js>"Submit"</js>),<jsm>button</jsm>(<js>"reset"</js>,<js>"Reset"</js>))),
<jsm>tr</jsm>(<jsm>th</jsm>().child(<js>"Contents"</js>)),
<jsm>tr</jsm>(<jsm>th</jsm>().child(
<jsm>textarea</jsm>().name(<js>"contents"</js>).rows(40).cols(120).style(<js>"white-space:pre;word-wrap:normal;overflow-x:scroll;font-family:monospace;"</js>)
.text(getServletConfig().getConfig().toString()))
)
)
)
);
}
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/{section}"</js>,
description=<js>"Show config file section."</js>,
swagger={
<js>"parameters:["</js>,
<js>"{name:'section',in:'path',description:'Section name.'}"</js>,
<js>"]"</js>
}
)
<jk>public</jk> ObjectMap getConfigSection(<ja>@Path</ja>(<js>"section"</js>) String section) <jk>throws</jk> Exception {
<jk>return</jk> getSection(section);
}
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/{section}/{key}"</js>,
description=<js>"Show config file entry."</js>,
swagger={
<js>"parameters:["</js>,
<js>"{name:'section',in:'path',description:'Section name.'},"</js>,
<js>"{name:'key',in:'path',description:'Entry name.'}"</js>,
<js>"]"</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);
}
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>, path=<js>"/"</js>,
description=<js>"Sets contents of config file from a FORM post."</js>,
swagger={
<js>"parameters:["</js>,
<js>"{name:'contents',in:'formData',description:'New contents in INI file format.'}"</js>,
<js>"]"</js>
}
)
<jk>public</jk> Config setConfigContentsFormPost(<ja>@FormData</ja>(<js>"contents"</js>) String contents) <jk>throws</jk> Exception {
<jk>return</jk> setConfigContents(<jk>new</jk> StringReader(contents));
}
<ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, path=<js>"/"</js>,
description=<js>"Sets contents of config file."</js>,
swagger={
<js>"parameters:["</js>,
<js>"{in:'body',description:'New contents in INI file format.'}"</js>,
<js>"]"</js>
}
)
<jk>public</jk> Config setConfigContents(<ja>@Body</ja> Reader contents) <jk>throws</jk> Exception {
<jk>return</jk> getServletConfig().getConfig().load(contents, <jk>true</jk>).asMap();
}
<ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, path=<js>"/{section}"</js>,
description=<js>"Add or overwrite a config file section."</js>,
swagger={
<js>"parameters:["</js>,
<js>"{name:'section',in:'path',description:'Section name.'}"</js>,
<js>"{in:'body',description:'New contents for section as a simple map with string keys and values.'}"</js>,
<js>"]"</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 {
getServletConfig().getConfig().setSection(section, contents);
<jk>return</jk> getSection(section);
}
<ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, path=<js>"/{section}/{key}"</js>,
description=<js>"Add or overwrite a config file entry."</js>,
swagger={
<js>"parameters:["</js>,
<js>"{name:'section',in:'path',description:'Section name.'}"</js>,
<js>"{name:'key',in:'path',description:'Entry name.'}"</js>,
<js>"{in:'body',description:'New value as a string.'}"</js>,
<js>"]"</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 {
getServletConfig().getConfig().put(section, key, value, <jk>false</jk>);
<jk>return</jk> getSection(section).getString(key);
}
<jk>private</jk> ObjectMap getSection(String name) {
ObjectMap m = getServletConfig().getConfig().getSectionMap(name);
<jk>if</jk> (m == <jk>null</jk>)
<jk>throw new</jk> RestException(<jsf>SC_NOT_FOUND</jsf>, <js>"Section not found."</js>);
<jk>return</jk> m;
}
}
</p>
</div><!-- END: 16.4 - juneau-examples-rest.ConfigResource -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest.LogsResource' id='juneau-examples-rest.LogsResource'>16.5 - LogsResource</a></h3>
<div class='topic'><!-- START: 16.5 - juneau-examples-rest.LogsResource -->
<p>
The {@link org.apache.juneau.microservice.resources.LogsResource} class is a reusable predefined resource.
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>
<p class='bpcode w800'>
http://localhost:10000/logs
</p>
<img class='bordered w800' src='doc-files/juneau-examples-rest.LogsResource.1.png'>
</div><!-- END: 16.5 - juneau-examples-rest.LogsResource -->
</div><!-- END: 16 - juneau-examples-rest -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest-jetty' id='juneau-examples-rest-jetty'>17 - juneau-examples-rest-jetty</a></h2>
<div class='topic'><!-- START: 17 - juneau-examples-rest-jetty -->
<div class='warn'>
The Juneau Microservice libraries are likely to be removed in Juneau 9.0 due to the popularity of the Spring Boot
framework for creating microservices and the ability for Juneau to be used within Spring Boot.
</div>
<h5 class='figure'>Starter Project Zip</h5>
<p class='bpcode w500'>
juneau-examples-rest-jetty-{@property juneauVersion}.zip
</p>
<p>
The <c>juneau-examples-rest-jetty</c> project includes everything you need create a Samples REST
microservice in an Eclipse workspace and build it as an executable jar.
</p>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest-jetty.Installing' id='juneau-examples-rest-jetty.Installing'>17.1 - Installing in Eclipse</a></h3>
<div class='topic'><!-- START: 17.1 - juneau-examples-rest-jetty.Installing -->
<p>
Follow these instructions to import the REST examples project using Jetty into Eclipse.
</p>
<ol class='spaced-list'>
<li>
Download the <c>juneau-examples-rest-jetty-{@property juneauVersion}.zip</c> file from the downloads page
(located in the binaries) and import it into your workspace as an existing project:
<br><br>
<img class='bordered' src='doc-files/juneau-examples-rest-jetty.Installing.1.png' style='width:524px'>
<li>
Select the archive file and import the project:
<br><br>
<img class='bordered' src='doc-files/juneau-examples-rest-jetty.Installing.2.png' style='width:549px'>
<li>
In your workspace, you should now see the following project:
<br><br>
<img class='bordered' src='doc-files/juneau-examples-rest-jetty.Installing.3.png' style='width:400px'>
</ol>
<p>
The important elements in this project are:
</p>
<ul class='spaced-list'>
<li>
<l>App.java</l> - The entry point.
<br>This class creates and starts our microservice:
<br><br>
<p class='bcode w800'>
<jk>public class</jk> App {
<jk>public static void</jk> main(String[] args) <jk>throws</jk> Exception {
JettyMicroservice
.<jsm>create</jsm>()
.args(args)
.servlet(RootResources.<jk>class</jk>)
.build()
.start()
.startConsole()
.join();
}
}
</p>
<li>
<l>RootResources.java</l> - The top-level REST resource.
<br>This class routes HTTP requests to child resources:
<br><br>
<p class='bcode w800'>
<ja>@Rest</ja>(
path=<js>"/*"</js>,
title=<js>"Root resources"</js>,
description=<js>"Example of a router resource page."</js>,
htmldoc=<ja>@HtmlDoc</ja>(
widgets={
ContentTypeMenuItem.<jk>class</jk>,
ThemeMenuItem.<jk>class</jk>
},
navlinks={
<js>"options: ?method=OPTIONS"</js>,
<js>"$W{ContentTypeMenuItem}"</js>,
<js>"$W{ThemeMenuItem}"</js>,
<js>"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"</js>
},
aside={
<js>"&lt;div style='max-width:400px' class='text'&gt;"</js>,
<js>" &lt;p&gt;This is an example of a 'router' page that serves as a jumping-off point to child resources.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Resources can be nested arbitrarily deep through router pages.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Note the &lt;span class='link'&gt;options&lt;/span&gt; link provided that lets you see the generated swagger doc for this page.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Also note the &lt;span class='link'&gt;sources&lt;/span&gt; link on these pages to view the source code for the page.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;All content on pages in the UI are serialized POJOs. In this case, it's a serialized array of beans with 2 properties, 'name' and 'description'.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Other features (such as this aside) are added through annotations.&lt;/p&gt;"</js>,
<js>"&lt;/div&gt;"</js>
}
),
children={
HelloWorldResource.<jk>class</jk>,
PetStoreResource.<jk>class</jk>,
DtoExamples.<jk>class</jk>,
ConfigResource.<jk>class</jk>,
LogsResource.<jk>class</jk>,
ShutdownResource.<jk>class</jk>
}
)
<ja>@SerializerConfig</ja>(
<jc>// For testing purposes, we want to use single quotes in all the serializers so it's easier to do simple
// String comparisons.</jc>
quoteChar=<js>"'"</js>
)
<jk>public class</jk> RootResources <jk>extends</jk> BasicRestServletJenaGroup {
<jc>// No code</jc>
}
</p>
<li>
<l>juneau-examples-rest-jetty.cfg</l> - The external configuration file.
<br>Contains various useful settings.
<br>Can be used for your own resource configurations.
<br><br>
<p class='bcode w800'>
<cc>#=======================================================================================================================
# Basic configuration file for REST microservices
# Subprojects can use this as a starting point.
#=======================================================================================================================</cc>
<cc>#=======================================================================================================================
# Jetty settings
#=======================================================================================================================</cc>
<cs>[Jetty]</cs>
<cc># Path of the jetty.xml file used to configure the Jetty server.</cc>
<ck>config</ck> = <cv>jetty.xml</cv>
<cc># Resolve Juneau variables in the jetty.xml file.</cc>
<ck>resolveVars</ck> = <cv>true</cv>
<cc># Port to use for the jetty server.
# You can specify multiple ports. The first available will be used. '0' indicates to try a random port.
# The resulting available port gets set as the system property "availablePort" which can be referenced in the
# jetty.xml file as "$S{availablePort}" (assuming resolveVars is enabled).</cc>
<ck>port</ck> = <cv>10000,0,0,0</cv>
<cc># Optionally specify your servlets here:
#servlets = org.apache.juneau.microservice.sample.RootResources</cc>
<cc>#=======================================================================================================================
# REST settings
#=======================================================================================================================</cc>
<cs>[REST]</cs>
<cc># Comma-delimited list of key-value pairs that represent locations of static files that can be served up by your @Rest-annotated
# classes. These are static files that are served up by the servlet under the specified sub-paths.
# For example, given the following setting...
# staticFiles = htdocs:my-docs,styles/my-styles
# ...the URI "/servletPath/htdocs/javadoc.css" resolves to the path "/my-docs/javadoc.css".
# This path can be relative to the working directory, classpath root, or package of your resource class.
# Used by the BasicRestConfig interface that defines the following value:
# staticFiles="$C{REST/staticFiles}"</cc>
<ck>staticFiles</ck> = htdocs:htdocs
<cc># Stylesheet to use for HTML views.
# Used by the BasicRestConfig interface that defines the following value:
# stylesheet="$C{REST/theme,servlet:/htdocs/themes/devops.css}"</cc>
<ck>theme</ck> = <cv>servlet:/htdocs/themes/devops.css</cv>
<cc># Various look-and-feel settings used in the BasicRestConfig interface.</cc>
<ck>headerIcon</ck> = <cv>servlet:/htdocs/images/juneau.png</cv>
<ck>headerLink</ck> = <cv>http://juneau.apache.org</cv>
<ck>footerIcon</ck> = <cv>servlet:/htdocs/images/asf.png</cv>
<ck>footerLink</ck> = <cv>http://www.apache.org</cv>
<ck>favicon</ck> = <cv>$C{REST/headerIcon}</cv>
<ck>header</ck> =
<cv>&lt;a href='$U{$C{REST/headerLink}}'&gt;
&lt;img src='$U{$C{REST/headerIcon}}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/&gt;
&lt;/a&gt;</cv>
<ck>footer</ck> =
<cv>&lt;a href='$U{$C{REST/footerLink}}'&gt;
&lt;img src='$U{$C{REST/footerIcon}}' style='float:right;padding-right:20px;height:32px'/&gt;
&lt;/a&gt;</cv>
<cc>#=======================================================================================================================
# Console settings
#=======================================================================================================================</cc>
<cs>[Console]</cs>
<ck>enabled</ck> = <cv>true</cv>
<cc># List of available console commands.
# These are classes that implements ConsoleCommand that allow you to submit commands to the microservice via
# the console.
# When listed here, the implementations must provide a no-arg constructor.
# They can also be provided dynamically by overriding the Microservice.createConsoleCommands() method.</cc>
<ck>commands</ck> =
<cv>org.apache.juneau.microservice.console.ExitCommand,
org.apache.juneau.microservice.console.RestartCommand,
org.apache.juneau.microservice.console.HelpCommand,
org.apache.juneau.microservice.console.ConfigCommand</cv>
<cc>#=======================================================================================================================
# Logger settings
#-----------------------------------------------------------------------------------------------------------------------
# See FileHandler Java class for details.
#=======================================================================================================================</cc>
<cs>[Logging]</cs>
...
<cc>#=======================================================================================================================
# System properties
#-----------------------------------------------------------------------------------------------------------------------
# These are arbitrary system properties that are set during startup.
#=======================================================================================================================</cc>
<cs>[SystemProperties]</cs>
<cc># Configure Jetty for StdErrLog Logging
# org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog</cc>
<cc># Configure Jetty to log using java-util logging</cc>
<ck>org.eclipse.jetty.util.log.class</ck> = <cv>org.apache.juneau.microservice.jetty.JettyLogger</cv>
<cc># Jetty logging level
# Possible values: ALL, DEBUG, INFO, WARN, OFF</cc>
<ck>org.eclipse.jetty.LEVEL</ck> = <cv>WARN
<ck>derby.stream.error.file</ck> = <cv>$C{Logging/logDir}/derby-errors.log</cv>
</p>
<li>
<l>jetty.xml</l> - The Jetty configuration file.
<br>A bare-bones config file that can be extended to use any Jetty features.
<br><br>
<p class='bcode w800'>
<xt>&lt;Configure</xt> <xa>id</xa>=<xs>"ExampleServer"</xs> <xa>class</xa>=<xs>"org.eclipse.jetty.server.Server"</xs>&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"connectors"</xs><xt>&gt;</xt>
<xt>&lt;Array</xt> <xa>type</xa>=<xs>"org.eclipse.jetty.server.Connector"</xs><xt>&gt;</xt>
<xt>&lt;Item&gt;</xt>
<xt>&lt;New</xt> <xa>class</xa>=<xs>"org.eclipse.jetty.server.ServerConnector"</xs><xt>&gt;</xt>
<xt>&lt;Arg&gt;</xt>
<xt>&lt;Ref</xt> <xa>refid</xa>=<xs>"ExampleServer"</xs><xt>/&gt;</xt>
<xt>&lt;/Arg&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"port"</xs><xt>&gt;</xt>$S{availablePort,8080}<xt>&lt;/Set&gt;</xt>
<xt>&lt;/New&gt;</xt>
<xt>&lt;/Item&gt;</xt>
<xt>&lt;/Array&gt;</xt>
<xt>&lt;/Set&gt;</xt>
<xt>&lt;New</xt> <xa>id</xa>=<xs>"context"</xs> <xa>class</xa>=<xs>"org.eclipse.jetty.servlet.ServletContextHandler"</xs><xt>&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"contextPath"</xs><xt>&gt;/&lt;/Set&gt;</xt>
<xc>&lt;!-- Optionally specify your servlets here --&gt;
&lt;!--Call name="addServlet"&gt;
&lt;Arg&gt;org.apache.juneau.microservice.sample.RootResources&lt;/Arg&gt;
&lt;Arg&gt;/*&lt;/Arg&gt;
&lt;/Call--&gt;</xc>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"sessionHandler"</xs><xt>&gt;</xt>
<xt>&lt;New</xt> <xa>class</xa>=<xs>"org.eclipse.jetty.server.session.SessionHandler"</xs><xt>/&gt;</xt>
<xt>&lt;/Set&gt;</xt>
<xt>&lt;/New&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"handler"</xs><xt>&gt;</xt>
<xt>&lt;New</xt> <xa>class</xa>=<xs>"org.eclipse.jetty.server.handler.HandlerCollection"</xs><xt>&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"handlers"</xs><xt>&gt;</xt>
<xt>&lt;Array</xt> <xa>type</xa>=<xs>"org.eclipse.jetty.server.Handler"</xs><xt>&gt;</xt>
<xt>&lt;Item&gt;</xt>
<xt>&lt;Ref</xt> <xa>refid</xa>=<xs>"context"</xs><xt>/&gt;</xt>
<xt>&lt;/Item&gt;</xt>
<xt>&lt;Item&gt;</xt>
<xt>&lt;New</xt> <xa>class</xa>=<xs>"org.eclipse.jetty.server.handler.DefaultHandler"</xs><xt>/&gt;</xt>
<xt>&lt;/Item&gt;</xt>
<xt>&lt;/Array&gt;</xt>
<xt>&lt;/Set&gt;</xt>
<xt>&lt;/New&gt;</xt>
<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"requestLog"</xs><xt>&gt;</xt>
<xt>&lt;New</xt> <xa>id</xa>=<xs>"RequestLogImpl"</xs> <xa>class</xa>=<xs>"org.eclipse.jetty.server.NCSARequestLog"</xs><xt>&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"filename"</xs><xt>&gt;&lt;Property</xt> <xa>name</xa>=<xs>"jetty.logs"</xs> <xa>default</xa>=<xs>"$C{Logging/logDir,logs}"</xs><xt>/&gt;</xt>/jetty-requests.log<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"filenameDateFormat</xs><xt>"&gt;</xt>yyyy_MM_dd<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"LogTimeZone"</xs><xt>&gt;</xt>GMT<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"retainDays"</xs><xt>&gt;</xt>90<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"append"</xs><xt>&gt;</xt>false<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"LogLatency"</xs><xt>&gt;</xt>true<xt>&lt;/Set&gt;</xt>
<xt>&lt;/New&gt;</xt>
<xt>&lt;/Set&gt;</xt>
<xt>&lt;Get</xt> <xa>name</xa>=<xs>"ThreadPool"</xs><xt>&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"minThreads"</xs> <xa>type</xa>=<xs>"int"</xs><xt>&gt;</xt>10<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"maxThreads"</xs> <xa>type</xa>=<xs>"int"</xs><xt>&gt;</xt>100<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"idleTimeout"</xs> <xa>type</xa>=<xs>"int"</xs><xt>&gt;</xt>60000<xt>&lt;/Set&gt;</xt>
<xt>&lt;Set</xt> <xa>name</xa>=<xs>"detailedDump"</xs><xt>&gt;</xt>true<xt>&lt;/Set&gt;</xt>
<xt>&lt;/Get&gt;</xt>
<xt>&lt;/Configure&gt;</xt>
</p>
</ul>
<p>
At this point, you're ready to start the microservice from your workspace.
</p>
</div><!-- END: 17.1 - juneau-examples-rest-jetty.Installing -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest-jetty.Running' id='juneau-examples-rest-jetty.Running'>17.2 - Running in Eclipse</a></h3>
<div class='topic'><!-- START: 17.2 - juneau-examples-rest-jetty.Running -->
<p>
The <l>juneau-examples-rest-jetty.launch</l> file is already provided to allow you to quickly start
your new microservice.
</p>
<p>
Go to <b>Run -&gt; Run Configurations -&gt; Java Application -&gt; juneau-examples-rest-jetty</b> and click <b>Run</b>.
In your console view, you should see the following output:
</p>
<p class='bpcode w800 console'>
Running class 'JettyMicroservice' using config file 'juneau-examples-rest-jetty.cfg'.
Server started on port 10000
List of available commands:
exit -- Shut down service
restart -- Restarts service
help -- Commands help
>
</p>
<p>
Now open your browser and point to <l>http://localhost:10000</l>.
You should see the following:
</p>
<p class='bpcode w400'>
http://localhost:10000
</p>
<img class='bordered w400' src='doc-files/juneau-examples-rest-jetty.Running.1.png'>
<p>
You can enter the command <c>exit</c> to shut it down.
</p>
</div><!-- END: 17.2 - juneau-examples-rest-jetty.Running -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest-jetty.Building' id='juneau-examples-rest-jetty.Building'>17.3 - Building and Running from Command-Line</a></h3>
<div class='topic'><!-- START: 17.3 - juneau-examples-rest-jetty.Building -->
<p>
The <l>pom.xml</l> file is a basic Maven build script for creating the examples microservice
as an executable uber-jar.
</p>
<p>
The easiest way to build the microservice is to run the following from the project root.
</p>
<p class='bpcode w800'>
mvn clean install
</p>
<p>
Your <c>target</c> directory should now contain the following files:
</p>
<ul>
<li><c>juneau-examples-rest-jetty-1.0.jar</c>
<li><c>juneau-examples-rest-jetty.cfg</c>
</ul>
<p>
To start from a command line, run the following command from inside your <c>target</c> directory:
</p>
<p class='bpcode w800'>
java -jar juneau-examples-rest-jetty-1.0.jar
</p>
<p>
You should see the following console output:
</p>
<p class='bpcode w800 console'>
Running class 'JettyMicroservice' using config file 'juneau-examples-rest-jetty.cfg'.
Server started on port 10000
List of available commands:
exit -- Shut down service
restart -- Restarts service
help -- Commands help
>
</p>
<p>
If you get this error message: <code class='snippet'>java.net.BindException: Address already in use</code>,
then this microservice is already running elsewhere and so it cannot bind to port 10000.
</p>
</div><!-- END: 17.3 - juneau-examples-rest-jetty.Building -->
</div><!-- END: 17 - juneau-examples-rest-jetty -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest-springboot' id='juneau-examples-rest-springboot'>18 - juneau-examples-rest-springboot</a></h2>
<div class='topic'><!-- START: 18 - juneau-examples-rest-springboot -->
<h5 class='figure'>Starter Project Zip</h5>
<p class='bpcode w500'>
juneau-examples-rest-springboot-{@property juneauVersion}.zip
</p>
<p>
The <c>juneau-examples-rest-springboot</c> library contains the same examples as <c>juneau-examples-rest</c>
but also includes the following:
</p>
<ul class='spaced-list'>
<li>
A starter class for invoking the examples using Spring Boot.
<li>
A resource resolver for resolving REST resources as injectable beans.
<li>
A POM that extends from <c>spring-boot-starter-parent</c> that allows you to build a fully-shaded executable jar.
<li>
Configuration files for deploying the microservice to Heroku.
</ul>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest-springboot.Installing' id='juneau-examples-rest-springboot.Installing'>18.1 - Installing in Eclipse</a></h3>
<div class='topic'><!-- START: 18.1 - juneau-examples-rest-springboot.Installing -->
<p>
Follow these instructions to import the REST examples project using Spring Boot into Eclipse.
</p>
<ol class='spaced-list'>
<li>
Download the <c>juneau-examples-rest-springboot-{@property juneauVersion}.zip</c> file from the downloads page
(located in the binaries) and import it into your workspace as an existing project:
<br><br>
<img class='bordered' src='doc-files/juneau-examples-rest-springboot.Installing.1.png' style='width:524px'>
<li>
Select the archive file and import the project:
<br><br>
<img class='bordered' src='doc-files/juneau-examples-rest-springboot.Installing.2.png' style='width:549px'>
<li>
In your workspace, you should now see the following project:
<br><br>
<img class='bordered' src='doc-files/juneau-examples-rest-springboot.Installing.3.png' style='width:400px'>
</ol>
<p>
The important elements in this project are:
</p>
<ul class='spaced-list'>
<li>
<l>App.java</l> - The entry point.
<br>This class creates and starts our microservice.
<br>Note that we're using the existing Spring Boot application logic for the microservice and we're retrieving
our root resource as a spring bean.
<br>Only the top-level resource needs to be annotated with {@link org.apache.juneau.rest.springboot.annotation.JuneauRestRoot @JuneauRestRoot}
<br><br>
<p class='bcode w800'>
<ja>@SpringBootApplication</ja>
<ja>@Controller</ja>
<jk>public class</jk> App {
<jk>public static void</jk> main(String[] args) {
<jk>new</jk> SpringApplicationBuilder(App.<jk>class</jk>)
.initializers(<jk>new</jk> JuneauRestInitializer(App.<jk>class</jk>))
.run(args);
}
<ja>@Bean @JuneauRestRoot</ja>
<jk>public</jk> RootResources getRootResources() {
<jk>return new</jk> RootResources();
}
}
</p>
<li>
<l>RootResources.java</l> - The top-level REST resource.
<br>This class routes HTTP requests to child resources:
<br><br>
<p class='bcode w800'>
<ja>@Rest</ja>(
path=<js>"/*"</js>,
title=<js>"Root resources"</js>,
description=<js>"Example of a router resource page."</js>,
htmldoc=<ja>@HtmlDoc</ja>(
widgets={
ContentTypeMenuItem.<jk>class</jk>,
ThemeMenuItem.<jk>class</jk>
},
navlinks={
<js>"options: ?method=OPTIONS"</js>,
<js>"$W{ContentTypeMenuItem}"</js>,
<js>"$W{ThemeMenuItem}"</js>,
<js>"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"</js>
},
aside={
<js>"&lt;div style='max-width:400px' class='text'&gt;"</js>,
<js>" &lt;p&gt;This is an example of a 'router' page that serves as a jumping-off point to child resources.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Resources can be nested arbitrarily deep through router pages.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Note the &lt;span class='link'&gt;options&lt;/span&gt; link provided that lets you see the generated swagger doc for this page.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Also note the &lt;span class='link'&gt;sources&lt;/span&gt; link on these pages to view the source code for the page.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;All content on pages in the UI are serialized POJOs. In this case, it's a serialized array of beans with 2 properties, 'name' and 'description'.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;Other features (such as this aside) are added through annotations.&lt;/p&gt;"</js>,
<js>"&lt;/div&gt;"</js>
}
),
children={
HelloWorldResource.<jk>class</jk>,
PetStoreResource.<jk>class</jk>,
DtoExamples.<jk>class</jk>,
ConfigResource.<jk>class</jk>,
LogsResource.<jk>class</jk>,
ShutdownResource.<jk>class</jk>
}
)
<ja>@SerializerConfig</ja>(
<jc>// For testing purposes, we want to use single quotes in all the serializers so it's easier to do simple
// String comparisons.</jc>
quoteChar=<js>"'"</js>
)
<jk>public class</jk> RootResources <jk>extends</jk> BasicRestServletJenaGroup {
<jc>// No code</jc>
}
</p>
<li>
<l>juneau.cfg</l> - The configuration file.
<br>Contains various useful settings.
<br>Can be used for your own resource configurations.
<br>Note that the Jetty configuration is not present.
<br>Also it's located in the classpath so that our microservice can be built as a single executable jar.
<br><br>
<p class='bcode w800'>
<cc>#=======================================================================================================================
# Basic configuration file for REST microservices
# Subprojects can use this as a starting point.
#=======================================================================================================================</cc>
<cc>#=======================================================================================================================
# REST settings
#=======================================================================================================================</cc>
<cs>[REST]</cs>
<cc># URL mappings to static files in the working directory or classpath.</cc>
<ck>staticFiles</ck> = htdocs:files/htdocs
<cc># Stylesheet to use for HTML views.</cc>
<ck>theme</ck> = <cv>servlet:/htdocs/themes/devops.css</cv>
<ck>headerIcon</ck> = <cv>servlet:/htdocs/images/juneau.png</cv>
<ck>headerLink</ck> = <cv>http://juneau.apache.org</cv>
<ck>footerIcon</ck> = <cv>servlet:/htdocs/images/asf.png</cv>
<ck>footerLink</ck> = <cv>http://www.apache.org</cv>
<ck>favicon</ck> = <cv>$C{REST/headerIcon}</cv>
<ck>header</ck> =
<cv>&lt;a href='$U{$C{REST/headerLink}}'&gt;
&lt;img src='$U{$C{REST/headerIcon}}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/&gt;
&lt;/a&gt;</cv>
<ck>footer</ck> =
<cv>&lt;a href='$U{$C{REST/footerLink}}'&gt;
&lt;img src='$U{$C{REST/footerIcon}}' style='float:right;padding-right:20px;height:32px'/&gt;
&lt;/a&gt;</cv>
</p>
</ul>
<p>
At this point, you're ready to start the microservice from your workspace.
</p>
</div><!-- END: 18.1 - juneau-examples-rest-springboot.Installing -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest-springboot.Running' id='juneau-examples-rest-springboot.Running'>18.2 - Running in Eclipse</a></h3>
<div class='topic'><!-- START: 18.2 - juneau-examples-rest-springboot.Running -->
<p>
The <l>juneau-examples-rest-springboot.launch</l> file is already provided to allow you to quickly start
your new microservice.
</p>
<p>
Go to <b>Run -&gt; Run Configurations -&gt; Java Application -&gt; juneau-examples-rest-springboot</b> and click <b>Run</b>.
In your console view, you should see the following output:
</p>
<p class='bpcode w800 console'>
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.1.RELEASE)
...
INFO: Tomcat started on port(s): 8080 (http) with context path ''
Dec 21, 2012 12:30:00 AM org.springframework.boot.StartupInfoLogger logStarted
INFO: Started App in 1.999 seconds (JVM running for 2.999)
</p>
<p>
Now open your browser and point to <l>http://localhost:5000</l>.
You should see the following:
</p>
<p class='bpcode w400'>
http://localhost:5000
</p>
<img class='bordered w400' src='doc-files/juneau-examples-rest-springboot.Running.1.png'>
</div><!-- END: 18.2 - juneau-examples-rest-springboot.Running -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest-springboot.Building' id='juneau-examples-rest-springboot.Building'>18.3 - Building and Running from Command-Line</a></h3>
<div class='topic'><!-- START: 18.3 - juneau-examples-rest-springboot.Building -->
<p>
The <l>pom.xml</l> file is a basic Maven build script for creating your microservice
as an executable uber-jar.
</p>
<p>
The easiest way to build your microservice is to run the following from the project root.
</p>
<p class='bpcode w800'>
mvn clean install
</p>
<p>
Your <c>target</c> directory should now contain the following files:
</p>
<ul>
<li><c>juneau-examples-rest-springboot-1.0.jar</c>
</ul>
<p>
To start from a command line, run the following command from inside your <c>target</c> directory:
</p>
<p class='bpcode w800'>
java -jar juneau-examples-rest-springboot-1.0.jar
</p>
<p>
You should see the following console output:
</p>
<p class='bpcode w800 console'>
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.1.RELEASE)
...
INFO: Tomcat started on port(s): 8080 (http) with context path ''
Dec 21, 2012 12:30:00 AM org.springframework.boot.StartupInfoLogger logStarted
INFO: Started App in 1.999 seconds (JVM running for 2.999)
</p>
</div><!-- END: 18.3 - juneau-examples-rest-springboot.Building -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#juneau-examples-rest-springboot.DeployingToHeroku' id='juneau-examples-rest-springboot.DeployingToHeroku'>18.4 - Deploying to Heroku</a></h3>
<div class='topic'><!-- START: 18.4 - juneau-examples-rest-springboot.DeployingToHeroku -->
<p>
<a href='https://www.heroku.com'>Heroku</a> is a platform-as-a-service that allows applications to be quickly hosted
in the cloud.
The <l>juneau-examples-rest-springboot</l> project contains additional metadata files for quickly
deploying and running the examples in Heroku using free services.
</p>
<ul class='spaced-list'>
<li>
<l>app.json</l>
<br><br>
This class provides basic metadata information to Heroku about our application.
<br><br>
<p class='bcode w800'>
{
<jok>"name"</jok>: <jov>"Start on Heroku: Juneau REST Examples"</jov>,
<jok>"description"</jok>: <jov>"Deployable REST examples to Heroku."</jov>
}
</p>
<li>
<l>Procfile</l>
<br><br>
This class tells Heroku how to deploy our application using the Web dyno.
<br><br>
<p class='bcode w800'>
web: java -jar target/juneau-examples-rest-springboot-8.0.0-SNAPSHOT.jar
</p>
<li>
<l>settings.xml</l>
<br><br>This is an optional Maven settings file that points to both the main Maven repo in
addition to the Apache snapshots repo if you happen to be using a snapshot version of Juneau.
</ul>
<p>
You'll need to sign up for an account on Heroku.
Afterwards, you can go to the apps page to create a new application:
</p>
<p class='bpcode w1000'>
https://dashboard.heroku.com/apps
</p>
<img class='bordered w1000' src='doc-files/juneau-examples-rest-springboot.Heroku.1.png'>
<p>
Click the <l>New</l> button to create a new app, give it a unique name:
</p>
<p class='bpcode w1000'>
https://dashboard.heroku.com/new-app
</p>
<img class='bordered w1000' src='doc-files/juneau-examples-rest-springboot.Heroku.2.png'>
<p>
After clicking the <l>Create app</l> button, you should see this page:
</p>
<p class='bpcode w1000'>
https://dashboard.heroku.com/apps/juneau-examples-rest/deploy/heroku-git
</p>
<img class='bordered w1000' src='doc-files/juneau-examples-rest-springboot.Heroku.3.png'>
<p>
For this example, we'll use the <l>Heroku Git</l> option for deploying our application.
Follow the instructions for installing the Heroku CLI and logging into Heroku:
</p>
<p class='bpcode w1000'>
https://dashboard.heroku.com/apps/juneau-examples-rest/deploy/heroku-git
</p>
<img class='bordered w1000' src='doc-files/juneau-examples-rest-springboot.Heroku.4.png'>
<p>
Next, run the following commands to cd into our Eclipse project and initialize it as a local git repo:
</p>
<p class='bpcode w800'>
$ cd juneau-examples-rest-springboot/
$ git init
</p>
<h5 class='figure'>Output</h5>
<p class='bpcode w800 console'>
$ cd juneau-examples-rest-springboot/
$ git init
Initialized empty Git repository in /.../juneau-examples-rest-springboot/.git/
</p>
<p>
Next, run the following command to link our project to the Heroku app:
</p>
<p class='bpcode w800'>
$ heroku git:remote -a juneau-examples-rest
</p>
<h5 class='figure'>Output</h5>
<p class='bpcode w800 console'>
$ heroku git:remote -a juneau-examples-rest
set git remote heroku to https://git.heroku.com/juneau-examples-rest.git
</p>
<p>
Next, run the following commands to add our files to the git repo and push to the Heroku master branch:
</p>
<p class='bpcode w800'>
$ git add .
$ git commit -am "Initial deploy"
$ git push heroku master
</p>
<h5 class='figure'>Output</h5>
<p class='bpcode w800 console'>
$ git add .
master (root-commit) 7c94cb9] Initial deploy
123 files changed, 11986 insertions(+)
Counting objects: 127, done.
$ git commit -am "Initial deploy"
$ git push heroku master
Delta compression using up to 8 threads.
Compressing objects: 100% (113/113), done.
Writing objects: 100% (127/127), 363.91 KiB | 21.41 MiB/s, done.
...
remote: -----> Compressing...
remote: Done: 85.9M
remote: -----> Launching...
remote: Released v3
remote: https://juneau-examples-rest.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/juneau-examples-rest.git
* [new branch] master -> master
</p>
<p>
If no errors were shown, then our application should now be live.
You can click on the <l>Open app</l> button to open the examples application in a browser:
</p>
<img class='bordered w400' src='doc-files/juneau-examples-rest-springboot.Heroku.5.png'>
<p>
If everything worked, your browser should now be loaded with our example REST app:
</p>
<p class='bpcode w1000'>
https://juneau-examples-rest.herokuapp.com
</p>
<img class='bordered w1000' src='doc-files/juneau-examples-rest-springboot.Heroku.6.png'>
</div><!-- END: 18.4 - juneau-examples-rest-springboot.DeployingToHeroku -->
</div><!-- END: 18 - juneau-examples-rest-springboot -->
<!-- ==================================================================================================== -->
<h2 class='topic new' onclick='toggle(this)'><a href='#Glossaries' id='Glossaries'>19 - Glossaries</a></h2>
<div class='topic'><!-- START: 19 - Glossaries -->
<p>
</p>
<!-- ==================================================================================================== -->
<h3 class='topic new' onclick='toggle(this)'><a href='#Glossaries.ConfigurablePropertiesGlossary' id='Glossaries.ConfigurablePropertiesGlossary'>19.1 - Configurable Properties Glossary</a></h3>
<div class='topic'><!-- START: 19.1 - Glossaries.ConfigurablePropertiesGlossary -->
<p>
The following is a list of all properties defined throughout Juneau:
</p>
<table class='styled w1000'>
<tr>
<th>Context</th><th>ID</th><th style='min-width:250px'>Description</th><th>Data type</th>
</tr>
<tr>
<td>{@link org.apache.juneau.BeanContext}</td>
<td>{@link org.apache.juneau.BeanContext#BEAN_annotations BEAN_annotations}</td>
<td>Annotations.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;{@link java.lang.annotation.Annotation}&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_beanClassVisibility BEAN_beanClassVisibility}</td>
<td>Minimum bean class visibility.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.Visibility}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_beanConstructorVisibility BEAN_beanConstructorVisibility}</td>
<td>Minimum bean constructor visibility.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.Visibility}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_beanDictionary BEAN_beanDictionary}</td>
<td>Bean dictionary.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;Class&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_beanFieldVisibility BEAN_beanFieldVisibility}</td>
<td>Minimum bean field visibility.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.Visibility}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_beanFilters BEAN_beanFilters}</td>
<td>Bean filters.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;Class&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_beanMapPutReturnsOldValue BEAN_beanMapPutReturnsOldValue}</td>
<td>BeanMap.put() returns old property value.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_beanMethodVisibility BEAN_beanMethodVisibility}</td>
<td>Minimum bean method visibility.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.Visibility}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_beanTypePropertyName BEAN_beanTypePropertyName}</td>
<td>Bean type property name.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_beansRequireDefaultConstructor BEAN_beansRequireDefaultConstructor}</td>
<td>Beans require no-arg constructors.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_beansRequireSerializable BEAN_beansRequireSerializable}</td>
<td>Beans require Serializable interface.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_beansRequireSettersForGetters BEAN_beansRequireSettersForGetters}</td>
<td>Beans require setters for getters.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_beansRequireSomeProperties BEAN_beansRequireSomeProperties}</td>
<td>Beans require at least one property.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_bpi BEAN_bpi}</td>
<td>Bean property includes.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_bpro BEAN_bpro}</td>
<td>Read-only bean properties.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_bpwo BEAN_bpwo}</td>
<td>Write-only bean properties.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_bpx BEAN_bpx}</td>
<td>Bean property excludes.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_debug BEAN_debug}</td>
<td>Debug mode.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_examples BEAN_examples}</td>
<td>POJO examples.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,Object&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_fluentSetters BEAN_fluentSetters}</td>
<td>Find fluent setters.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_ignoreInvocationExceptionsOnGetters BEAN_ignoreInvocationExceptionsOnGetters}</td>
<td>Ignore invocation errors on getters.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_ignoreInvocationExceptionsOnSetters BEAN_ignoreInvocationExceptionsOnSetters}</td>
<td>Ignore invocation errors on setters.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_ignorePropertiesWithoutSetters BEAN_ignorePropertiesWithoutSetters}</td>
<td>Ignore properties without setters.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_ignoreUnknownBeanProperties BEAN_ignoreUnknownBeanProperties}</td>
<td>Ignore unknown properties.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_ignoreUnknownNullBeanProperties BEAN_ignoreUnknownNullBeanProperties}</td>
<td>Ignore unknown properties with null values.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_implClasses BEAN_implClasses}</td>
<td>Implementation classes.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,Class&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_locale BEAN_locale}</td>
<td>Locale.</td>
<td style='max-width:250px;overflow:hidden'>{@link java.util.Locale}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_mediaType BEAN_mediaType}</td>
<td>Media type.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.http.MediaType}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_notBeanClasses BEAN_notBeanClasses}</td>
<td>Bean class exclusions.</td>
<td style='max-width:250px;overflow:hidden'><c>Set&lt;Class&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_notBeanPackages BEAN_notBeanPackages}</td>
<td>Bean package exclusions.</td>
<td style='max-width:250px;overflow:hidden'><c>Set&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_pojoSwaps BEAN_pojoSwaps}</td>
<td>POJO swaps.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;Object&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_propertyNamer BEAN_propertyNamer}</td>
<td>Bean property namer.</td>
<td style='max-width:250px;overflow:hidden'><code>Class&lt;{@link org.apache.juneau.PropertyNamer}&gt;</code></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_sortProperties BEAN_sortProperties}</td>
<td>Sort bean properties.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_timeZone BEAN_timeZone}</td>
<td>Time zone.</td>
<td style='max-width:250px;overflow:hidden'>{@link java.util.TimeZone}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_useEnumNames BEAN_useEnumNames}</td>
<td>Use enum names.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_useInterfaceProxies BEAN_useInterfaceProxies}</td>
<td>Use interface proxies.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanContext#BEAN_useJavaBeanIntrospector BEAN_useJavaBeanIntrospector}</td>
<td>Use Java Introspector.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.BeanTraverseContext}</td>
<td>{@link org.apache.juneau.BeanTraverseContext#BEANTRAVERSE_detectRecursions BEANTRAVERSE_detectRecursions}</td>
<td>Automatically detect POJO recursions.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanTraverseContext#BEANTRAVERSE_ignoreRecursions BEANTRAVERSE_ignoreRecursions}</td>
<td>Ignore recursion errors.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanTraverseContext#BEANTRAVERSE_initialDepth BEANTRAVERSE_initialDepth}</td>
<td>Initial depth.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.BeanTraverseContext#BEANTRAVERSE_maxDepth BEANTRAVERSE_maxDepth}</td>
<td>Max traversal depth.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.config.Config}</td>
<td>{@link org.apache.juneau.config.Config#CONFIG_binaryFormat CONFIG_binaryFormat}</td>
<td>Binary value format.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.BinaryFormat}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.config.Config#CONFIG_binaryLineLength CONFIG_binaryLineLength}</td>
<td>Binary value line length.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.config.Config#CONFIG_encoder CONFIG_encoder}</td>
<td>Value encoder.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.config.encode.ConfigEncoder}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.config.Config#CONFIG_multiLineValuesOnSeparateLines CONFIG_multiLineValuesOnSeparateLines}</td>
<td>Multi-line values should always be on separate lines.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.config.Config#CONFIG_name CONFIG_name}</td>
<td>Configuration name.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.config.Config#CONFIG_parser CONFIG_parser}</td>
<td>POJO parser.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.parser.ReaderParser}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.config.Config#CONFIG_readOnly CONFIG_readOnly}</td>
<td>Read-only.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.config.Config#CONFIG_serializer CONFIG_serializer}</td>
<td>POJO serializer.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.serializer.WriterSerializer}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.config.Config#CONFIG_store CONFIG_store}</td>
<td>Configuration store.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.config.store.ConfigStore}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.config.Config#CONFIG_varResolver CONFIG_varResolver}</td>
<td>SVL variable resolver.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.svl.VarResolver}</td>
</tr>
<tr>
<td>{@link org.apache.juneau.config.store.ConfigFileStore}</td>
<td>{@link org.apache.juneau.config.store.ConfigFileStore#FILESTORE_charset FILESTORE_charset}</td>
<td>Charset.</td>
<td style='max-width:250px;overflow:hidden'>{@link java.nio.charset.Charset}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.config.store.ConfigFileStore#FILESTORE_directory FILESTORE_directory}</td>
<td>Local file system directory.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.config.store.ConfigFileStore#FILESTORE_extensions FILESTORE_extensions}</td>
<td>File extensions.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c> (comma-delimited)</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.config.store.ConfigFileStore#FILESTORE_updateOnWrite FILESTORE_updateOnWrite}</td>
<td>Update-on-write.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.config.store.ConfigFileStore#FILESTORE_useWatcher FILESTORE_useWatcher}</td>
<td>Use watcher.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.config.store.ConfigFileStore#FILESTORE_watcherSensitivity FILESTORE_watcherSensitivity}</td>
<td>Watcher sensitivity.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.config.store.WatcherSensitivity}</td>
</tr>
<tr>
<td>{@link org.apache.juneau.html.HtmlDocSerializer}</td>
<td>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_aside HTMLDOC_aside}</td>
<td>Aside section contents.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_footer HTMLDOC_footer}</td>
<td>Footer section contents.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_head HTMLDOC_head}</td>
<td>Additional head section content.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_header HTMLDOC_header}</td>
<td>Header section contents.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_nav HTMLDOC_nav}</td>
<td>Nav section contents.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_navlinks HTMLDOC_navlinks}</td>
<td>Page navigation links.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_noResultsMessage HTMLDOC_noResultsMessage}</td>
<td>No-results message.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_nowrap HTMLDOC_nowrap}</td>
<td>Prevent word wrap on page.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_script HTMLDOC_script}</td>
<td>Javascript code.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_style HTMLDOC_style}</td>
<td>CSS style code.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_stylesheet HTMLDOC_stylesheet}</td>
<td>Stylesheet import URLs.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_template HTMLDOC_template}</td>
<td>HTML document template.</td>
<td style='max-width:250px;overflow:hidden'><code>Class&lt;{@link org.apache.juneau.html.HtmlDocTemplate}&gt;</code></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_widgets HTMLDOC_widgets}</td>
<td>HTML Widgets.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;{@link org.apache.juneau.html.HtmlWidget}|Class&lt;{@link org.apache.juneau.html.HtmlWidget}&gt;&gt;</c></td>
</tr>
<tr>
<td>{@link org.apache.juneau.html.HtmlSerializer}</td>
<td>{@link org.apache.juneau.html.HtmlSerializer#HTML_addBeanTypes HTML_addBeanTypes}</td>
<td>Add <js>"_type"</js> properties when needed.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlSerializer#HTML_addKeyValueTableHeaders HTML_addKeyValueTableHeaders}</td>
<td>Add key/value headers on bean/map tables.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlSerializer#HTML_detectLabelParameters HTML_detectLabelParameters}</td>
<td>Look for link labels in URIs.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlSerializer#HTML_detectLinksInStrings HTML_detectLinksInStrings}</td>
<td>Look for URLs in {@link String Strings}.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlSerializer#HTML_labelParameter HTML_labelParameter}</td>
<td>Link label parameter name.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.html.HtmlSerializer#HTML_uriAnchorText HTML_uriAnchorText}</td>
<td>Anchor text source.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.html.AnchorText}</td>
</tr>
<tr>
<td>{@link org.apache.juneau.parser.InputStreamParser}</td>
<td>{@link org.apache.juneau.parser.InputStreamParser#ISPARSER_binaryFormat ISPARSER_binaryFormat}</td>
<td>Binary input format.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.BinaryFormat}</td>
</tr>
<tr>
<td>{@link org.apache.juneau.json.JsonParser}</td>
<td>{@link org.apache.juneau.json.JsonParser#JSON_validateEnd JSON_validateEnd}</td>
<td>Validate end.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator}</td>
<td>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator#JSONSCHEMA_addDescriptionsTo JSONSCHEMA_addDescriptionsTo}</td>
<td>Add descriptions to types.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator#JSONSCHEMA_addExamplesTo JSONSCHEMA_addExamplesTo}</td>
<td>Add examples.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator#JSONSCHEMA_allowNestedDescriptions JSONSCHEMA_allowNestedDescriptions}</td>
<td>Allow nested descriptions.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator#JSONSCHEMA_allowNestedExamples JSONSCHEMA_allowNestedExamples}</td>
<td>Allow nested examples.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator#JSONSCHEMA_beanDefMapper JSONSCHEMA_beanDefMapper}</td>
<td>Bean schema definition mapper.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.jsonschema.BeanDefMapper}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator#JSONSCHEMA_defaultSchemas JSONSCHEMA_defaultSchemas}</td>
<td>Default schemas.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,{@link org.apache.juneau.ObjectMap}&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator#JSONSCHEMA_ignoreTypes JSONSCHEMA_ignoreTypes}</td>
<td>Ignore types from schema definitions.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c> (comma-delimited)</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator#JSONSCHEMA_useBeanDefs JSONSCHEMA_useBeanDefs}</td>
<td>Use bean definitions.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.json.JsonSerializer}</td>
<td>{@link org.apache.juneau.json.JsonSerializer#JSON_addBeanTypes JSON_addBeanTypes}</td>
<td>Add <js>"_type"</js> properties when needed.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.json.JsonSerializer#JSON_escapeSolidus JSON_escapeSolidus}</td>
<td>Prefix solidus <js>'/'</js> characters with escapes.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.json.JsonSerializer#JSON_simpleMode JSON_simpleMode}</td>
<td>Simple JSON mode.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.msgpack.MsgPackSerializer}</td>
<td>{@link org.apache.juneau.msgpack.MsgPackSerializer#MSGPACK_addBeanTypes MSGPACK_addBeanTypes}</td>
<td>Add <js>"_type"</js> properties when needed.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.serializer.OutputStreamSerializer}</td>
<td>{@link org.apache.juneau.serializer.OutputStreamSerializer#OSSERIALIZER_binaryFormat OSSERIALIZER_binaryFormat}</td>
<td>Binary output format.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.BinaryFormat}</td>
</tr>
<tr>
<td>{@link org.apache.juneau.parser.Parser}</td>
<td>{@link org.apache.juneau.parser.Parser#PARSER_autoCloseStreams PARSER_autoCloseStreams}</td>
<td>Auto-close streams.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.parser.Parser#PARSER_debugOutputLines PARSER_debugOutputLines}</td>
<td>Debug output lines.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.parser.Parser#PARSER_listener PARSER_listener}</td>
<td>Parser listener.</td>
<td style='max-width:250px;overflow:hidden'><c>Class&lt;{@link org.apache.juneau.parser.ParserListener}&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.parser.Parser#PARSER_strict PARSER_strict}</td>
<td>Strict mode.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.parser.Parser#PARSER_trimStrings PARSER_trimStrings}</td>
<td>Trim parsed strings.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.parser.Parser#PARSER_unbuffered PARSER_unbuffered}</td>
<td>Unbuffered.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.jena.RdfCommon}</td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_collectionFormat RDF_collectionFormat}</td>
<td>RDF format for representing collections and arrays.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_abbrevBaseUri RDF_n3_abbrevBaseUri}</td>
<td>N3/Turtle property: <c>abbrevBaseURI</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_indentProperty RDF_n3_indentProperty}</td>
<td>N3/Turtle property: <c>indentProperty</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_minGap RDF_n3_minGap}</td>
<td>N3/Turtle property: <c>minGap</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_objectLists RDF_n3_objectLists}</td>
<td>N3/Turtle property: <c>objectLists</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_propertyColumn RDF_n3_propertyColumn}</td>
<td>N3/Turtle property: <c>propertyColumn</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_subjectColumn RDF_n3_subjectColumn}</td>
<td>N3/Turtle property: <c>subjectColumn</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_useDoubles RDF_n3_useDoubles}</td>
<td>N3/Turtle property: <c>useDoubles</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_usePropertySymbols RDF_n3_usePropertySymbols}</td>
<td>N3/Turtle property: <c>usePropertySymbols</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_useTripleQuotedStrings RDF_n3_useTripleQuotedStrings}</td>
<td>N3/Turtle property: <c>useTripleQuotedStrings</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_n3_widePropertyLen RDF_n3_widePropertyLen}</td>
<td>N3/Turtle property: <c>widePropertyLen</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_err_ RDF_arp_err_}</td>
<td>RDF/XML ARP property: <c>ERR_xxx</c>.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_ign_ RDF_arp_ign_}</td>
<td></td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_warn_ RDF_arp_warn_}</td>
<td>RDF/XML ARP property: <c>WARN_xxx</c>.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_allowBadUris RDF_rdfxml_allowBadUris}</td>
<td>RDF/XML property: <c>allowBadURIs</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_attributeQuoteChar RDF_rdfxml_attributeQuoteChar}</td>
<td>RDF/XML property: <c>attributeQuoteChar</c>.</td>
<td style='max-width:250px;overflow:hidden'><c>Character</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_blockRules RDF_rdfxml_blockRules}</td>
<td>RDF/XML property: <c>blockRules</c>.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_embedding RDF_arp_embedding}</td>
<td>RDF/XML ARP property: <c>embedding</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_errorMode RDF_arp_errorMode}</td>
<td>RDF/XML ARP property: <c>error-mode</c>.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_arp_iriRules RDF_arp_iriRules}</td>
<td>RDF/XML property: <c>iri_rules</c>.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_longId RDF_rdfxml_longId}</td>
<td>RDF/XML property: <c>longId</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_relativeUris RDF_rdfxml_relativeUris}</td>
<td>RDF/XML property: <c>relativeURIs</c>.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_showDoctypeDeclaration RDF_rdfxml_showDoctypeDeclaration}</td>
<td>RDF/XML property: <c>showDoctypeDeclaration</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_showXmlDeclaration RDF_rdfxml_showXmlDeclaration}</td>
<td>RDF/XML property: <c>showXmlDeclaration</c>.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_tab RDF_rdfxml_tab}</td>
<td>RDF/XML property: <c>tab</c>.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_rdfxml_xmlBase RDF_rdfxml_xmlBase}</td>
<td>RDF/XML property: <c>xmlbase</c>.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_juneauBpNs RDF_juneauBpNs}</td>
<td>Default XML namespace for bean properties.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.xml.Namespace}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_juneauNs RDF_juneauNs}</td>
<td>XML namespace for Juneau properties.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.xml.Namespace}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_language RDF_language}</td>
<td>RDF language.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfCommon#RDF_looseCollections RDF_looseCollections}</td>
<td>Collections should be serialized and parsed as loose collections.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.jena.RdfParser}</td>
<td>{@link org.apache.juneau.jena.RdfParser#RDF_trimWhitespace RDF_trimWhitespace}</td>
<td>Trim whitespace from text elements.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.jena.RdfSerializer}</td>
<td>{@link org.apache.juneau.jena.RdfSerializer#RDF_useXmlNamespaces RDF_useXmlNamespaces}</td>
<td>Reuse XML namespaces when RDF namespaces not specified.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfSerializer#RDF_addBeanTypes RDF_addBeanTypes}</td>
<td>Add <js>"_type"</js> properties when needed.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfSerializer#RDF_addLiteralTypes RDF_addLiteralTypes}</td>
<td>Add XSI data types to non-<c>String</c> literals.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfSerializer#RDF_addRootProperty RDF_addRootProperty}</td>
<td>Add RDF root identifier property to root node.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfSerializer#RDF_autoDetectNamespaces RDF_autoDetectNamespaces}</td>
<td>Auto-detect namespace usage.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.jena.RdfSerializer#RDF_namespaces RDF_namespaces}</td>
<td>Default namespaces.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;{@link org.apache.juneau.xml.Namespace}&gt;</c></td>
</tr>
<tr>
<td>{@link org.apache.juneau.parser.ReaderParser}</td>
<td>{@link org.apache.juneau.parser.ReaderParser#RPARSER_fileCharset RPARSER_fileCharset}</td>
<td>File charset.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.parser.ReaderParser#RPARSER_streamCharset RPARSER_streamCharset}</td>
<td>Input stream charset.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.client.RestClient}</td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_debug RESTCLIENT_debug}</td>
<td>Debug.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_executorService RESTCLIENT_executorService}</td>
<td>Executor service.</td>
<td style='max-width:250px;overflow:hidden'><ul><li><c>Class&lt;{@link java.util.concurrent.ExecutorService}&gt;</c><li>{@link java.util.concurrent.ExecutorService}</ul></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_executorServiceShutdownOnClose RESTCLIENT_executorServiceShutdownOnClose}</td>
<td>Shut down executor service on close.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_interceptors RESTCLIENT_interceptors}</td>
<td>Call interceptors.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;Class&lt;{@link org.apache.juneau.rest.client.RestCallInterceptor}&gt;|{@link org.apache.juneau.rest.client.RestCallInterceptor}&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_keepHttpClientOpen RESTCLIENT_keepHttpClientOpen}</td>
<td>Keep HttpClient open.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_parser RESTCLIENT_parser}</td>
<td>Parser.</td>
<td style='max-width:250px;overflow:hidden'><ul><li><c>Class&lt;{@link org.apache.juneau.parser.Parser}&gt;</c><li>{@link org.apache.juneau.parser.Parser}</ul></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_partParser RESTCLIENT_partParser}</td>
<td>Part parser.</td>
<td style='max-width:250px;overflow:hidden'><ul><li><c>Class&lt;{@link org.apache.juneau.httppart.HttpPartParser}&gt;</c><li>{@link org.apache.juneau.httppart.HttpPartParser}</ul></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_partSerializer RESTCLIENT_partSerializer}</td>
<td>Part serializer.</td>
<td style='max-width:250px;overflow:hidden'><ul><li><c>Class&lt;{@link org.apache.juneau.httppart.HttpPartSerializer}&gt;</c><li>{@link org.apache.juneau.httppart.HttpPartSerializer}</ul></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_query RESTCLIENT_query}</td>
<td>Request query parameters.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_headers RESTCLIENT_headers}</td>
<td>Request headers.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_retries RESTCLIENT_retries}</td>
<td>Number of retries to attempt.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_retryInterval RESTCLIENT_retryInterval}</td>
<td>The time in milliseconds between retry attempts.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_retryOn RESTCLIENT_retryOn}</td>
<td>Retry-on determination object.</td>
<td style='max-width:250px;overflow:hidden'><ul><li><c>Class&lt;{@link org.apache.juneau.rest.client.RetryOn}&gt;</c><li>{@link org.apache.juneau.rest.client.RetryOn}</ul></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_rootUri RESTCLIENT_rootUri}</td>
<td>Root URI.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_serializer RESTCLIENT_serializer}</td>
<td>Serializer.</td>
<td style='max-width:250px;overflow:hidden'><ul><li><c>Class&lt;{@link org.apache.juneau.serializer.Serializer}&gt;</c><li>{@link org.apache.juneau.serializer.Serializer}</ul></td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.RestContext}</td>
<td>{@link org.apache.juneau.rest.RestContext#REST_allowBodyParam REST_allowBodyParam}</td>
<td>Allow body URL parameter.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_allowedHeaderParams REST_allowedHeaderParams}</td>
<td>Allowed header URL parameters.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c> (comma-delimited)</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_allowedMethodHeaders REST_allowedMethodHeaders}</td>
<td>Allowed method headers.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c> (comma-delimited)</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_allowedMethodParams REST_allowedMethodParams}</td>
<td>Allowed method URL parameters.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c> (comma-delimited)</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_callHandler REST_callHandler}</td>
<td>REST call handler.</td>
<td style='max-width:250px;overflow:hidden'><ul><li>{@link org.apache.juneau.rest.RestCallHandler}<li><c>Class&lt;{@link org.apache.juneau.rest.RestCallHandler}&gt;</c></ul></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_callLogger REST_callLogger}</td>
<td>REST call logger.</td>
<td style='max-width:250px;overflow:hidden'><ul><li>{@link org.apache.juneau.rest.RestCallLogger}<li><c>Class&lt;{@link org.apache.juneau.rest.RestCallLogger}&gt;</c></ul></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_callLoggerConfig REST_callLoggerConfig}</td>
<td>REST call logging rules.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.rest.RestCallLoggerConfig}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_children REST_children}</td>
<td>Children.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;Class|Object|{@link org.apache.juneau.rest.RestChild}&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_classpathResourceFinder REST_classpathResourceFinder}</td>
<td>Classpath resource finder.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.utils.ClasspathResourceFinder}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_clientVersionHeader REST_clientVersionHeader}</td>
<td>Client version header.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_consumes REST_consumes}</td>
<td>Supported content media types.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_converters REST_converters}</td>
<td>Class-level response converters.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;{@link org.apache.juneau.rest.RestConverter}|Class&lt;{@link org.apache.juneau.rest.RestConverter}&gt;&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_debug REST_debug}</td>
<td>Debug mode.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.rest.Enablement}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_defaultCharset REST_defaultCharset}</td>
<td>Default character encoding.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_encoders REST_encoders}</td>
<td>Compression encoders.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;{@link org.apache.juneau.encoders.Encoder}|Class&lt;{@link org.apache.juneau.encoders.Encoder}&gt;&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_guards REST_guards}</td>
<td>Class-level guards.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;{@link org.apache.juneau.rest.RestGuard}|Class&lt;{@link org.apache.juneau.rest.RestGuard}&gt;&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_infoProvider REST_infoProvider}</td>
<td>REST info provider.</td>
<td style='max-width:250px;overflow:hidden'><ul><li>{@link org.apache.juneau.rest.RestInfoProvider}<li><c>Class&lt;{@link org.apache.juneau.rest.RestInfoProvider}&gt;</c></ul></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_maxInput REST_maxInput}</td>
<td>The maximum allowed input size (in bytes) on HTTP requests.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_messages REST_messages}</td>
<td>Messages.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;{@link org.apache.juneau.rest.MessageBundleLocation}&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_mimeTypes REST_mimeTypes}</td>
<td>MIME types.</td>
<td style='max-width:250px;overflow:hidden'><c>Set&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_paramResolvers REST_paramResolvers}</td>
<td>Java method parameter resolvers.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;{@link org.apache.juneau.rest.RestMethodParam}|Class&lt;{@link org.apache.juneau.rest.RestMethodParam}&gt;&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_parsers REST_parsers}</td>
<td>Parsers.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;{@link org.apache.juneau.parser.Parser}|Class&lt;{@link org.apache.juneau.parser.Parser}&gt;&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_partParser REST_partParser}</td>
<td>HTTP part parser.</td>
<td style='max-width:250px;overflow:hidden'><c>{@link org.apache.juneau.httppart.HttpPartParser}|Class&lt;{@link org.apache.juneau.httppart.HttpPartParser}&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_partSerializer REST_partSerializer}</td>
<td>HTTP part serializer.</td>
<td style='max-width:250px;overflow:hidden'><ul><li>{@link org.apache.juneau.httppart.HttpPartSerializer}<li><c>Class&lt;{@link org.apache.juneau.httppart.HttpPartSerializer}&gt;</c></ul></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_path REST_path}</td>
<td>Resource path.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_produces REST_produces}</td>
<td>Supported accept media types.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_properties REST_properties}</td>
<td>Properties.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_renderResponseStackTraces REST_renderResponseStackTraces}</td>
<td>Render response stack traces in responses.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_reqAttrs REST_reqAttrs}</td>
<td>Default request attributes.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,Object&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_reqHeaders REST_reqHeaders}</td>
<td>Default request headers.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_resHeaders REST_resHeaders}</td>
<td>Default response headers.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_resourceResolver REST_resourceResolver}</td>
<td>REST resource resolver.</td>
<td style='max-width:250px;overflow:hidden'><ul><li>{@link org.apache.juneau.rest.RestResourceResolver}<li><c>Class&lt;{@link org.apache.juneau.rest.RestResourceResolver}&gt;</c></ul></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_responseHandlers REST_responseHandlers}</td>
<td>Response handlers.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;{@link org.apache.juneau.rest.ResponseHandler}|Class&lt;{@link org.apache.juneau.rest.ResponseHandler}&gt;&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_roleGuard REST_roleGuard}</td>
<td>Role guard.</td>
<td style='max-width:250px;overflow:hidden'><c>Set&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_rolesDeclared REST_rolesDeclared}</td>
<td>Declared roles.</td>
<td style='max-width:250px;overflow:hidden'><c>Set&lt;String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_serializers REST_serializers}</td>
<td>Serializers.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;{@link org.apache.juneau.serializer.Serializer}|Class&lt;{@link org.apache.juneau.serializer.Serializer}&gt;&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_staticFileResponseHeaders REST_staticFileResponseHeaders}</td>
<td>Static file response headers.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,String&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_staticFiles REST_staticFiles}</td>
<td>Static file mappings.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;{@link org.apache.juneau.rest.StaticFileMapping}&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_uriAuthority REST_uriAuthority}</td>
<td>Resource URI authority path.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_uriContext REST_uriContext}</td>
<td>Resource URI context path.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_uriRelativity REST_uriRelativity}</td>
<td>URI resolution relativity.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_uriResolution REST_uriResolution}</td>
<td>URI resolution.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestContext#REST_useClasspathResourceCaching REST_useClasspathResourceCaching}</td>
<td>Use classpath resource caching.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.rest.RestMethodContext}</td>
<td>{@link org.apache.juneau.rest.RestMethodContext#RESTMETHOD_callLoggerConfig RESTMETHOD_callLoggerConfig}</td>
<td>Logging rules.</td>
<td style='max-width:250px;overflow:hidden'><c>{@link org.apache.juneau.rest.RestCallLoggerConfig}</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestMethodContext#RESTMETHOD_clientVersion RESTMETHOD_clientVersion}</td>
<td>Client version pattern matcher.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestMethodContext#RESTMETHOD_debug RESTMETHOD_debug}</td>
<td>Debug mode.</td>
<td style='max-width:250px;overflow:hidden'>{@link Enablement}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestMethodContext#RESTMETHOD_defaultFormData RESTMETHOD_defaultFormData}</td>
<td>Default form data.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,Object&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestMethodContext#RESTMETHOD_defaultQuery RESTMETHOD_defaultQuery}</td>
<td>Default query parameters.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,Object&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestMethodContext#RESTMETHOD_httpMethod RESTMETHOD_httpMethod}</td>
<td>HTTP method name.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestMethodContext#RESTMETHOD_matchers RESTMETHOD_matchers}</td>
<td>Method-level matchers.</td>
<td style='max-width:250px;overflow:hidden'><c>List&lt;{@link org.apache.juneau.rest.RestMatcher}|Class&lt;{@link org.apache.juneau.rest.RestMatcher}&gt;&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestMethodContext#RESTMETHOD_path RESTMETHOD_path}</td>
<td>Resource method path.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestMethodContext#RESTMETHOD_priority RESTMETHOD_priority}</td>
<td>Priority.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestMethodContext#RESTMETHOD_reqAttrs RESTMETHOD_reqAttrs}</td>
<td>Default request attributes.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,Object&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.rest.RestMethodContext#RESTMETHOD_reqHeaders RESTMETHOD_reqHeaders}</td>
<td>Default request headers.</td>
<td style='max-width:250px;overflow:hidden'><c>Map&lt;String,Object&gt;</c></td>
</tr>
<tr>
<td>{@link org.apache.juneau.serializer.Serializer}</td>
<td>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_addBeanTypes SERIALIZER_addBeanTypes}</td>
<td>Add <js>"_type"</js> properties when needed.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_addRootType SERIALIZER_addRootType}</td>
<td>Add type attribute to root nodes.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_listener SERIALIZER_listener}</td>
<td>Serializer listener.</td>
<td style='max-width:250px;overflow:hidden'><c>Class&lt;{@link org.apache.juneau.serializer.SerializerListener}&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_sortCollections SERIALIZER_sortCollections}</td>
<td>Sort arrays and collections alphabetically.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_sortMaps SERIALIZER_sortMaps}</td>
<td>Sort maps alphabetically.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_trimEmptyCollections SERIALIZER_trimEmptyCollections}</td>
<td>Trim empty lists and arrays.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_trimEmptyMaps SERIALIZER_trimEmptyMaps}</td>
<td>Trim empty maps.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_trimNullProperties SERIALIZER_trimNullProperties}</td>
<td>Trim null bean property values.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_trimStrings SERIALIZER_trimStrings}</td>
<td>Trim strings.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriContext SERIALIZER_uriContext}</td>
<td>URI context bean.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.UriContext}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriRelativity SERIALIZER_uriRelativity}</td>
<td>URI relativity.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.UriRelativity}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriResolution SERIALIZER_uriResolution}</td>
<td>URI resolution.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.UriResolution}</td>
</tr>
<tr>
<td>{@link org.apache.juneau.soap.SoapXmlSerializer}</td>
<td>{@link org.apache.juneau.soap.SoapXmlSerializer#SOAPXML_SOAPAction SOAPXML_SOAPAction}</td>
<td>The <c>SOAPAction</c> HTTP header value to set on responses.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td>{@link org.apache.juneau.dto.swagger.ui.SwaggerUI}</td>
<td>{@link org.apache.juneau.dto.swagger.ui.SwaggerUI#SWAGGERUI_resolveRefsMaxDepth SWAGGERUI_resolveRefsMaxDepth}</td>
<td>Resolve <c>$ref</c> references in schema up to the specified depth.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.uon.UonParser}</td>
<td>{@link org.apache.juneau.uon.UonParser#UON_decoding UON_decoding}</td>
<td>Decode <js>"%xx"</js> sequences.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.uon.UonParser#UON_validateEnd UON_validateEnd}</td>
<td>Validate end.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.uon.UonSerializer}</td>
<td>{@link org.apache.juneau.uon.UonSerializer#UON_addBeanTypes UON_addBeanTypes}</td>
<td>Add <js>"_type"</js> properties when needed.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.uon.UonSerializer#UON_encoding UON_encoding}</td>
<td>Encode non-valid URI characters.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.uon.UonSerializer#UON_paramFormat UON_paramFormat}</td>
<td>Format to use for query/form-data/header values.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.uon.ParamFormat}</td>
</tr>
<tr>
<td>{@link org.apache.juneau.urlencoding.UrlEncodingParser}</td>
<td>{@link org.apache.juneau.urlencoding.UrlEncodingParser#URLENC_expandedParams URLENC_expandedParams}</td>
<td>Parser bean property collections/arrays as separate key/value pairs.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.urlencoding.UrlEncodingSerializer}</td>
<td>{@link org.apache.juneau.urlencoding.UrlEncodingSerializer#URLENC_expandedParams URLENC_expandedParams}</td>
<td>Serialize bean property collections/arrays as separate key/value pairs.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.serializer.WriterSerializer}</td>
<td>{@link org.apache.juneau.serializer.WriterSerializer#WSERIALIZER_fileCharset WSERIALIZER_fileCharset}</td>
<td>File charset.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.WriterSerializer#WSERIALIZER_maxIndent WSERIALIZER_maxIndent}</td>
<td>Maximum indentation.</td>
<td style='max-width:250px;overflow:hidden'><jk>int</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.WriterSerializer#WSERIALIZER_quoteChar WSERIALIZER_quoteChar}</td>
<td>Quote character.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.WriterSerializer#WSERIALIZER_streamCharset WSERIALIZER_streamCharset}</td>
<td>Output stream charset.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.serializer.WriterSerializer#WSERIALIZER_useWhitespace WSERIALIZER_useWhitespace}</td>
<td>Use whitespace.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.xml.XmlParser}</td>
<td>{@link org.apache.juneau.xml.XmlParser#XML_eventAllocator XML_eventAllocator}</td>
<td>XML event allocator.</td>
<td style='max-width:250px;overflow:hidden'><code>Class&lt;{@link javax.xml.stream.util.XMLEventAllocator}&gt;</code></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.xml.XmlParser#XML_preserveRootElement XML_preserveRootElement}</td>
<td>Preserve root element during generalized parsing.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.xml.XmlParser#XML_reporter XML_reporter}</td>
<td>XML reporter.</td>
<td style='max-width:250px;overflow:hidden'><code>Class&lt;{@link javax.xml.stream.XMLReporter}&gt;</code></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.xml.XmlParser#XML_resolver XML_resolver}</td>
<td>XML resolver.</td>
<td style='max-width:250px;overflow:hidden'><code>Class&lt;{@link javax.xml.stream.XMLResolver}&gt;</code></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.xml.XmlParser#XML_validating XML_validating}</td>
<td>Enable validation.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td>{@link org.apache.juneau.xml.XmlSerializer}</td>
<td>{@link org.apache.juneau.xml.XmlSerializer#XML_addBeanTypes XML_addBeanTypes}</td>
<td>Add <js>"_type"</js> properties when needed.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.xml.XmlSerializer#XML_addNamespaceUrisToRoot XML_addNamespaceUrisToRoot}</td>
<td>Add namespace URLs to the root element.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.xml.XmlSerializer#XML_autoDetectNamespaces XML_autoDetectNamespaces}</td>
<td>Auto-detect namespace usage.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.xml.XmlSerializer#XML_defaultNamespace XML_defaultNamespace}</td>
<td>Default namespace.</td>
<td style='max-width:250px;overflow:hidden'>{@link org.apache.juneau.xml.Namespace}</td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.xml.XmlSerializer#XML_enableNamespaces XML_enableNamespaces}</td>
<td>Enable support for XML namespaces.</td>
<td style='max-width:250px;overflow:hidden'><jk>boolean</jk></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.xml.XmlSerializer#XML_namespaces XML_namespaces}</td>
<td>Default namespaces.</td>
<td style='max-width:250px;overflow:hidden'><c>Set&lt;{@link org.apache.juneau.xml.Namespace}&gt;</c></td>
</tr>
<tr>
<td></td>
<td>{@link org.apache.juneau.xml.XmlSerializer#XML_xsNamespace XML_xsNamespace}</td>
<td>XMLSchema namespace.</td>
<td style='max-width:250px;overflow:hidden'><c>String</c> ({@link org.apache.juneau.xml.Namespace})</td>
</tr>
</table>
</div><!-- END: 19.1 - Glossaries.ConfigurablePropertiesGlossary -->
</div><!-- END: 19 - Glossaries -->
<!-- ==================================================================================================== -->
<h2 class='topic ' onclick='toggle(this)'><a href='#Security' id='Security'>20 - Security Best-Practices</a></h2>
<div class='topic'><!-- START: 20 - Security -->
<p>
Security is always an ongoing concern in any library.
If you discover any security vulnerabilities in this code, please refer to the instructions found here:
</p>
<ul class='spaced-list'>
<li class='extlink'>{@doc http://www.apache.org/security SECURITY}
</ul>
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#Security.juneau-marshall' id='Security.juneau-marshall'>20.1 - juneau-marshall</a></h3>
<div class='topic'><!-- START: 20.1 - Security.juneau-marshall -->
<h5 class='topic'>Demarshalling vulnerabilities</h5>
<p>
One common security vulnerability is the ability to create arbitrary Java object instances through crafted
user input. For example, support for constructing POJOs based on an input attribute defining a
fully-qualified class name like <js>"{class:'com.foo.MyBean',...}"</js>
</p>
<p>
Fortunately, Juneau does not support an open-ended <js>"class</js> attribute.
As a rule, it should not be possible to create arbitrary POJOs by any of the parsers.
The demarshalled object types are inferred via reflection of the class objects passed in through the parser
method (e.g. <c>JsonParser.<jsf>DEFAULT</jsf>.parse(input, MyBean.<jk>class</jk>)</c>).
As long as the <c>Class</c> object passed into this method is not constructed from user-generated input,
it should be free from demarshalling vulnerabilities.
</p>
<p>
The following example shows a potential vector that circumvents the restriction above:
</p>
<p class='bpcode w800'>
<jc>// Don't do this!</jc>
Class c = Class.<jsf>forName</jsf>(someUserInputString);
JsonParser.<jsf>DEFAULT</jsf>.parse(input, c); <jc>// Oops! Security hole!</jc>
</p>
<p>
Juneau does support something similar to a <js>"class"</js> attribute that allows you to define the
POJO type at runtime.
This is the <js>"type"</js> attribute.
The difference is that it's not possible to specify fully-qualified class names in <js>"type"</js> attributes,
and instead can only specify type keys defined through bean dictionaries.
Instead of serializing the fully-qualified class names in the output, we instead serialize type
names that represent those POJO types.
i.e. instead of <js>"class='com.foo.MyBean'"</js>, we instead serialize <js>"type='MyBeanIdentifier'"</js>.
Since bean types are defined at compile time, it's impossible to instantiate arbitrary POJOs.
</p>
<p>
POJO types of generalized input are also inferred through swaps.
Again, since the POJO types are hardcoded at compile time, these should not be subject to demarshalling
vulnerabilities. However, it is possible to circumvent this through your swap implementation as shown
below:
</p>
<p class='bpcode w800'>
<jc>// Don't do this!</jc>
<jk>public class</jk> MyInsecureSwap <jk>extends</jk> PojoSwap&lt;ObjectMap,Object&gt; {
<jk>public</jk> Object swap(BeanSession session, ObjectMap input) <jk>throws</jk> Exception {
<jc>// Security hole!</jc>
<jk>return</jk> Class.<jsf>forName</jsf>(input.getString(<js>"class"</js>)).newInstance();
}
}
</p>
<p>
Note that the {@link org.apache.juneau.jso.JsoParser}, a thin layer of the Juneau Parser API written on
top of plain-old Java Object Serialization which itself is vulnerable to demarshalling issues.
Due to this, the JSO parser is not included in any of the default REST servlet implementations.
Be especially careful when using this parser, particularly if you want to use it for handing
<c>application/x-java-serialized-object</c> input through REST servlets.
</p>
<p>
All other parsers (JSON, URL-Encoding, MessagePack, etc...) work the same way in determining POJO types, so
should be safe from demarshalling vulnerabilities.
</p>
<h5 class='topic'>Dependent libraries</h5>
<p>
When accessing security vulnerabilities of any library, dependent libraries must also be taken into account:
</p>
<ul>
<li>The JSON, HTML, MsgPack, URL-Encoding, and UON parsers are written from scratch and do not rely on
any other parsing technologies.
<li>The XML and HTML parsers uses the built-in Java StAX parser.
This *should* be free from vulnerabilities.
<li>The RDF parsers rely on Apache Jena 2.7.1.
As of <c>7.0.1</c>, no known security vulnerabilities exist that affect Juneau at this time.
</ul>
</div><!-- END: 20.1 - Security.juneau-marshall -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#Security.juneau-svl' id='Security.juneau-svl'>20.2 - juneau-svl</a></h3>
<div class='topic'><!-- START: 20.2 - Security.juneau-svl -->
<p>
Care must be used when defining new {@link org.apache.juneau.svl.Var Vars} using the SVL API since mistakes
could potentially expose system properties, environment variables, or even file system files.
</p>
<p>
For recap, the SVL support allows you to embed variables of the form <js>"$X{key}"</js> inside strings that
get resolved to other strings. The resolved strings themselves can also contain variables that also
get recursively resolved.
</p>
<p>
An example of a potential security hole is shown below that could potentially expose any file on a file
system through a REST request:
</p>
<p class='bpcode w800'>
<jk>public</jk> String doUnsafeGet(RestRequest req) {
<jc>// Security hole!</jc>
<jk>return</jk> req.getVarResolver().resolve(<js>"$RQ{foo}"</js>);
}
</p>
<p>
This code is simply echoing the value of the <c>foo</c> query parameter.
Now say for example that a bad actor passes in the query string <js>"foo=$F{/some/file/on/file/system}"</js>.
The <c>$F</c> variable allows you to resolve the contents of files using SVL, and is provided
by default using the built-in variable resolver returned by the <c>RestRequest</c> object.
You've potentially just exposed the contents of that file through your REST interface.
</p>
<p>
In reality, the above security hole does not exist because of the following restrictions:
</p>
<ul class='spaced-list'>
<li>
<c>Vars</c> have two methods {@link org.apache.juneau.svl.Var#allowNested()} and
{@link org.apache.juneau.svl.Var#allowRecurse()} that can be overridden to prevent recursive processing
of string variables. These are both <jk>false</jk> for the <c>$R</c> variable, so the <c>$F</c>
variable in the result will never get processed and instead be treated as plain text.
<li>
The <c>$F</c> variable only allows you to retrieve files within the JVM starting directory.
</ul>
<p>
Even though the built-in Juneau variables are safe, special care is needed when defining your own custom
variables. If your variable resolves user input in any way, it's HIGHLY recommended that you override the
{@link org.apache.juneau.svl.Var#allowNested()} and {@link org.apache.juneau.svl.Var#allowRecurse()}
methods to prevent recursive handling of variables.
</p>
</div><!-- END: 20.2 - Security.juneau-svl -->
<!-- ==================================================================================================== -->
<h3 class='topic ' onclick='toggle(this)'><a href='#Security.juneau-rest-server' id='Security.juneau-rest-server'>20.3 - juneau-rest-server</a></h3>
<div class='topic'><!-- START: 20.3 - Security.juneau-rest-server -->
<p>
Denial of service attacks can be alleviated through the {@link org.apache.juneau.rest.annotation.Rest#maxInput() maxInput()}
setting. Arbitrarily-large input will trigger an exception before causing out-of-memory errors.
The default value for this setting is 100MB.
</p>
<p>
Since the parsers do not use intermediate DOMs and instead parse directly into Java objects,
deeply nested data structures will almost always trigger stack overflow errors long before memory consumption
becomes an issue. However, this is NOT true of the RDF parsers that use an intermediate DOM. If parsing
RDF, you may want to consider lowering the max-input value above.
</p>
</div><!-- END: 20.3 - Security.juneau-rest-server -->
</div><!-- END: 20 - Security -->
<h2 class='topic' onclick='toggle(this)'><a href='#ReleaseNotes' id='ReleaseNotes'>Release Notes</a></h2>
<div class='topic'>
<h5 class='toc'>Release Notes</h5>
<ul class='toc'>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.0'>5.0.0.0 (Jun 11, 2012)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.1'>5.0.0.1 (Jun 14, 2012)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.2'>5.0.0.2 (Sept 28, 2012)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.3'>5.0.0.3 (Oct 3, 2012)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.4'>5.0.0.4 (Oct 7, 2012)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.5'>5.0.0.5 (Oct 29, 2012)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.6'>5.0.0.6 (Oct 30, 2012)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.7'>5.0.0.7 (Jan 20, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.8'>5.0.0.8 (Jan 30, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.9'>5.0.0.9 (Feb 26, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.10'>5.0.0.10 (Mar 7, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.11'>5.0.0.11 (Mar 8, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.12'>5.0.0.12 (Mar 10, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.13'>5.0.0.13 (Mar 14, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.14'>5.0.0.14 (Mar 23, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.15'>5.0.0.15 (Mar 24, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.16'>5.0.0.16 (Mar 25, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.17'>5.0.0.17 (Mar 25, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.18'>5.0.0.18 (Mar 27, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.19'>5.0.0.19 (Apr 1, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.20'>5.0.0.20 (Apr 7, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.21'>5.0.0.21 (Apr 9, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.22'>5.0.0.22 (Apr 12, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.23'>5.0.0.23 (Apr 14, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.24'>5.0.0.24 (May 9, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.25'>5.0.0.25 (May 11, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.26'>5.0.0.26 (Jun 5, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.27'>5.0.0.27 (July 7, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.28'>5.0.0.28 (July 9, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.29'>5.0.0.29 (Aug 2, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.30'>5.0.0.30 (Aug 8, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.31'>5.0.0.31 (Aug 9, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.32'>5.0.0.32 (Oct 5, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.33'>5.0.0.33 (Oct 20, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.34'>5.0.0.34 (Nov 10, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.35'>5.0.0.35 (Nov 26, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.0.0.36'>5.0.0.36 (Dec 18, 2013)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.0'>5.1.0.0 (Jan 18, 2014)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.1'>5.1.0.1 (Jan 25, 2014)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.2'>5.1.0.2 (Apr 27, 2014)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.3'>5.1.0.3 (Jun 28, 2014)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.4'>5.1.0.4 (Aug 25, 2014)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.5'>5.1.0.5 (Sept 1, 2014)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.6'>5.1.0.6 (Sept 21, 2014)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.7'>5.1.0.7 (Oct 5, 2014)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.8'>5.1.0.8 (Oct 25, 2014)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.9'>5.1.0.9 (Dec 1, 2014)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.10'>5.1.0.10 (Dec 23, 2014)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.11'>5.1.0.11 (Feb 14, 2015)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.12'>5.1.0.12 (Mar 28, 2015)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.13'>5.1.0.13 (Apr 24, 2015)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.14'>5.1.0.14 (May 10, 2015)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.15'>5.1.0.15 (May 24, 2015)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.16'>5.1.0.16 (June 28, 2015)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.17'>5.1.0.17 (Aug 3, 2015)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.18'>5.1.0.18 (Aug 5, 2015)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.19'>5.1.0.19 (Aug 15, 2015)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.1.0.20'>5.1.0.20 (Sept 5, 2015)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.2.0.0'>5.2.0.0 (Dec 30, 2015)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#5.2.0.1'>5.2.0.1 (Mar 23, 2016)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#6.0.0'>6.0.0 (Oct 3, 2016)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#6.0.1'>6.0.1 (Jan 3, 2017)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#6.1.0'>6.1.0 (Feb 25, 2017)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#6.2.0'>6.2.0 (Apr 28, 2017)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#6.3.0'>6.3.0 (Jun 30, 2017)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#6.3.1'>6.3.1 (Aug 1, 2017)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#6.4.0'>6.4.0 (Oct 5, 2017)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#7.0.0'>7.0.0 (Oct 25, 2017)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#7.0.1'>7.0.1 (Dec 24, 2017)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#7.1.0'>7.1.0 (Mar 08, 2018)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#7.2.0'>7.2.1 (Sept 25, 2018)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#7.2.1'>7.2.1 (Oct 23, 2018)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#7.2.2'>7.2.2 (Nov 7, 2018)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#8.0.0'>8.0.0 (Jan 01, 2019)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#8.1.0'>8.1.0 (Aug 21, 2019)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#8.1.1'>8.1.1 (Sept 20, 2019)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#8.1.2'>8.1.2 (TBD)</a></p>
<li><p><a class='doclink' href='{OVERVIEW_URL}#8.1.3'>8.1.3 (TBD)</a></p>
</ul>
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.0' id='5.0.0.0'>5.0.0.0 (Jun 11, 2012)</a></h3>
<div class='topic'><!-- START: 5.0.0.0 -->
<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 <dc>Transform</dc> class, which is associated with the <c>BeanContext</c> class (and thus the Serializer and Parser classes too) through the <c>BeanContext.addTransforms(Class[])</c> method.<br>
Two new subclasses of <dc>Transform</dc>:
<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 <c>Cast</c> and <c>BeanFilter</c> APIs which were considerably more complicated and puts them under a common API.
</li>
<li>
Elimination of <c>_class</c> 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 <c>BeanMap</c> API.<br>
The number of reflection calls have been significantly reduced in the <c>BeanMap</c> 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 <c>RestServlets</c>.<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 (<c>Accept-Encoding: gzip</c>) and charsets (e.g <c>Accept-Charset: SJIS</c>) 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 <c>OPTIONS</c> pages for resources.
</li>
</ul>
</li>
<li>
Automatic support for SOAP XML output on <js>"text/soap+xml"</js> requests against <c>RestServlet</c>.
</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 <c>Enum</c>.
</li>
<li>
Significant improved support for various flavors of parameterized types, such as subclasses of parameterized types (e.g. <c>MyBeanList <jk>extends</jk> LinkedList&lt;MyBean&gt;</c>).
</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><!-- END: 5.0.0.0 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.1' id='5.0.0.1'>5.0.0.1 (Jun 14, 2012)</a></h3>
<div class='topic'><!-- START: 5.0.0.1 -->
<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><!-- END: 5.0.0.1 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.2' id='5.0.0.2'>5.0.0.2 (Sept 28, 2012)</a></h3>
<div class='topic'><!-- START: 5.0.0.2 -->
<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 <c>org.apache.juneau.json</c>).
</li>
<li>
Automatic support for parsing maps with <c>Enum</c> keys, and parsing <c>Enum</c> strings.<br>
This was previously possible using filters, but now it's built-in for all the parsers.
</li>
<li>
Replaced the <c>ObjectList.toXArray()</c> methods with a new <c>elements(Class&lt;T&gt; type)</c> method that's more efficient and avoids creating an unnecessary array.
</li>
<li>
Support for parsing into beans with read-only properties.<br>
New <dc>@BeanConstructor</dc> 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><!-- END: 5.0.0.2 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.3' id='5.0.0.3'>5.0.0.3 (Oct 3, 2012)</a></h3>
<div class='topic'><!-- START: 5.0.0.3 -->
<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 <dc>@BeanConstructor</dc> 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><!-- END: 5.0.0.3 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.4' id='5.0.0.4'>5.0.0.4 (Oct 7, 2012)</a></h3>
<div class='topic'><!-- START: 5.0.0.4 -->
<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} annotation 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 <dc>BeanContext.convertToType(Object,Class)</dc> to be able to convert <c>Strings</c> to classes with
<c>fromString(String)</c>/<c>valueOf(String)</c> static methods or <c>T(String)</c> constructors.
</li>
</ul>
</div><!-- END: 5.0.0.4 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.5' id='5.0.0.5'>5.0.0.5 (Oct 29, 2012)</a></h3>
<div class='topic'><!-- START: 5.0.0.5 -->
<p>
Juno 5.0.0.5 is a major update.
</p>
<ul class='spaced-list'>
<li>New <c><ja>@RestChild</ja></c> annotation for identifying child resources.</li>
<li>
New <c>traversable</c> and <c>filterable</c> attributes added to {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod} annotation.<br>
Eliminates the need for <dc>PojoResource</dc> and <dc>FilteredRestResource</dc> 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 <c>resourceUri</c> 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 <c>RdfXmlSerializer</c>.</li>
</ul>
</li>
</ul>
</div><!-- END: 5.0.0.5 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.6' id='5.0.0.6'>5.0.0.6 (Oct 30, 2012)</a></h3>
<div class='topic'><!-- START: 5.0.0.6 -->
<p>
Juno 5.0.0.6 is a minor update that fixes a small bug in 5.0.0.5.
</p>
</div><!-- END: 5.0.0.6 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.7' id='5.0.0.7'>5.0.0.7 (Jan 20, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.7 -->
<p>
Juno 5.0.0.7 is a major update.
</p>
<h5 class='topic w800'>Core API updates</h5>
<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 <c>@Xml.namespaces</c> annotation.<br>
Namespaces can be defined at package, class, method, or field levels.
</li>
<li>
New <c>@Xml.nsUri</c> annotation.<br>
Shortcut for specifying namespace URIs.
</li>
<li>
New <c>@Xml.valAttr</c> 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><dc>SerializerContext</dc></li>
<li><dc>ParserContext</dc></li>
</ul>
</li>
<li>
Enhancements to {@link org.apache.juneau.BeanContext}:
<ul>
<li>
Ability to mark bean properties as hidden using <dc>@BeanProperty(hidden)</dc> so that they don't get serialized.
</li>
<li>
Simplified <c>ClassType</c> {@link org.apache.juneau.ClassMeta} API.<br>
Combined 4 classes into a single class.
</li>
<li>
New <dc>@Bean.filter</dc> and <dc>@BeanProperty.filter</dc> annotations.<br>
Used for defining filters on bean classes and bean properties instead of just globally through <c>BeanContext.addTransforms(Class[])</c>.
</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 <dc>@BeanProperty.beanUri</dc> and <dc>@BeanProperty.id</dc> 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 <c>rdf:resource</c> attributes.
</li>
<li>
New <dc>BeanProperty.properties()</dc> 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>
<h5 class='topic w800'>REST client updates</h5>
<ul class='spaced-list'>
<li>GZIP compression support.</li>
<li>Bug fixes.</li>
</ul>
<h5 class='topic w800'>REST server updates</h5>
<ul class='spaced-list'>
<li>
Support for overriding bean context and serializer properties in a REST method call through new <dc>RestResponse.setProperty(String,Object)</dc> 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><dc>@RestResource(filters)</cc> - Associate post-formatting filters on a resource level.</li>
<li><dc>@RestResource.guards</dc> - Associate resource-level guards.</li>
<li><dc>@RestResource.messages</dc> - Associate a resource bundle with a REST servlet. Comes with several convenience methods for looking up messages for the client locale.</li>
<li><dc>@RestResource.properties</dc> - Override default bean context, serializer, and parser properties though an annotation.</li>
</ul>
</li>
<li>
Several new annotations on REST methods:
<ul>
<li><c>@RestMethod(filters)</c> - 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><dc>@Attr</dc> - A parameter or URL variable value as a parsed POJO.</li>
<li><dc>@Param</dc> - A query parameter value as a parsed POJO.</li>
<li><dc>@PathRemainder</dc>- The remainder after a URL pattern match as a String.</li>
<li><dc>@Header</dc> - An HTTP header value as a parsed POJO.</li>
<li><dc>@Content</dc> - 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><!-- END: 5.0.0.7 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.8' id='5.0.0.8'>5.0.0.8 (Jan 30, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.8 -->
<p>
Juno 5.0.0.8 is a minor update.
</p>
<ul class='spaced-list'>
<li>
New {@link org.apache.juneau.config 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><!-- END: 5.0.0.8 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.9' id='5.0.0.9'>5.0.0.9 (Feb 26, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.9 -->
<p>
Juno 5.0.0.9 is a moderate update.
</p>
<h5 class='topic w800'>Core API changes</h5>
<ul class='spaced-list'>
<li>
{@link org.apache.juneau.config 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 <c>ObjectMaps</c> directly to beans.</li>
</ul>
<h5 class='topic w800'>REST server API changes</h5>
<ul class='spaced-list'>
<li>Build-in default <c>OPTIONS</c> pages.</li>
<li>New <dc>@RestResource.defaultRequestHeaders</dc> and <dc>@RestResource.defaultResponseHeaders</dc> 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 <dc>@RestMethod(defaultRequestHeaders)</dc> 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><c>Readers</c> and <c>InputStreams</c> can be specified on <dc>@Content</dc> annotated parameters.</li>
<li>New <dc>@HasParam</dc> annotation.</li>
<li>Full RFC2616 support for matching <c>Accept</c> headers to serializers.</li>
</ul>
<h5 class='topic w800'>Other notes</h5>
<ul class='spaced-list'>
<li>Smaller library size (460kB).</li>
</ul>
</div><!-- END: 5.0.0.9 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.10' id='5.0.0.10'>5.0.0.10 (Mar 7, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.10 -->
<p>
Juno 5.0.0.10 is a minor update.
</p>
<h5 class='topic w800'>Core API changes</h5>
<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>
<h5 class='topic w800'>REST server API changes</h5>
<ul class='spaced-list'>
<li>New <c>RestServletProperties</c> class that defines all the class-level properties that can be set on the servlet.</li>
<li>Properties can be set through <dc>@RestResource.propertie</dc> annotation, or new <dc>RestServlet.setProperty(String,Object)</dc> 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 <c>RestServletProperties.REST_useStackTraceHashes</c> property to prevent the same stack trace from being logged multiple times.</li>
<li>New <c>RestServletProperties.REST_renderResponseStackTraces</c> property for preventing stack traces in responses for security reasons.</li>
<li>New overridable <c>RestServlet.onError(HttpServletRequest,HttpServletResponse,RestException,boolean)</c> and <dc>RestServlet.onSuccess(RestRequest,RestResponse,long)</dc> methods for plugging in your own logging and peformance monitoring.</li>
<li>Eliminated <c>RestServlet.getInitParams()</c> method, since it's now redundant with <dc>RestServlet.getProperties()</dc>.</li>
<li>Header parameters passed as URL parameters are now case-insensitive.</li>
</ul>
</div><!-- END: 5.0.0.10 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.11' id='5.0.0.11'>5.0.0.11 (Mar 8, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.11 -->
<p>
Juno 5.0.0.11 is a moderate update.
</p>
<h5 class='topic w800'>REST server API changes</h5>
<ul class='spaced-list'>
<li>
New <c>UrlEncodingRestSerializer</c> and <c>UrlEncodingRestParser</c> classes.<br>
Allows parsing form posts directly to POJOs.
</li>
<li>
Support for <c>Accept</c> and <c>Content-Type</c> <js>"application/x-www-form-urlencoded"</js> added by default on {@link org.apache.juneau.rest.BasicRestServlet}.
</li>
<li>
New <dc>RestServlet.renderError(HttpServletRequest,HttpServletResponse,RestException)</dc> method to allow customized handling of response errors.
</li>
</ul>
</div><!-- END: 5.0.0.11 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.12' id='5.0.0.12'>5.0.0.12 (Mar 10, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.12 -->
<p>
Juno 5.0.0.12 is a minor update.
</p>
<h5 class='topic w800'>Core API changes</h5>
<ul class='spaced-list'>
<li>
Relaxed method naming conventions when using <dc>@BeanProperty</dc> annotation.<br>
Methods with zero parameters are interpreted as getters, and methods with one parameter are interpreted as setters.<br>
Eliminated the <c>BeanProperty.method</c> annotation, since it's now unnecessary.
</li>
</ul>
<h5 class='topic w800'>REST server API changes</h5>
<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 <c>PlainTextRestSerializer</c> class for serializing <js>"plain/text"</js> requests.<br>
Useful for debugging purposes.
</li>
<li>
<c>Readers</c> and <c>InputStreams</c> can now be passed in as <dc>@Content</dc> 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 <c>?debug</c> parameter.<br>
Dumps better information to the log file, such as all header parameters.
</li>
</ul>
</div><!-- END: 5.0.0.12 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.13' id='5.0.0.13'>5.0.0.13 (Mar 14, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.13 -->
<p>
Juno 5.0.0.13 is a minor update.
</p>
<h5 class='topic w800'>Core API changes</h5>
<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 <c>SerializerContext.SERIALIZER_uriContext</c> and <c>SerializerContext.SERIALIZER_uriAuthority</c> 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 <c>java.net.URI</c> or <c>java.net.URL</c>.
</li>
<li>
New {@link org.apache.juneau.html.HtmlSerializer#HTML_uriAnchorText} HTML serializer property for tailoring how anchor text is rendered.
</li>
<li>
Renamed <c>BeanProperty#uri</c> annotation to <c>BeanProperty#beanUri</c> 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 <c>BeanProperty#id</c> annotation.
</li>
</ul>
<h5 class='topic w800'>REST server API changes</h5>
<ul class='spaced-list'>
<li>
Improvements to {@link org.apache.juneau.rest.RestServlet} to automatically handle relative URIs in POJOs.
<ul>
<li><c>SerializerContext.SERIALIZER_uriContext</c> property set by default to web app context root.</li>
<li><c>SerializerContext.SERIALIZER_uriAuthority</c> property set by default to the request scheme+hostname+port.</li>
</ul>
</li>
<li>
Fixed bug involving <c>Accept-Charset</c> header in Chrome that prevented HTML output from rendering correctly in that browser.<br>
<c>Accept-Charset</c> handling should now be fully W3C compliant.
</li>
</ul>
</div><!-- END: 5.0.0.13 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.14' id='5.0.0.14'>5.0.0.14 (Mar 23, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.14 -->
<p>
Juno 5.0.0.14 is a major update.
</p>
<p>
The biggest change is that the <c>RestSerializer</c>, <c>RestParser</c>, <c>RestSerializerGroup</c>, and <c>RestParserGroup</c> 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>
<h5 class='topic w800'>Core API changes</h5>
<ul class='spaced-list'>
<li>
New <c>org.apache.juneau.serializer</c> 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 <c>Accept-Content</c> headers.</li>
<li>Improved cloning support on serializers and serializer groups.</li>
</ul>
</li>
<li>
New <c>org.apache.juneau.parser</c> 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 <c>org.apache.juneau.transform</c> 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 <c>ObjectFilter</c>).</li>
</ul>
</li>
<li>
New <c>org.apache.juneau.encoders</c> 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 <c>Accept-Encoding</c> header values.</li>
</ul>
</li>
<li>
New <c>org.apache.juneau.plaintext</c> 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 <c>org.apache.juneau.jso</c> package.
<ul>
<li>New {@link org.apache.juneau.jso.JsoSerializer} class for serializing <c>application/x-java-serialized-object</c> content.</li>
</ul>
</li>
<li>
New <c>org.apache.juneau.soap</c> package.
<ul>
<li>New {@link org.apache.juneau.soap.SoapXmlSerializer} class for serializing <c>text/xml+soap</c> 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>
<c>JsonMap</c> and <c>JsonList</c> 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 <c>PojoSwap</c> to {@link org.apache.juneau.utils.PojoQuery} to not confuse it with the new Filter API.
</li>
</ul>
<h5 class='topic w800'>REST server API changes</h5>
<ul class='spaced-list'>
<li>
Eliminated <c>org.apache.juneau.rest.serializers</c> and <c>org.apache.juneau.rest.parsers</c> packages.
<ul>
<li>All existing REST serializers and parsers merged into the core API.</li>
</ul>
</li>
</ul>
<h5 class='topic w800'>REST client API changes</h5>
<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 <c>RestCmdLine</c> (since it's essentially redundant with CURL).
</li>
</ul>
</div><!-- END: 5.0.0.14 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.15' id='5.0.0.15'>5.0.0.15 (Mar 24, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.15 -->
<p>
Juno 5.0.0.15 is a moderate update.
</p>
<ul class='spaced-list'>
<li>
Juno-Wink integration components that have been requested by many for a long time!<br>
Refer to <del>org.apache.juneau.rest.jaxrs</del> for information.
</li>
<li>
New <dc>@Produces</dc> annotation in place of <c>ISerializer.getMediaTypes()</c> for specifying what media types a serializer produces.<br>
Available when subclassing from {@link org.apache.juneau.serializer.Serializer}.
</li>
<li>
New <dc>@Consumes</dc> annotation in place of <c>IParser.getMediaTypes()</c> for specifying what media types a parser consumes.<br>
Available when subclassing from {@link org.apache.juneau.parser.Parser}.
</li>
</ul>
</div><!-- END: 5.0.0.15 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.16' id='5.0.0.16'>5.0.0.16 (Mar 25, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.16 -->
<p>
Juno 5.0.0.16 is a minor update.
</p>
<ul class='spaced-list'>
<li>
New <dc>@Properties</dc> 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><!-- END: 5.0.0.16 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.17' id='5.0.0.17'>5.0.0.17 (Mar 25, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.17 -->
<p>
Juno 5.0.0.17 is a minor update.
</p>
<ul class='spaced-list'>
<li>
Charset now passed as a parameter to <c>IOutputStreamSerializer.serialize()</c> and <c>IInputStreamParser.parse()</c>.
</li>
</ul>
</div><!-- END: 5.0.0.17 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.18' id='5.0.0.18'>5.0.0.18 (Mar 27, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.18 -->
<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 <c>RdfParser</c> 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 <c>RdfXmlSerializer</c> 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>
<h5 class='topic w800'>Other changes</h5>
<ul class='spaced-list'>
<li>
New {@link org.apache.juneau.jso.JsoParser} class.
</li>
</ul>
</div><!-- END: 5.0.0.18 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.19' id='5.0.0.19'>5.0.0.19 (Apr 1, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.19 -->
<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><dc>RestServlet.onPreCall(RestRequest)</dc></li>
<li><dc>RestServlet.onPostCall(RestRequest,RestResponse)</dc></li>
</ul>
</li>
<li>
<jsf>TRIM_NULLS</jsf> setting changed to <dc>SerializerContext.SERIALIZER_trimNullProperties</dc>.<br>
New property default is <jk>true</jk>.
Only applies to bean properties, not map or collection entries.
</li>
</ul>
</div><!-- END: 5.0.0.19 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.20' id='5.0.0.20'>5.0.0.20 (Apr 7, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.20 -->
<p>
Juno 5.0.0.20 is a major update.
</p>
<h5 class='topic w800'>Core API changes</h5>
<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>
<dc>XmlSerializerContext.XML_autoDetectNamespaces</dc> 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 <dc>XmlSerializerContext.XML_namespaces</dc> 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>
<h5 class='topic w800'>REST server API changes</h5>
<ul class='spaced-list'>
<li>
Allow inheritance of <dc>@RestResource</dc> 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 <c>RestMethod.filters()</c> annotation for defining POJO filters at the method level.
</li>
<li>
New <dc>RestMethod.serializersInherit()</dc> and <dc>RestMethod.parsersInherit()</dc> annotations for controlling how serializers and parsers (and associated filters and properties) are inherited from the class.<br>
This replaces the previous <c>addSerializers</c> and <c>addParsers</c> annotations.
</ul>
</li>
<li>
New <dc>RestServletJenaDefault</dc> servlet that includes serialization/parsing support for all Jena-based serializers and parsers.
</li>
<li>
New <dc>DefaultJenaProvider</dc> JAX-RS provider that includes serialization/parsing support for all Jena-based serializers and parsers.
</li>
<li>
Eliminated <c>RestServletChild</c> class.<br>
It's redundant with the introduction of inheritable annotations.
</li>
<li>
New methods on {@link org.apache.juneau.rest.RestServlet}:
<ul>
<li><c>RestServlet.createConfigFactory()</c></li>
<li><c>RestServlet.createSerializers()</c></li>
<li><c>RestServlet.createParsers()</c></li>
</ul>
These augment the existing <c>getBeanContext()</c> / <c>getSerializers()</c> / <c>getParsers()</c> methods.
</li>
</ul>
<h5 class='topic w800'>REST client API changes</h5>
<ul class='spaced-list'>
<li>
New <c>RestCall.setDateHeader(String,Object)</c> method for setting ISO8601 datetime headers.
</li>
</ul>
</div><!-- END: 5.0.0.20 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.21' id='5.0.0.21'>5.0.0.21 (Apr 9, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.21 -->
<p>
Juno 5.0.0.21 is a minor update.
</p>
<h5 class='topic w800'>Core API changes</h5>
<ul class='spaced-list'>
<li>
New <dc>HtmlDocSerializerContext.HTMLDOC_navlinks</dc> annotation for addint links to HTML page views.
</li>
<li>
Renamed the properties in <dc>HtmlDocSerializerContext</dc> for clarity.
</li>
</ul>
<h5 class='topic w800'>Servlet API changes</h5>
<ul class='spaced-list'>
<li>
Added new <c>RestServlet.addDefaultProperties(ObjectMap,RestRequest)</c> 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 <c>SerializerContext.SERIALIZER_uriAuthority</c> and <c>SerializerContext.SERIALIZER_uriContext</c> properties were previously available.
<ul>
<li><c>RestServletProperties.REST_servletPath</c></li>
<li><c>RestServletProperties.REST_pathInfo</c></li>
<li><c>RestServletProperties.REST_method</c></li>
</ul>
</li>
<li>
Path variables annotated with <dc>@Attr</dc> are now automatically URL-decoded.
</li>
</ul>
</div><!-- END: 5.0.0.21 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.22' id='5.0.0.22'>5.0.0.22 (Apr 12, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.22 -->
<p>
Juno 5.0.0.22 is a minor update.
</p>
<h5 class='topic w800'>Core API changes</h5>
<ul class='spaced-list'>
<li>
New <c><ja>@Property</ja>.nls()</c> 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 <c>AddressBookResource</c> class for an example.
</li>
</ul>
<h5 class='topic w800'>REST Servlet API changes</h5>
<ul class='spaced-list'>
<li>Fix a bug where the <c>&amp;Content</c> query parameter was not always parsed correctly.</li>
</ul>
</div><!-- END: 5.0.0.22 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.23' id='5.0.0.23'>5.0.0.23 (Apr 14, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.23 -->
<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 <c><ja>@Xml</ja></c> annotation was not being inherited by inner classes.
</li>
<li>
Javadoc stylesheet improvements.
</li>
</ul>
</div><!-- END: 5.0.0.23 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.24' id='5.0.0.24'>5.0.0.24 (May 9, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.24 -->
<p>
Juno 5.0.0.24 is a major update.
</p>
<h5 class='topic w800'>Core API updates</h5>
<ul class='spaced-list'>
<li>
New support for {@link org.apache.juneau.dto.atom ATOM}.
<ul>
<li>New <c>AtomFeedResource</c> class added to sample war.
</ul>
</li>
<li>
New <dc>XmlFormat.CONTENT</dc> enum value.<br>
Allows bean properties to be persisted as XML element text.
</li>
<li>
New <dc>XmlContentHandler</dc> class and <dc>@Xml.contentHandler</dc> 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 <c><ja>@Xml</ja>.valAttr</c> annotation since it's now redundant with <c><ja>@Xml</ja>(format=<jsf>CONTENT</jsf>)</c>.
</li>
<li>
Fixed timezone bug in {@link org.apache.juneau.transforms.CalendarSwap}.
</li>
<li>
Simplified <c>Serializer.serialize(Object,Object,SerializerContext)</c> 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>
<h5 class='topic w800'>Documentation updates</h5>
<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><!-- END: 5.0.0.24 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.25' id='5.0.0.25'>5.0.0.25 (May 11, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.25 -->
<p>
Juno 5.0.0.25 is a minor update.
</p>
<h5 class='topic w800'>Core API updates</h5>
<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 <c>SqlQueryResource</c> class in the sample war for demonstrating the <c>ResultSetList</c> DTO.
</li>
</ul>
<h5 class='topic w800'>Server API updates</h5>
<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 <c>Servlet.init()</c> so that <c>getProperties()</c> can be called during servlet initialization.
</li>
<li>
New <c><ja>@Property</ja>.type</c> annotation with support for using system properties as resource properties.
</li>
</ul>
</div><!-- END: 5.0.0.25 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.26' id='5.0.0.26'>5.0.0.26 (Jun 5, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.26 -->
<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 <dc>@RestResource(children)</dc> defined on the resource class itself.<br>
Child resource paths are specified through <dc>@RestResource(path)</dc>.
</li>
<li>
New <dc>ChildResourceDescriptions</dc> bean for automatically generating the contents of router resource pages.
</li>
<li>
Changed <c><ja>@RestMethod</ja>.pattern()</c> to {@link org.apache.juneau.rest.annotation.RestMethod#path() @RestMethod(path)} for naming consistency.
</li>
</ul>
</div><!-- END: 5.0.0.26 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.27' id='5.0.0.27'>5.0.0.27 (July 7, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.27 -->
<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.BasicRestServlet} 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 <c>OPTIONS</c> pages through new method <dc>ResourceOptions.getChildren()</dc>.
</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><!-- END: 5.0.0.27 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.28' id='5.0.0.28'>5.0.0.28 (July 9, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.28 -->
<p>
Juno 5.0.0.28 is a moderate update.
</p>
<ul class='spaced-list'>
<li>
Fixes an <c>OutOfMemoryError</c> and performance issue caused by incorrect caching of class metadata.
</li>
<li>
Added <c>WriterSerializer.serialize(Object,Writer)</c> convenience method for serializing directly to a writer.<br>
Applies to all serializers.
</li>
</ul>
</div><!-- END: 5.0.0.28 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.29' id='5.0.0.29'>5.0.0.29 (Aug 2, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.29 -->
<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 <dc>Bean.subTypeProperty() subtypes</dc>. </li>
<li>Replaced <c><ja>@Bean</ja>(filter=xxx)</c> with new <dc>@Transform</dc> 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><c>org.apache.juneau.transforms.DateSwap.ISO8601DTP</c></li>
<li><c>org.apache.juneau.transforms.DateSwap.ISO8601DTZP</c></li>
</ul>
</li>
</ul>
</div><!-- END: 5.0.0.29 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.30' id='5.0.0.30'>5.0.0.30 (Aug 8, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.30 -->
<p>
Juno 5.0.0.30 is a minor update.
</p>
<ul class='spaced-list'>
<li>
Fixed bug involving beans using <dc>Bean.subTypes()</dc> annotation in addition to <c>subTypes</c> 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><!-- END: 5.0.0.30 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.31' id='5.0.0.31'>5.0.0.31 (Aug 9, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.31 -->
<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><!-- END: 5.0.0.31 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.32' id='5.0.0.32'>5.0.0.32 (Oct 5, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.32 -->
<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 <dc>org.apache.juneau.dto.jsonschema</dc> for information.
</li>
<li>
New methods added to {@link org.apache.juneau.parser.Parser}:
<ul>
<li><c>org.apache.juneau.parser.Parser.parseMap(Object,int,Class,Class,Class)</c></li>
<li><c>org.apache.juneau.parser.Parser.parseCollection(Object,int,Class,Class)</c></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 <c>Enums</c> through overriding <c>toString()</c> and <c>fromString()</c> on the enum class.<br>
Previously used <c>Enum.valueOf()</c> to convert strings back into <c>Enums</c>.<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 <c>Object</c> when the type is erased.
</li>
<li>
Bug fixes:
<ul>
<li>
When duplicate fluent-style setters were defined with different parameter types (e.g. <c>setFoo(Foo f)</c>, <c>setFoo(Bar b)</c>), 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 <c>Accept</c> GET parameters with <js>'+'</js> (e.g. <c>&amp;Accept=text/json+simple</c>) wasn't working anymore.<br>
The <c>Accept</c> parameter is supposed to interpret spaces as <js>'+'</js> to allow you to not have to write <c>&amp;Accept=text/json%2Bsimple</c>.
</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><!-- END: 5.0.0.32 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.33' id='5.0.0.33'>5.0.0.33 (Oct 20, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.33 -->
<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>
<c>WriterSerializer s = <jk>new</jk> JsonSerializer();</c><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 <c>addNotBeanClassPatterns(String...)</c> 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 <c>RestServletProperties</c>.
<ul>
<li><c>RestServletProperties.REST_trimTrailingUriSlashes</c><br>
Also removed <c>RestRequest.getRequestURI(boolean trimTrailingSlashes)</c> method which is now redundant with this property.
<li><c>RestServletProperties.REST_pathInfoBlankForNull</c><br>
Also removed <c>RestRequest.getPathInfo(boolean returnBlankForNull)</c> method which is now redundant with this property.
</ul>
</li>
<li>
New JSON-Schema {@link org.apache.juneau.dto.jsonschema.JsonSchemaMap} class for supporting linked schemas.
</li>
<li>
Serializers will no longer throw an exception when <c>maxDepth</c> 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: <c>?x-response-headers={Refresh=1}</c>
</li>
<li>
Removed <c>HtmlDocSerializerContext.<jsf>HTML_REFRESH</jsf></c> setting that added a Refresh meta tag to HTML documents, since this can now be controlled through <c>X-Response-Headers</c>.
</li>
<li>
Small improvements to samples.
<ul>
<li><c>PhotosResource</c> now includes a default entry.
</ul>
</li>
</ul>
</div><!-- END: 5.0.0.33 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.34' id='5.0.0.34'>5.0.0.34 (Nov 10, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.34 -->
<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 w800'>
<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 <c>RestServlet.createRequestVarResolver(RestRequest)</c> 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><dc>RestRequest.getVarResolver()</dc></li>
<li><dc>RestRequest.getServletURI()</dc></li>
<li><dc>RestRequest.getRequestParentURI()</dc></li>
</ul>
</li>
<li>
New methods on {@link org.apache.juneau.rest.RestResponse}:
<ul>
<li><c>RestResponse.sendRedirect(CharSequence)</c>
</ul>
</li>
<li>
New methods on {@link org.apache.juneau.rest.RestServlet} that allow easier customization by subclasses:
<ul>
<li><dc>RestServlet.createConfigFactory()</dc></li>
<li><dc>RestServlet.createConverters()</dc></li>
<li><dc>RestServlet.createDefaultRequestHeaders()</dc></li>
<li><dc>RestServlet.createDefaultResponseHeaders()</dc></li>
<li><dc>RestServlet.createEncoders()</dc></li>
<li><dc>RestServlet.createFilters()</dc></li>
<li><dc>RestServlet.createGuards()</dc></li>
<li><dc>RestServlet.createMimetypesFileTypeMap()</dc></li>
<li><dc>RestServlet.createParsers()</dc></li>
<li><dc>RestServlet.createProperties()</dc></li>
<li><dc>RestServlet.createRequestProperties(ObjectMap,RestRequest)</dc></li>
<li><dc>RestServlet.createRequestVarResolver(RestRequest)</dc></li>
<li><dc>RestServlet.createSerializers()</dc></li>
<li><dc>RestServlet.createUrlEncodingParser()</dc></li>
</ul>
</li>
<li>
Changed <c>RestServletNls</c> to use <c>ResourceDescription/MethodDescription</c>
instead of <c>RestResource/RestMethod</c>
</li>
<li>
New property <c>RestServletProperties.REST_htDocsFolder</c>.<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 <dc>BeanFilter.setStopClass(Class)</dc> which is the program equivalent to the annotation above.
</li>
<li>
New methods on {@link org.apache.juneau.dto.ResultSetList}:
<ul>
<li><c>ResultSetList.handleBlob(Blob)</c></li>
<li><c>ResultSetList.handleClob(Clob)</c></li>
</ul>
</ul>
</div><!-- END: 5.0.0.34 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.35' id='5.0.0.35'>5.0.0.35 (Nov 26, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.35 -->
<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><!-- END: 5.0.0.35 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.0.0.36' id='5.0.0.36'>5.0.0.36 (Dec 18, 2013)</a></h3>
<div class='topic'><!-- START: 5.0.0.36 -->
<p>
Juno 5.0.0.36 is a minor update.
</p>
<ul class='spaced-list'>
<li>Implemented <c>org.apache.juneau.urlencoding.UrlEncodingParser.parseArgs(Reader,int,ClassMeta[])</c>.
<li><c>name</c> parameter of <dc>ResourceDescription#ResourceDescription(String,String,String)</dc>.
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 <dc>BeanContext.getClassMetaFromString(String)</dc>.
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><!-- END: 5.0.0.36 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.0' id='5.1.0.0'>5.1.0.0 (Jan 18, 2014)</a></h3>
<div class='topic'><!-- START: 5.1.0.0 -->
<p>
Juno 5.1.0.0 is a major update.
</p>
<h5 class='topic w800'>Major changes</h5>
<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 <c>HttpClient</c> that performs
serialization and parsing using Juno parsers, but leaves all the details of the HTTP connection
to the Apache code. <br>
See the <del>org.apache.juneau.rest.client</del> package for details.
<li>New <c>org.apache.juneau.rest.client.jazz</c> package and <c>org.apache.juneau.rest.client.jazz.JazzRestClient</c> 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 <dc>org.apache.juneau.urlencoding</dc> package for details.
<li>Changes to Parser API.
<ul>
<li>Removal of <c>ExtendedReaderParser</c> abstract class and moved methods into
{@link org.apache.juneau.parser.ReaderParser} class.
<li>Removal of <c>DataFormat</c> class from API since it was no longer necessary
due to API change above.
<li>Removal of <c>ParserStringReader</c> class.<br>
This was a reader optimized to work with <c>String</c> 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 <c>String</c> input, and tests show no significant performance differences.
<li>New <c>org.apache.juneau.parser.Parser.parse(Object,int,ClassMeta)</c> convenience method added.
</ul>
</ul>
<h5 class='topic w800'>Other changes</h5>
<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 <dc>BeanContext.getClassMetaFromString(String)</dc>.<br>
Now supports resolving <c>"long[]"</c>, and so forth.
<li><dc>ResourceDescription</dc> 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. <c>http://host/contextRoot/foo%2Fbar</c>).
<li>Removed lazy-initialization that required locking in {@link org.apache.juneau.ClassMeta}.
<li>New <c>BeanContext.setDefaultParser(ReaderParser)</c> method added for specifying
a default parser to use in a bean context (used when converting beans to <c>Strings</c> using
<dc>BeanContext.convertToType(Object,Class)</dc>.
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 <dc>RestRequest#getParameter(String,Class)</dc>.
<li>Added <c>RestRequest.getMapParameter(String,Class,Class,Class)</c> and
<c>RestRequest.getCollectionParameter(String,Class,Class)}</c> methods.
</ul>
</ul>
</div><!-- END: 5.1.0.0 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.1' id='5.1.0.1'>5.1.0.1 (Jan 25, 2014)</a></h3>
<div class='topic'><!-- START: 5.1.0.1 -->
<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 <dc>@PathRemainder</dc>.
<li>Fixed bug involving incorrect calculation of <c>pathInfo</c> on child resources.
</ul>
</div><!-- END: 5.1.0.1 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.2' id='5.1.0.2'>5.1.0.2 (Apr 27, 2014)</a></h3>
<div class='topic'><!-- START: 5.1.0.2 -->
<p>
Juno 5.1.0.2 is a minor update.
</p>
<ul class='spaced-list'>
<li>Fixed issue preventing <c>&amp;Accept-Language</c> 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 <c>RestServletProperties.REST_allowMethodParam</c> to be disabled by default.
</ul>
</div><!-- END: 5.1.0.2 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.3' id='5.1.0.3'>5.1.0.3 (Jun 28, 2014)</a></h3>
<div class='topic'><!-- START: 5.1.0.3 -->
<p>
Juno 5.1.0.3 is a moderate update.
</p>
<h5 class='topic w800'>Core API updates</h5>
<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_beanMethodVisibility} - Control which getters/setters are visible to Juno as bean properties.
</ul>
Removed <c>BeanContext.<jsf>INCLUDE_BEAN_FIELD_PROPERTIES</jsf></c> and <c>BeanContext.<jsf>INCLUDE_BEAN_METHOD_PROPERTIES</jsf></c> 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 <dc>@BeanProperty</dc> annotation can now be used on non-public fields/getters/setters to override
the default behavior defined by the <c>VISIBILITY</c> 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 <c>Introspector</c>
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 <dc>@BeanProperty(hidden=true)</dc> 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 <dc>Bean.subTypeProperty()</dc> 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 <c><xt>&lt;div</xt> <xa>id</xa>=<xs>'data'</xs><xt>&gt;</xt></c> element to make it easier to extract the data portion of the page in Javascript in browsers.
</ul>
<h5 class='topic w800'>REST Server API updates</h5>
<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 <dc>$A{...}</dc> (request attributes) and <dc>$P{...}</dc> (request parameters) to <c>RestServlet.createRequestVarResolver(RestRequest)</c>.
</ul>
</div><!-- END: 5.1.0.3 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.4' id='5.1.0.4'>5.1.0.4 (Aug 25, 2014)</a></h3>
<div class='topic'><!-- START: 5.1.0.4 -->
<p>
Juno 5.1.0.4 is a minor update.
</p>
<ul class='spaced-list'>
<li>New <dc>RestServlet.getPath()</dc> method.
<li>New <c>SerializerContext.getJavaMethod()</c> and <c>ParserContext.getJavaMethod()</c>
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 <c>BeanContext.addTransforms(Class[])</c>.
Previously, adding multiple conflicting filters resulted in random behavior.
Now filters are overridden when multiple matching filters are applied.
<li>Allow <dc>HtmlDocSerializerContext</dc> properties to be set via <dc>Serializer.setProperty(String,Object)</dc>.
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><!-- END: 5.1.0.4 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.5' id='5.1.0.5'>5.1.0.5 (Sept 1, 2014)</a></h3>
<div class='topic'><!-- START: 5.1.0.5 -->
<p>
Juno 5.1.0.5 is a moderate update.
</p>
<ul class='spaced-list'>
<li>New <dc>Redirect</dc> class that simplifies performing redirections in REST methods.
<li>New pluggable {@link org.apache.juneau.rest.ResponseHandler} class and <dc>@RestResource(responseHandlers)</dc> annotation
for defining customer response handlers for special kinds of POJOs.
<li>New method <dc>UrlEncodingSerializer.serializeUrlPart(Object)</dc> method.
<li>New method <dc>RestRequest.getServletURIBuilder()</dc> 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 <dc>CoreObject.setProperties(ObjectMap)</dc>
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 <c>Content-Encoding</c> and<c>Character-Encoding</c> 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 <c>RestResponse.sendRedirect(...)</c> methods due to the introduction of the <dc>Redirect</dc> class.
</ul>
</div><!-- END: 5.1.0.5 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.6' id='5.1.0.6'>5.1.0.6 (Sept 21, 2014)</a></h3>
<div class='topic'><!-- START: 5.1.0.6 -->
<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 <c>beanContext</c> parameter was replaced with a <dc>PojoSwap#getBeanContext()</dc> 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, <dc>Img</dc> is an example of defining an XHTML element using Juno DTOs.
<li>{@link org.apache.juneau.json.JsonParser} now ignores trailing <c>';'</c> characters in input so that it can
parse strings of the form <js>"var x = {'foo':'bar'};"</js>.
<li>New <c>TumblrParserResource</c> 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><!-- END: 5.1.0.6 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.7' id='5.1.0.7'>5.1.0.7 (Oct 5, 2014)</a></h3>
<div class='topic'><!-- START: 5.1.0.7 -->
<p>
Juno 5.1.0.7 is a moderate update.
</p>
<ul class='spaced-list'>
<li>Improved error handling.
<li>New <dc>ParserContext.PARSER_debug</dc> and <dc>SerializerContext.SERIALIZER_debug</dc>.
settings for logging additional information for debugging problems.
<li>New <dc>SERIALIZER_ignoreRecursions</dc> setting for explicitly 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 <c>StackOverflowErrors</c>. 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 <c>SerializerContext.getProperties()</c> and
<c>ParserContext.getProperties()</c>.
<li>Removed media-type and encoding attributes from <dc>SerializerContext</dc> and <dc>ParserContext</dc>
since these are now available through context properties, and are typically not used.
<li>{@link org.apache.juneau.xml.XmlParser} now accepts <c>application/xml</c>.
<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><!-- END: 5.1.0.7 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.8' id='5.1.0.8'>5.1.0.8 (Oct 25, 2014)</a></h3>
<div class='topic'><!-- START: 5.1.0.8 -->
<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 <c>estimatedSize</c> 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 <c>BeanPropertyStore</c> class that handles creation of {@link org.apache.juneau.BeanContext} objects.
This allows <c>BeanContext</c> 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 <del>org.apache.juneau.rest.client</del> APIs to make it easier to work with custom Apache HTTP clients.
<ul>
<li>Added overridable <dc>RestClient#createHttpClient()</dc> to allow customized subclasses to construct customized HTTP clients.
<li>Removed the <c>DefaultRestClient</c> class since it's now fully redundant with <c>RestClient</c>.
<li>Added <c>RestClient.shutdown()</c> method for cleaning up the internal HTTP client when you're done using a REST client.
</ul>
</li>
</ul>
</div><!-- END: 5.1.0.8 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.9' id='5.1.0.9'>5.1.0.9 (Dec 1, 2014)</a></h3>
<div class='topic'><!-- START: 5.1.0.9 -->
<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><c>org.apache.juneau</c> - Core serializers and parsers.
<li><c>org.apache.juneau.rest</c> - REST server component.
<li><c>org.apache.juneau.rest.client</c> - REST client component.
</ul>
<li>Code changes to facilitate breaking up bundles:
<ul>
<li><c>org.apache.juneau.rest.labels.Link</c> class moved to <dc>Link</dc>.
<li>References to <c>org.apache.juneau.rest.RestException</c> in {@link org.apache.juneau.encoders.Encoder} class changed to <c>IOException</c>.
</ul>
<li>Changed configuration names for consistency with Jazz Framework.
<li><dc>RestClient.execute(HttpUriRequest)</dc> method that allows subclasses to handle their own HTTP request execution.
<li>Changes in <c>JazzRestClient</c> to handle introduction of SSO support in v6.
<li><c>&amp;plainText</c> debug feature was broken.
<li>Removed double-buffering in <c>RestRequest</c>.
<li>Metadata cleanup, Find Bug fixes.
</ul>
</div><!-- END: 5.1.0.9 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.10' id='5.1.0.10'>5.1.0.10 (Dec 23, 2014)</a></h3>
<div class='topic'><!-- START: 5.1.0.10 -->
<p>
Juno 5.1.0.10 is a moderate update.
</p>
<h5 class='topic w800'>Core</h5>
<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 <c>BeanRuntimeExceptions</c> weren't being thrown on subsequent calls to {@link org.apache.juneau.BeanContext#getClassMeta(Class)}.
<li>Moved logic for <c>BeanContext.getPrimitiveDefault(Class)</c> to new {@link org.apache.juneau.ClassMeta#getPrimitiveDefault()} method for performance reasons.
<li>Fixed bug in <dc>BeanContext.addTransforms(Class[])</dc> 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 <c>RuntimeExceptions</c> to make the serializer easier to use for debugging.
</ul>
<h5 class='topic w800'>Server</h5>
<ul class='spaced-list'>
<li>Fixed major issue that prevented parsing URL-Encoded form posts into POJOs.
Calling <dc>HttpServlet.getParameter(String)</dc> was forcing the underlying servlet code to process the HTTP body itself, preventing the <c>UrlEncodingSerializer</c>
class from being able to parse the content. Updated code no longer inadvertantly calls this method.
<li>New <dc>RestRequest.getQueryParameter(String)</dc>, <dc>RestRequest.hasQueryParameter(String)</dc>, and <dc>RestRequest.hasAnyQueryParameters(String[])</dc>
methods that only look for parameters in the URL query string to prevent loading and parsing of URL-Encoded form posts.
<li>New <dc>@QParam</dc> and <dc>@HasQParam</dc> annotations for accessing query parameters from the URL query string.
<li><c>&amp;plainText</c> parameter can now specify a false value.
<li>Removed properties parameters from <dc>RestServlet.onPreCall(RestRequest)</dc> and <dc>RestServlet#onPostCall(RestRequest,RestResponse)</dc> methods
since the properties are already accessible through <c>RestRequest.getProperties()</c>.
<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.BasicRestServlet} and <dc>RestServletJenaDefault</dc>.
</ul>
<h5 class='topic w800'>Client</h5>
<ul class='spaced-list'>
<li>Moved to Apache HttpClient 4.3 to match Jazz 6.0.
<li>Renamed <c>RestResponseEntity</c> 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><dc>RestClient#setProperty(String,Object)</dc>
<li><dc>RestClient#setProperties(ObjectMap)</dc>
<li><dc>RestClient#addNotBeanClasses(Class[])</dc>
<li><dc>RestClient.addTransforms(Class[])</dc>
<li><dc>RestClient#addImplClass(Class,Class)</dc>
</ul>
<li>Renamed <c>RestClient.shutdown()</c> to {@link org.apache.juneau.rest.client.RestClient#close()} to mirror change in Apache API.
</ul>
<h5 class='topic w800'>Samples</h5>
<ul class='spaced-list'>
<li>New <c>CodeFormatterResource</c> for quickly formatting Java and XML code samples in Javadocs.
<li>New <c>UrlEncodedFormResource</c> for showing how to work with URL-Encoded form posts.
</ul>
</div><!-- END: 5.1.0.10 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.11' id='5.1.0.11'>5.1.0.11 (Feb 14, 2015)</a></h3>
<div class='topic'><!-- START: 5.1.0.11 -->
<p>
Juno 5.1.0.11 is a moderate update.
</p>
<h5 class='topic w800'>Core</h5>
<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 <dc>UonParserContext.UON_whitespaceAware</dc> property for controlling whether whitespace is ignored.
<li>New <dc>UrlEncodingContext.URLENC_expandedParams</dc> 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. <c>&amp;key=val1&amp;key=val2</c>).
</ul>
</li>
<li>New <dc>JsonSerializerContext.JSON_escapeSolidus</dc> 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 <dc>BeanPropertyMeta.add(BeanMap,Object)</dc> method for adding values to Collection and array properties.
<li>Config INI files now support keys with name <js>"*"</js>.
</ul>
<h5 class='topic w800'>Server</h5>
<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 <dc>@Param(multipart)</dc>
and <dc>@Query(multipart)</dc> annotations
for handling multi-part GET and POST parameters.
<li>GET parameters are now CASE-SENSITIVE per W3C standards.
<ul>
<li>
<li><c>&amp;Content</c> must now be specified as <c>&amp;content</c>.
<li><c>&amp;Method</c> must now be specified as <c>&amp;method</c>.
<li><c>&amp;debug</c> must now be specified as <c>&amp;debug=true</c>.
<li><c>&amp;plainText</c> must now be specified as <c>&amp;plainText=true</c>.
<li><c>&amp;notrace</c> must now be specified as <c>&amp;noTrace=true</c>.
</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><dc>RestRequest.getParameters(String,Class)</dc>
<li><dc>RestRequest#getQueryParameters(String,Class)</dc>
</ul>
</li>
<li>Fixed Jetty issue in {@link org.apache.juneau.rest.RestResponse#setHeader(String,String)} where setting
the <c>Content-Type</c> through this method was inconsistent with the behavior in WAS/Tomcat.
<li><c>&amp;noTrace=true</c> now prevents any errors from being logged in log file.
<li>Workaround for Jetty issue where <c>ServletContext.getContextPath()</c> always ends with <js>"null"</js>.
<li><c>RestServletProperties.REST_allowMethodParam</c> is now <jk>true</jk> by default on all subclasses
of {@link org.apache.juneau.rest.BasicRestServlet} and <dc>RestServletJenaDefault</dc>.
</ul>
<h5 class='topic w800'>Client</h5>
<ul class='spaced-list'>
<li>New method {@link org.apache.juneau.rest.client.RestCall#allowRedirectsOnPosts(boolean)}.
<li>New method <c>RestCall.peekInputStream()</c> 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 <c>HttpResponse</c> object for easier debugging.
<li>New method <c>RestClient.addListener(RestClientListener)</c> for registering request/response listeners.
<li>New <dc>RestClient.setClassLoader(ClassLoader)</dc> method.
<li>TLS support in <c>JazzRestClient</c>.
</ul>
<h5 class='topic w800'>Other changes</h5>
<ul class='spaced-list'>
<li><c>samples.ear</c> and <c>samples.war</c> projects
have been replaced with an OSGi bundle with activated servlets in <c>juno.samples</c>.
</ul>
</div><!-- END: 5.1.0.11 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.12' id='5.1.0.12'>5.1.0.12 (Mar 28, 2015)</a></h3>
<div class='topic'><!-- START: 5.1.0.12 -->
<p>
Juno 5.1.0.12 is a minor update.
</p>
<h5 class='topic w800'>Core</h5>
<ul class='spaced-list'>
<li>Fixed <dc>ConfigFile.isEmpty()</dc> 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: <c>( ) , $ = ~</c>.
</ul>
<h5 class='topic w800'>Client</h5>
<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 <c>RestClientListener</c> class.
<li>Minor connection cleanup fixes.
</ul>
</div><!-- END: 5.1.0.12 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.13' id='5.1.0.13'>5.1.0.13 (Apr 24, 2015)</a></h3>
<div class='topic'><!-- START: 5.1.0.13 -->
<p>
Juno 5.1.0.13 is a minor update.
</p>
<h5 class='topic w800'>Core</h5>
<ul class='spaced-list'>
<li>{@link org.apache.juneau.ClassMeta#newInstance()} method can now create new instances of arrays.
<li>Arguments passed to <dc>Link</dc> are now serialized using {@link org.apache.juneau.urlencoding.UrlEncodingSerializer}, so arbitrary POJOs can now be passed as arguments.
<li>New date filters: <c>org.apache.juneau.transforms.Datefilter.ISO8601DTZP</c> and <c>org.apache.juneau.transforms.Datefilter.SimpleP</c>.
<li>New <dc>HtmlDocSerializerContext.HTMLDOC_nowrap</dc> 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 <c>ClassCastException</c>.
New behavior creates an empty array or <c>Collection</c>.
<li>Improved implementation of <dc>UrlEncodingSerializer.serializeUrlPart(Object)</dc> method.
</ul>
<h5 class='topic w800'>Server</h5>
<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><dc>@RestResource(messages)</dc> annotation can now be defined on super and subclasses so that NLS messages can be defined in multiple resource bundles.
<li>Performance improvements in <c>RestServletNls</c> 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>
<h5 class='topic w800'>Client</h5>
<ul class='spaced-list'>
<li>New <dc>RestCall.setRedirectMaxAttempts(int)</dc> method to prevent endless redirection loops.
<li>New <dc>RestCall#setRetryable(int,long,RetryOn)</dc> method to automatically retry on failed connection attempts.
<li>New <c>RestCallInterceptor.onRetry(RestCall,int,HttpRequest,HttpResponse)</c> method for listening in on retry attempts.
</ul>
</div><!-- END: 5.1.0.13 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.14' id='5.1.0.14'>5.1.0.14 (May 10, 2015)</a></h3>
<div class='topic'><!-- START: 5.1.0.14 -->
<p>
Juno 5.1.0.14 is a moderate update.
</p>
<p>
The major addition is support for <dc>Remoteable Services</dc>, the ability
to invoke server-side POJO methods through client-side proxy interfaces.
</p>
<h5 class='topic w800'>Core</h5>
<ul class='spaced-list'>
<li>Simplified {@link org.apache.juneau.utils.PojoIntrospector} class.
<li>New <dc>ClassUtils.getMethodSignature(Method)</dc> method.
</ul>
<h5 class='topic w800'>Client</h5>
<ul class='spaced-list'>
<li>New methods in {@link org.apache.juneau.rest.client.RestClient} for working with remoteable services:
<ul>
<li><dc>RestClient.setRemoteableServletUri(String)</dc>
<li><dc>RestClient#getRemoteableProxy(Class)</dc>
</ul>
</ul>
<h5 class='topic w800'>Server</h5>
<ul class='spaced-list'>
<li>Added a default OPTIONS page to {@link org.apache.juneau.rest.BasicRestServlet} and <dc>RestServletJenaDefault</dc>.
<li><c>RestServletProperties.REST_allowMethodParam</c> has been enhanced to allow you to
explicitly specify which HTTP methods can be used in the <c>&amp;method</c> parameter.
<li>New methods added to {@link org.apache.juneau.rest.RestRequest}:
<ul>
<li><dc>RestRequest.getParser()</dc>
<li><dc>RestRequest.getReaderParser()</dc>
</ul>
</ul>
</div><!-- END: 5.1.0.14 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.15' id='5.1.0.15'>5.1.0.15 (May 24, 2015)</a></h3>
<div class='topic'><!-- START: 5.1.0.15 -->
<p>
Juno 5.1.0.15 is a minor update.
</p>
<h5 class='topic w800'>Core</h5>
<ul class='spaced-list'>
<li>New properties in <dc>SerializerContext</dc>:
<ol>
<li><dc>SerializerContext.SERIALIZER_relativeUriBase</dc>
<li><dc>SerializerContext.SERIALIZER_absolutePathUriBase</dc>
</ol>
These replace the <c>SERIALIZER_uriAuthority</c> and <c>SERIALIZER_uriContext</c> properties.
</li>
<li>Improvements in {@link org.apache.juneau.csv.CsvSerializer}.
</ul>
<h5 class='topic w800'>Server</h5>
<ul class='spaced-list'>
<li>New properties in <c>RestServletProperties</c>:
<ol>
<li><c>REST_defaultCharset</c>
<li><c>REST_servletURI</c>
<li><c>REST_relativeServletURI</c>
</ol>
<li>Improvements involving path calculations when servlets deployed outside of a war file with a context root.
</ul>
<h5 class='topic w800'>Client</h5>
<ul class='spaced-list'>
<li>New methods in {@link org.apache.juneau.rest.client.RestCall}:
<ol>
<li><dc>RestRequest.getHeader(String,Class)</dc>
<li><dc>RestRequest.getHeader(String,Object,Class)</dc>
<li><dc>RestRequest.getHeader(String,Type,Type...)</dc>
<li><dc>RestRequest.getQueryParameter(String,Class)</dc>
<li><dc>RestRequest.getQueryParameter(String,Object,Class)</dc>
<li><dc>RestRequest.getQueryParameter(String,Type,Type...)</dc>
<li><dc>RestRequest.getQueryParameter(String,Object,Type,Type...)</dc>
<li><dc>RestRequest.getQueryParameters(String,Class)</dc>
<li><dc>RestRequest.getQueryParameters(String,Type,Type...)</dc>
<li><dc>RestRequest.getFormDataParameter(String,Class)</dc>
<li><dc>RestRequest.getFormDataParameter(String,Object,Class)</dc>
<li><dc>RestRequest.getFormDataParameters(String,Class)</dc>
<li><dc>RestRequest.getFormDataParameter(String,Type,Type...)</dc>
<li><dc>RestRequest.getFormDataParameters(String,Type,Type...)</dc>
<li><dc>RestRequest.getPathParameter(String,Class)</dc>
<li><dc>RestRequest.getPathParameter(String,Type,Type...)</dc>
<li><dc>RestRequest.getBody(Class)</dc>
<li><dc>RestRequest.getBody(Type,Type...)</dc>
</ol>
</li>
</ul>
</div><!-- END: 5.1.0.15 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.16' id='5.1.0.16'>5.1.0.16 (June 28, 2015)</a></h3>
<div class='topic'><!-- START: 5.1.0.16 -->
<p>
Juno 5.1.0.16 is a moderate update.
</p>
<h5 class='topic w800'>Core</h5>
<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><dc>ClassMeta.getXmlMeta()</dc>
<li><dc>ClassMeta.getJsonMeta()</dc>
<li><dc>ClassMeta.getHtmlMeta()</dc>
<li><dc>ClassMeta.getUrlEncodingMeta()</dc>
<li><dc>ClassMeta.getRdfMeta()</dc>
</ul>
<li>New {@link org.apache.juneau.dto.jsonschema.JsonType#ANY} enum.
<li>New <dc>@Html(asPlainText)</dc> annotation.
<li>New <dc>HtmlDocSerializerContext.HTMLDOC_cssImports</dc> property.
<li>Significant 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 <dc>SerializerContext.SERIALIZER_sortCollections</dc> and
<dc>SerializerContext.SERIALIZER_sortMaps</dc> properties.
<li>FindBug fixes.
</ul>
<h5 class='topic w800'>Server</h5>
<ul class='spaced-list'>
<li>New <dc>RestRequest.getServletParentURI()</dc> method.
<li>New <c>$R{servletParentURI}</c> variable.
<li>Removed final modifier from <dc>ChildResourceDescriptions</dc>.
</ul>
<h5 class='topic w800'>Samples</h5>
<ul class='spaced-list'>
<li>Added source code links to examples.
</ul>
</div><!-- END: 5.1.0.16 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.17' id='5.1.0.17'>5.1.0.17 (Aug 3, 2015)</a></h3>
<div class='topic'><!-- START: 5.1.0.17 -->
<p>
Juno 5.1.0.17 is a major update.
</p>
<h5 class='topic w800'>Core</h5>
<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><c>BeanMap.getFiltered(String)</c>
<li><c>BeanMap.putFiltered(String,Object)</c>
<li><c>BeanMapEntry.getFiltered(String)</c>
<li><c>BeanMapEntry.putFiltered(String,Object)</c>
<li><c>BeanMapEntry.putFiltered(String,Object)</c>
<li><c>BeanPropertyMeta.getFiltered()</c>
<li><c>BeanPropertyMeta.setFiltered(Object)</c>
<li><c>BeanPropertyMeta.getTransformedClassMeta()</c>
</ul>
<li>{@link org.apache.juneau.BeanPropertyMeta#getClassMeta()} now returns the filtered type of the property.
</ul>
<li><dc>StringVarResolver</dc> now has support for chained resolvers.
<li><dc>StringVarResolver</dc> 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 <dc>RestResource.filters()</dc> 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 <c>RdfProperties.RDF_useXmlNamespaces</c> property.
<li>New <dc>XmlParserContext.XML_preserveRootElement</dc> 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>
<h5 class='topic w800'>Server</h5>
<ul class='spaced-list'>
<li>New <dc>ZipFileListResponseHandler</dc> class.
<li>Simplified labels in servlet resource bundles:
<ul>
<li><c>"[ClassName].ResourceDescription"</c> is now <c>"[ClassName].label"</c>.
<li><c>"[ClassName].MethodDescription.[methodName]"</c> is now <c>"[ClassName].[methodName]"</c>.
</ul>
<li>Several changes to {@link org.apache.juneau.rest.RestRequest}:
<ul>
<li>Added new methods:
<ul>
<li><dc>RestRequest.getQueryParameterMap()</dc>
<li><dc>RestRequest.getQueryParameterNames()</dc>
<li><dc>RestRequest.getPathInfoUndecoded()</dc>
<li><dc>RestRequest.getPathRemainderUndecoded()</dc>
<li><dc>RestRequest.getTrimmedRequestURI()</dc>
<li><dc>RestRequest.getTrimmedRequestURL()</dc>
<li><dc>RestRequest.getServletTitle()</dc>
<li><dc>RestRequest.getServletDescription()</dc>
<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><dc>RestRequest.getPathRemainder()</dc> now automatically decodes the path remainder.
Use <dc>RestRequest.getPathRemainderUndecoded()</dc> to get the unencoded path remainder.
<li>Bug fixes in <dc>RestRequest.getRequestParentURI()</dc> when servlet is mapped to <js>"/*"</js>.
<li>Bug fixes in <dc>RestRequest.getServletURI()</dc> when servlet is mapped to <js>"/*"</js>.
</ul>
<li>New string replacement variables:
<ul>
<li><c>$R{contextPath}</c> - Returns value from {@link org.apache.juneau.rest.RestRequest#getContextPath()}
<li><c>$R{methodDescription}</c> - Returns value from {@link org.apache.juneau.rest.RestRequest#getMethodDescription()}
<li><c>$R{resourceTitle}</c> - Returns value from <dc>RestRequest.getServletTitle()</dc>
<li><c>$R{resourceDescription}</c> - Returns value from <dc>RestRequest.getServletDescription()</dc>
<li><c>$R{trimmedRequestURI}</c> - Returns value from <dc>RestRequest.getTrimmedRequestURI()</dc>
<li><c>$E{var}</c> - Environment variables.
</ul>
<li>Added methods <dc>RestServlet.getDescription(RestRequest)</dc> and <dc>RestServlet.getLabel(RestRequest)</dc>.
<li>{@link org.apache.juneau.rest.BasicRestServlet} and <dc>RestServletJenaDefault</dc> now provide default HTML titles
and descriptions:
<p class='bcode w800'>
<ja>@Property</ja>(name=<jsf>HTMLDOC_title</jsf>, value=<js>"$R{resourceTitle}"</js>),
<ja>@Property</ja>(name=<jsf>HTMLDOC_description</jsf>, value=<js>"$R{resourceDescription}"</js>)
</p>
<li>Options pages on {@link org.apache.juneau.rest.BasicRestServlet} and <dc>RestServletJenaDefault</dc> now provide default descriptions and back links:
and descriptions:
<p class='bcode w800'>
<ja>@Property</ja>(name=<jsf>HTMLDOC_navlinks</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.BasicRestServletGroup} class.
<li>Removed <c>RestServletProperties.REST_trimTrailingUriSlashes</c> and <c>RestServletProperties.REST_pathInfoBlankForNull</c>.
<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><dc>RestResource.label()</dc>
<li><dc>@RestResource(description)</dc>
<li>{@link org.apache.juneau.rest.annotation.RestMethod#description() @RestMethod(description)}
<li><dc>RestMethod#responses()</dc>
<li><dc>Attr.description()</dc>
<li><dc>Content.description()</dc>
<li><dc>HasParam.description()</dc>
<li><dc>HasQParam.description()</dc>
<li><dc>Header.description()</dc>
<li><dc>Param.description()</dc>
<li><dc>QParam.description()</dc>
</ul>
<li>Support for sorting resources by name in <dc>ChildResourceDescriptions</dc>.
</ul>
<h5 class='topic w800'>Samples</h5>
<ul class='spaced-list'>
<li>Added <c>/tempDir/upload</c> showing how to use <c>ServletFileUpload</c> with multipart form posts.
</ul>
</div><!-- END: 5.1.0.17 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.18' id='5.1.0.18'>5.1.0.18 (Aug 5, 2015)</a></h3>
<div class='topic'><!-- START: 5.1.0.18 -->
<p>
Juno 5.1.0.18 is a minor update affecting the server component only.
</p>
<h5 class='topic w800'>Server</h5>
<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 <dc>RestMethod.input()</dc> and <dc>RestMethod.responses()</dc>
annotations.
These replace the various <c>description</c> annotations added 2 days ago with a simpler design.
<li>New methods on {@link org.apache.juneau.rest.RestServlet}:
<ul>
<li><dc>RestServlet.getMethodDescription(String,RestRequest)</dc> so that subclasses
can override the method description in the OPTIONS page.
<li><dc>RestServlet.createRequestVarResolver(RestRequest)</dc> so that subclasses
can override and augment the variable resolver.
<li><dc>RestServlet.resolveChild(Class)</dc> and <dc>RestServlet.replaceChild(RestServlet)</dc>
classes that allows customized resolution of servlet instances (e.g. if services are defined in OSGi).
</ul>
<li>Reverted the <dc>MethodDescription</dc> back to 5.1.0.16 since it was being used by someone.
</ul>
</div><!-- END: 5.1.0.18 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.19' id='5.1.0.19'>5.1.0.19 (Aug 15, 2015)</a></h3>
<div class='topic'><!-- START: 5.1.0.19 -->
<p>
Juno 5.1.0.19 is a minor update in terms of core functionality.
But it introduces a <dc>Microservices</dc> project for building REST microservices and docker containers.
</p>
<h5 class='topic w800'>Core</h5>
<ul class='spaced-list'>
<li>Beans can now be serialized to and parsed from {@link org.apache.juneau.ObjectMap ObjectMaps}.
See <del>Serializing to ObjectMaps</del> 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 <dc>StringVarResolver</dc>. <jk>null</jk> input now results in blank strings instead of <jk>null</jk>.
</ul>
<h5 class='topic w800'>Client</h5>
<ul class='spaced-list'>
<li>New {@link org.apache.juneau.rest.client.RestClient#doCallback(String)} method.
</ul>
<h5 class='topic w800'>Server</h5>
<ul class='spaced-list'>
<li>New {@link org.apache.juneau.rest.RestRequest#getHeaders()} method.
<li>New <c>RestResponse.getUnbufferedWriter()</c> method.
<li>Fixed bug that was preventing <c>x-response-headers</c> parameter from working correctly.
<li>Added {@link org.apache.juneau.annotation.Bean#properties() @Bean.properties} annotations to the various
classes in <c>org.apache.juneau.rest.labels</c> 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 <dc>ResourceDescription.ResourceDescription(RestRequest,String,String)</dc> constructor.
</ul>
</div><!-- END: 5.1.0.19 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.1.0.20' id='5.1.0.20'>5.1.0.20 (Sept 5, 2015)</a></h3>
<div class='topic'><!-- START: 5.1.0.20 -->
<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 <dc>ConfigFile</dc> functionality.
</p>
<h5 class='topic w800'>Core</h5>
<ul class='spaced-list'>
<li>Significant API changes to <c>org.apache.juneau.config</c> API.
<ul>
<li><dc>ConfigFile</dc> is now thread safe and can be shared across multiple threads.
<li>New <dc>ConfigMgr</dc> 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 <dc>ObjectMap.remove(Class,String,Object)</dc> method.
<li><js>"class='link'"</js> added to links generated by {@link org.apache.juneau.html.HtmlDocSerializer}.
<li>New <dc>EncoderGroup#append(EncoderGroup)</dc> method.
<li>New <c>HtmlDocSerializerContext.HTMLDOC_addLinks</c> configuration property.
<li>Modified the <c>Parser.createContext(ObjectMap,Method,Object)</c> 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 <dc>ReflectionUtils.getResource(Class,String)</dc> 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>
<h5 class='topic w800'>Server</h5>
<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>
<dc>RestServlet.getConfig()</dc><br>
<dc>RestServlet.createConfigFile()</dc>
<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>
<dc>RestServlet.getResource(String)</dc><br>
<dc>RestServlet.getResourceAsString(String)</dc><br>
<dc>RestServlet.getResource(Class,String,String)</dc>.
Useful if you want to load predefined POJOs from JSON files in your classpath.
<li>New <dc>RestServlet.handleNotFound(int,RestRequest,RestResponse)</dc> method for customized handling
of when a resource or method was not found.
</ul>
<li>{@link org.apache.juneau.rest.BasicRestServlet} now automatically processes <js>"/favicon.ico"</js> requests by
overriding the new <dc>RestServlet.handleNotFound(int,RestRequest,RestResponse)</dc> method.
<li>New {@link org.apache.juneau.rest.RestRequest} methods:
<ul>
<li><dc>RestRequest.resolveVars(String)</dc>
<li><c>RestRequest.getVarResource(String)</c>
<li><dc>RestRequest.getConfig()</dc>
</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()}.
<c>getWriter()</c> now returns an unnegotiated writer.
<c>getUnbufferedWriter()</c> has been removed.
</ul>
<li>New {@link org.apache.juneau.rest.annotation.RestMethod#encoders() @RestMethod(encoders)} and
<dc>RestMethod.inheritEncoders()</dc> annotations.
Allows encoders to be fine-tuned at the method level.
<li>New <dc>@RestResource(config)</dc> annotation for associating external <dc>ConfigFile</dc> config files with servlets.
<li><dc>ResourceLink</dc>.
<li>New <c>org.apache.juneau.rest.matchers</c> 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>
<h5 class='topic w800'>Microservice</h5>
<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><!-- END: 5.1.0.20 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.2.0.0' id='5.2.0.0'>5.2.0.0 (Dec 30, 2015)</a></h3>
<div class='topic'><!-- START: 5.2.0.0 -->
<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>
<h5 class='topic w800'>Core</h5>
<ul class='spaced-list'>
<li>Significant changes and enhancements to the <c>org.apache.juneau.config</c> API.
<ul>
<li>More consistent handling of comma-delimited lists of objects.
<li>New methods in <dc>ConfigFile</dc>:
<ul>
<li><dc>ConfigFile.getStringArray(String)</dc>,<dc>ConfigFile.getStringArray(String,String[])</dc>
<li><dc>ConfigFile.getSectionAsBean(String,Class)</dc> - Instantiate a new bean with property values in the specified section..
<li><dc>ConfigFile.writeProperties(String,Object,boolean,Class[])</dc> - Copy the properties in a config file section into properties on an existing bean or POJO.
<li><dc>ConfigFile.getSectionMap(String)</dc> - Get all the resolved values in a section.
<li><dc>ConfigFile.containsNonEmptyValue(String)</dc>
<li><dc>ConfigFile.isEncoded(String)</dc>
<li><dc>ConfigFile.addListener(ConfigFileListener)</dc> - Listen for modification events on the config file.
<li><dc>ConfigFile.merge(ConfigFile)</dc> - Merge the contents of another config file into this config file.
<li><dc>ConfigFile.getResolving()</dc>, <dc>ConfigFile.getResolving(StringVarResolver)</dc> - 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><dc>ConfigFile.toWritable()</dc> - 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><dc>ConfigFile.getInt(String)</dc> - Now supports <js>"M"</js> and <js>"K"</js> to identify millions and thousands.
</ul>
<li>New methods in <dc>ConfigMgr</dc>:
<ul>
<li><dc>ConfigMgr.create()</dc>, <dc>ConfigMgr.create(Reader)</dc>, <dc>ConfigMgr.create(File)</dc>
<li><dc>ConfigMgr.deleteAll()</dc>
</ul>
<li>New methods in <dc>Section</dc>:
<ul>
<li><dc>Section.setParent(ConfigFileImpl)</dc> - Used by parsers to set the config file for this section.
<li><dc>Section.setName(String)</dc> - Used by parsers to set the name for this section.
</ul>
<li>New interfaces:
<ul>
<li><dc>org.apache.juneau.config.ConfigFileListener</dc>
<li><dc>org.apache.juneau.config.SectionListener</dc>
<li><dc>org.apache.juneau.config.EntryListener</dc>
</ul>
<li><dc>org.apache.juneau.config.Encoder</dc> 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><dc>org.apache.juneau.config.XorEncoder</dc> XOR key can be overridden through the <js>"org.apache.juneau.config.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><c>fromString(String)</c>
<li><c>valueOf(String)</c> (e.g. enums)
<li><c>parse(String)</c> (e.g. logging <c>Level</c> class)
<li><c>parseString(String)</c>
<li><c>forName(String)</c> (e.g. <c>Class</c> and <c>Charset</c> classes)
</ul>
<li>Support for parsing into objects with unbound type variables.
For example, if you have a class <c>Pair&lt;S,T&gt;</c> and you try to parse into this
class (e.g. <c>parser.parse(in, Pair.<jk>class</jk>)</c>), the unbound type variables
is interpreted as <c>Object</c> instead of throwing an exception.
<li>Support for serializing/parsing the following new types:
<ul>
<li><c>AtomicInteger</c>
<li><c>AtomicLong</c>
<li><c>BigInteger</c>
<li><c>BigDecimal</c>
</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 <dc>Section</dc> class represents a section
in a config file. It needs to know it's own name and have a link to the <dc>ConfigFile</dc>
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><dc>StringObject</dc> class that can be used for delayed object serialization.
<li><dc>ByteArrayCache</dc>
<li>{@link org.apache.juneau.internal.ByteArrayInOutStream}
<li>{@link org.apache.juneau.internal.FileUtils}
<li>{@link org.apache.juneau.internal.ThrowableUtils}
<li><dc>StringVarMultipart</dc>
<li><dc>StringVarWithDefault</dc>
</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><dc>IOUtils.pipe(Reader,Writer)</dc>
<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><dc>PojoRest.get(Class,String,Object)</dc>
<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><dc>StringUtils.parseISO8601Date(String)</dc>
<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 <dc>StringVar.doResolve(String)</dc> method.
<li>New <dc>StringVarResolver.DEFAULT</dc> field.
<li>Eliminated dependency on <c>javax.mail.internet.MimeUtility</c> 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 <c>/servletPath/style.css</c> instead of <c>/servletPath/htdocs/juneau.css</c>.
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. <c>&lt;div class='outerdata'&gt;&lt;div class='data' id='data'&gt;...&lt;/div&gt;&lt;/div&gt;</c>).
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 <del>HtmlSchemaDocSerializer</del>.
<li>RDF serializers and parsers now support <c>RdfProperties.RDF_looseCollection</c> 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 <c>NoClassDefFoundErrors</c>.
<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 <dc>UrlEncodingSerializer.DEFAULT_SIMPLE_EXPANDED</dc> serializer.
<li>Changes to {@link org.apache.juneau.utils.Args}:
<ul>
<li><c>getMainArg(int)</c> 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 <c>org.apache.juneau.utils.CharsetUtils</c> class.
<li>Removed <c>org.apache.juneau.utils.ConcurrentIdentityList</c> 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 <c>ReaderParser</c>.
Simplifies the API on the class.
<li>{@link org.apache.juneau.utils.PojoRest} must now be instantiated with a <c>ReaderParser</c>.
Simplifies the API on the class.
<li>{@link org.apache.juneau.utils.MessageBundle} and <c>SafeResourceMultiBundle</c> moved from server component.
<li>Several bug fixes and performance improvements in <dc>StringVarResolver</dc>.
<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 <c>NoClassDefFoundErrors</c>
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>
<h5 class='topic w800'>Client</h5>
<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><dc>SSLOpts</dc>
</ul>
<li>Removed <c>org.apache.juneau.rest.client.LaxRedirectStrategy</c>. Use HTTP Client equivalent.
<li>New methods on {@link org.apache.juneau.rest.client.RestCall}:
<ul>
<li><dc>RestCall#addInterceptor(RestCallInterceptor)</dc>
<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><dc>RestCall#addResponsePattern(ResponsePattern)</dc>
<li>{@link org.apache.juneau.rest.client.RestCall#run()} - Renamed from <c>execute()</c>.
<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><dc>RestClient.setBasicAuth(String,int,String,String)</dc>
<li><dc>RestClient.logTo(Level,Logger)</dc>
<li><dc>RestClient.setRootUrl(String)</dc>
<li><dc>RestClient.enableSSL(SSLOpts)</dc>
<li><dc>RestClient.enableLaxSSL()</dc>
<li>{@link org.apache.juneau.rest.client.RestClient#doCall(HttpMethod,Object,Object)}
<li><dc>RestClient.createHttpClientBuilder()</dc>
</ul>
<li>New passthrough methods on {@link org.apache.juneau.rest.client.RestClient} defined on <c>HttpClientBuilder</c>:
<ul>
<li><dc>RestClient.setRedirectStrategy(RedirectStrategy)</dc>
<li><dc>RestClient.setDefaultCookieSpecRegistry(Lookup)</dc>
<li><dc>RestClient.setRequestExecutor(HttpRequestExecutor)</dc>
<li><dc>RestClient.setSSLHostnameVerifier(HostnameVerifier)</dc>
<li><dc>RestClient.setPublicSuffixMatcher(PublicSuffixMatcher)</dc>
<li><dc>RestClient.setSSLContext(SSLContext)</dc>
<li><dc>RestClient.setSSLSocketFactory(LayeredConnectionSocketFactory)</dc>
<li><dc>RestClient.setMaxConnTotal(int)</dc>
<li><dc>RestClient.setMaxConnPerRoute(int)</dc>
<li><dc>RestClient.setDefaultSocketConfig(SocketConfig)</dc>
<li><dc>RestClient.setDefaultConnectionConfig(ConnectionConfig)</dc>
<li><dc>RestClient.setConnectionTimeToLive(long,TimeUnit)</dc>
<li><dc>RestClient.setConnectionManager(HttpClientConnectionManager)</dc>
<li><dc>RestClient.setConnectionManagerShared(boolean)</dc>
<li><dc>RestClient.setConnectionReuseStrategy(ConnectionReuseStrategy)</dc>
<li><dc>RestClient.setKeepAliveStrategy(ConnectionKeepAliveStrategy)</dc>
<li><dc>RestClient.setTargetAuthenticationStrategy(AuthenticationStrategy)</dc>
<li><dc>RestClient.setProxyAuthenticationStrategy(AuthenticationStrategy)</dc>
<li><dc>RestClient.setUserTokenHandler(UserTokenHandler)</dc>
<li><dc>RestClient.disableConnectionState()</dc>
<li><dc>RestClient.setSchemePortResolver(SchemePortResolver)</dc>
<li><dc>RestClient.setUserAgent(String userAgent)</dc>
<li><dc>RestClient.setDefaultHeaders(Collection)</dc>
<li><dc>RestClient.addInterceptorFirst(HttpResponseInterceptor)</dc>
<li><dc>RestClient.addInterceptorLast(HttpResponseInterceptor)</dc>
<li><dc>RestClient.addInterceptorFirst(HttpRequestInterceptor)</dc>
<li><dc>RestClient.addInterceptorLast(HttpRequestInterceptor)</dc>
<li><dc>RestClient.disableCookieManagement()</dc>
<li><dc>RestClient.disableContentCompression()</dc>
<li><dc>RestClient.disableAuthCaching()</dc>
<li><dc>RestClient.setHttpProcessor(HttpProcessor)</dc>
<li><dc>RestClient.setRetryHandler(HttpRequestRetryHandler)</dc>
<li><dc>RestClient.disableAutomaticRetries()</dc>
<li><dc>RestClient.setProxy(HttpHost)</dc>
<li><dc>RestClient.setRoutePlanner(HttpRoutePlanner)</dc>
<li><dc>RestClient.disableRedirectHandling()</dc>
<li><dc>RestClient.setConnectionBackoffStrategy(ConnectionBackoffStrategy)</dc>
<li><dc>RestClient.setBackoffManager(BackoffManager)</dc>
<li><dc>RestClient.setServiceUnavailableRetryStrategy(ServiceUnavailableRetryStrategy)</dc>
<li><dc>RestClient.setDefaultCookieStore(CookieStore)</dc>
<li><dc>RestClient.setDefaultCredentialsProvider(CredentialsProvider)</dc>
<li><dc>RestClient.setDefaultAuthSchemeRegistry(Lookup)</dc>
<li><dc>RestClient.setContentDecoderRegistry(Map)</dc>
<li><dc>RestClient.setDefaultRequestConfig(RequestConfig)</dc>
<li><dc>RestClient.useSystemProperties()</dc>
<li><dc>RestClient.evictExpiredConnections()</dc>
<li><dc>RestClient.evictIdleConnections(long,TimeUnit)</dc>
</ul>
<li><c>JazzRestClient</c> now supports OIDC authentication.
<li>These classes are now deprecated and will be removed in a future release:
<ul>
<li><c>org.apache.juneau.rest.client.jazz.CertificateStore</c>
<li><c>org.apache.juneau.rest.client.jazz.ICertificateValidator</c>
<li><c>org.apache.juneau.rest.client.jazz.ITrustStoreProvider</c>
<li><c>org.apache.juneau.rest.client.jazz.LenientCertificateValidator</c>
<li><c>org.apache.juneau.rest.client.jazz.SharedTrustStoreProvider</c>
<li><c>org.apache.juneau.rest.client.jazz.ValidatingX509TrustManager</c>
</ul>
</ul>
<h5 class='topic w800'>Server</h5>
<ul class='spaced-list'>
<li>New <dc>ReaderResource</dc> class.
Represents the contents of a text file with convenience methods for resolving
<dc>StringVar</dc> variables and adding HTTP response headers.
REST Java methods can return instances of these to serialize <c>Readers</c>
containing text with <dc>StringVarResolver</dc> variables in them.
<li>New <dc>StreamResource</dc> class.
REST Java methods can return instances of these to serialize <c>OutputStreams</c>.
<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><dc>RestRequest.getReaderResource(String)</dc> - Replaces <c>getVarResource(String)</c>.
<li><dc>RestRequest.getReaderResource(String,boolean)</dc>
<li><dc>RestRequest.getReaderResource(String,boolean,String)</dc>
</ul>
<li>Changes in {@link org.apache.juneau.rest.RestResponse}:
<ul>
<li>Don't set <c>Content-Encoding: identity</c> 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><dc>RestServlet.getChildClasses()</dc> - Programmatic equivalent to <dc>@RestResource(children)</dc> annotation.
<li><dc>RestServlet.shouldLog(HttpServletRequest,HttpServletResponse,RestException)</dc>
<li><dc>RestServlet.shouldLogStackTrace(HttpServletRequest,HttpServletResponse,RestException)</dc>
<li><dc>RestServlet.logObjects(Level,String,Object[])</dc>
<li><dc>RestServlet.resolveStaticFile(String)</dc>
<li><dc>RestServlet.createStyleSheet()</dc>
<li><dc>RestServlet.createFavIcon()</dc>
<li><dc>RestServlet.createStaticFilesMap()</dc>
<li><dc>RestServlet.getConfigMgr()</dc>
</ul>
<li>Removed {@link org.apache.juneau.jso.JsoParser}
from {@link org.apache.juneau.rest.BasicRestServlet} and <dc>RestServletJenaDefault</dc>.
These may represent a security risk if not handled correctly, so removed
them as a precaution.
<li>Removed <c>RestServletProperties.REST_htDocsFolder</c>. Replaced with <dc>@RestResource(staticFiles)</dc>}.
<li>New annotations on <dc>@RestResource</dc>.
<ul>
<li><dc>RestResource.stylesheet()</dc>
<li><dc>RestResource.favicon()</dc>
<li><dc>@RestResource(staticFiles)</dc>
</ul>
<li>Eliminated <c>org.apache.juneau.rest.jaxrs.JsonProvider</c> class.
Some JAX-RS implementations use code scanning to find providers, so if you were using <c>DefaultJenaProvider</c>, it would
pick up <c>JsonProvider</c> as well. It's easy enough to create your own implementation if needed.
<li>OPTIONS pages now specify <c>consumes</c> and <c>produces</c> fields instead of <c>accept</c> and <c>contentType</c> which was confusing.
<li>Eliminated <c>properties</c> from OPTIONS pages.
<li>New <dc>ResourceLink.ResourceLink(String,RestRequest,String,Object[])</dc> constructor.
<li>New response handlers:
<ul>
<li><dc>StreamableHandler</dc> - Allows REST Java methods to return instances of {@link org.apache.juneau.Streamable}.
<li><dc>WritableHandler</dc> - 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 <dc>RestUtils.trimPathInfo(StringBuffer,String,String)</dc> method.
</ul>
<h5 class='topic w800'>Microservice</h5>
<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 <dc>RestMicroservice</dc> 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 <c>org.apache.juneau.microservice.Main</c> class. This is replaced by
the microservice classes defined above.
<li><dc>Resource</dc> and <dc>ResourceGroup</dc>
classes now support the following new string variables:
<ul>
<li><js>"$A{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 <dc>BasicRestServletJena</dc> class if you want your REST interface to support RDF.
<li>Eliminated the following classes:
<ul>
<li><c>org.apache.juneau.microservice.RootResource</c>
<li><c>org.apache.juneau.microservice.SampleResource</c>
</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>
<h5 class='topic w800'>Samples</h5>
<ul class='spaced-list'>
<li>Converted to a REST microservice.
<li>Look-and-feel changed to IBM DevOps.
</ul>
<h5 class='topic w800'>Documentation Updates</h5>
<ul class='spaced-list'>
<li><del>org.apache.juneau.microservice</del> - New package-level javadoc.
<li><del>org.apache.juneau.config</del> - New package-level javadoc.
<li><dc>StringVarResolver</dc> - New documentation.
<li><del>org.apache.juneau.rest.client</del> - New package-level javadoc.
<li><dc>Overview / Samples</dc> - New section.
<li><del>org.apache.juneau.transform / Stop Classes</del> - New section.
<li><del>org.apache.juneau.rest</del> - Extensive updates.
</ul>
</div><!-- END: 5.2.0.0 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#5.2.0.1' id='5.2.0.1'>5.2.0.1 (Mar 23, 2016)</a></h3>
<div class='topic'><!-- START: 5.2.0.1 -->
<p>
Juno 5.2.0.1 is a moderate update.
</p>
<h5 class='topic w800'>com.ibm.team.juno</h5>
<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><dc>ObjectList.getAt(Class,String)</dc>
<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><dc>ObjectMap.getAt(Class,String)</dc>
<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><dc>@ThreadSafe</dc> annotation.
<li>New <c>ClassFilter</c> class.
<li><dc>ConfigFile.getResolving(StringVarResolver,boolean)</dc> method.
<li><dc>ConfigFile.getStringVar()</dc> method.
<li>New <dc>ParserContext.PARSER_trimStrings</dc> property.
<li>New <dc>SerializerContext.SERIALIZER_trimStrings</dc> property.
<li><dc>Args.getStringVar()}</dc> 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 <dc>StringMapVar</dc> class.
<li>New <dc>StringVars</dc> class with reusable common <dc>StringVar</dc> instances.
<li>New {@link org.apache.juneau.internal.JuneauLogger} class.
<li>Default value for <dc>XmlParserContext.XML_trimWhitespace</dc> changed to <jk>true</jk>.
</ul>
<h5 class='topic w800'>Server</h5>
<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>
<h5 class='topic w800'>Client</h5>
<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><!-- END: 5.2.0.1 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#6.0.0' id='6.0.0'>6.0.0 (Oct 3, 2016)</a></h3>
<div class='topic'><!-- START: 6.0.0 -->
<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>
<h5 class='topic w800'>org.apache.juneau</h5>
<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 - <c>org.apache.juneau.svl</c>.
<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><dc>@BeanProperty(beanDictionary)</dc> - Define a type dictionary
for a particular bean property value. This overrides the value specified using {@link org.apache.juneau.BeanContext#BEAN_beanDictionary}.
<li><dc>SerializerContext.SERIALIZER_addBeanTypeProperties</dc> - Controls whether type properties are serialized.
</ul>
In addition, the {@link org.apache.juneau.annotation.Bean#typeName() @Bean(typeName)} value replaces the <c>@Xml(name)</c> 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 <c>BeanFilter</c> 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. <c>java.util.Date</c>).
<li>Renamed 'Filters' to 'BeanFilters' and 'PojoSwaps'. Filters is just too overloaded a term.
<li>Internal utility classes moved to a new <c>org.apache.juneau.internal</c> 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><c>org.apache.juneau.parser.Parser.createSession(ObjectMap,Method,Object)</c>
<li><dc>Parser.getMediaRanges()</dc>
</ul>
</li>
<li>New methods on {@link org.apache.juneau.serializer.Serializer}:
<ul>
<li><c>org.apache.juneau.serializer.Serializer.createSession(ObjectMap,Method)</c>
<li><dc>Serializer.getMediaRanges()</dc>
</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 <dc>ClassUtils.getReadableClassName(Class)</dc>.
<li>Eliminated the <c>ClassFilter</c> 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 <dc>BeanContext.convertToType(Object,Class)</dc>.
<li>New properties on {@link org.apache.juneau.html.HtmlSerializer}:
<ul>
<li><dc>HtmlSerializerContext.HTML_detectLinksInStrings</dc> - Automatically detect hyperlinks in strings.
<li><dc>HtmlSerializerContext.HTML_lookForLabelParameters</dc> - Specify anchor text by appending <c>&amp;label=MyLabel</c> to URL.
<li><dc>HtmlSerializerContext.HTML_labelParameter</dc> - Specify what URL parameter to use as the anchor text label.
<li><dc>HtmlSerializerContext.URI_ANCHOR</dc> option for <dc>HtmlSerializerContext.HTML_uriAnchorText</dc>.
</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 <c>@Transform</c> annotation to <dc>@Pojo</dc> 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>
<h5 class='topic w800'>org.apache.juneau.rest</h5>
<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 <c>ResourceOptions</c> and related code.
<li>New annotations and related methods:
<ul>
<li><dc>@RestResource(title)</dc> / {@link org.apache.juneau.rest.RestInfoProvider#getTitle(RestRequest)}
<li><dc>@RestResource(description)</dc> / {@link org.apache.juneau.rest.RestInfoProvider#getDescription(RestRequest)}
<li><dc>@RestResource(termsOfService)</dc> / <dc>RestInfoProvider.getTermsOfService(RestRequest)</dc>
<li><dc>@RestResource(contact)</dc> / <dc>RestInfoProvider.getContact(RestRequest)</dc>
<li><dc>@RestResource(license)</dc> / <dc>RestInfoProvider.getLicense(RestRequest)</dc>
<li><dc>@RestResource(version)</dc> / <dc>RestInfoProvider.getVersion(RestRequest)</dc>
<li><dc>@RestResource(tags)</dc> / <dc>RestInfoProvider.getTags(RestRequest)</dc>
<li><dc>@RestResource(externalDocs)</dc> / <dc>RestInfoProvidergetExternalDocs(RestRequest)</dc>
<li>{@link org.apache.juneau.rest.annotation.RestMethod#summary() @RestMethod(summary)} / <dc>RestInfoProvider.getMethodSummary(String,RestRequest)</dc>
<li>{@link org.apache.juneau.rest.annotation.RestMethod#description() @RestMethod(description)} /<dc>RestInfoProvider.getMethodDescription(String,RestRequest)</dc>
<li><dc>@RestMethod(externalDocs)</dc>
<li><dc>@RestMethod(tags)</dc>
<li><dc>@RestMethod(deprecated)</dc>
<li><dc>@RestMethod(parameters)</dc>
<li><dc>@RestMethod(responses)</dc>
</ul>
</li>
</ul>
<li>New <dc>RestServletContext.paramFormat</dc> context property.
<li>New/updated methods on {@link org.apache.juneau.rest.RestServlet}:
<ul>
<li><dc>RestServlet.createProperties()</dc>
<li><dc>RestServlet.createBeanContext(ObjectMap,Class[],Class[])</dc>
<li><dc>RestServlet.createBeanFilters()</dc>
<li><dc>RestServlet.createPojoSwaps()</dc>
<li><dc>RestServlet.createParsers(ObjectMap,Class[],Class[])</dc>
<li><dc>RestServlet.createUrlEncodingSerializer(ObjectMap,Class[],Class[])</dc>
<li><dc>RestServlet.createUrlEncodingParser(ObjectMap,Class[],Class[])</dc>
<li><dc>RestServlet.createConverters(ObjectMap)</dc>
<li><dc>RestServlet.createDefaultRequestHeaders(ObjectMap)</dc>
<li><dc>RestServlet.createDefaultResponseHeaders(ObjectMap)</dc>
<li><dc>RestServlet.createEncoders(ObjectMap)</dc>
<li><dc>RestServlet.createGuards(ObjectMap)</dc>
<li><dc>RestServlet.createMimetypesFileTypeMap(ObjectMap)</dc>
<li><dc>RestServlet.createResponseHandlers(ObjectMap)</dc>
</ul>
</li>
<li>New client-version annotations:
<ul>
<li><dc>RestResource.clientVersionHeader</dc> - 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>
<h5 class='topic w800'>org.apache.juneau.rest.client</h5>
<ul class='spaced-list'>
<li>Removed the <c>JazzRestClient</c> class.
<li>New method <dc>RestClient.setClientVersion(String)</dc>.
</ul>
</div><!-- END: 6.0.0 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#6.0.1' id='6.0.1'>6.0.1 (Jan 3, 2017)</a></h3>
<div class='topic'><!-- START: 6.0.1 -->
<p>
Juneau 6.0.1 is a minor update.
</p>
<h5 class='topic w800'>org.apache.juneau</h5>
<ul class='spaced-list'>
<li>General improvements to JSON parser.
<ul>
<li>Several fixes to handle obscure edge cases.
</ul>
<li>New properties in <dc>ParserContext</dc>.
<ul>
<li><dc>ParserContext.PARSER_strict</dc>
<li><dc>ParserContext.PARSER_inputStreamCharset</dc>
<li><dc>ParserContext.PARSER_fileCharset</dc>
</ul>
<li>Removed <c>JsonParserContext.JSON_strictMode</c>. Replaced by <c>PARSER_strict</c>.
<li><c><jk>byte[]</jk></c> arrays can now be passed to {@link org.apache.juneau.parser.Parser#parse(Object,Class)} for reader-based parsers.
</ul>
</div><!-- END: 6.0.1 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#6.1.0' id='6.1.0'>6.1.0 (Feb 25, 2017)</a></h3>
<div class='topic'><!-- START: 6.1.0 -->
<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>
<h5 class='topic w800'>org.apache.juneau</h5>
<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 <dc>org.apache.juneau.xml</dc> documentation.
<li>Eliminated unnecessary <xt>&lt;string&gt;</xt> elements.
<li>Eliminated <dc>XmlContentHandler</dc> 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 <c>addJsonTypeAttrs</c> and <c>addJsonStringTypeAttrs</c> settings.
<li>Namespace support is now disabled by default.
</ul>
<li>Significant modifications and improvements to HTML serialization support.
<ul>
<li>Parser converted from <c>XMLEventReader</c>-based to <c>XMLStreamReader</c>.
<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 <dc>org.apache.juneau.html</dc> documentation.
</ul>
<li>New HTML5 DTO support: <dc>org.apache.juneau.dto.html5</dc>.
<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><dc>SerializerContext</dc> and <dc>ParserContext</dc>
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. <c>parseMap()</c>, <c>parseCollection()</c>)
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 <c>ClassMeta</c> object.
<br>For example:
<p class='bcode w800'>
<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 <c>ClassMeta</c> objects.
<li>No need for casting anymore if you were using the old <c>parseMap()</c> and <c>parseCollection()</c> methods!
<li>Changes allow me to eliminate <c>BeanContext.normalizeClassMeta()</c> method.
<li>Convenience methods added for setting parser properties:
<p class='bcode w800'>
<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 w800'>
<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 <c>toObjectMap()</c> and <c>fromObjectMap()/T(ObjectMap)</c> methods with
generalized <c>swap(BeanSession)</c>/<c>unswap(BeanSession,X)</c>/<c>T(BeanSession,X)</c> methods.<br>
See new section <dc>Swap methods</dc> 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() @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() @Bean(typeName)}.
<li>New <dc>@Bean(beanDictionary)</dc> annotation.
</ul>
<li>Removed restriction on getters and setters to be prefixed with "getX/setX/isX" if a <dc>@BeanProperty(name)</dc> 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 <dc>org.apache.juneau.dto.atom</dc> 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 <c>getMapClassMeta()</c>/<c>getCollectionClassMeta()</c> methods.
<li>New section added to this document: <dc>Juneau Data Transfer Objects (org.apache.juneau.dto)</dc>
<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 <c>UonParser.<jsf>DEFAULT_WS_AWARE</jsf></c> and <c>UrlEncodingParser.<jsf>DEFAULT_WS_AWARE</jsf></c> 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 <c>UonParserContext.<jsf>UON_whitespaceAware</jsf></c> configuration setting.
<li>Eliminated the <c>UonSerializer.<jsf>DEFAULT_SIMPLE</jsf></c>, <c>UonSerializer.<jsf>DEFAULT_SIMPLE_ENCODING</jsf></c>
and <c>UrlEncodingSerializer.<jsf>DEFAULT_SIMPLE</jsf></c>
serializers since there is no separate simple mode anymore.
<li>Eliminated the <c>UonParserContext.<jsf>UON_simpleMode</jsf></c> configuration setting.
</ul>
<li>Added new <dc>OutputStreamSerializer.serializeToHex(Object)</dc> 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 <c><ja>@Bean</ja>(subTypeProperty)</c> and <c><ja>@Bean</ja>(subTypes)</c> annotations
and replaced them with the ability to define subtypes using the existing <dc>@Bean(beanDictionary)</dc>
annotation on parent classes and interfaces.
<br>This has the added benefit of simplifying the overall code.
<li>The <dc>SerializerContext.SERIALIZER_addBeanTypeProperties</dc> setting is now enabled by default.
<li>Combined the <c>SERIALIZER_addIndentation</c>/<c>JSON_addWhitespace</c>/<c>UON_addWhitespace</c>
properties into a single <dc>SerializerContext.SERIALIZER_useWhitespace</dc> setting.
</ul>
<h5 class='topic w800'>org.apache.juneau.rest</h5>
<ul class='spaced-list'>
<li>{@link org.apache.juneau.rest.RestRequest} now passes locale and timezone to serializers/parsers/transforms.
<li><dc>RestRequest.getTimeZone()</dc> method.
<li>Standardized the following methods in {@link org.apache.juneau.rest.RestRequest} to remove dependency on <c>ClassMeta</c>
objects and eliminate the need for casts:
<ul>
<li><dc>RestRequest.getHeader(String,Class)</dc>
<li><dc>RestRequest.getHeader(String,Object,Class)</dc>
<li><dc>RestRequest.getHeader(String,Type,Type...)</dc>
<li><dc>RestRequest.getQueryParameter(String,Class)</dc>
<li><dc>RestRequest.getQueryParameter(String,Object,Class)</dc>
<li><dc>RestRequest.getQueryParameter(String,Type,Type...)</dc>
<li><dc>RestRequest.getQueryParameter(String,Object,Type,Type...)</dc>
<li><dc>RestRequest.getQueryParameters(String,Class)</dc>
<li><dc>RestRequest.getQueryParameters(String,Type,Type...)</dc>
<li><dc>RestRequest.getFormDataParameter(String,Class)</dc>
<li><dc>RestRequest.getFormDataParameter(String,Object,Class)</dc>
<li><dc>RestRequest.getFormDataParameters(String,Class)</dc>
<li><dc>RestRequest.getFormDataParameter(String,Type,Type...)</dc>
<li><dc>RestRequest.getFormDataParameters(String,Type,Type...)</dc>
<li><dc>RestRequest.getPathParameter(String,Class)</dc>
<li><dc>RestRequest.getPathParameter(String,Type,Type...)</dc>
<li><dc>RestRequest.getBody(Class)</dc>
<li><dc>RestRequest.getBody(Type,Type...)</dc>
</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 <c>&amp;plainText=true</c> specified.
</ul>
</div><!-- END: 6.1.0 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#6.2.0' id='6.2.0'>6.2.0 (Apr 28, 2017)</a></h3>
<div class='topic'><!-- START: 6.2.0 -->
<p>
Juneau 6.2.0 is a major update.
</p>
<h5 class='topic w800'>org.apache.juneau</h5>
<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 w800'>
<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 = JsonSerializer.<jsm>create</jsm>().ws().pojoSwaps(BSwap.<jk>class</jk>).build();
<jc>/* Cloning an existing serializer or parser */ </jc>
<jc>// Old way</jc>
WriterSerializer s = SimpleJsonSerializer.<jsf>DEFAULT</jsf>
.clone().setUseWhitespace(<jk>true</jk>).pojoSwaps(BSwap.<jk>class</jk>).lock();
<jc>// New way</jc>
WriterSerializer s = SimpleJsonSerializer.<jsf>DEFAULT</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: <dc>ConfigFileBuilder</dc>.
<li>Removed the <dc>Lockable</dc> interface.
<li>New <c>addBeanTypeProperties</c> setting added to serializers to override the
<dc>SerializerContext.SERIALIZER_addBeanTypeProperties</dc> setting
for individual serializers in a serializer group:
<ul>
<li><dc>HtmlSerializerContext.HTML_addBeanTypeProperties</dc>
<li><dc>JsonSerializerContext.JSON_addBeanTypeProperties</dc>
<li><dc>MsgPackSerializerContext.MSGPACK_addBeanTypeProperties</dc>
<li><dc>UonSerializerContext.UON_addBeanTypeProperties</dc>
<li><dc>XmlSerializerContext.#XML_addBeanTypeProperties</dc>
<li><dc>RdfSerializerContext.RDF_addBeanTypeProperties</dc>
</ul>
<li>UON notation serializers and parsers moved into the new <c>org.apache.juneau.uon</c> 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 <c>style()</c> 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 <dc>here</dc> and in the <del>org.apache.juneau.dto.swagger</del> 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><dc>$SWITCH</dc> 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: <dc>SerializerContext.SERIALIZER_abridged</dc>.
<li>Support for defining interface proxies against 3rd-party REST interfaces.
<br>New package <dc>org.apache.juneau.remoteable</dc> for all remoteable proxy interface annotations.
<br><ja>@Remoteable</ja> annotation has been moved to this package.
<li>Updated doc: <dc>6 - Remoteable Services</dc>
<li>New doc: <dc>6.1 - Interface proxies against 3rd-party REST interfaces</dc>
<li>New URL-encoding serializer setting: <dc>UrlEncodingSerializerContext.URLENC_paramFormat</dc>.
<li>New methods on {@link org.apache.juneau.urlencoding.UrlEncodingSerializerBuilder}:
<ul>
<li><dc>UrlEncodingSerializerBuilder.paramFormat(String)</dc>
<li><dc>UrlEncodingSerializerBuilder.plainTextParams()</dc>
</ul>
</ul>
<h5 class='topic w800'>org.apache.juneau.rest</h5>
<ul class='spaced-list'>
<li><dc>@RestResource</dc> 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 <c>RestServlet</c>
should have an equivalent for non-<c>RestServlet</c> classes.
<br>The only restriction is that the top-level resource must subclass from <c>RestServlet</c>.
Child resources do not.
<br><br>
The majority of code has been split up into two separate classes:
<ul>
<li><dc>RestConfig</dc> - 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><dc>RestServlet.init(RestConfig)</dc> - A modifiable configuration of a resource.
</ul>
Non-<c>RestServlet</c> classes must have one of the following to allow it to be instantiated:
<ul>
<li>A <c><jk>public</jk> T(RestConfig)</c> constructor.
<li>A <c><jk>public</jk> T()</c> constructor.
<li>The parent resource must have a customized {@link org.apache.juneau.rest.RestResourceResolver} for instantiating it.
</ul>
<br>
Non-<c>RestServlet</c> classes can optionally include the following init methods to gain access to the config and context:
<ul>
<li><dc><jk>public</jk> init(RestConfig)</dc>
<li><dc><jk>public</jk> init(RestContext)</dc>
</ul>
<li>New annotations added to <dc>@RestResource</dc> to allow non-<c>RestServlet</c>
resources to do the same as subclassing directly from <c>RestServlet</c>:
<ul>
<li><dc>RestResource.resourceResolver()</dc>
- Specify a {@link org.apache.juneau.rest.RestResourceResolver} class for resolving child resources.
<li><dc>RestResource.callHandler()</dc>
- Specify a {@link org.apache.juneau.rest.RestCallHandler} class for handling the lifecycle of a REST call.
<li><dc>RestResource.infoProvider()</dc>
- Specify a {@link org.apache.juneau.rest.RestInfoProvider} class for customizing title/description/Swagger information on a REST resource.
<li><dc>RestResource.logger()</dc>
- Specify a {@link org.apache.juneau.rest.RestLogger} class for handling logging.
</ul>
<li>New annotations added to <dc>@RestResource</dc> and {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod}
to simplify defining page title, text, and links on HTML views:
<ul>
<li><dc>@RestResource(pageTitle)</dc>
<li><dc>@RestMethod(pageTitle)</dc>
<li><dc>@RestResource(pageText)</dc>
<li><dc>@RestMethod(pageText)</dc>
<li><dc>@RestResource(pageLinks)</dc>
<li><dc>@RestMethod(pageLinks)</dc>
</ul>
<p class='bcode w800'>
<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_navlinks</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 <c>title</c> and <c>description</c> annotations
which apply to both the page title/text and the swagger doc:
</p>
<p class='bcode w800'>
<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><dc>RestResource.stylesheet()</dc> can now take in a comma-delimited list of stylesheet paths.
<li><dc>StreamResource</dc> can now contain multiple sources from a variety of source types (e.g. <c><jk>byte</jk>[]</c> arrays, <c>InputStreams</c>, <c>Files</c>, etc...)
and is now immutable. It also includes a new <dc>StreamResourceBuilder</dc> class.
<li>Simplified remoteable proxies using the <c><ja>@RestMethod</ja>(name=<js>"PROXY"</js>)</c> annotation on REST methods.
Used to expose interface proxies without the need for <dc>RemoteableServlet</dc>.
<p class='bcode w800'>
<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 = RestClient.<jsm>create</jsm>().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() @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>{@link org.apache.juneau.rest.annotation.RestMethod#name() @RestMethod(name)} annotation is now optional. Defaults to <js>"GET"</js>.
</ul>
<h5 class='topic w800'>org.apache.juneau.rest.client</h5>
<ul class='spaced-list'>
<li>Revamped the client API to use builders.
<li>New doc: <del>1.5 - Debugging</del>
<li>The <c>RestClient</c> class <c>doX(Object url)</c> methods now handle HttpClient <c>URIBuilder</c> instances.
<li>New methods added/updated to {@link org.apache.juneau.rest.client.RestClient}:
<ul>
<li><dc>RestClient.getRemoteableProxy(Class,Object)</dc> - For interface proxies defined using <c><ja>@RestMethod</ja>(name=<js>"PROXY"</js>)</c>.
<li><dc>RestClient.getRemoteableProxy(Class,Object,Serializer,Parser)</dc> - 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><dc>query(String,Object,boolean,PartSerializer)</dc>
<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><dc>formData(String,Object,boolean,PartSerializer)</dc>
<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><dc>header(String,Object,boolean,PartSerializer)</dc>
<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><dc>RestClientBuilder.plainTextParams()</dc>
<li>{@link org.apache.juneau.rest.client.RestClientBuilder#noTrace() noTrace()} - Adds a <c>No-Trace: true</c> 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 <c>Debug: true</c> 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><dc>input(Object)</dc> - 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 <c>HttpResponse</c> returned by the inner <c>HttpClient</c>.
<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><dc>append(String,Object,PartSerializer)</dc>
</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>
<h5 class='topic w800'>org.apache.juneau.microservice</h5>
<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 <c>0</c>s to try a random port.
<li>Methods added to <dc>RestMicroservice</dc> class:
<ul>
<li><dc>getPort()</dc>
<li><dc>getURI()</dc>
<li>Override methods added from {@link org.apache.juneau.microservice.Microservice} class for easier method chaining.
</ul>
</ul>
</div><!-- END: 6.2.0 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#6.3.0' id='6.3.0'>6.3.0 (Jun 30, 2017)</a></h3>
<div class='topic'><!-- START: 6.3.0 -->
<p>
Juneau 6.3.0 is a major update with significant new functionality for defining proxy interfaces against
arbitrary 3rd-party REST interfaces.
</p>
<h5 class='topic w800'>org.apache.juneau</h5>
<ul class='spaced-list'>
<li>
New package: {@link org.apache.juneau.http}.
<li>
Support for dynamic beans. See <dc>@BeanProperty(name)</dc>.
<li>
New doc: <dc>2.8 - Virtual Beans</dc>
<li>
New doc: <dc>2.13 - Comparison with Jackson</dc>
<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 w800'>
<jc>// Example</jc>
<jk>int</jk> i = JsonParser.<jsf>DEFAULT</jsf>.parse(<js>"123M"</js>); <jc>// 123MB</jc>
</p>
<li>New/modified methods on <dc>ConfigFile</dc>:
<ul>
<li><dc>ConfigFile.put(String,String,String,boolean)</dc>
<li><dc>ConfigFile.put(String,String,Object,Serializer,boolean,boolean)</dc>
<li><dc>ConfigFile.getObject(String,Type,Type...)</dc>
<li><dc>ConfigFile.getObject(String,Parser,Type,Type...)</dc>
<li><dc>ConfigFile.getObject(String,Class)</dc>
<li><dc>ConfigFile.getObject(String,Parser,Class)</dc>
<li><dc>ConfigFile.getObject(String,String,Type,Type...)</dc>
<li><dc>ConfigFile.getObject(String,String,Parser,Type,Type...)</dc>
<li><dc>ConfigFile.getObject(String,String,Class)</dc>
<li><dc>ConfigFile.getObject(String,String,Parser,Class)</dc>
<li><dc>ConfigFile.getObjectWithDefault(String,Object,Type,Type...)</dc>
<li><dc>ConfigFile.getObjectWithDefault(String,Parser,Object,Type,Type...)</dc>
<li><dc>ConfigFile.getObjectWithDefault(String,Object,Class)</dc>
<li><dc>ConfigFile.getObjectWithDefault(String,Parser,Object,Class)</dc>
</ul>
<li>New ability to interact with config file sections with proxy interfaces with new method <dc>ConfigFile.getSectionAsInterface(String,Class)</dc>.
<li><dc>@BeanProperty</dc> 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><dc>Session.getProperty(String)</dc>
<li><dc>Session.getProperty(String,String)</dc>
<li><dc>Session.getProperty(Class,String)</dc>
<li><dc>Session.getProperty(Class,String,Object)</dc>
</ul>
<li>New <dc>org.apache.juneau.serializer.PartSerializer</dc> 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><dc>org.apache.juneau.rest.client.RestClientBuilder.partSerializer(Class)</dc>
<li><dc>org.apache.juneau.remoteable.Path.serializer</dc>
<li><dc>org.apache.juneau.remoteable.Query.serializer</dc>
<li><dc>org.apache.juneau.remoteable.QueryIfNE.serializer</dc>
<li><dc>org.apache.juneau.remoteable.FormData.serializer</dc>
<li><dc>org.apache.juneau.remoteable.FormDataIfNE.serializer</dc>
<li><dc>org.apache.juneau.remoteable.Header.serializer</dc>
<li><dc>org.apache.juneau.remoteable.HeaderIfNE.serializer</dc>
</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 w800'>
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 w800'>
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><dc>SerializerContext.SERIALIZER_uriContext</dc>
<li><dc>SerializerContext.SERIALIZER_uriRelativity</dc>
<li><dc>SerializerContext.SERIALIZER_uriResolution</dc>
<li><dc>SerializerContext.SERIALIZER_maxIndent</dc>
</ul>
<li>New annotation property: <dc>@BeanProperty(value)</dc>.
<br>The following two annotations are considered equivalent:
<p class='bcode w800'>
<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 <dc>UonSerializer.UON_paramFormat</dc>,
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><dc>@RestResource(serializerListener)</dc>
<li><dc>RestConfig.serializerListener(Class)</dc>
<li>{@link org.apache.juneau.parser.ParserListener}
<li>{@link org.apache.juneau.parser.ParserBuilder#listener(Class)}
<li><dc> @RestResource(parserListener)</dc>
<li><dc>RestConfig.parserListener(Class)</dc>
<li><dc>RestClientBuilder.listeners(Class,Class)</dc>
</ul>juneau-examples-core.import1.pngjuneau-examples-core.import1.png
<li>The {@link org.apache.juneau.BeanContext#BEAN_debug} flag will now capture parser input and make it
available through the <dc>ParserSession.getInputAsString()</dc> 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/ReleaseNotes.630.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><dc>HtmlDocSerializerContext.HTMLDOC_title</dc>
<li><dc>HtmlDocSerializerContext.HTMLDOC_description</dc>
<li><dc>HtmlDocSerializerContext.HTMLDOC_branding</dc>
<li><dc>HtmlDocSerializerContext.HTMLDOC_header</dc>
<li><dc>HtmlDocSerializerContext.HTMLDOC_nav</dc>
<li><dc>HtmlDocSerializerContext.HTMLDOC_aside</dc>
<li><dc>HtmlDocSerializerContext.HTMLDOC_footer</dc>
<li><dc>HtmlDocSerializerContext.HTMLDOC_noResultsMessage</dc>
<li><dc>HtmlDocSerializerContext.HTMLDOC_cssUrl</dc>
<li><dc>HtmlDocSerializerContext.HTMLDOC_css</dc>
<li><dc>HtmlDocSerializerContext.HTMLDOC_template</dc>
</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><dc>BEAN_includeProperties</dc>
<li><dc>BEAN_excludeProperties</dc>
</ul>
<li>New annotation property: <dc>@BeanProperty(format)</dc>.
</ul>
<h5 class='topic w800'>org.apache.juneau.rest</h5>
<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.RequestPath}
</ul>
<li>
The un-annotated 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 <c>RestRequest</c>.
<li>{@link org.apache.juneau.rest.RestResponse} - The response object.
<li>{@link javax.servlet.http.HttpServletResponse} - The superclass of <c>RestResponse</c>.
</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.RequestPath} - 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 <c><ja>@RestMethod</ja>(name=<js>"*"</js>)</c>)
<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><dc>ConfigFile</dc> - The external config file for the resource.
</ul>
So, for example...
<p class='bcode w800'>
<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>(<js>"a1"</js>) String a1,
<ja>@Path</ja>(<js>"a2"</js>) <jk>int</jk> a2,
<ja>@Path</ja>(<js>"a3"</js>) 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 <dc>@RestResource(paramResolvers)</dc>}
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 annotations 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><dc>bpIncludes()</dc>
<li><dc>bpExcludes()</dc>
</ul>
<li>
Default values on header, query, and form-data annotations:
<ul>
<li><dc>@Header(def)</dc> - Default header value.
<li><dc>@Query(def)</dc> - Default query parameter value.
<li><dc>@FormData(def)</dc> - Default form data parameter value.
</ul>
<li>
New attributes on <dc>@RestResource</dc>:
<ul>
<li><dc>serializerListener()</dc>
<li><dc>parserListener()</dc>
<li><dc>widgets()</dc>
<li><dc>swagger()</dc>
<li><dc>htmldoc()</dc>
</ul>
<li>
New attributes on {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod}:
<ul>
<li><dc>widgets()</dc>
<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 <dc>RestConfig</dc>:
<ul>
<li><dc>setHtmlTitle(String)</dc>
<li><dc>setHtmlDescription(String)</dc>
<li><dc>setHtmlBranding(String)</dc>
<li><dc>setHtmlHeader(String)</dc>
<li><dc>setHtmlLinks(String)</dc>
<li><dc>setHtmlNav(String)</dc>
<li><dc>setHtmlAside(String)</dc>
<li><dc>setHtmlFooter(String)</dc>
<li><dc>setHtmlCss(String)</dc>
<li><dc>setHtmlCssUrl(String)</dc>
<li><dc>setHtmlNoWrap(boolean)</dc>
<li><dc>setHtmlNoResultsMessage(String)</dc>
<li><dc>setHtmlTemplate(Class)</dc>
<li><dc>setHtmlTemplate(HtmlDocTemplate)</dc>
<li><dc>addWidget(Class)</dc>
</ul>
<li>
New methods on {@link org.apache.juneau.rest.RestResponse}:
<ul>
<li><dc>setHtmlTitle(Object)</dc>
<li><dc>setHtmlDescription(Object)</dc>
<li><dc>setHtmlBranding(Object)</dc>
<li><dc>setHtmlHeader(Object)</dc>
<li><dc>setHtmlLinks(Object)</dc>
<li><dc>setHtmlNav(Object)</dc>
<li><dc>setHtmlAside(Object)</dc>
<li><dc>setHtmlFooter(Object)</dc>
<li><dc>setHtmlCss(Object)</dc>
<li><dc>setHtmlCssUrl(Object)</dc>
<li><dc>setHtmlNoWrap(boolean)</dc>
<li><dc>setHtmlNoResultsMessage(Object)</dc>
<li><dc>setHtmlTemplate(Class)</dc>
<li><dc>setHtmlTemplate(HtmlDocTemplate)</dc>
</ul>
<li>
<c>&amp;plainText=true</c> 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><dc>PoweredByJuneauWidget</dc>
<li><dc>ContentTypeLinksColumnWidget</dc>
<li><dc>ContentTypeLinksRowWidget</dc>
<li><dc>QueryWidget</dc>
</ul>
<li>
<c>devops.css</c> 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.http.annotation.Query#name() @Query(name)}
<li>{@link org.apache.juneau.http.annotation.FormData#name() @FormData(name)}
<li>{@link org.apache.juneau.http.annotation.Header#name() @Header(name)}
<li>{@link org.apache.juneau.http.annotation.Path#name() @Path(name)}
<li>{@link org.apache.juneau.http.annotation.HasQuery#name() @HasQuery(name)}
<li>{@link org.apache.juneau.http.annotation.HasFormData#name() @HasFormData(name)}
</ul>
</li>
</ul>
<h5 class='topic w800'>org.apache.juneau.rest.client</h5>
<ul class='spaced-list'>
<li>
New <dc>org.apache.juneau.remoteable.Path</dc> annotation for specifying path variables on remoteable interfaces.
<li>
New <dc>@RequestBean</dc> annotation for specifying beans with remoteable annotations
defined on properties.
<li>
The following annotations (and related methods on RestCall) can now take <c>NameValuePairs</c> and beans as input
when using <js>"*"</js> as the name.
<br><dc>org.apache.juneau.remoteable.FormData</dc>,<dc>org.apache.juneau.remoteable.FormDataIfNE</dc>,
<dc>org.apache.juneau.remoteable.Query</dc>,<dc>org.apache.juneau.remoteable.QueryIfNE</dc>,
<dc>org.apache.juneau.remoteable.Header</dc>,<dc>org.apache.juneau.remoteable.HeaderIfNE</dc>
</ul>
<h5 class='topic w800'>org.apache.juneau.microservice</h5>
<ul class='spaced-list'>
</ul>
<h5 class='topic w800'>org.apache.juneau.examples.rest</h5>
<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/ReleaseNotes.630.2.png'>
</ul>
</div><!-- END: 6.3.0 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#6.3.1' id='6.3.1'>6.3.1 (Aug 1, 2017)</a></h3>
<div class='topic'><!-- START: 6.3.1 -->
<p>
Juneau 6.3.1 is a minor release.
</p>
<h5 class='topic w800'>org.apache.juneau</h5>
<ul class='spaced-list'>
<li>
{@link org.apache.juneau.utils.PojoQuery} improvements.
<li>
New <dc>RemoteMethod.returns()</dc> annotation.
<br>Allows you to specify whether the remote method returns the HTTP body or status code.
<li>
Fixed bugs with <dc>BEAN_includeProperties</dc> and <dc>BEAN_excludeProperties</dc> settings.
<li>
New/modified settings in <dc>HtmlDocSerializerContext</dc>:
<ul>
<li><dc>HTMLDOC_script</dc>
<li><dc>HTMLDOC_style</dc> - Was <jsf>HTMLDOC_css</jsf>.
<li><dc>HTMLDOC_stylesheet</dc> - Was <jsf>HTMLDOC_cssUrl</jsf>. Now an array.
</ul>
<li>
New <dc>ResourceFinder</dc> utility class.
Allows you to search for resources up the parent hierarchy chain.
Also allows you to search for localized resources.
<li>
Eliminated the following properties from <dc>HtmlDocSerializerContext</dc>:
<jsf>HTMLDOC_title</jsf>, <jsf>HTMLDOC_description</jsf>, <jsf>HTMLDOC_description</jsf>
<br>See below on changes to simplify HTML headers.
<li>
{@link org.apache.juneau.svl.Var} implementations can now throw exceptions and will be converted to
<js>""{exceptionMessage}"</js> values.
</ul>
<h5 class='topic w800'>org.apache.juneau.rest</h5>
<ul class='spaced-list'>
<li>
New 'light' stylesheet:
<br><img src='doc-files/ReleaseNotes.631.LightStyle.png'>
<br>Compared with previous 'devops':
<br><img src='doc-files/ReleaseNotes.631.DevopsStyle.png'>
<br>For those nolstalgic for old times, there's also 'original':
<br><img src='doc-files/ReleaseNotes.631.OriginalStyle.png'>
<li>
Simplified the stylesheets and HTML code.
<br>For example, the nav links are now an ordered list of elements which makes rendering as as side-bar
(for example) easier to do in CSS.
<li>
Modifications to the following <ja>@HtmlDoc</ja> annotations:
<ul>
<li>{@link org.apache.juneau.rest.annotation.HtmlDoc#navlinks() navlinks()} - Now an array of strings instead of a JSON object. Simplified syntax.
<br>For example:
<p class='bcode w800'>
<jc>// Old syntax</jc>
htmldoc=<ja>@HtmlDoc</ja>(
links=<js>"{"</js>
+ <js>"up:'request:/..',"</js>
+ <js>"options:'servlet:/?method=OPTIONS',"</js>
+ <js>"contentTypes:'$W{ContentTypeMenuItem}',"</js>
+ <js>"styles:'$W{StyleMenuItem}',"</js>
+ <js>"source:'$C{Source/gitHub}/org/apache/juneau/examples/rest/PetStoreResource.java'"</js>
+ <js>"}"</js>
)
<jc>// New syntax</jc>
htmldoc=<ja>@HtmlDoc</ja>(
navlinks={
<js>"up: request:/.."</js>,
<js>"options: servlet:/?method=OPTIONS"</js>,
<js>"$W{ContentTypeMenuItem}"</js>,
<js>"$W{StyleMenuItem}"</js>,
<js>"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/PetStoreResource.java"</js>
}
)
</p>
Previous syntax will still work, but you're encouraged to use the simplified syntax.
<li>Several annotations are now arrays of strings instead of simple strings.
Values are simply concatenated with newlines which makes multi-line values cleaner.
<ul>
<li>{@link org.apache.juneau.rest.annotation.HtmlDoc#header() header()}
<li>{@link org.apache.juneau.rest.annotation.HtmlDoc#nav() nav()}
<li>{@link org.apache.juneau.rest.annotation.HtmlDoc#aside() aside()}
<li>{@link org.apache.juneau.rest.annotation.HtmlDoc#footer() footer()}
<li>{@link org.apache.juneau.rest.annotation.HtmlDoc#script() script()}
<li>{@link org.apache.juneau.rest.annotation.HtmlDoc#style() style()}
</ul>
Additionally, the <js>"INHERIT"</js> string literal can be used to combine the value with
the value defined on the servlet or parent class. Links can also be inserted at specific
index positions.
</ul>
<li>
Improvements made to the {@link org.apache.juneau.rest.widget.Widget} API.
<ul>
<li>
You can now add arbitrary CSS and Javascript along with your widgets through new methods:
<ul>
<li><dc>Widget#getHtml(RestRequest)</dc>
<li><dc>Widget#getScript(RestRequest)</dc>
<li><dc>Widget#getStyle(RestRequest)</dc>
</ul>
</li>
<li>
Declaration of widgets moved to {@link org.apache.juneau.rest.annotation.HtmlDoc#widgets() @HtmlDoc(widgets)}
instead of separately on <dc>@RestResource</dc> and <ja>@RestMethod</ja> annotations.
<li>
{@link org.apache.juneau.rest.widget.Widget#getName()} now defaults to the simple class name.
<br>So now you can just refer to the class name: <js>"$W{ContentTypeMenuItem}"</js>.
<li>
Renamed widgets:
<ul>
<li><c>PoweredByApacheWidget</c> -&gt; <c>PoweredByApache</c>
<li><c>PoweredByJuneauWidget</c> -&gt; <c>PoweredByJuneau</c>
</ul>
<li>
New {@link org.apache.juneau.rest.widget.MenuItemWidget} can be used as a starting point for creatint pull-down menu items.
<li>
New {@link org.apache.juneau.rest.widget.ContentTypeMenuItem} widget that provides a pull-down menu
with hyperlinks for all supported languages for that page:
<br><img src='doc-files/ReleaseNotes.631.ContentTypeMenuItem.png'>
<li>
Improved {@link org.apache.juneau.rest.widget.QueryMenuItem} widget that provides a pull-down menu
of a search/view/order-by/page form:
<br><img src='doc-files/ReleaseNotes.631.QueryMenuItem.png'>
<br>Fields are now pre-filled with current query parameters.
<li>
New {@link org.apache.juneau.rest.widget.ThemeMenuItem} widget that provides a pull-down menu
with hyperlinks to show the content in the default stylesheets:
<br><img src='doc-files/ReleaseNotes.631.StyleMenuItem.png'>
</ul>
<li>
New/modified annotations on {@link org.apache.juneau.rest.annotation.HtmlDoc @HtmlDoc}:
<ul>
<li>{@link org.apache.juneau.rest.annotation.HtmlDoc#style() style()} - Renamed from <c>css()</c>.
<li>{@link org.apache.juneau.rest.annotation.HtmlDoc#stylesheet() stylesheet()} - Renamed from <c>cssUrl()</c>.
<br>Can now be a comma-delimited list of URLs.
<li>{@link org.apache.juneau.rest.annotation.HtmlDoc#script() script()} - Add arbitrary Javascript to page header.
</ul>
<li>
Bug fix with {@link org.apache.juneau.rest.annotation.HtmlDoc#nowrap() @HtmlDoc(nowrap)} so that the setting only applies
to the data contents, not the whole page.
<li>
Two convenience methods added to {@link org.apache.juneau.rest.RestRequest}:
<ul>
<li>{@link org.apache.juneau.rest.RestRequest#attr(String,Object) attr(String,Object)}
<li>{@link org.apache.juneau.rest.RestRequest#prop(String,Object) prop(String,Object)}
</ul>
</li>
<li>
Annotations added:
<ul>
<li><dc>@RestResource(siteName)</dc>
<li><dc>@RestResource(flags)</dc>
<li>{@link org.apache.juneau.rest.annotation.RestMethod#flags() @RestMethod(flags)}
</ul>
</li>
<li>
Eliminated the <dc>@RestResource(stylesheet)</dc> annotation.
It's no longer needed now that you can easily specify styles via <ja>@Htmldoc</ja>.
<li>
Eliminated the following annotations since they are now redundant with {@link org.apache.juneau.rest.annotation.HtmlDoc#header() @HtmlDoc(header)}:
<ul>
<li><c>title()</c>
<li><c>description()</c>
<li><c>branding()</c>
</ul>
Instead, the {@link org.apache.juneau.rest.BasicRestServlet} class defines the following default header
that can be easily overridden:
<p class='bcode w800'>
htmldoc=<ja>@HtmlDoc</ja>(
header={
<js>"&lt;h1&gt;$R{resourceTitle}&lt;/h1&gt;"</js>,
<js>"&lt;h2&gt;$R{methodSummary,resourceDescription}&lt;/h2&gt;"</js>,
<js>"&lt;a href='http://juneau.apache.org'&gt;&lt;img src='$U{servlet:/htdocs/juneau.png}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/&gt;&lt;/a&gt;"</js>
}
)
</p>
Note that the subtitle first tries using the method summary and then the servlet description.
<li>
New {@link org.apache.juneau.rest.vars.FileVar $F} variable resolver for resolving the contents of
files in the classpath.
<br>The <c>DockerRegistryResource</c> examples shows how it can be used to pull in a localized
file from the classpath to populate the aside section of a page.
<p class='bcode w800'>
htmldoc=<ja>@HtmlDoc</ja>(
<jc>// Pull in aside contents from file.</jc>
aside=<js>"$F{resources/DockerRegistryResourceAside.html}"</js>
)
</p>
<li>
New <dc>ReaderResource.toCommentStrippedString()</dc> method.
<li>
The <c>bpIncludes()</c> and <c>bpExcludes()</c> annotations on <ja>@RestMethod</ja>
has been replaced with the following:
<ul>
<li>{@link org.apache.juneau.rest.annotation.RestMethod#bpi() bpi()} - Now an array of simplified values instead of LAX JSON.
<li>{@link org.apache.juneau.rest.annotation.RestMethod#bpx() bpx()} - Now an array of simplified values instead of LAX JSON.
</ul>
<li>
Two new variables added to <c>$R</c> variable: <js>"$R{servletClass}"</js>, <js>"$R{servletClassSimple}"</js>
</ul>
<h5 class='topic w800'>org.apache.juneau.rest.examples</h5>
<ul class='spaced-list'>
<li>
Added CONTENT-TYPE and STYLES menu items to most pages.
<li>
Added improved QUERY menu item to PetStore page.
</ul>
</div><!-- END: 6.3.1 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#6.4.0' id='6.4.0'>6.4.0 (Oct 5, 2017)</a></h3>
<div class='topic'><!-- START: 6.4.0 -->
<p>
The major change in this release is the project structure.
</p>
<p>
The library now consists of the following artifacts found in the Maven group <c>"org.apache.juneau"</c>:
</p>
<table class='styled w800'>
<tr>
<th>Category</th><th>Maven Artifacts</th><th>Description</th><th>Prereqs</th>
</tr>
<tr class='dark bb'>
<td rowspan='5' style='text-align:center;font-weight:bold;padding:20px;'>Juneau Core</td>
<td class='code'>juneau-marshall</td>
<td>Serializers and parsers for:
<ul style='margin:0px 10px;'>
<li>JSON
<li>XML
<li>HTML
<li>UON
<li>URL-Encoding
<li>MessagePack
<li>SOAP/XML
<li>CSV
<li>BSON (coming soon)
<li>YAML (coming soon)
<li>Protobuf (coming soon)
</ul>
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 6
</ul>
</td>
</tr>
<tr class='dark bb'>
<td class='code'>juneau-marshall-rdf</td>
<td>
Serializers and parsers for:
<ul style='margin:0px 10px;'>
<li>RDF/XML
<li>RDF/XML-Abbrev
<li>N-Triple
<li>Turtle
<li>N3
</ul>
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 6
<li>Apache Jena 2.7.1
</ul>
</td>
</tr>
<tr class='dark bb'>
<td class='code'>juneau-dto</td>
<td>
Data Transfer Objects for:
<ul style='margin:0px 10px;'>
<li>HTML5
<li>Atom
<li>Cognos
<li>JSON-Schema
<li>Swagger 2.0
</ul>
</td>
<td><ul style='margin:0px 10px;'><li>Java 6</li></ul></td>
</tr>
<tr class='dark bb'>
<td class='code'>juneau-svl</td>
<td>
Simple Variable Language API
</td>
<td><ul style='margin:0px 10px;'><li>Java 6</li></ul></td>
</tr>
<tr class='dark bb'>
<td class='code'>juneau-config</td>
<td>
Configuration file API
</td>
<td><ul style='margin:0px 10px;'><li>Java 6</li></ul></td>
</tr>
<tr class='light bb'>
<td rowspan='3' style='text-align:center;font-weight:bold;padding:20px;'>Juneau REST</td>
<td class='code'>juneau-rest-server</td>
<td>
REST Servlet API
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 6
<li>Servlet 3.1
</ul>
</td>
</tr>
<tr class='light bb'>
<td class='code'>juneau-rest-server-jaxrs</td>
<td>
Optional JAX-RS support
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 6
<li>JAX-RS 2.0
</ul>
</td>
</tr>
<tr class='light bb'>
<td class='code'>juneau-rest-client</td>
<td>
REST Client API
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 6
<li>Apache HttpClient 4.5
</ul>
</td>
</tr>
<tr class='dark bb'>
<td rowspan='2' style='text-align:center;font-weight:bold;padding:20px;'>Juneau Microservice</td>
<td class='code'>juneau-microservice-server</td>
<td>
REST Microservice Server API
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 8
<li>Eclipse Jetty 9.4.3
</ul>
</td>
</tr>
<tr class='dark bb'>
<td class='code'>juneau-microservice-template</td>
<td>
Developer template project
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 8
<li>Eclipse Jetty 9.4.3
</ul>
</td>
</tr>
<tr class='light bb'>
<td rowspan='2' style='text-align:center;font-weight:bold;padding:20px;'>Examples</td>
<td class='code'><c>juneau-examples-core</c></td>
<td>
Core code examples
</td>
<td></td>
</tr>
<tr class='light bb'>
<td class='code'><c>juneau-examples-rest</c></td>
<td>
REST code examples
</td>
<td></td>
</tr>
<tr class='dark bb'>
<td rowspan='1' style='text-align:center;font-weight:bold;padding:20px;'>Juneau All</td>
<td class='code'><c>juneau-all</c></td>
<td>
Combination of the following:
<ul style='margin:0px 10px;'>
<li>juneau-marshall
<li>juneau-dto
<li>juneau-svl
<li>juneau-config
<li>juneau-rest-server
<li>juneau-rest-client
</ul>
</td>
<td>
<ul style='margin:0px 10px;'>
<li>Java 6
<li>Servlet 3.1
<li>Apache HttpClient 4.5
</ul>
</td>
</tr>
</table>
<h5 class='topic w800'>juneau-marshall</h5>
<ul class='spaced-list'>
<li>
Improvements to swap support.
<ul>
<li>New {@link org.apache.juneau.annotation.Swap @Swap} annotation.
<br>Replaces the <c>@Pojo</c> and <dc>@BeanProperty(swap)</dc> annotations.
<li>Support for per-media-type swaps.
<br>Programmatic example:
<p class='bcode w800'>
<ja>@Swap</ja>(MyJsonOnlySwap.<jk>class</jk>)
<jk>public class</jk> MyPojo {}
<jk>public class</jk> MyJsonOnlySwap <jk>extends</jk> PojoSwap&lt;MyPojo,String&gt; {
<jk>public</jk> MediaType[] forMediaTypes() {
<jk>return</jk> MediaType.<jsm>forStrings</jsm>(<js>"&#42;/json"</js>);
}
<jk>public</jk> String swap(BeanSession session, MyPojo o) <jk>throws</jk> Exception {
<jk>return</jk> <js>"It's JSON!"</js>;
}
</p>
<br>Annotated example:
<p class='bcode w800'>
<ja>@Swap</ja>(impl=ToStringSwap.<jk>class</jk>, mediaTypes=<js>"&#42;/json"</js>)
<jk>public class</jk> MyBean { ... }
<jk>public class</jk> ToStringSwap <jk>extends</jk> PojoSwap&lt;Object,String&gt; {
<jk>public</jk> String swap(BeanSession session, Object o) <jk>throws</jk> Exception {
<jk>return</jk> o.toString();
}
}
</p>
<li>Support for templated swaps which provide additional context information for a swap.
<br>The following is an example of a templated swap class used to serialize POJOs to HTML using FreeMarker:
<p class='bcode w800'>
<jc>// Our abstracted templated swap class.</jc>
<jk>public abstract class</jk> FreeMarkerSwap <jk>extends</jk> PojoSwap&lt;Object,Reader&gt; {
<jk>public</jk> MediaType[] forMediaTypes() {
<jk>return</jk> MediaType.<jsm>forStrings</jsm>(<js>"&#42;/html"</js>);
}
<jk>public</jk> Reader swap(BeanSession session, Object o, String template) <jk>throws</jk> Exception {
<jk>return</jk> getFreeMarkerReader(template, o); <jc>// Some method that creates raw HTML.</jc>
}
}
</p>
<p class='bcode w800'>
<ja>@Swap</ja>(impl=FreeMarkerSwap.<jk>class</jk>, template=<js>"MyPojo.div.ftl"</js>)
<jk>public class</jk> MyPojo {}
</p>
<li>New {@link org.apache.juneau.annotation.Swaps @Swaps} annotation for defining multiple swaps
against the same POJO when they're differentiated by media types:
<p class='bcode w800'>
<ja>@Swaps</ja>(
{
<ja>@Swap</ja>(MyJsonSwap.<jk>class</jk>),
<ja>@Swap</ja>(MyXmlSwap.<jk>class</jk>),
<ja>@Swap</ja>(MyOtherSwap.<jk>class</jk>)
}
)
<jk>public class</jk> MyPojo {}
</p>
</ul>
<li>
New {@link org.apache.juneau.transform.Surrogate} interface for identifying surrogate classes.
<li>
Serializers can now serialize to {@link java.util.StringBuilder StringBuilders}.
<li>
Serializers now serialize the contents of {@link java.io.Reader Readers} and {@link java.io.InputStream InputStreams}
directly to the output stream or writer.
<br>When used with conjunction with <c>PojoSwaps</c>, this can be used to provide customized
output for specific content types.
<p class='bcode w800'>
<ja>@Pojo</ja>(swap=MyBeanSwap.<jk>class</jk>)
<jk>public class</jk> MyBean {...}
<jk>public class</jk> MyBeanSwap <jk>extends</jk> PojoSwap&lt;MyBean,Object&gt; {
<jk>public</jk> Object swap(BeanSession session, MyPojo o) <jk>throws</jk> Exception {
MediaType mt = session.getMediaType();
<jk>if</jk> (mt.hasSubType(<js>"json"</js>))
<jk>return new</jk> StringReader(<js>"{foo:'bar'}"</js>); <jc>// Custom JSON output</jc>
<jk>return</jk> o; <jc>// Otherwise treat as normal bean</jc>
}
}
<jc>// Produces "{foo:'bar'}"</jc>
String json = SimpleJsonSerializer.<jsf>DEFAULT</jsf>
.toString(<jk>new</jk> MyBean());
</p>
<br>This feature helps with the implementation of language-agnostic template support such as for
using FreeMaker to serialize POJOs to HTML.
<li>
{@link org.apache.juneau.serializer.SerializerSession} and {@link org.apache.juneau.parser.ParserSession}
objects are now reusable if used within the same thread.
<p class='bcode w800'>
<jc>// Old way (still works)</jc>
JsonSerializer.<jsf>DEFAULT</jsf>.serialize(writer1, pojo1);
JsonSerializer.<jsf>DEFAULT</jsf>.serialize(writer2, pojo2);
<jc>// Same, but using a session object</jc>
SerializerSession session = JsonSerializer.<jsf>DEFAULT</jsf>.createSession();
<jk>try</jk> {
session.serialize(writer1, pojo1);
session.serialize(writer2, pojo2);
} <jk>finally</jk> {
session.close();
}
</p>
This is mostly an internal change and doesn't affect the existing APIs.
<li>
{@link org.apache.juneau.transform.PojoSwap#swap(BeanSession,Object)} and {@link org.apache.juneau.transform.PojoSwap#unswap(BeanSession,Object,ClassMeta)}
can now throw arbitrary exceptions instead of having to wrap them in <c>SerializeException</c>/<c>ParseException</c>.
<li>
New {@link org.apache.juneau.utils.CalendarUtils} class that encapsulates serialization/parsing logic from {@link org.apache.juneau.transforms.CalendarSwap} and
{@link org.apache.juneau.transforms.DateSwap}.
<li>
New annotation {@link org.apache.juneau.html.annotation.Html#anchorText}.
<li>
New methods on {@link org.apache.juneau.ObjectList}:
<ul>
<li>{@link org.apache.juneau.ObjectList#get(int,Class) get(int,Class)}
<li>{@link org.apache.juneau.ObjectList#get(int,Type,Type...) get(int,Type,Type...)}
<li>{@link org.apache.juneau.ObjectList#getMap(int,Class,Class) getMap(int,Class,Class)}
<li>{@link org.apache.juneau.ObjectList#getList(int,Class) getList(int,Class)}
</ul>
<li>
New methods on {@link org.apache.juneau.ObjectMap}:
<ul>
<li>{@link org.apache.juneau.ObjectMap#get(String,Class) get(String,Class)}
<li>{@link org.apache.juneau.ObjectMap#get(String,Type,Type...) get(String,Type,Type...)}
<li>{@link org.apache.juneau.ObjectMap#getWithDefault(String,Object) getWithDefault(String,Object)}
<li>{@link org.apache.juneau.ObjectMap#getWithDefault(String,Object,Class) getWithDefault(String,Object,Class)}
<li>{@link org.apache.juneau.ObjectMap#getWithDefault(String,Object,Type,Type...) getWithDefault(String,Object,Type,Type...)}
<li>{@link org.apache.juneau.ObjectMap#getSwapped(String,PojoSwap) getSwapped(String,PojoSwap)}
<li>{@link org.apache.juneau.ObjectMap#getAt(String,Class) getAt(String,Class)}
<li>{@link org.apache.juneau.ObjectMap#getAt(String,Type,Type...) getAt(String,Type,Type...)}
<li>{@link org.apache.juneau.ObjectMap#getMap(String,Class,Class,Map) getMap(String,Class,Class,Map)}
<li>{@link org.apache.juneau.ObjectMap#getList(String,Class,List) getList(String,Class,List)}
</ul>
<li>
New methods on {@link org.apache.juneau.utils.PojoRest}:
<ul>
<li>{@link org.apache.juneau.utils.PojoRest#get(String,Class) get(String,Class)}
<li>{@link org.apache.juneau.utils.PojoRest#get(String,Type,Type...) get(String,Type,Type...)}
<li>{@link org.apache.juneau.utils.PojoRest#getWithDefault(String,Object) getWithDefault(String,Object)}
<li>{@link org.apache.juneau.utils.PojoRest#getWithDefault(String,Object,Class) getWithDefault(String,Object,Class)}
<li>{@link org.apache.juneau.utils.PojoRest#getWithDefault(String,Object,Type,Type...) getWithDefault(String,Object,Type,Type...)}
</ul>
<li>
Fixed bug where {@link org.apache.juneau.BeanSession#getMediaType()} wasn't returning a value.
<li>
Eliminated the <ja>@Consumes</ja> and <ja>@Produces</ja> annotations.
<br>The supported media types are now passed in through the constructors.
<br>This was changed to eliminate a performance issue where a field could not be set as final because
the call to <c>getClass()</c> to retrieve the annotation value could not be called before calling
the <c><jk>super</jk>()</c> method.
<li>
New class: {@link org.apache.juneau.utils.PojoMerge}
<li>
New doc: <del>2.6.2 - @Pojo annotation</del>
<li>
New doc: <del>2.6.5 - Serializing Readers and InputStreams</del>
</ul>
<h5 class='topic w800'>juneau-dto</h5>
<ul class='spaced-list'>
<li>
{@link org.apache.juneau.dto.html5.HtmlElementMixed#children(Object...)} can now take in collections
of objects.
<li>
The DTO beans can now be serialized to strings of their typical language by calling the <c>toString()</c> method.
<br>For example, <c>Swagger.toString()</c> produces JSON and the HTML5 <c>Form.toString()</c>
produces HTML.
</ul>
<h5 class='topic w800'>juneau-rest-server</h5>
<ul class='spaced-list'>
<li>
Revamped and simplified servlet and REST-call lifecycle handling through new
{@link org.apache.juneau.rest.annotation.RestHook @RestHook} annotation.
<ul>
<li>The {@link org.apache.juneau.rest.RestServlet#init(ServletConfig)} method is now final and can
no longer be extended.
<br>Instead, use {@link org.apache.juneau.rest.annotation.HookEvent#INIT} or
{@link org.apache.juneau.rest.annotation.HookEvent#POST_INIT} for initialization.
<li>The following methods on {@link org.apache.juneau.rest.RestServlet} have been removed:
<ul>
<li><c>init(RestConfig)</c>
- Use {@link org.apache.juneau.rest.annotation.HookEvent#INIT} instead.
<li><c>onSuccess(RestRequest, RestResponse, long)</c>
- Use {@link org.apache.juneau.rest.annotation.HookEvent#END_CALL} instead.
<li><c>onPreCall(RestRequest)</c>
- Use {@link org.apache.juneau.rest.annotation.HookEvent#PRE_CALL} instead.
<li><c>onPostCall(RestRequest, RestResponse)</c>
- Use {@link org.apache.juneau.rest.annotation.HookEvent#POST_CALL} instead.
</ul>
</ul>
<li>
Simplified {@link org.apache.juneau.rest.widget.MenuItemWidget}.
<br>Exposes an abstract method <dc>getContent(RestRequest)</dc> that
can return raw HTML via readers or char-sequences, or any other object (such as HTML5 beans) that will
get converted to HTML using {@link org.apache.juneau.html.HtmlSerializer#DEFAULT}.
<li>
{@link org.apache.juneau.rest.RestResourceResolver} instances are now inherited from parent resources to child resources
unless explicitly overridden at the child level.
<br>It's also been changed to an interface.
<li>New annotations on <dc>@RestResource</dc>:
<ul>
<li><dc>resourceResolver()</dc>
<br>Allows you to specify a resource resolver on the servlet context to make it easier to work with
dependency injection frameworks.
<li><dc>contextPath()</dc> -
<br>Allows you to override the context path value inherited from the servlet container.
<li><dc>allowHeaderParams()</dc> -
<br>Replaces the <c>RestContext.REST_allowHeaderParams</c> setting.
<li><dc>allowMethodParam()</dc> -
<br>Replaces the <c>RestContext.REST_allowMethodParam</c> setting.
<li><dc>allowBodyParam()</dc> -
<br>Replaces the <c>RestContext.REST_allowBodyParam</c> setting.
<li><dc>renderResponseStackTraces()</dc> -
<br>Replaces the <c>RestContext.REST_xxx</c> setting.
<li><dc>useStackTraceHashes()</dc> -
<br>Replaces the <c>RestContext.REST_useStackTraceHashes</c> setting.
<li><dc>defaultCharset()</dc> -
<br>Replaces the <c>RestContext.REST_defaultCharset</c> setting.
<li><dc>paramFormat()</dc> -
<br>Replaces the <c>RestContext.REST_paramFormat</c> setting.
</ul>
<li>New annotations on {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod}:
<ul>
<li>{@link org.apache.juneau.rest.annotation.RestMethod#defaultCharset() defaultCharset()} -
<br>Replaces the <c>RestContext.REST_defaultCharset</c> setting.
<li><dc>RestMethod.paramFormat()</dc> -
<br>Replaces the <c>RestContext.REST_paramFormat</c> setting.
</ul>
<li>
The following implementation classes can now be defined as non-static inner classes of servlets/resources:
<ul>
<li>{@link org.apache.juneau.rest.widget.Widget}
<li>{@link org.apache.juneau.rest.RestConverter}
<li>{@link org.apache.juneau.rest.RestGuard}
<li>{@link org.apache.juneau.rest.ResponseHandler}
<li>{@link org.apache.juneau.rest.RestCallHandler}
<li>{@link org.apache.juneau.rest.RestInfoProvider}
<li>{@link org.apache.juneau.rest.RestResourceResolver}
<li>{@link org.apache.juneau.rest.RestLogger}
<li>{@link org.apache.juneau.html.HtmlDocTemplate}
</ul>
<li>
New tooltip template: {@link org.apache.juneau.rest.widget.Tooltip}
<li>
New dark theme:
<br><img src='doc-files/ReleaseNotes.632.DarkStyle.png'>
<li>
Stylesheet selection now stored in HTTP session when passed in via <c>?stylesheet</c> query parameter.
<li>
New doc: <del>Lifecycle Hooks</del>
<li>
Eliminated the <c>RestServletJenaDefault</c> class to remove the Jena dependency class on
the <c>juneau-rest-server</c> artifact.
<br>It's simple enough to simply extend <c>BasicRestServlet</c> and add the RDF serializers and
parsers.
</ul>
<h5 class='topic w800'>juneau-microservice</h5>
<ul class='spaced-list'>
<li>
The microservice has been significantly modified to be configured via a <c>jetty.xml</c> file
for maximum flexibility instead of the hodge-podge of support in the config file.
<br>Top-level servlets should now be defined in the provided <c>jetty.xml</c> file.
<li>
New methods on <dc>RestMicroservice</dc>:
<ul>
<li><dc>addServlet(Servlet,String)</dc>
<li><dc>addServletAttribute(String,Object)</dc>
<li><dc>getServer()</dc>
<li><dc>getInstance()</dc>
<li><dc>getPort()</dc>
<li><dc>getContextPath()</dc>
<li><dc>getProtocol()</dc>
<li><dc>getHostName()</dc>
</ul>
<li>
New methods on {@link org.apache.juneau.microservice.Microservice}:
<ul>
<li>{@link org.apache.juneau.microservice.Microservice#getInstance() getInstance()}
</ul>
<li>
New class <dc>JettyLogger</dc> for directing Jetty logging to the
java.util.logging framework.
<li>
New class <dc>DebugResource</dc> for viewing and generating
Jetty thread dumps through REST calls.
</ul>
<h5 class='topic w800'>org.apache.juneau.rest.examples</h5>
<ul class='spaced-list'>
<li>
New example of adding a menu-item widget to the Pet Store resource (including tooltips):
<br><img src='doc-files/ReleaseNotes.632.PetStoreAdd.png'>
</ul>
</div><!-- END: 6.4.0 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#7.0.0' id='7.0.0'>7.0.0 (Oct 25, 2017)</a></h3>
<div class='topic'><!-- START: 7.0.0 -->
<p>
This release ups the Java prerequisite to Java 7.
</p>
<h5 class='topic w800'>juneau-marshall</h5>
<ul class='spaced-list'>
<li>
New class {@link org.apache.juneau.http.HttpMethodName} with valid static string HTTP method names.
</ul>
<h5 class='topic w800'>juneau-dto</h5>
<ul class='spaced-list'>
<li>
Class <c>org.apache.juneau.dto.Link</c> renamed to {@link org.apache.juneau.dto.LinkString}.
Helps avoid confusion since there are other Link classes in the library.
</ul>
<h5 class='topic w800'>juneau-rest-server</h5>
<ul class='spaced-list'>
<li>
Annotation <c><ja>@HtmlDoc</ja>(links)</c> renamed to {@link org.apache.juneau.rest.annotation.HtmlDoc#navlinks() navlinks}.
<li>
New annotation {@link org.apache.juneau.rest.annotation.HtmlDoc#head() @HtmlDoc(head)}.
<br>Allows you to specify arbitrary HTML content in the <xt>&lt;head&gt;</xt> section of the page.
<li>
Removed annotation <c><ja>@HtmlDoc</ja>(favIcon)</c>.
<br>This was a discouraged way of defining fav-icons anyway, and with the addition of
<c><ja>@HtmlDoc</ja>(head)</c>, you can define them using:
<p class='bcode w800'>
head={
<js>"&lt;link rel='icon' href='$U{servlet:/htdocs/juneau.png}'/&gt;"</js>
}
</p>
<li>
Removed several of the HTMLDOC-related methods from the <c>RestResponse/RestConfig/RestContext</c>
classes and moved it into the new {@link org.apache.juneau.rest.HtmlDocBuilder} class.
</ul>
</div><!-- END: 7.0.0 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#7.0.1' id='7.0.1'>7.0.1 (Dec 24, 2017)</a></h3>
<div class='topic'><!-- START: 7.0.1 -->
<p>
This release is a minor update.
It includes the following prereq updates:
</p>
<ul class='spaced-list'>
<li>Apache HttpClient: 4.5.3 to 4.5.4
<li>Eclipse Jetty: 9.4.6.v20170531 to 9.4.8.v20171121
</ul>
<h5 class='topic w800'>juneau-marshall</h5>
<ul class='spaced-list'>
<li>New static <c>create()</c> methods for builders on serializers and parsers.
<br>This simplifies the syntax of creation of serializers and parsers by scratch.
<p class='bcode w800'>
<jc>// Old way</jc>
JsonSerializer s1 = <jk>new</jk> JsonSerializerBuilder().ws().build();
<jc>// New way</jc>
JsonSerializer s2 = JsonSerializer.<jsm>create</jsm>().ws().build();
</p>
<br>The same static create methods have also been added to the following classes:
<ul>
<li>{@link org.apache.juneau.serializer.SerializerGroup#create()}
<li>{@link org.apache.juneau.parser.ParserGroup#create()}
<li>{@link org.apache.juneau.encoders.EncoderGroup#create()}
<li>{@link org.apache.juneau.rest.client.RestClient#create()}
<li><dc>ConfigFile.create()</dc>
</ul>
<li>
The order of the parameters in {@link org.apache.juneau.serializer.SerializerSession#serialize(Object,Object)}
has been change to match {@link org.apache.juneau.serializer.Serializer#serialize(Object,Object)}.
<li>
Fixed some bugs in the XML parser related to whitespace and comments.
</ul>
<h5 class='topic w800'>juneau-svl</h5>
<ul class='spaced-list'>
<li>New methods on {@link org.apache.juneau.svl.Var} class to restrict when nested and embedded variables
are resolved.
<ul>
<li>{@link org.apache.juneau.svl.Var#allowNested()}
<li>{@link org.apache.juneau.svl.Var#allowRecurse()}
</ul>
</ul>
<h5 class='topic w800'>juneau-rest-server</h5>
<ul class='spaced-list'>
<li>
New <dc>@RestResource(maxInput)</dc> and
{@link org.apache.juneau.rest.annotation.RestMethod#maxInput() @RestMethod(maxInput)} for alleviating
potential DoS attacks.
</ul>
<h5 class='topic w800'>juneau-microservice-server</h5>
<ul class='spaced-list'>
<li>
New pluggable console commands.
<br>When you start up the microservice, you'll now see the following:
<p class='bcode w800'>
Running class 'RestMicroservice' using config file 'examples.cfg'.
Server started on port 10000
List of available commands:
exit -- Shut down service
restart -- Restarts service
help -- Commands help
echo -- Echo command
&gt; <span style='color:green'>help help</span>
NAME
help -- Commands help
SYNOPSIS
help [command]
DESCRIPTION
When called without arguments, prints the descriptions of all available commands.
Can also be called with one or more arguments to get detailed information on a command.
EXAMPLES
List all commands:
&gt; help
List help on the help command:
&gt; help help
&gt;
</p>
<p>
Commands are pluggable and extensible through the config file.
<p class='bcode w800'>
<cc>#=======================================================================================================================
# Console settings
#=======================================================================================================================</cc>
<cs>[Console]</cs>
<ck>enabled</ck> = <cv>true</cv>
<cc># List of available console commands.
# These are classes that implements ConsoleCommand that allow you to submit commands to the microservice via
# the console.
# When listed here, the implementations must provide a no-arg constructor.
# They can also be provided dynamically by overriding the Microservice.createConsoleCommands() method.</cc>
<ck>commands</ck> =
<cv>org.apache.juneau.microservice.console.ExitCommand,
org.apache.juneau.microservice.console.RestartCommand,
org.apache.juneau.microservice.console.HelpCommand</cv>
</p>
<ul>
<li>New classes:
<ul>
<li>{@link org.apache.juneau.microservice.console.ConsoleCommand}
<li>{@link org.apache.juneau.microservice.console.ExitCommand}
<li>{@link org.apache.juneau.microservice.console.RestartCommand}
<li>{@link org.apache.juneau.microservice.console.HelpCommand}
</ul>
<li>New methods on {@link org.apache.juneau.microservice.Microservice}
<ul>
<li>{@link org.apache.juneau.microservice.Microservice#startConsole() startConsole()}
<li><dc>createConsoleCommands()</dc>
<li>{@link org.apache.juneau.microservice.Microservice#getConsoleReader() getConsoleReader()}
<li>{@link org.apache.juneau.microservice.Microservice#getConsoleWriter() getConsoleWriter()}
</ul>
</ul>
<li>
Console input reader and output writer can now be overridden.
<li>
Console strings are now internationalized.
</ul>
</div><!-- END: 7.0.1 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#7.1.0' id='7.1.0'>7.1.0 (Mar 08, 2018)</a></h3>
<div class='topic'><!-- START: 7.1.0 -->
<p>
Version 7.1.0 is a major update with major implementation refactoring across all aspects of the product.
</p>
<h5 class='topic w800'>juneau-marshall</h5>
<ul class='spaced-list'>
<li>
Significant improvements made to the internals of the Serializer and Parser classes.
<ul>
<li>
Caching improvements on serializers and parsers have reduced execution time of the core
JUnits by approximately 1/3.
<br>The 17000+ JUnit tests now execute in less than 10 seconds and have a cache-reuse hit rate
of 98% (164104 serializers/parsers/bean-contexts retrieved, but only 1801 created from scratch).
<li>
All the various separate <c>Context</c> classes (e.g. <c>JsonSerializerContext</c>) have been folded into
their respective serializer or parser classes (e.g. <c>JsonSerializer</c>).
<br>Additionally, these classes are their own bean contexts.
<br>For example, the class hierarchy of <c>JsonSerializer</c> is now:
<ul class='doctree'>
<li class='jac'>{@link org.apache.juneau.Context}
<ul>
<li class='jc'>{@link org.apache.juneau.BeanContext}
<ul>
<li class='jac'>{@link org.apache.juneau.serializer.Serializer}
<ul>
<li class='jac'>{@link org.apache.juneau.serializer.WriterSerializer}
<ul>
<li class='jc'>{@link org.apache.juneau.json.JsonSerializer}
</ul>
</ul>
</ul>
</ul>
</ul>
All <c>Context</c> objects are thread-safe and read-only.
<li>
Session objects also now have a consistent class hierarchy.
<br>For example, the class hierarchy of <c>JsonSerializerSession</c> is now:
<ul class='doctree'>
<li class='jac'>{@link org.apache.juneau.Session}
<ul>
<li class='jc'>{@link org.apache.juneau.BeanSession}
<ul>
<li class='jac'>{@link org.apache.juneau.serializer.SerializerSession}
<ul>
<li class='jac'>{@link org.apache.juneau.serializer.WriterSerializerSession}
<ul>
<li class='jc'>{@link org.apache.juneau.json.JsonSerializerSession}
</ul>
</ul>
</ul>
</ul>
</ul>
Session objects are transient objects that live for the duration of a single parse.
<li>
Builder objects also now have a consistent class hierarchy.
<br>For example, the class hierarchy of <c>JsonSerializerBuilder</c> is now:
<ul class='doctree'>
<li class='jac'>{@link org.apache.juneau.ContextBuilder}
<ul>
<li class='jc'>{@link org.apache.juneau.BeanContextBuilder}
<ul>
<li class='jac'>{@link org.apache.juneau.serializer.SerializerBuilder}
<ul>
<li class='jc'>{@link org.apache.juneau.json.JsonSerializerBuilder}
</ul>
</ul>
</ul>
</ul>
Builder objects are used for building up and creating <c>Context</c> objects.
<li>
The {@link org.apache.juneau.PropertyStore} class has been completely rewritten.
It is now a read-only configuration store build using the {@link org.apache.juneau.PropertyStoreBuilder}
class.
<br>The previous <c>PropertyStore</c> class was overly-complicated with many read/write
locks to ensure thread-safety.
<br>The new design shifts to a builder-based model with read-only <c>PropertyStore</c> objects
that can be used as hash keys.
</ul>
<li>
Improvements to the HTTP-Part APIs.
<br>The existing <c>PartSerializer</c>/<c>PartParser</c> classes
have been replaced with the following all located in the new <c>org.apache.juneau.httppart</c> package:
<ul class='doctree'>
<li class='jp'>{@link org.apache.juneau.httppart}
<ul>
<li class='jc'>{@link org.apache.juneau.httppart.HttpPartType}
<li class='jic'>{@link org.apache.juneau.httppart.HttpPartSerializer}
<ul>
<li class='jc'><dc>UonPartSerializer</dc>
<li class='jc'><dc>SimpleUonPartSerializer</dc>
<li class='jc'>{@link org.apache.juneau.httppart.SimplePartSerializer}
</ul>
<li class='jic'>{@link org.apache.juneau.httppart.HttpPartParser}
<ul>
<li class='jc'><dc>UonPartParser</dc>
<li class='jc'><dc>SimplePartParser</dc>
</ul>
</ul>
</ul>
Code for marshalling of parts have been removed from the URL-Encoding serializers and parsers.
<li>
<c>ContextBuilder.property(String,Object)</c> renamed to {@link org.apache.juneau.ContextBuilder#set(String,Object)}.
<li>
<c>ResourceFinder</c> class has been replaced with the following:
<ul>
<li>{@link org.apache.juneau.utils.ClasspathResourceFinder}
<li>{@link org.apache.juneau.utils.ClasspathResourceFinderSimple}
<li>{@link org.apache.juneau.utils.ClasspathResourceFinderBasic}
<li>{@link org.apache.juneau.utils.ClasspathResourceFinderRecursive}
<li>{@link org.apache.juneau.utils.ClasspathResourceManager}
</ul>
<li>
New methods on {@link org.apache.juneau.serializer.SerializerSession}:
<ul>
<li>{@link org.apache.juneau.serializer.SerializerSession#getListener() getListener()}
<li>{@link org.apache.juneau.serializer.SerializerSession#getListener(Class) getListener(Class)}
</ul>
<li>
New methods on {@link org.apache.juneau.parser.ParserSession}:
<ul>
<li>{@link org.apache.juneau.parser.ParserSession#getListener() getListener()}
<li>{@link org.apache.juneau.parser.ParserSession#getListener(Class) getListener(Class)}
</ul>
<li>
New {@link org.apache.juneau.parser.Parser#PARSER_unbuffered} setting allows you to disable internal
buffering on the JSON and UON parsers so that they can be used to read continous streams of objects.
<li>
New {@link org.apache.juneau.json.JsonParser#JSON_validateEnd} and {@link org.apache.juneau.uon.UonParser#UON_validateEnd}
settings allow you to control whether we validate that there is no garbage at the end of the parsed input.
<li>
New {@link org.apache.juneau.parser.Parser#PARSER_autoCloseStreams} setting allows input streams and
readers passed into parsers to be automatically closed after parsing.
<li>
Syntax changed on unswap method on {@link org.apache.juneau.transform.Surrogate} classes.
<br>It's now a regular method instead of a static method.
<li>
{@link org.apache.juneau.annotation.Swap @Swap} annotation can now be used with
{@link org.apache.juneau.transform.Surrogate} classes.
<li>
New support for {@doc juneau-marshall.Transforms.PojoBuilders POJO Builders}.
</ul>
<h5 class='topic w800'>juneau-svl</h5>
<ul class='spaced-list'>
<li>
New variables:
<ul>
<li>{@link org.apache.juneau.svl.vars.CoalesceVar}
<li>{@link org.apache.juneau.svl.vars.PatternMatchVar}
<li>{@link org.apache.juneau.svl.vars.NotEmptyVar}
<li>{@link org.apache.juneau.svl.vars.UpperCaseVar}
<li>{@link org.apache.juneau.svl.vars.LowerCaseVar}
</ul>
<li>
Variables moved from <l>juneau-microservice</l>:
<ul>
<li>{@link org.apache.juneau.svl.vars.ArgsVar}
<li>{@link org.apache.juneau.svl.vars.ManifestFileVar}
</ul>
</ul>
<h5 class='topic w800'>juneau-config</h5>
<ul class='spaced-list'>
<li>
The Config API has been completely revamped.
<br>New features include:
<ul>
<li>Support for pluggable storage.
<li>File-system watcher integration support.
<br>Changes made to file system files now automatically reflected in configurations
and interface proxies.
<li>New builder-based design.
</ul>
</ul>
<h5 class='topic w800'>juneau-dto</h5>
<ul class='spaced-list'>
<li>
Enhancements to Swagger DTO:
<ul>
<li>New methods for setting and retrieving properties via name:
<ul>
<li>{@link org.apache.juneau.dto.swagger.SwaggerElement#get(String,Class)}
<li>{@link org.apache.juneau.dto.swagger.SwaggerElement#set(String,Object)}
</ul>
<li>
Support for setting non-standard fields such as <js>"$ref"</js> via getter and setter
above.
<li>
Setter methods that take in beans and collections of beans can now take in
JSON strings.
</ul>
</ul>
<h5 class='topic w800'>juneau-rest-server</h5>
<ul class='spaced-list'>
<li>
<c>RestServletDefault</c> renamed to {@link org.apache.juneau.rest.BasicRestServlet}.
<li>
<c>RestServletGroupDefault</c> renamed to {@link org.apache.juneau.rest.BasicRestServletGroup}.
<li>
The <js>"$R{...}"</js> variable has been split into the following:
<ul>
<li><js>"$RA{key1[,key2...]}"</js> - {@link org.apache.juneau.rest.vars.RequestAttributeVar}, first non-null value returned by <c>HttpServletRequest.getAttribute(String)</c>.
<li><js>"$RF{key1[,key2...]}"</js> - {@link org.apache.juneau.rest.vars.RequestFormDataVar}, first non-null value returned by {@link org.apache.juneau.rest.RestRequest#getFormData(String)}.
<li><js>"$RH{key1[,key2...]}"</js> - {@link org.apache.juneau.rest.vars.RequestHeaderVar}, first non-null value returned by {@link org.apache.juneau.rest.RestRequest#getHeader(String)}.
<li><js>"$RI{key1[,key2...]}"</js> - {@link org.apache.juneau.rest.vars.RestInfoVar}, first non-null value returned by {@link org.apache.juneau.rest.RestRequest#getInfoProvider()}.
<br>The possible values are:
<ul>
<li><js>"contact"</js> - Value returned by {@link org.apache.juneau.dto.swagger.Info#getContact()}
<li><js>"description"</js> - Value returned by {@link org.apache.juneau.rest.RestInfoProvider#getDescription(RestRequest)}
<li><js>"externalDocs"</js> - Value returned by {@link org.apache.juneau.dto.swagger.Swagger#getExternalDocs()}
<li><js>"license"</js> - Value returned by {@link org.apache.juneau.dto.swagger.Info#getLicense()}
<li><js>"methodDescription"</js> - Value returned by {@link org.apache.juneau.rest.RestInfoProvider#getMethodDescription(Method,RestRequest)}
<li><js>"methodSummary"</js> - Value returned by {@link org.apache.juneau.rest.RestInfoProvider#getMethodSummary(Method,RestRequest)}
<li><js>"siteName"</js> - Value returned by {@link org.apache.juneau.rest.RestInfoProvider#getSiteName(RestRequest)}
<li><js>"tags"</js> - Value returned by {@link org.apache.juneau.dto.swagger.Swagger#getTags()}
<li><js>"termsOfService"</js> - Value returned by {@link org.apache.juneau.dto.swagger.Info#getTermsOfService()}
<li><js>"title"</js> - See {@link org.apache.juneau.rest.RestInfoProvider#getTitle(RestRequest)}
<li><js>"version"</js> - See {@link org.apache.juneau.dto.swagger.Info#getVersion()}
</ul>
<li><js>"$RP{key1[,key2...]}"</js> - {@link org.apache.juneau.rest.vars.RequestPathVar}, first non-null value returned by {@link org.apache.juneau.rest.RestRequest#getPath(String)}.
<li><js>"$RQ{key1[,key2...]}"</js> - {@link org.apache.juneau.rest.vars.RequestQueryVar}, first non-null value returned by {@link org.apache.juneau.rest.RestRequest#getQuery(String)}
<li><js>"$R{key1[,key2...]}"</js> - {@link org.apache.juneau.rest.vars.RequestVar}, first non-null other request variable.
<br>The possible values are:
<ul>
<li><js>"contextPath"</js> - Value returned by {@link org.apache.juneau.rest.RestRequest#getContextPath()}
<li><js>"method"</js> - Value returned by {@link org.apache.juneau.rest.RestRequest#getMethod()}
<li><js>"methodDescription"</js> - Value returned by {@link org.apache.juneau.rest.RestRequest#getMethodDescription()}
<li><js>"methodSummary"</js> - Value returned by {@link org.apache.juneau.rest.RestRequest#getMethodSummary()}
<li><js>"pathInfo"</js> - Value returned by {@link org.apache.juneau.rest.RestRequest#getPathInfo()}
<li><js>"requestParentURI"</js> - Value returned by {@link org.apache.juneau.UriContext#getRootRelativePathInfoParent()}
<li><js>"requestURI"</js> - Value returned by {@link org.apache.juneau.rest.RestRequest#getRequestURI()}
<li><js>"resourceDescription"</js> - Value returned by {@link org.apache.juneau.rest.RestRequest#getResourceDescription()}
<li><js>"resourceTitle"</js> - See {@link org.apache.juneau.rest.RestRequest#getResourceTitle()}
<li><js>"servletParentURI"</js> - Value returned by {@link org.apache.juneau.UriContext#getRootRelativeServletPathParent()}
<li><js>"servletPath"</js> - See {@link org.apache.juneau.rest.RestRequest#getServletPath()}
<li><js>"servletURI"</js> - See {@link org.apache.juneau.UriContext#getRootRelativeServletPath()}
<li><js>"siteName"</js> - See {@link org.apache.juneau.rest.RestRequest#getSiteName()}
</ul>
</ul>
<li>
Refactored the <c>RestConfig</c> class into {@link org.apache.juneau.rest.RestContextBuilder}.
<br>Settings on {@link org.apache.juneau.rest.RestContext} objects can now be set declaratively through the
following new properties:
<ul>
<li>{@link org.apache.juneau.rest.RestContext#REST_allowHeaderParams REST_allowHeaderParams}
<li>{@link org.apache.juneau.rest.RestContext#REST_allowBodyParam REST_allowBodyParam}
<li>{@link org.apache.juneau.rest.RestContext#REST_allowedMethodParams REST_allowedMethodParams}
<li>{@link org.apache.juneau.rest.RestContext#REST_renderResponseStackTraces REST_renderResponseStackTraces}
<li>{@link org.apache.juneau.rest.RestContext#REST_useStackTraceHashes REST_useStackTraceHashes}
<li>{@link org.apache.juneau.rest.RestContext#REST_defaultCharset REST_defaultCharset}
<li>{@link org.apache.juneau.rest.RestContext#REST_maxInput REST_maxInput}
<li>{@link org.apache.juneau.rest.RestContext#REST_paramResolvers REST_paramResolvers}
<li>{@link org.apache.juneau.rest.RestContext#REST_converters REST_converters}
<li>{@link org.apache.juneau.rest.RestContext#REST_guards REST_guards}
<li>{@link org.apache.juneau.rest.RestContext#REST_responseHandlers REST_responseHandlers}
<li><dc>REST_defaultRequestHeaders</dc>
<li><dc>REST_defaultResponseHeaders</dc>
<li>{@link org.apache.juneau.rest.RestContext#REST_produces REST_produces}
<li>{@link org.apache.juneau.rest.RestContext#REST_consumes REST_consumes}
<li>{@link org.apache.juneau.rest.RestContext#REST_clientVersionHeader REST_clientVersionHeader}
<li>{@link org.apache.juneau.rest.RestContext#REST_resourceResolver REST_resourceResolver}
<li>{@link org.apache.juneau.rest.RestContext#REST_logger REST_logger}
<li>{@link org.apache.juneau.rest.RestContext#REST_callHandler REST_callHandler}
<li>{@link org.apache.juneau.rest.RestContext#REST_infoProvider REST_infoProvider}
<li>{@link org.apache.juneau.rest.RestContext#REST_path REST_path}
<li><dc>REST_contextPath</dc>
<li>{@link org.apache.juneau.rest.RestContext#REST_staticFiles REST_staticFiles}
<li>{@link org.apache.juneau.rest.RestContext#REST_staticFileResponseHeaders REST_staticFileResponseHeaders}
<li>{@link org.apache.juneau.rest.RestContext#REST_classpathResourceFinder REST_classpathResourceFinder}
<li>{@link org.apache.juneau.rest.RestContext#REST_useClasspathResourceCaching REST_useClasspathResourceCaching}
<li>{@link org.apache.juneau.rest.RestContext#REST_widgets REST_widgets}
<li>{@link org.apache.juneau.rest.RestContext#REST_mimeTypes REST_mimeTypes}
</ul>
<li>
Support for static files has been simplified and improved.
<ul>
<li>Syntax on <dc>@RestResource(staticFiles)</dc> has been simplified, and
now allows you to specify response headers in the strings.
<li>Response headers for static files can also be configured through
{@link org.apache.juneau.rest.RestContext#REST_staticFileResponseHeaders REST_staticFileResponseHeaders}.
<li>Static file in-memory caching now configurable through
{@link org.apache.juneau.rest.RestContext#REST_useClasspathResourceCaching REST_useClasspathResourceCaching}.
<li>Static file retrieval can be customized through
{@link org.apache.juneau.rest.RestContext#REST_classpathResourceFinder REST_classpathResourceFinder}
</ul>
<li>
Eliminated the <c>RestMatcherReflecting</c> class.
<br>You can now simply create a {@link org.apache.juneau.rest.RestMatcher} that has a public constructor that
takes in the server and method arguments.
<li>
<dc>@RestResource.allowMethodParam</dc> renamed to <dc>RestResource.allowedMethodParams</dc>.
<li>
<c>@RestMethod.serializersInherit</c> and <c>@RestMethod.parsersInherit</c> replaced with
simplified <dc>@RestMethod(inherit)</dc>.
<li>
Changes to {@link org.apache.juneau.rest.RequestFormData}:
<ul>
<li>{@link org.apache.juneau.rest.RequestFormData#addDefault(Map) addDefault(Map)} takes in a
<c>Map&lt;String,Object&gt;</c> instead of <c>Map&lt;String,String&gt;</c>.
</ul>
<li>
Changes to {@link org.apache.juneau.rest.RequestHeaders}:
<ul>
<li>{@link org.apache.juneau.rest.RequestHeaders#addDefault(Map) addDefault(Map)} takes in a
<c>Map&lt;String,Object&gt;</c> instead of <c>Map&lt;String,String&gt;</c>.
</ul>
<li>
Changes to {@link org.apache.juneau.rest.RequestQuery}:
<ul>
<li>{@link org.apache.juneau.rest.RequestQuery#addDefault(Map) addDefault(Map)} takes in a
<c>Map&lt;String,Object&gt;</c> instead of <c>Map&lt;String,String&gt;</c>.
</ul>
<li>
Changes to {@link org.apache.juneau.rest.RestContext}:
<ul>
<li><c>getResource(String,Locale)</c> renamed to {@link org.apache.juneau.rest.RestContext#getClasspathResource(String,Locale) getClasspathResource(String,Locale)}
<li><c>getResourceAsString(String,Locale)</c> renamed to {@link org.apache.juneau.rest.RestContext#getClasspathResourceAsString(String,Locale) getClasspathResourceAsString(String,Locale)}
<li><c>getResource(Class,MediaType,String,Locale)</c> renamed to {@link org.apache.juneau.rest.RestContext#getClasspathResource(Class,MediaType,String,Locale) getClasspathResourceAsString(Class,MediaType,String,Locale)}
<li>New method {@link org.apache.juneau.rest.RestContext#getClasspathResource(Class,String,Locale) getClasspathResource(Class,String,Locale)}.
<li>New method {@link org.apache.juneau.rest.RestContext#getClasspathResourceAsString(Class,String,Locale) getClasspathResourceAsString(Class,String,Locale)}.
<li>New method {@link org.apache.juneau.rest.RestContext#getClasspathResource(Class,Class,MediaType,String,Locale) getClasspathResource(Class,Class,MediaType,String,Locale)}.
<li>{@link org.apache.juneau.rest.RestContext#getDefaultRequestHeaders() getDefaultRequestHeaders} returns a
<c>Map&lt;String,Object&gt;</c> instead of <c>Map&lt;String,String&gt;</c>.
<li>{@link org.apache.juneau.rest.RestContext#getDefaultResponseHeaders() getDefaultRequestHeaders} returns a
<c>Map&lt;String,Object&gt;</c> instead of <c>Map&lt;String,String&gt;</c>.
</ul>
<li>
Changes to {@link org.apache.juneau.rest.RestRequest}:
<ul>
<li><c>getSupportedMediaTypes()</c> replaced with
{@link org.apache.juneau.rest.RestRequest#getConsumes() getConsumes()} and
{@link org.apache.juneau.rest.RestRequest#getProduces() getProduces()}.
<li><c>getReaderResource(String,boolean,MediaType)</c> renamed to
<dc>getClasspathReaderResource(String,boolean,MediaType)</dc>
<li><c>getReaderResource(String,boolean)</c> renamed to
{@link org.apache.juneau.rest.RestRequest#getClasspathReaderResource(String,boolean) getClasspathReaderResource(String,boolean)}
<li><c>getReaderResource(String)</c> renamed to
{@link org.apache.juneau.rest.RestRequest#getClasspathReaderResource(String) getClasspathReaderResource(String)}
</ul>
<li>
Changes to <dc>@RestResource</dc>
<ul>
<li>New <dc>mimeTypes()</dc> annotation.
</ul>
<li>
Changes to {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod}:
<ul>
<li>New {@link org.apache.juneau.rest.annotation.RestMethod#consumes() consumes()} and
{@link org.apache.juneau.rest.annotation.RestMethod#produces() produces()}
for overriding the supported media types inferred from the serializers and parsers.
</ul>
<li>
<c>RestCallHandler</c> split up into {@link org.apache.juneau.rest.RestCallHandler} and
{@link org.apache.juneau.rest.BasicRestCallHandler}
<li>
<c>RestInfoProvider</c> split up into {@link org.apache.juneau.rest.RestInfoProvider} and
{@link org.apache.juneau.rest.BasicRestInfoProvider}
<li>
<c>RestLogger</c> split up into {@link org.apache.juneau.rest.RestLogger},
{@link org.apache.juneau.rest.BasicRestLogger} and {@link org.apache.juneau.rest.NoOpRestLogger}
<li>
<c>RestResourceResolverSimple</c> renamed to {@link org.apache.juneau.rest.BasicRestResourceResolver}
<li>
Introduced the following classes that helps make the code more understandable:
<ul>
<li>{@link org.apache.juneau.rest.RestContextProperties}
<li>{@link org.apache.juneau.rest.RestMethodProperties}
<li>{@link org.apache.juneau.rest.RequestProperties}
</ul>
<li>
Eliminated the <c>@Messages</c> and <c>@Properties</c> REST java method parameter
annotations.
<br>These aren't needed anymore since you can just pass in <c>MessageBundle</c> and
<c>RestRequestProperties</c> as unannotated parameters.
<li>
Revamped the {@link org.apache.juneau.rest.RestInfoProvider} class.
<li>
New builder classes:
<ul>
<li><dc>ReaderResourceBuilder</dc>
<li><dc>StreamResourceBuilder</dc>
</ul>
<li>
{@link org.apache.juneau.rest.RestResponse#getNegotiatedOutputStream()} now returns a
<dc>FinishableServletOutputStream</dc> and {@link org.apache.juneau.rest.RestResponse#getNegotiatedWriter()}
now returns a <dc>FinishablePrintWriter</dc> that allows you to finish the output
without closing the stream.
<br>The {@link org.apache.juneau.rest.reshandlers.DefaultHandler} class now calls <c>finish()</c>
instead of <c>close()</c> on the stream.
<li>
Added the following annotations to the {@link org.apache.juneau.rest.BasicRestServlet} class
(which were previously defined on the <dc>Resource</dc> class):
<p class='bcode w800'>
<ja>@RestResource</ja>(
htmldoc=<ja>@HtmlDoc</ja>(
navlinks={
<js>"up: request:/.."</js>,
<js>"options: servlet:/?method=OPTIONS"</js>
},
stylesheet=<js>"$C{REST/stylesheet,servlet:/styles/devops.css}"</js>
),
<jc>// Optional external configuration file.</jc>
config=<js>"$S{juneau.configFile}"</js>
)
</p>
</ul>
<h5 class='topic w800'>juneau-rest-client</h5>
<ul class='spaced-list'>
<li>
New configuration property {@link org.apache.juneau.rest.client.RestClient#RESTCLIENT_query} and
builder method {@link org.apache.juneau.rest.client.RestClientBuilder#query(String,Object)}.
<li>
API changes to replace <c>PartSerializer</c> with {@link org.apache.juneau.httppart.HttpPartSerializer}.
<br>The default value is now <dc>SimpleUonPartSerializer</dc> which will
serialize strings as plain-text and collections/arrays as comma-delimited lists.
<br>We decided to change the default behavior in favor of practicality over purity.
<li>
New methods on {@link org.apache.juneau.rest.client.RestCall} class:
<ul>
<li>{@link org.apache.juneau.rest.client.RestCall#getResponseHeader(String) getResponseHeader(String)}
<li>{@link org.apache.juneau.rest.client.RestCall#getResponseCode() getResponseCode()}
</ul>
<li>
{@link org.apache.juneau.rest.client.RestCall} and {@link org.apache.juneau.rest.client.RestClient}
now implement the <c>Closeable</c> interface.
</ul>
<h5 class='topic w800'>juneau-microservice</h5>
<ul class='spaced-list'>
<li>
<c>Resource</c> and <c>ResourceGroup</c> classes removed.
<br>{@link org.apache.juneau.rest.BasicRestServlet} and {@link org.apache.juneau.rest.BasicRestServletGroup} can be used instead.
<li>
<c>ResourceJena</c> and <c>ResourceJenaGroup</c> classes renamed to
<dc>BasicRestServletJena</dc> and <dc>BasicRestServletJenaGroup</dc>.
</ul>
</div><!-- END: 7.1.0 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#7.2.0' id='7.2.0'>7.2.1 (Sept 25, 2018)</a></h3>
<div class='topic'><!-- START: 7.2.0 -->
<p>
7.2.1 is a major release that introduces several significant new features:
</p>
<ul class='spaced-list'>
<li>OpenAPI part serializing and parsing with full support for OpenAPI validation of input and output in the REST servlet and client APIs.
<li>Swagger UI.
<li>New HTTP-Part annotations that are applicable to both the servlet and client APIs.
<li>Serverless servlet and client unit testing.
<li>Simplified UI customization.
<li>Marshalls that combines serializers and parsers into a single API.
</ul>
<h5 class='topic w800'>juneau-marshall</h5>
<ul class='spaced-list'>
<li>
The REST client <ja>@Remoteable</ja> annotations and REST server <ja>@RemoteMethod</ja> annotations which used to be
in separate packages in the client and server projects have been combined into a single set of annotations in
the {@link org.apache.juneau.http.annotation} package.
<br>This fixes a long-standing problem where it was easy to mix up using client-side annotations in server-side code, and vis-versa.
<br>Additionally, much work has been done on these annotations to add support for Swagger-style validations and documentation.
<ul class='doctree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Body}
<li class='ja'>{@link org.apache.juneau.http.annotation.FormData}
<li class='ja'>{@link org.apache.juneau.http.annotation.Header}
<li class='ja'>{@link org.apache.juneau.http.annotation.Path}
<li class='ja'>{@link org.apache.juneau.http.annotation.Query}
<li class='ja'>{@link org.apache.juneau.http.annotation.HasFormData}
<li class='ja'>{@link org.apache.juneau.http.annotation.HasQuery}
<li class='ja'>{@link org.apache.juneau.http.annotation.Request}
</ul>
<br>These are used with new Swagger schema/documentation annotations to produce schema-based serialization/parsing/validation
and auto-generated Swagger documentation:
<ul class='doctree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Contact}
<li class='ja'><dc>ExternalDocs</dc>
<li class='ja'><dc>Items</dc>
<li class='ja'>{@link org.apache.juneau.http.annotation.License}
<li class='ja'><dc>Schema</dc>
<li class='ja'><dc>SubItems</dc>
<li class='ja'>{@link org.apache.juneau.http.annotation.Tag}
</ul>
<br>Additionally, the <ja>@Remoteable</ja> annotation has been split into the following two annotations:
<ul class='doctree'>
<li class='ja'>{@link org.apache.juneau.remote.RemoteInterface}
- Used for remote proxy interfaces served up through
<dc>RemoteInterfaceServlet</dc> or REST <js>"PROXY"</js> methods.
<br>Defaults to <js>"POST"</js> with method signatures as paths.
<li class='ja'><dc>RemoteResource</dc>
- Used for 3rd-party REST interfaces.
<br>Defaults to <js>"GET"</js> with standardized naming conventions for paths.
</ul>
<li>
Support for multi-valued parameters as maps or beans on server-side annotations (it was previously supported on client-side):
<c><ja>@Query</ja>(<js>"*"</js>)</c>, <c><ja>@FormData</ja>(<js>"*"</js>)</c>, <c><ja>@Header</ja>(<js>"*"</js>)</c>, <c><ja>@Path</ja>(<js>"*"</js>)</c>
<li>
Support for server-side use of <ja>@Request</ja> annotation on <ja>@RestMethod</ja> annotations and new {@link org.apache.juneau.rest.RestRequest#getRequest(RequestBeanMeta)} method.
<li>
Fixed bug where <c><ja>@Bean</ja>(typeName)</c> was not being detected on non-bean POJO classes.
<li>
Fixed bug where HTML-Schema was not being rendered correctly.
<li>
Support for POJO examples:
<ul class='doctree'>
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_examples}
<li class='ja'>{@link org.apache.juneau.annotation.Example}
</ul>
<li>
Fixed bug where parsers could report the wrong line number when an error occurred.
<li>
A runtime exception is now thrown if you define a <dc>@BeanProperty(name)</dc> but forget to
add it to your <c><ja>@Bean</ja>(properties)</c> annotation.
<li>
<c><ja>@Html</ja>(asXml)</c> and <c><ja>@Html</ja>(asPlainText)</c> replaced with
{@link org.apache.juneau.html.annotation.Html#format() @Html(format)}.
<li>
HTML serializer will now serializers beans and maps as HTML even when those objects are embedded
within an object with <c><ja>@Html</ja>(format=<jsf>XML</jsf>)</c>.
<br>The previous behavior was to serialize it as XML.
<li>
New settings for binary-based serializers and parsers:
<ul class='doctree'>
<li class='jf'>{@link org.apache.juneau.serializer.OutputStreamSerializer#OSSERIALIZER_binaryFormat}
<li class='jf'>{@link org.apache.juneau.parser.InputStreamParser#ISPARSER_binaryFormat}
</ul>
<li>
Added support for auto-detection of fluent-style setters:
<ul class='doctree'>
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_fluentSetters}
<li class='ja'>{@link org.apache.juneau.annotation.Bean#fluentSetters()}
</ul>
<li>
The <jsf>SERIALIZER_abridged</jsf> setting has been replaced with {@link org.apache.juneau.serializer.Serializer#SERIALIZER_addRootType SERIALIZER_addRootType}
<li>
The <jsf>SERIALIZER_addBeanTypeProperties</jsf> setting has been replaced with {@link org.apache.juneau.serializer.Serializer#SERIALIZER_addBeanTypes SERIALIZER_addBeanTypes}
and is disabled by default.
<li>
Parse exception messages are now clearer and include code snippets of where a parse exception occurred:
<p class='bcode w800' style='color:red'>
org.apache.juneau.parser.ParseException: Expected '[' at beginning of JSON array.
At line 80, column 20.
While parsing into:
currentClass: List&lt;String&gt;
currentProperty: required: java.util.List, field=[null], getter=[public java.util.List org.apache.juneau.dto.swagger.SchemaInfo.getRequired()], setter=[public org.apache.juneau.dto.swagger.SchemaInfo org.apache.juneau.dto.swagger.SchemaInfo.setRequired(java.util.Collection)]
---start--
0075: "name": "body",
0076: "description": "Pet object that needs to be added to the store",
0077: "required": true,
0078: "schema": {
0079: "required": true,
0080: }
0081: }
0082: ],
0083: "responses": {
0084: "405": {
0085: "description": "Invalid input"
---end---
</p>
<li>
New property {@link org.apache.juneau.parser.Parser#PARSER_debugOutputLines} for controlling how many input lines are added to the exception message above.
<li>
New property {@link org.apache.juneau.BeanContext#BEAN_useEnumNames} for controlling whether enums are serialized
using their name or the <c>toString()</c> method.
<li>
New property {@link org.apache.juneau.BeanContext#BEAN_examples} for defining examples of POJOs.
<li>
New {@link org.apache.juneau.annotation.Example @Example} annotation for defining examples of POJOs.
<br>Used heavily in JSON-Schema support.
<li>
If a bean has both a <c>getX()</c> and <c>isX()</c> method, the <c>getX()</c> method takes precedence.
<br>The previous behavior was arbitrary.
<li>
Significant improvements to JSON-Schema serialization support.
<ul>
<li>New <dc>@JsonSchema</dc> annotation.
</ul>
<li>
Fixed <c>NullPointerException</c> when serializing beans with a dyna-property (i.e. <c><ja>@Bean</ja>(<js>"*"</js>)</c>)
which returns a <jk>null</jk> value.
<li>
New option for dyna-property (i.e. <c><ja>@Bean</ja>(<js>"*"</js>)</c>) using a method that returns a collection of extra keys.
<br>See new options #4 on {@link org.apache.juneau.annotation.BeanProperty#name()}
<li>
New formats for the {@link org.apache.juneau.html.annotation.Html#format() @Html(format)} annotation:
<ul class='doctree'>
<li class='jf'>{@link org.apache.juneau.html.annotation.HtmlFormat#HTML_CDC} - Format collections as comma-delimited lists.
<li class='jf'>{@link org.apache.juneau.html.annotation.HtmlFormat#HTML_SDC} - Format collections as space-delimited lists.
</ul>
<li>
Serializers now allow for q-values on the media types they handle.
<br>For example, the accept media type on <c>JsonSerializer.Simple</c> is <js>"application/json+simple,application/json;q=0.9"</js>.
<br>This means the serializer CAN handle requests for <js>"application/json"</js> if no other serializers provide a better match.
<li>
New methods for creating unmodifiable {@link org.apache.juneau.ObjectMap ObjectMaps} and {@link org.apache.juneau.ObjectList ObjectLists}.
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.ObjectMap}
<ul>
<li class='jm'>{@link org.apache.juneau.ObjectMap#isUnmodifiable() isUnmodifable()}
<li class='jm'>{@link org.apache.juneau.ObjectMap#unmodifiable() unmodifiable()}
<li class='jm'>{@link org.apache.juneau.ObjectMap#modifiable() modifiable()}
</ul>
<li class='jp'>{@link org.apache.juneau.ObjectList}
<ul>
<li class='jm'>{@link org.apache.juneau.ObjectList#isUnmodifiable() isUnmodifable()}
<li class='jm'>{@link org.apache.juneau.ObjectList#unmodifiable() unmodifiable()}
<li class='jm'>{@link org.apache.juneau.ObjectList#modifiable() modifiable()}
</ul>
</ul>
<li>
The <c>JsonSerializer.Simple</c> class has been moved into the top-level {@link org.apache.juneau.json.SimpleJsonSerializer} class.
<li>
RDF serializer subclasses have been moved into top-level classes:
<ul>
<li><c>RdfSerializer.Xml</c> -&gt; {@link org.apache.juneau.jena.RdfXmlSerializer}
<li><c>RdfSerializer.XmlAbbrev</c> -&gt; {@link org.apache.juneau.jena.RdfXmlAbbrevSerializer}
<li><c>RdfSerializer.N3</c> -&gt; {@link org.apache.juneau.jena.N3Serializer}
<li><c>RdfSerializer.NTriple</c> -&gt; {@link org.apache.juneau.jena.NTripleSerializer}
<li><c>RdfSerializer.Turtle</c> -&gt; {@link org.apache.juneau.jena.TurtleSerializer}
<li><c>RdfParser.Xml</c> -&gt; {@link org.apache.juneau.jena.RdfXmlParser}
<li><c>RdfParser.N3</c> -&gt; {@link org.apache.juneau.jena.N3Parser}
<li><c>RdfParser.NTriple</c> -&gt; {@link org.apache.juneau.jena.NTripleParser}
<li><c>RdfParser.Turtle</c> -&gt; {@link org.apache.juneau.jena.TurtleParser}
</ul>
<li>
New API for pairing serializers and parsers for simplified syntax:
<h5 class='figure'>Examples:</h5>
<p class='bpcode w800'>
<jc>// Using instance.</jc>
Json json = <jk>new</jk> Json();
MyPojo myPojo = json.read(string, MyPojo.<jk>class</jk>);
String string = json.write(myPojo);
</p>
<p class='bpcode w800'>
<jc>// Using DEFAULT instance.</jc>
MyPojo myPojo = Json.<jsf>DEFAULT</jsf>.read(string, MyPojo.<jk>class</jk>);
String string = Json.<jsf>DEFAULT</jsf>.write(myPojo);
</p>
<ul class='doctree'>
<li class='jac'>{@link org.apache.juneau.marshall.Marshall}
<ul>
<li class='jac'>{@link org.apache.juneau.marshall.CharMarshall}
<ul>
<li class='jc'>{@link org.apache.juneau.marshall.Html}
<li class='jc'>{@link org.apache.juneau.marshall.Json}
<li class='jc'>{@link org.apache.juneau.marshall.PlainText}
<li class='jc'>{@link org.apache.juneau.marshall.SimpleJson}
<li class='jc'>{@link org.apache.juneau.marshall.Uon}
<li class='jc'>{@link org.apache.juneau.marshall.UrlEncoding}
<li class='jc'>{@link org.apache.juneau.marshall.Xml}
<li class='jc'>{@link org.apache.juneau.marshall.N3}
<li class='jc'>{@link org.apache.juneau.marshall.NTriple}
<li class='jc'>{@link org.apache.juneau.marshall.RdfXml}
<li class='jc'>{@link org.apache.juneau.marshall.RdfXmlAbbrev}
<li class='jc'>{@link org.apache.juneau.marshall.Turtle}
</ul>
<li class='jac'>{@link org.apache.juneau.marshall.StreamMarshall}
<ul>
<li class='jc'>{@link org.apache.juneau.marshall.Jso}
<li class='jc'>{@link org.apache.juneau.marshall.MsgPack}
</ul>
</ul>
</ul>
<li>
New/updated documentation:
<ul>
<li><a href='#juneau-marshall.JsonDetails.SimplifiedJson'>2.15.3 - Simplified JSON</a>
</ul>
</ul>
<h5 class='topic w800'>juneau-dto</h5>
<ul class='spaced-list'>
<li>
Fixed bug where Swagger {@link org.apache.juneau.dto.swagger.SchemaInfo#required(Object...)} was defined as a boolean
instead of a list of strings.
<li>
Boolean attributes are now handled correctly for HTML5.
<br>For example, calling <c><jk>new</jk> Select().disabled(<jk>true</jk>)</c> will produce <c>&lt;select disabled='disabled'&gt;</c>
</ul>
<h5 class='topic w800'>juneau-rest-server</h5>
<ul class='spaced-list'>
<li>
Auto-generated {@doc juneau-rest-server.Swagger Swagger UI}.
<li>
Simplified <dc>@RestResource(swagger)</dc>
and {@link org.apache.juneau.rest.annotation.RestMethod#swagger() @RestMethod(swagger)} annotations.
<li>
Fixed bug in <c>UriResolver</c> when request path info had special characters.
<li>
Fixed bug where incorrect media type was being set on responses (e.g. <c>text/html+schema</c> instead of <c>text/html</c> for schema documents).
<li>
The <c>RemoteableServlet</c> class has been moved and renamed to <dc>RemoteInterfaceServlet</dc>.
<li>
<dc>RemoteInterfaceServlet</dc> now provides a form page for invoking remote interface methods in a browser.
<li>
Newlines were being stripped from <c><ja>@HtmlDoc</ja>(script)</c> when serialized which could cause script lines to become commented out.
<li>
New {@link org.apache.juneau.http.annotation.Response @Response} annotation that can be applied to
throwables thrown from REST methods and POJOs returned by REST methods to specify non-200 status return codes and descriptions in Swagger documentation.
<li>
Swagger fields added to the following annotations:
<ul class='doctree'>
<li class='ja'>{@link org.apache.juneau.http.annotation.Body}
<li class='ja'>{@link org.apache.juneau.http.annotation.FormData}
<li class='ja'>{@link org.apache.juneau.http.annotation.Header}
<li class='ja'>{@link org.apache.juneau.http.annotation.Path}
<li class='ja'>{@link org.apache.juneau.http.annotation.Query}
</ul>
<li>
The <ja>@PathRemainder</ja> annotation has been removed entirely.
<br>Use <c><ja>@Path</ja>(<js>"/*"</js>)</c> to access the path remainder which includes all the new OpenAPI parsing support.
<li>
"Helper" classes (i.e. reusable beans that can be returned by REST methods) have been moved to the following package with some new additions:
<ul class='doctree'>
<li class='jp'>{@link org.apache.juneau.rest.helper}
<ul>
<li class='jc'>{@link org.apache.juneau.rest.helper.BeanDescription}
<li class='jc'>{@link org.apache.juneau.rest.helper.ChildResourceDescriptions}
<li class='jc'><dc>ReaderResource</dc>
<li class='jc'><dc>ReaderResourceBuilder</dc>
<li class='jc'>{@link org.apache.juneau.rest.helper.SeeOtherRoot}
<li class='jc'>{@link org.apache.juneau.rest.helper.ResourceDescription}
<li class='jc'><dc>StreamResource</dc>
<li class='jc'><dc>StreamResourceBuilder</dc>
</ul>
</ul>
<li>
Predefined HTTP responses.
<ul class='doctree'>
<li class='jp'>{@link org.apache.juneau.rest.response}
<ul>
<li class='jc'>{@link org.apache.juneau.rest.response.Accepted}
<li class='jc'>{@link org.apache.juneau.rest.response.AlreadyReported}
<li class='jc'>{@link org.apache.juneau.rest.response.Continue}
<li class='jc'>{@link org.apache.juneau.rest.response.Created}
<li class='jc'>{@link org.apache.juneau.rest.response.EarlyHints}
<li class='jc'>{@link org.apache.juneau.rest.response.Found}
<li class='jc'>{@link org.apache.juneau.rest.response.IMUsed}
<li class='jc'>{@link org.apache.juneau.rest.response.MovedPermanently}
<li class='jc'>{@link org.apache.juneau.rest.response.MultipleChoices}
<li class='jc'>{@link org.apache.juneau.rest.response.MultiStatus}
<li class='jc'>{@link org.apache.juneau.rest.response.NoContent}
<li class='jc'>{@link org.apache.juneau.rest.response.NonAuthoritiveInformation}
<li class='jc'>{@link org.apache.juneau.rest.response.NotModified}
<li class='jc'>{@link org.apache.juneau.rest.response.Ok}
<li class='jc'>{@link org.apache.juneau.rest.response.PartialContent}
<li class='jc'>{@link org.apache.juneau.rest.response.PermanentRedirect}
<li class='jc'>{@link org.apache.juneau.rest.response.Processing}
<li class='jc'>{@link org.apache.juneau.rest.response.ResetContent}
<li class='jc'>{@link org.apache.juneau.rest.response.SeeOther}
<li class='jc'>{@link org.apache.juneau.rest.response.SwitchingProtocols}
<li class='jc'>{@link org.apache.juneau.rest.response.TemporaryRedirect}
<li class='jc'>{@link org.apache.juneau.rest.response.UseProxy}
</ul>
</ul>
<li>
Predefined HTTP error throwables.
<br>When added to REST Java methods, reflected in generated Swagger documentation.
<ul class='doctree'>
<li class='jp'>{@link org.apache.juneau.rest.exception}
<ul>
<li class='jc'>{@link org.apache.juneau.rest.exception.BadRequest}
<li class='jc'>{@link org.apache.juneau.rest.exception.Conflict}
<li class='jc'>{@link org.apache.juneau.rest.exception.ExpectationFailed}
<li class='jc'>{@link org.apache.juneau.rest.exception.FailedDependency}
<li class='jc'>{@link org.apache.juneau.rest.exception.Forbidden}
<li class='jc'>{@link org.apache.juneau.rest.exception.Gone}
<li class='jc'>{@link org.apache.juneau.rest.exception.HttpVersionNotSupported}
<li class='jc'>{@link org.apache.juneau.rest.exception.InsufficientStorage}
<li class='jc'>{@link org.apache.juneau.rest.exception.InternalServerError}
<li class='jc'>{@link org.apache.juneau.rest.exception.LengthRequired}
<li class='jc'>{@link org.apache.juneau.rest.exception.Locked}
<li class='jc'>{@link org.apache.juneau.rest.exception.LoopDetected}
<li class='jc'>{@link org.apache.juneau.rest.exception.MethodNotAllowed}
<li class='jc'>{@link org.apache.juneau.rest.exception.MisdirectedRequest}
<li class='jc'>{@link org.apache.juneau.rest.exception.NetworkAuthenticationRequired}
<li class='jc'>{@link org.apache.juneau.rest.exception.NotAcceptable}
<li class='jc'>{@link org.apache.juneau.rest.exception.NotExtended}
<li class='jc'>{@link org.apache.juneau.rest.exception.NotFound}
<li class='jc'>{@link org.apache.juneau.rest.exception.NotImplemented}
<li class='jc'>{@link org.apache.juneau.rest.exception.PayloadTooLarge}
<li class='jc'>{@link org.apache.juneau.rest.exception.PreconditionFailed}
<li class='jc'>{@link org.apache.juneau.rest.exception.PreconditionRequired}
<li class='jc'>{@link org.apache.juneau.rest.exception.RangeNotSatisfiable}
<li class='jc'>{@link org.apache.juneau.rest.exception.RequestHeaderFieldsTooLarge}
<li class='jc'>{@link org.apache.juneau.rest.exception.ServiceUnavailable}
<li class='jc'>{@link org.apache.juneau.rest.exception.TooManyRequests}
<li class='jc'>{@link org.apache.juneau.rest.exception.Unauthorized}
<li class='jc'>{@link org.apache.juneau.rest.exception.UnavailableForLegalReasons}
<li class='jc'>{@link org.apache.juneau.rest.exception.UnprocessableEntity}
<li class='jc'>{@link org.apache.juneau.rest.exception.UnsupportedMediaType}
<li class='jc'>{@link org.apache.juneau.rest.exception.UpgradeRequired}
<li class='jc'>{@link org.apache.juneau.rest.exception.UriTooLong}
<li class='jc'>{@link org.apache.juneau.rest.exception.VariantAlsoNegotiates}
</ul>
</ul>
<li>
The {@link org.apache.juneau.rest.annotation.HtmlDoc#nav() @HtmlDoc(nav)} and {@link org.apache.juneau.rest.annotation.HtmlDoc#navlinks() @HtmlDoc(navlinks)}
can now both be used on the same annotation.
<br>The contents of <c>nav()</c> are free-form HTML that gets rendered immediately after the navigation links.
<li>
The following new parameter types can be used on REST methods:
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.parser.ReaderParser} - The reader parser matching the request content type.
<li class='jc'>{@link org.apache.juneau.parser.InputStreamParser} - The input stream parser matching the request content type.
</ul>
<li>
The <c>$F</c> variable can now be used as a initialization time variable.
<br>For example, the <c>AtomFeedResource</c> example pulls a bean example from a file on the classpath:
<p class='bcode w800'>
<ja>@RestResource</ja>(
path=<js>"/atom"</js>,
title=<js>"Sample ATOM feed resource"</js>,
properties={
<ja>@Property</ja>(name=<jsf>BEAN_examples</jsf>, value=<js>"{'org.apache.juneau.dto.atom.Feed': $F{AtomFeedResource_example.json}}"</js>)
},
...
)
</p>
<br>It should be noted that you cannot use the <c>$F</c> variable to retrieve localized versions of files (since you're not within
the scope of a client request.
<li>
The <dc>RestResource.nowrap()</dc> annotation has been changed to a string with a default value of <js>"true"</js>.
<br>Having it as a string allows us to differentiate between a set and unset value so that it can be overridden in subclasses.
<li>
The {@link org.apache.juneau.http.annotation.Path#name()} annotation parameter is now required.
<li>
New class for mock unit testing of REST resources:
<ul class='doctree'>
<li class='jc'><dc>MockRest</dc>
</ul>
<li>
<c><ja>@RestMethod</ja>(inherit)</c> annotation has been removed and replaced with the following classes:
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.rest.Inherit}
<li class='jc'>{@link org.apache.juneau.rest.None}
</ul>
<br>These can be used in the following locations:
<ul class='doctree'>
<li class='ja'><dc>RestResource.serializers()</dc>
<li class='ja'><dc>RestResource.parsers()</dc>
<li class='ja'><dc>RestResource.beanFilters()</dc>
<li class='ja'><dc>RestResource.pojoSwaps()</dc>
<li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#serializers()}
<li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#parsers()}
<li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#beanFilters()}
<li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#pojoSwaps()}
</ul>
<br>One advantage is that you now have control over the precedence of serializers and parsers by where you insert the <c>Inherit</c> class.
<li>
<c>RequestPathMatch</c> class has been renamed to {@link org.apache.juneau.rest.RequestPath}.
<li>
{@link org.apache.juneau.http.annotation.Request @Request} objects can now be used as parameters in <ja>@RestMethod</ja> methods.
<br>Includes new methods on {@link org.apache.juneau.rest.RestRequest}:
<ul class='doctree'>
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getRequest(Class) getRequest(Class)}
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getRequest(RequestBeanMeta) getRequest(RequestBeanMeta)}
</ul>
<li>
New methods added to {@link org.apache.juneau.rest.widget.MenuItemWidget} to allow population of menu item content using Javascript and Ajax calls:
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.rest.widget.MenuItemWidget}
<ul>
<li class='jm'><dc>getBeforeShowScript(RestRequest)</dc>
<li class='jm'><dc>getAfterShowScript(RestRequest)</dc>
</ul>
</ul>
<li>
New methods added to {@link org.apache.juneau.rest.widget.Widget} to allow retrieving classpath resources with embedded SVL variables:
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.rest.widget.Widget}
<ul>
<li class='jm'><dc>loadHtmlWithVars(RestRequest,String)</dc>
<li class='jm'><dc>loadScriptWithVars(RestRequest,String)</dc>
<li class='jm'><dc>loadStyleWithVars(RestRequest,String)</dc>
</ul>
</ul>
<li>
New/updated documentation:
<br><dc>juneau-rest-server.UnitTesting</dc>
<li>
The behavior of the default values for {@link org.apache.juneau.rest.annotation.RestMethod#name()} and {@link org.apache.juneau.rest.annotation.RestMethod#path()}
have changed.
<br>If not specified, the values are inferred from the Java method name.
<br>See Also: {@doc juneau-rest-server.RestMethod}
<li>
<c>RedirectToServletRoot</c> class has been renamed to {@link org.apache.juneau.rest.helper.SeeOtherRoot}.
<li>
New REST context settings:
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.rest.RestContext}
<ul>
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_uriAuthority REST_uriAuthority}
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_uriContext REST_uriContext}
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_uriRelativity REST_uriRelativity}
<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_uriResolution REST_uriResolution}
</ul>
</ul>
<li>
New convenience annotations for specifying default <c>Accept</c> and <c>Content-Type</c> headers:
<ul class='doctree'>
<li class='jc'><dc>RestResource</dc>
<ul>
<li class='jf'><dc>defaultAccept</dc>
<li class='jf'><dc>defaultContentType</dc>
</ul>
<li class='jc'>{@link org.apache.juneau.rest.annotation.RestMethod}
<ul>
<li class='jf'>{@link org.apache.juneau.rest.annotation.RestMethod#defaultAccept defaultAccept}
<li class='jf'>{@link org.apache.juneau.rest.annotation.RestMethod#defaultContentType defaultContentType}
</ul>
</ul>
</ul>
<h5 class='topic w800'>juneau-rest-client</h5>
<ul class='spaced-list'>
<li>
Remote Resource interfaces support OpenAPI annotations.
<li>
Made improvements to the builder API for defining SSL support.
<br>New methods added:
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.rest.client.RestClientBuilder}
<ul>
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#sslProtocols(String...) sslProtocols(String...)}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#cipherSuites(String...) cipherSuites(String...)}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#hostnameVerifier(HostnameVerifier) hostnameVerifier(HostnameVerifier)}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#keyManagers(KeyManager...) keyManagers(KeyManager...)}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#trustManagers(TrustManager...)}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#secureRandom(SecureRandom)}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#httpClientConnectionManager(HttpClientConnectionManager)}
</ul>
</ul>
<li>
Clients no longer have JSON defined as the default serializer and parser.
<br>Instead, the clients can now be used with no serializer/parser if you're working with InputStreams/Readers or
POJOs that can be converted to Strings and converted from Strings/InputStreams/Readers.
<li>
Methods added to client builder to make it easy to define the transport language:
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.rest.client.RestClientBuilder}
<ul>
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#json() json()}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#xml() xml()}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#html() html()}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#uon() uon()}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#urlEnc() urlEnc()}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#msgpack() msgpack()}
<li class='jf'>{@link org.apache.juneau.rest.client.RestClientBuilder#plainText() plainText()}
</ul>
</ul>
<li>
New method added for allowing serverless client testing against REST interfaces.
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.rest.client.RestClientBuilder}
<ul>
<li class='jf'><dc>mockHttpConnection(MockHttpConnection)</dc>
</ul>
</ul>
<li>
Removed the deprecated <c>RestCall.execute()</c> method.
<br>Use {@link org.apache.juneau.rest.client.RestCall#run()}.
<li>
<c>RestCall.input(Object)</c> method renamed to {@link org.apache.juneau.rest.client.RestCall#body(Object)} to match OpenAPI terminology.
<li>
Made constructors on <c>RestClient</c> and <c>RestClientBuilder</c> protected so that they can be subclassed.
<li>
The <c>RestClient.getRemoteableProxy()</c> methods have been split into separate methods for Remote Interfaces and Remote Resources:
<ul class='doctree'>
<li class='jc'>{@link org.apache.juneau.rest.client.RestClient}
<ul>
<li class='jm'><dc>RestClient.getRemoteInterface(Class)</dc>
<li class='jm'><dc>RestClient.getRemoteInterface(Class,Object)</dc>
<li class='jm'><dc>RestClient.getRemoteInterface(Class,Object,Serializer,Parser)</dc>
<li class='jm'>{@link org.apache.juneau.rest.client.RestClient#getRemoteResource(Class)}
<li class='jm'>{@link org.apache.juneau.rest.client.RestClient#getRemoteResource(Class,Object)}
<li class='jm'>{@link org.apache.juneau.rest.client.RestClient#getRemoteResource(Class,Object,Serializer,Parser)}
</ul>
</ul>
</ul>
<h5 class='topic w800'>juneau-rest-microservice</h5>
<ul class='spaced-list'>
<li>
The look-and-feel of an application is now controlled through the external configuration file and access to
CSS stylesheets in the working directory in a new folder called <c>files</c>:
<br><img class='bordered' style='width:170px' src='doc-files/ReleaseNotes.711.1.png'>
<br><br>
The default configuration is this:
<p class='bcode w800'>
<cc>#=======================================================================================================================
# REST settings
#=======================================================================================================================</cc>
<cs>[REST]</cs>
<ck>staticFiles</ck> = <cv>htdocs:files/htdocs</cv>
<cc># Stylesheet to use for HTML views.</cc>
<ck>theme</ck> = <cv>servlet:/htdocs/themes/devops.css</cv>
<ck>headerIcon</ck> = <cv>servlet:/htdocs/images/juneau.png</cv>
<ck>headerLink</ck> = <cv>http://juneau.apache.org</cv>
<ck>footerIcon</ck> = <cv>servlet:/htdocs/images/asf.png</cv>
<ck>footerLink</ck> = <cv>http://www.apache.org</cv>
<ck>icon</ck> = <cv>$C{REST/headerIcon}</cv>
<ck>header</ck> = <cv>&lt;a href='$U{$C{REST/headerLink}}'&gt;&lt;img src='$U{$C{REST/headerIcon}}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/&gt;&lt;/a&gt;</cv>
<ck>footer</ck> = <cv>&lt;a href='$U{$C{REST/footerLink}}'&gt;&lt;img style='float:right;padding-right:20px;height:32px' src='$U{$C{REST/footerIcon}}'&gt;</cv>
</p>
<br><br>
Note that static files can now be served up from the <c>files</c> directory in the working directory,
and you have access to modify the CSS theme files.
<br>The <c>SwaggerUI.css</c> file controls the look-and-feel of the Swagger UI, so you can make
modification there as well.
<br><br>
The <c>BasicRestConfig</c> interface (which defines the default settings for the <c>BasicRestServlet</c> class)
now looks like this...
<p class='bcode w800'>
<ja>@RestResource</ja>(
...
htmldoc=<ja>@HtmlDoc</ja>(
header={
<js>"&lt;h1&gt;$R{resourceTitle}&lt;/h1&gt;"</js>,
<js>"&lt;h2&gt;$R{methodSummary,resourceDescription}&lt;/h2&gt;"</js>,
<js>"$C{REST/header}"</js>
},
navlinks={
<js>"up: request:/.."</js>
},
stylesheet=<js>"$C{REST/theme,servlet:/htdocs/themes/devops.css}"</js>,
head={
<js>"&lt;link rel='icon' href='$U{$C{REST/icon}}'/&gt;"</js>
},
footer=<js>"$C{REST/footer}"</js>
),
<jc>// These are static files that are served up by the servlet under the specified sub-paths.
// For example, "/servletPath/htdocs/javadoc.css" resolves to the file "[servlet-package]/htdocs/javadoc.css"</jc>
staticFiles={<js>"$C{REST/staticFiles}"</js>}
)
<jk>public interface</jk> BasicRestConfig {}
</p>
<br><br>
The <c>PoweredByApache</c> widget which used to serve as a page footer has been eliminated.
<br><br>
If you're testing out changes in the theme stylesheets, you may want to set the following system property
that prevents caching of those files so that you don't need to restart the microservice each time a change is made:
<p class='bcode w800'>
<cc>#=======================================================================================================================
# System properties
#=======================================================================================================================</cc>
<cs>[SystemProperties]</cs>
<cc># Disable classpath resource caching.
# Useful if you're attached using a debugger and you're modifying classpath resources while running.</cc>
<ck>RestContext.useClasspathResourceCaching.b</ck> = <cv>false</cv>
</p>
<li>
Upgraded to Jetty 9.4.12.
</ul>
</div><!-- END: 7.2.0 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#7.2.1' id='7.2.1'>7.2.1 (Oct 23, 2018)</a></h3>
<div class='topic'><!-- START: 7.2.1 -->
<p>
This release contains mostly bug fixes.
Code changes have been made to preserve binary backwards compatibility with 7.1.0.
</p>
<h5 class='topic w800'>juneau-marshall</h5>
<ul class='spaced-list'>
<li>
The <dc>@JsonSchema</dc> annotation has been merged with the {@link org.apache.juneau.jsonschema.annotation.Schema @Schema} annotation.
<li>
Annotations typically used on bean properties (getters/setters/public fields) can now be used on private fields.
This is inline with behavior on JPA-annotated beans.
These include: <ja>@Swap</ja>, <ja>@Html</ja>, <ja>@Xml</ja>, <jd>@BeanProperty</jd>.
</ul>
<h5 class='topic w800'>juneau-rest-server</h5>
<ul class='spaced-list'>
<li>
Method-level annotations (e.g. <ja>@RestMethod</ja>) and parameter-level annotations (e.g. <ja>@Query</ja>) are now inheritable
from parent classes and interfaces.
<br>This allows you to define {@doc juneau-rest-client.RestProxies.DualPurposeInterfaces}.
<li>
The <c>ReaderResource</c> and <c>StreamResource</c> classes have been moved to the <c>org.apache.juneau.http</c>
package in <c>juneau-marshall</c>. This allows them to be used as return types in remote REST interfaces.
<br>A new {@link org.apache.juneau.rest.helper.ResolvingReaderResource} class has been added that includes the variable-resolving support since
this relies on the <c>juneau-svl</c> package.
<li>
The <c>RemoteInterfaceServlet</c> class has been renamed to {@link org.apache.juneau.rest.remote.RrpcServlet}.
<li>
<c><ja>@RestMethod</ja>(name=<js>"PROXY"</js>)</c> has been changed to <c><ja>@RestMethod</ja>(name=<js>"RRPC"</js>)</c>.
</ul>
<h5 class='topic w800'>juneau-rest-client</h5>
<ul class='spaced-list'>
<li>
The <c>RestClient.getRemoteInterface()</c> method has been renamed to {@link org.apache.juneau.rest.client.RestClient#getRrpcInterface(Class)}.
<li>
Fixed a bug where <c><ja>@RemoteMethod</ja>(path)</c> values containing '/' characters were erroneously being encoded.
</ul>
</div><!-- END: 7.2.1 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#7.2.2' id='7.2.2'>7.2.2 (Nov 7, 2018)</a></h3>
<div class='topic'><!-- START: 7.2.2 -->
<p>
This release contains minor bug fixes and general improvements to the PetStore sample application.
</p>
</div><!-- END: 7.2.2 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#8.0.0' id='8.0.0'>8.0.0 (Jan 01, 2019)</a></h3>
<div class='topic'><!-- START: 8.0.0 -->
<p>
This release cleans up deprecated APIs from the 7.2.0 release and makes significant modifications
to the Microservice APIs.
</p>
<p>
The project structures of the REST, Microservice, and Examples have been modified to fit new Spring Boot
integration support.
The structure is now as follows:
</p>
<ul>
<li><c>juneau-rest</c>
<ul>
<li><c>juneau-rest-client</c>
<li><c>juneau-rest-server</c>
<li><c>juneau-rest-server-jaxrs</c>
<li><c>juneau-rest-server-rdf</c>
<li><b><c>juneau-rest-server-springboot</c></b> - New Spring Boot integration support classes.
</ul>
<li><c>juneau-microservice</c>
<ul>
<li><b><c>juneau-microservice-core</c></b> - New. Contains base {@link org.apache.juneau.microservice.Microservice} class.
<li><b><c>juneau-microservice-jetty</c></b> - New. Contains new {@link org.apache.juneau.microservice.jetty.JettyMicroservice} class.
<li><b><c>juneau-my-jetty-microservice</c></b> - New. Template starter project for Jetty-based microservices.
<li><b><c>juneau-my-springboot-microservice</c></b> - New. Template starter project for Spring-Boot-based microservices.
</ul>
<li><c>juneau-examples</c>
<ul>
<li><c>juneau-core</c>
<li><b><c>juneau-microservice-rest</c></b> - Now contains only servlet example classes. No Jetty configuration.
<li><b><c>juneau-microservice-rest-jetty</c></b> - Servlet examples deployed using Jetty.
<li><b><c>juneau-microservice-rest-springboot</c></b> - Servlet examples deployed using Spring Boot.
</ul>
</ul>
<h5 class='topic w800'>juneau-svl</h5>
<ul class='spaced-list'>
<li>
New SVL variables:
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.svl.vars.SubstringVar}
<li class='jc'>{@link org.apache.juneau.svl.vars.PatternExtractVar}
<li class='jc'>{@link org.apache.juneau.svl.vars.PatternReplaceVar}
<li class='jc'>{@link org.apache.juneau.svl.vars.LenVar}
</ul>
</ul>
<h5 class='topic w800'>juneau-config</h5>
<ul class='spaced-list'>
<li>
New methods for setting a system default configuration:
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.Config}
<ul>
<li class='jm'>{@link org.apache.juneau.config.Config#getSystemDefault() getSystemDefault()}
<li class='jm'>{@link org.apache.juneau.config.Config#setSystemDefault(Config) setSystemDefault(Config)}
</ul>
</ul>
<li>
New classpath store.
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.store.ConfigClasspathStore}
</ul>
<li>
New API method:
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.config.store.ConfigStore}
<ul>
<li class='jm'>{@link org.apache.juneau.config.store.ConfigStore#exists(String) exists(String)}
</ul>
</ul>
</ul>
<h5 class='topic w800'>juneau-rest-server</h5>
<ul class='spaced-list'>
<li>
New methods on {@link org.apache.juneau.rest.RestServlet}:
<ul class='javatree'>
<li class='jm'>{@link org.apache.juneau.rest.RestServlet#setRestResourceResolver(RestResourceResolver) setRestResourceResolver(RestResourceResolver)}
<li class='jm'>{@link org.apache.juneau.rest.RestServlet#getPath() getPath()}
</ul>
<li>
The registered resource resolver is now used to instantiate objects of classes defined via <dc>@RestResource</dc>.
<br>This allows for any of those instance to be injectable beans.
</ul>
<h5 class='topic w800'>juneau-rest-server-springboot</h5>
<ul class='spaced-list'>
<li>
New project containing classes for making it easy to use Juneau with Spring Boot.
</ul>
<h5 class='topic w800'>juneau-microservice-core</h5>
<ul class='spaced-list'>
<li>
New project that consist of just the core {@link org.apache.juneau.microservice.Microservice} class and console support.
<li>
The Microservice API has been revamped to use a builder-based approach to creating microservices.
<br>The new API is considerably more flexible in design and allows for the configuration and external
files to be located in either the home directory or inside the jar classpath.
<li>
If the microservice cannot find a config file in the home directory with the same name as the jar and
the <js>"juneau.configFile"</js> system property is not found, it will try to find any file in the home
directory that ends with <js>".cfg"</js>.
<li>
New {@link org.apache.juneau.microservice.MicroserviceListener} API for defining lifecycle event listeners.
<li>
New {@link org.apache.juneau.microservice.console.ConfigCommand} class for performing config queries and updates through
the microservice console.
</ul>
<h5 class='topic w800'>juneau-microservice-jetty</h5>
<ul class='spaced-list'>
<li>
New {@link org.apache.juneau.microservice.jetty.JettyMicroservice} class replaces the previous <c>RestMicroservice</c>.
</ul>
<h5 class='topic w800'>juneau-my-jetty-microservice</h5>
<ul class='spaced-list'>
<li>
New template starter project for Jetty-based microservices.
</ul>
<h5 class='topic w800'>juneau-my-springboot-microservice</h5>
<ul class='spaced-list'>
<li>
Template starter project for Spring-Boot-based microservices.
<li>
<c>app.json</c> and <c>Procfile</c> files for deploying examples into Heroku.
<br>Includes instructions.
</ul>
</div><!-- END: 8.0.0 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#8.1.0' id='8.1.0'>8.1.0 (Aug 21, 2019)</a></h3>
<div class='topic'><!-- START: 8.1.0 -->
<p>
8.1.0 introduces some significant new features including:
</p>
<ul class='spaced-list'>
<li>
<a href='#juneau-marshall.ConfigurableAnnotations'>Configurable Annotations</a>
<li>
<a href='#juneau-marshall.Transforms.DefaultPojoSwaps'>Default PojoSwaps</a>
<li>
<a href='#juneau-config.Imports'>Config Imports</a>
<li>
<a href='#juneau-rest-server.Instantiation.BasicRest'>BasicRest</a>, <a href='#juneau-rest-server.Instantiation.BasicRestGroup'>BasicRestGroup</a> classes
<li>
<a href='#juneau-rest-server.Rest.RestPath'>Path variables on resource paths</a>
<li>
<a href='#juneau-rest-server.RestMethod.RequestAttributes'>Request Attributes API</a>
<li>
<a href='#juneau-rest-server.RoleGuards'>Role Guards</a>
<li>
<a href='#juneau-rest-server.LoggingAndDebugging'>Improved REST logging/debugging</a>
<li>
<a href='#juneau-rest-mock'>New MockRest API</a>
</ul>
<h5 class='topic w800'>juneau-marshall</h5>
<ul class='spaced-list'>
<li>
New utility class for diffing beans:
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.utils.BeanDiff}
</ul>
<li>
New annotation for defining bean property names:
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.annotation.Name}
</ul>
<li>
New serializer properties:
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.serializer.WriterSerializer}
<ul>
<li class='jf'>{@link org.apache.juneau.serializer.WriterSerializer#WSERIALIZER_fileCharset WSERIALIZER_fileCharset}
<li class='jf'>{@link org.apache.juneau.serializer.WriterSerializer#WSERIALIZER_streamCharset WSERIALIZER_streamCharset}
</ul>
</ul>
<li>
The following POJO methods can be used to convert a POJO to/from a Map before serialization and after parsing.
<br>It's a convenient way of defining a POJO transform.
<ul class='javatree'>
<li class='jm'><c><jk>public</jk> Map toMap()</c> - Can be any type of map with string keys and object vals.
<li class='jm'><c><jk>public</jk> ObjectMap toMap()</c>
<li class='jm'><c><jk>public</jk> Map toMap(BeanSession bs)</c> - Can be any type of map with string keys and object vals.
<li class='jm'><c><jk>public</jk> ObjectMap toMap(BeanSession bs)</c>
<li class='jm'><c><jk>public static</jk> T fromMap(Map m)</c> - Can be any type of map with string keys and object vals.
<li class='jm'><c><jk>public static</jk> T fromMap(ObjectMap m)</c>
<li class='jm'><c><jk>public static</jk> T fromMap(BeanSession bs, Map m)</c> - Can be any type of map with string keys and object vals.
<li class='jm'><c><jk>public static</jk> T fromMap(BeanSession bs, ObjectMap m)</c>
</ul>
<li>
New convenience debugging methods on Marshall API:
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.marshall.Marshall}
<ul>
<li class='jm'>{@link org.apache.juneau.marshall.Marshall#format(String,Object...) format(String,Object...)} - <c>MessageFormat</c>-style formatter.
<li class='jm'>{@link org.apache.juneau.marshall.Marshall#out(String,Object...) out(String,Object...)} - Prints <c>MessageFormat</c>-style messages to STDOUT.
<li class='jm'>{@link org.apache.juneau.marshall.Marshall#err(String,Object...) err(String,Object...)} - Prints <c>MessageFormat</c>-style messages to STDERR.
</ul>
</ul>
<li>
Serializer and parser APIs now throw <c>IOExceptions</c> in addition to <c>SerializeException</c> and <c>ParseException</c> to make it
easier to determine if problems are stream based or syntax based.
<li>
New Java 8 date-time transforms:
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.transforms.TemporalSwap} - For all Java 8 temporal types (e.g. {@link java.time.ZonedDateTime})
<li class='jc'>{@link org.apache.juneau.transforms.TemporalDateSwap} - For {@link java.util.Date}
<li class='jc'>{@link org.apache.juneau.transforms.TemporalCalendarSwap} - For {@link java.util.Calendar}
</ul>
<li>
All serializers and parsers now have built-in default swaps for common class types:
<ul class='javatree'>
<li class='jc'>{@link java.util.Enumeration}
<li class='jc'>{@link java.util.Iterator}
<li class='jc'>{@link java.util.Locale}
<li class='jc'>{@link java.util.Calendar} - ISO offset date-time.
<li class='jc'>{@link java.util.Date} - Local date-time
<li class='jc'>{@link java.time.Instant} - ISO instant.
<li class='jc'>{@link java.time.ZonedDateTime} - ISO offset date-time.
<li class='jc'>{@link java.time.LocalDate} - ISO local date.
<li class='jc'>{@link java.time.LocalDateTime} - ISO local date-time.
<li class='jc'>{@link java.time.LocalTime} - ISO local time.
<li class='jc'>{@link java.time.OffsetDateTime} - ISO offset date-time.
<li class='jc'>{@link java.time.OffsetTime} - ISO offset time.
<li class='jc'>{@link java.time.Year} - ISO year.
<li class='jc'>{@link java.time.YearMonth} - ISO year-month.
<li class='jc'>{@link java.time.Temporal} - ISO instant.
<li class='jc'>{@link java.util.TimeZone}
<li class='jc'>{@link javax.xml.datatype.XMLGregorianCalendar}
<li class='jc'>{@link java.time.ZoneId}
</ul>
</ul>
<h5 class='topic w800'>juneau-config</h5>
<ul class='spaced-list'>
<li>
Support for import statements:
<p class='bpcode'>
<cc># Import values from another configuration:</cc>
<ci>&lt;ParentConfig1&gt;</ci>
<cs>[Foo]</cs>
<ck>bar</ck> = <cv>baz</cv>
</p>
<li>
The {@link org.apache.juneau.config.store.ConfigFileStore} now automatically resolves file extensions.
<br>New configuration property for specifying search paths for file extensions:
<ul class='javatree'>
<li class='jf'>{@link org.apache.juneau.config.store.ConfigFileStore#FILESTORE_extensions}
</ul>
<li>
Fixed a bug where instances of {@link org.apache.juneau.config.store.ConfigMemoryStore} ended up resolving to the same object.
<li>
Uses <js>"application.properties"</js> file as a system default if present.
<br>Useful when being used in a Spring Boot application.
<li>
New {@link org.apache.juneau.config.Config#setSystemProperties} method for quickly moving configuration settings into the
system properties.
<li>
Entries in the system config are automatically set as system properties.
<br>This mean you can set any of the various serializer and parser settings (e.g. <js>"JsonSerializer.simpleMode.b"</js>)
in the default configuration area or <c>application.properties</c>.
</ul>
<h5 class='topic w800'>juneau-rest-server</h5>
<ul class='spaced-list'>
<li>
New annotations that can be applied to REST classes and methods to configure serializers and parsers.
<p class='bcode w800'>
<jc>// Old way using generic properties.</jc>
<ja>@RestResource</ja>(
path=<js>"/atom"</js>,
title=<js>"Sample ATOM feed resource"</js>,
properties={
<ja>@Property</ja>(name=<jsf>WSERIALIZER_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>),
<ja>@Property</ja>(name=<jsf>BEAN_examples</jsf>, value=<js>"{'org.apache.juneau.dto.atom.Feed': $F{AtomFeedResource_example.json}}"</js>)
}
...
)
<jk>public class</jk> AtomFeedResource <jk>extends</jk> BasicRestServletJena {
...
}
</p>
<p class='bcode w800'>
<jc>// New way using specific annotations.</jc>
<ja>@RestResource</ja>(
path=<js>"/atom"</js>,
title=<js>"Sample ATOM feed resource"</js>
...
)
<ja>@SerializerConfig</ja>(quoteChar=<js>"'"</js>)
<ja>@RdfConfig</ja>(rdfxml_tab=<js>"5"</js>, addRootProperty=<js>"true"</js>)
<ja>@BeanConfig</ja>(examples=<js>"Feed: $F{AtomFeedResource_example.json}"</js>)
<jk>public class</jk> AtomFeedResource <jk>extends</jk> BasicRestServletJena {
...
}
</p>
<p>
Config annotations are provided for all serializers and parsers:
</p>
<ul class='javatree'>
<li class='ja'>{@link org.apache.juneau.annotation.BeanConfig BeanConfig}
<li class='ja'>{@link org.apache.juneau.csv.annotation.CsvConfig CsvConfig}
<li class='ja'>{@link org.apache.juneau.html.annotation.HtmlConfig HtmlConfig}
<li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig HtmlDocConfig}
<li class='ja'>{@link org.apache.juneau.jso.annotation.JsoConfig JsoConfig}
<li class='ja'>{@link org.apache.juneau.json.annotation.JsonConfig JsonConfig}
<li class='ja'>{@link org.apache.juneau.jsonschema.annotation.JsonSchemaConfig JsonSchemaConfig}
<li class='ja'>{@link org.apache.juneau.msgpack.annotation.MsgPackConfig MsgPackConfig}
<li class='ja'>{@link org.apache.juneau.oapi.annotation.OpenApiConfig OpenApiConfig}
<li class='ja'>{@link org.apache.juneau.parser.annotation.ParserConfig ParserConfig}
<li class='ja'>{@link org.apache.juneau.plaintext.annotation.PlainTextConfig PlainTextConfig}
<li class='ja'>{@link org.apache.juneau.jena.annotation.RdfConfig RdfConfig}
<li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig SerializerConfig}
<li class='ja'>{@link org.apache.juneau.soap.annotation.SoapXmlConfig SoapXmlConfig}
<li class='ja'>{@link org.apache.juneau.uon.annotation.UonConfig UonConfig}
<li class='ja'>{@link org.apache.juneau.urlencoding.annotation.UrlEncodingConfig UrlEncodingConfig}
<li class='ja'>{@link org.apache.juneau.xml.annotation.XmlConfig XmlConfig}
</ul>
<li>
New support for using Servlet request attributes.
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.RequestAttributes}
<li class='jc'>{@link org.apache.juneau.rest.RestContext}
<ul>
<li class='jf'><dc>REST_attrs</dc>
</ul>
<li class='jc'>{@link org.apache.juneau.rest.RestContextBuilder}
<ul>
<li class='jm'><dc>attrs(String...)</dc>
<li class='jm'><dc>attr(String,Object)</dc>
</ul>
<li class='jc'>{@link org.apache.juneau.rest.RestMethodContext}
<ul>
<li class='jf'>{@link org.apache.juneau.rest.RestMethodContext#RESTMETHOD_attrs RESTMETHOD_attrs}
</ul>
<li class='jc'>{@link org.apache.juneau.rest.RestRequest}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getAttributes() getAttributes()}
</ul>
<li class='jc'>{@link org.apache.juneau.rest.RestResponse}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RestResponse#getAttributes() getAttributes()}
<li class='jm'>{@link org.apache.juneau.rest.RestResponse#attr(String,Object) attr(String,Object)}
</ul>
<li class='ja'>{@link org.apache.juneau.rest.annotation.Attr}
<li class='ja'><dc>RestMethod#attrs()</dc>
<li class='ja'><dc>RestResource.attrs()</dc>
</ul>
<br>This deprecates the following APIs:
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.RequestProperties}
<li class='jc'>{@link org.apache.juneau.rest.RestMethodProperties}
<li class='jc'>{@link org.apache.juneau.rest.RestRequest}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getProperties() getProperties()}
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#prop(String,Object) prop(String,Object)}
</ul>
</ul>
<li>
Added the following classes that provide the same support as the servlet classes but doesn't extend from <c>HttpServlet</c>.
<br>This fixes an issue where instances of {@link org.apache.juneau.rest.BasicRestServlet} are registered as top-level servlets even though
you don't want them to be.
<ul class='javatree'>
<li class='jac'>{@link org.apache.juneau.rest.BasicRest} - Non-servlet equivalent to {@link org.apache.juneau.rest.BasicRestServlet}
<li class='jac'>{@link org.apache.juneau.rest.BasicRestGroup} - Non-servlet equivalent to {@link org.apache.juneau.rest.BasicRestServletGroup}
<li class='jac'>{@link org.apache.juneau.rest.BasicRestJena} - Non-servlet equivalent to {@link org.apache.juneau.rest.BasicRestServletJena}
<li class='jac'>{@link org.apache.juneau.rest.BasicRestJenaGroup} - Non-servlet equivalent to {@link org.apache.juneau.rest.BasicRestServletJenaGroup}
</ul>
<li>
HTML widgets now have access to the <c>RestResponse</c> object if they need access to the output bean.
<li>
New annotations for simplified role-based guards on classes and methods:
<ul class='javatree'>
<li class='ja'><dc>RestResource</dc>
<ul>
<li class='jm'><dc>roleGuard()</dc>
<li class='jm'><dc>rolesDeclared()</dc>
</ul>
<li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.annotation.RestMethod#roleGuard roleGuard()}
<li class='jm'>{@link org.apache.juneau.rest.annotation.RestMethod#rolesDeclared rolesDeclared()}
</ul>
</ul>
<li>
New annotations for fine-tuned handling of http-methods/http-headers as query parameters and others:
<ul class='javatree'>
<li class='ja'><dc>RestResource</dc>
<ul>
<li class='jm'><dc>allowedHeaderParams()</dc>
<li class='jm'><dc>allowedMethodHeaders()}</dc>
<li class='jm'><dc>allowedMethodParams()</dc>
</ul>
</ul>
<li>
The <dc>@RestResource(path)</dc> annotation can now use variables:
<p class='bcode'>
<ja>@RestResource</ja>(
path=<js>"/myResource/{foo}/{bar}"</js>
)
<jk>public class</jk> MyResource <jk>extends</jk> BasicRestServlet {...}
</p>
<li>
New methods:
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.RestRequest}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getCharset() getCharset()}
</ul>
<li class='jc'>{@link org.apache.juneau.rest.RestResponse}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RestResponse#getCharset() getCharset()}
</ul>
</ul>
<li>
New interface method for catching arbitrary thrown objects and converting them to other throwables.
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.RestCallHandler}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.RestCallHandler#convertThrowable(Throwable) convertThrowable(Throwable)}
</ul>
<li class='jc'>{@link org.apache.juneau.rest.BasicRestCallHandler}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.BasicRestCallHandler#convertThrowable(Throwable) convertThrowable(Throwable)}
</ul>
</ul>
<li>
Support for fine-tuned logging of HTTP requests and responses.
<p class='bpcode'>
<ja>@RestResource</ja>(
debug=<js>"per-request"</js>,
logging=<ja>@Logging</ja>(
level=<js>"info"</js>,
rules={
<ja>@LoggingRule</ja>(codes<js>"400-499"</js>, level=<js>"warning"</js>, req=<js>"short"</js>, res=<js>"short"</js>)
<ja>@LoggingRule</ja>(codes<js>"500-"</js>, level=<js>"severe"</js>, req=<js>"long"</js>, res=<js>"long"</js>)
}
)
)
<jk>public class</jk> MyRest {
<ja>@RestMethod</ja>(
method=<js>"POST"</js>,
path=<js>"foo"</js>
logging=<ja>@Logging</ja>(
level=<js>"info"</js>,
rules={
<ja>@LoggingRule</ja>(exceptions<js>"NotFound*"</js>, level=<js>"info"</js>)
<ja>@LoggingRule</ja>(codes<js>"200"</js>, disabled=<js>"true"</js>)
}
)
)
<jk>public</jk> String myMethod() <jk>throws</jk> Exception {...}
</p>
See {@doc juneau-rest-server.LoggingAndDebugging} for details.
<li>
Fixed a bug where the HTTP response was returning 405 (method not found) but should really be 404 (not found)
when no path patterns match on any of the Java methods.
</ul>
<h5 class='topic w800'>juneau-rest-client</h5>
<ul class='spaced-list'>
<li>
PATCH support added.
</ul>
</div><!-- END: 8.1.0 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#8.1.1' id='8.1.1'>8.1.1 (Sept 20, 2019)</a></h3>
<div class='topic'><!-- START: 8.1.1 -->
<p>
Juneau 8.1.1 is a minor release but introduces some new features/modifications.
</p>
<h5 class='topic w800'>juneau-marshall</h5>
<ul class='spaced-list'>
<li>
Support for serializing/parsing {@link java.util.Optional} objects and bean properties.
<li>
Fixed a bug in the parsers where the generic subtype of a complex bean property type involving both collections and arrays
was not being found. (e.g. <c>List&lt;Long&gt;[]</c>)
<li>
New packages of HTTP response/exceptions beans from <c>juneau-rest-server</c> bundle and REST proxy annotations from <c>juneau-rest-client</c>
so that they can be used when building REST proxy interfaces while only pulling in the marshall bundle.
<ul>
<li class='jp'>{@link org.apache.juneau.http.response}
<li class='jp'>{@link org.apache.juneau.http.exception}
<li class='jp'>{@link org.apache.juneau.http.remote}
</ul>
These replace the <c>org.apache.juneau.rest.response</c>, <c>org.apache.juneau.rest.exception</c>, and <c>org.apache.juneau.rest.client.remote</c> packages.
<li>
Defaulting SVL variables now won't ignore additional parameters.
<br><js>"$S{Foo,bar,baz}"</js> used to default to <js>"bar"</js> but now will default to <js>"bar,baz"</js>.
<li>
Ranking support has been added to all <ja>@XConfig</ja> annotations.
This allows you to override the normal precedence of application of config annotations on class and method hierarchies.
</ul>
<h5 class='topic w800'>juneau-rest-server</h5>
<ul class='spaced-list'>
<li>
Support for {@link java.util.Optional} on method parameters annotated with {@link org.apache.juneau.http.annotation.Header}, {@link org.apache.juneau.http.annotation.FormData},
{@link org.apache.juneau.http.annotation.Query}, {@link org.apache.juneau.http.annotation.Path}.
<li>
Fixed issue where {@link org.apache.juneau.rest.annotation.RestMethod#debug() RestMethod.debug()} annotation wasn't resulting
in the HTTP request being logged.
<li>
{@link org.apache.juneau.rest.RestException} has been deprecated and replaced by {@link org.apache.juneau.http.exception.HttpException}.
<li>
Resolved issue where parameterized types on <ja>@RestMethod</ja>-annotated method parameters of Spring beans.
This is due to Spring relying on CGLIB for runtime-recompilation of beans that results in loss of parameterized-type
information.
<br>In the following example, the <c>beans</c> parameter would resolve as an unparameterized <c>List</c>
which would typically result in getting a <c>List&lt;ObjectMap&gt;<c> and subsequent <c>ClassCastExceptions</c>.
<p class='bpcode w800'>
<ja>@RestMethod</ja>
<jk>public void</jk> doFoo(<ja>@Body</ja> List&lt;MyBean&gt; beans) {...}
</p>
The fix involves resolving the original bean class for resolving parameterized type while leaving
method invocation on the proxy method so as not to bypass Spring features.
<li>
New methods on {@link org.apache.juneau.rest.BasicRest} to provide feature-parity with {@link org.apache.juneau.rest.RestServlet}:
<ul class='javatree'>
<li class='jc'>{@link org.apache.juneau.rest.BasicRest}
<ul>
<li class='jm'>{@link org.apache.juneau.rest.BasicRest#getContext() getContext()}
<li class='jm'>{@link org.apache.juneau.rest.BasicRest#getRequest() getRequest()}
<li class='jm'>{@link org.apache.juneau.rest.BasicRest#getResponse() getResponse()}
<li class='jm'>{@link org.apache.juneau.rest.BasicRest#log(String) log(String)}
<li class='jm'>{@link org.apache.juneau.rest.BasicRest#log(String,Throwable) log(String,Throwable)}
<li class='jm'>{@link org.apache.juneau.rest.BasicRest#log(Level,String,Object[]) log(Level,String,Object[])}
<li class='jm'>{@link org.apache.juneau.rest.BasicRest#logObjects(Level,String,Object[]) logObjects(Level,String,Object[])}
<li class='jm'>{@link org.apache.juneau.rest.BasicRest#log(Level,Throwable,String,Object[]) log(Level,Throwable,String,Object[])}
</ul>
</ul>
<li>
The <dc>@RestResource(staticFiles)</dc> annotation now supports absolute path locations and multiple mappings:
<p class='bpcode w800'>
<jc>// Resolves static files in root package "htdocs" or working directory "htdocs", and then relative package "htdocs".</jc>
<ja>@RestResource</ja>(staticFiles=<js>"htdocs:/htdocsfolder,htdocs:htdocs.package"</js>)
</p>
<li>
Fixed a bug in <dc>@RestResource(staticFiles)</dc> where the order of lookup between parent and child resources
was wrong.
</ul>
<h5 class='topic w800'>juneau-rest-client</h5>
<ul class='spaced-list'>
<li>
Removed the dependency on the <c>juneau-rest-server</c> module.
Allows the client API to be used without pulling in all the javax.servlet and server dependencies.
</ul>
<h5 class='topic w800'>juneau-examples</h5>
<ul class='spaced-list'>
<li>
The PetStore application has been moved to a separate Git repository.
<ul>
<li><a class='doclink' href='https://github.com/apache/juneau-petstore'>GitHub Repo</a>
<li><a class='doclink' href='http://juneau.apache.org/index.html#petstore.html'>Documentation</a>
</ul>
</ul>
</div><!-- END: 8.1.1 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#8.1.2' id='8.1.2'>8.1.2 (TBD)</a></h3>
<div class='topic'><!-- START: 8.1.2 -->
<p>
Juneau 8.1.2 is a moderate release.
</p>
<h5 class='topic w800'>juneau-marshall</h5>
<ul class='spaced-list'>
<li>
Support for read-only and write-only properties.
<ul>
<li class='ja'>{@link org.apache.juneau.annotation.Bean#bpro()}
<li class='ja'>{@link org.apache.juneau.annotation.Bean#bpwo()}
<li class='ja'>{@link org.apache.juneau.annotation.Beanp#ro()}
<li class='ja'>{@link org.apache.juneau.annotation.Beanp#wo()}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_bpro}
<li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_bpwo}
<li class='jm'>{@link org.apache.juneau.BeanContextBuilder#bpro(Map)}
<li class='jm'>{@link org.apache.juneau.BeanContextBuilder#bpwo(Map)}
</ul>
<li>
New convenience methods:
<ul>
<li class='jm'>{@link org.apache.juneau.ObjectMap#parse(CharSequence)}
<li class='jm'>{@link org.apache.juneau.ObjectList#parse(CharSequence)}
</ul>
<li>
{@link org.apache.juneau.marshall.CharMarshall} and {@link org.apache.juneau.marshall.StreamMarshall} now have public constructors.
<li>
{@link org.apache.juneau.annotation.Beanp @Beanp} replaces {@link org.apache.juneau.annotation.BeanProperty @BeanProperty}.
<li>
{@link org.apache.juneau.annotation.Beanc @Beanc} replaces {@link org.apache.juneau.annotation.BeanConstructor @BeanConstructor}.
<li>
{@link org.apache.juneau.http.remote.Remote @Remote} replaces {@link org.apache.juneau.http.remote.RemoteResource @RemoteResource}.
<li>
Shortened names for {@link org.apache.juneau.annotation.Bean#dictionary @Bean(dictionary)} and {@link org.apache.juneau.BeanContextBuilder#dictionary(Class...)}.
</ul>
<h5 class='topic w800'>juneau-rest-server</h5>
<ul class='spaced-list'>
<li>
{@link org.apache.juneau.rest.annotation.Rest @Rest} replaces {@link org.apache.juneau.rest.annotation.RestResource @RestResource} with shorter syntax.
<li>
New method {@link org.apache.juneau.rest.RestResponse#setHeaderSafe(String,String)} to strip invalid characters from header values.
<li>
Fixed issues related to invalid characters being set on HTTP header values.
</ul>
<h5 class='topic w800'>juneau-rest-client</h5>
<ul class='spaced-list'>
<li>
{@link org.apache.juneau.rest.client.RestClient} is now extendible. The constructor has been made public and simplified to:
{@link org.apache.juneau.rest.client.RestClient#RestClient(RestClientBuilder)}.
<li>
Duplicate methods between {@link org.apache.juneau.rest.client.RestClientBuilder} and {@link org.apache.http.impl.client.HttpClientBuilder}
have been made deprecated on the former. This eliminates the need to try to keep the two builder classes in
sync.
</ul>
</div><!-- END: 8.1.2 -->
<!-- ==================================================================================================== -->
<h3 class='topic' onclick='toggle(this)'><a href='#8.1.3' id='8.1.3'>8.1.3 (TBD)</a></h3>
<div class='topic'><!-- START: 8.1.3 -->
<p>
Juneau 8.1.3 is a minor release.
</p>
<h5 class='topic w800'>juneau-marshall</h5>
<ul class='spaced-list'>
<li>
Better representation of nulls for XML and HTML content properties.
<br>Old: <js>"&lt;myBean&gt;&lt;null&gt;&lt;/myBean&gt;"</js>
<br>New: <js>"&lt;myBean nil='true'&gt;&lt;/myBean&gt;"</js>
<li>
Configurable properties such as {@link org.apache.juneau.BeanContext#BEAN_debug} can now be set globally by either
system properties or environment variables.
<br>For <jsf>BEAN_debug</jsf> which resolves to <js>"BEAN_debug"</js>, you can use either the system
property <js>"BeanContext.debug.b"</js> or environment variables <js>"BeanContext_debug_b"</js> or
<js>"BEANCONTEXT_DEBUG_B"</js>.
</ul>
<h5 class='topic w800'>juneau-rest-server</h5>
<ul class='spaced-list'>
<li>
Fixed bug in {@link org.apache.juneau.rest.BasicRestCallHandler} where if you have the following REST methods...
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foo"</js>)
<ja>@RestMethod</ja>(name=<js>"*"</js>, path=<js>"/bar"</js>)
</p>
...and you tried to make a GET request to /bar, you'd erroneously get a 404 error instead of matching the 2nd method.
<li>
Fixed an issue involving using Juneau REST with Spring Security. When Spring Security cannot authenticate a
request, it sets the URL on the request to <js>"/error"</js> with a 401 status. When Juneau then processes
this request, it cannot find that mapping and changes the status to 404 which messes with HTTP clients.
<br>Solution was to add a default no-op error method to the {@link org.apache.juneau.rest.BasicRestConfig} (and implementers):
<p class='bpcode w800'>
<ja>@RestMethod</ja>(name=<js>"*"</js>, path=<js>"/error"</js>)
<jk>public void</jk> error() {}
</p>
<li>
Fixed a bug where <c><ja>@RestResource</ja>(debug=<js>"true"</js>)</c> wouldn't log requests if a
<ja>@RestMethod</ja>-annotated method was not matched.
<li>
Renamed the following annotations:
<ul>
<li><ja>@Rest(attrs)</ja> --&gt; {@link org.apache.juneau.rest.annotation.Rest#reqAttrs() @Rest(reqAttrs)}
<li><ja>@Rest(defaultRequestHeaders)</ja> --&gt; {@link org.apache.juneau.rest.annotation.Rest#reqHeaders() @Rest(reqHeaders)}
<li><ja>@Rest(defaultResponseHeaders)</ja> --&gt; {@link org.apache.juneau.rest.annotation.Rest#resHeaders() @Rest(resHeaders)}
<li><ja>@RestMethod(attrs)</ja> --&gt; {@link org.apache.juneau.rest.annotation.RestMethod#reqAttrs() @RestMethod(reqAttrs)}
<li><ja>@RestMethod(defaultRequestHeaders)</ja> --&gt; {@link org.apache.juneau.rest.annotation.RestMethod#reqHeaders() @RestMethod(reqHeaders)}
</ul>
</ul>
<h5 class='topic w800'>juneau-rest-client</h5>
<ul class='spaced-list'>
<li>
Several convenience methods defined in {@link org.apache.juneau.rest.client.RestClientBuilder} that were deprecated in 8.1.2 have been
undeprecated in this release due to user feedback.
</ul>
</div><!-- END: 8.1.3 -->
</div>
</body>