Marshallingcreated: 9.0.0
End-to-End RESTcreated: 9.0.0
REST Clientcreated: 9.0.0
DTOscreated: 9.0.0
Config Filescreated: 9.0.0
Fluent Assertionscreated: 9.0.0
General Designcreated: 9.0.0
Serializers and Parsersupdated: 9.0.0
Bean Contextsupdated: 9.0.0
Java Beans Supportcreated: 8.2.0, updated: 9.0.0
@Bean Annotationupdated: 8.2.0,9.0.0
@Beanp Annotationupdated: 8.1.0,8.1.2,9.0.0
@Beanc Annotationupdated: 8.1.0,8.1.2
POJO Buildersupdated: 9.0.0
HTTP Part Serializers and Parsersupdated: 8.2.0,9.0.0
Context Settingsupdated: 8.1.3,9.0.0
Context Annotationscreated: 8.1.0, updated: 8.1.3,8.2.0,9.0.0
JsonMap and JsonListupdated: 8.2.0
Complex Data Typescreated: 9.0.0
SerializerSets and ParserSetsupdated: 9.0.0
Swapsupdated: 9.0.0
Auto-detected swapscreated: 8.1.0
Per-media-type Swapsupdated: 8.1.0,8.2.0
@Swap Annotationupdated: 8.0.0,9.0.0
Dynamically Applied Annotationscreated: 8.1.3, updated: 9.0.0
Bean Names and Dictionariesupdated: 9.0.0
Virtual Beansupdated: 9.0.0
Non-Tree Models and Recursion Detectionupdated: 9.0.0
Parsing into Generic Modelsupdated: 8.2.0
Reading Continuous Streamsupdated: 9.0.0
URIsupdated: 9.0.0
Comparison with Jacksonupdated: 9.0.0
SVL Variablesupdated: 8.0.0,8.1.0
VarResolvers and VarResolverSessionsupdated: 9.0.0
VarResolver.DEFAULTcreated: 8.1.0
Encoderscreated: 9.0.0
Object Toolscreated: 9.0.0
JSON Serializersupdated: 9.0.0
JSON 5updated: 9.0.0
JSON Parsersupdated: 9.0.0
XML Serializersupdated: 9.0.0
XML Parsersupdated: 9.0.0
HTML Serializersupdated: 9.0.0
HTML Parsersupdated: 9.0.0
HtmlDocSerializerupdated: 9.0.0
UON Serializersupdated: 9.0.0
UON Parsersupdated: 9.0.0
URL-Encoding Serializersupdated: 9.0.0
URL-Encoding Parsersupdated: 9.0.0
MessagePack Serializersupdated: 9.0.0
MessagePack Parsersupdated: 9.0.0
OpenAPI Detailsupdated: 8.2.0
OpenAPI Methodologyupdated: 8.2.0
OpenAPI Serializersupdated: 8.2.0,9.0.0
OpenAPI Parsersupdated: 8.2.0,9.0.0
Overviewupdated: 9.0.0
Reading Entriesupdated: 9.0.0
POJOsupdated: 9.0.0
Java Collection Framework Objectsupdated: 9.0.0
Binary Dataupdated: 9.0.0
Variablesupdated: 9.0.0
Modded/Encoded Entriesupdated: 9.0.0
Sectionsupdated: 9.0.0
Serializingupdated: 9.0.0
Importsupdated: 8.1.0
Config Storesupdated: 9.0.0
FileStoreupdated: 9.0.0
Custom ConfigStoresupdated: 9.0.0
Read-only Configsupdated: 9.0.0
System Default Configcreated: 8.0.0, updated: 8.1.0
juneau-assertionscreated: 9.0.0
Overviewcreated: 9.0.0
juneau-rest-commoncreated: 9.0.0
Helper Classescreated: 9.0.0
Annotationscreated: 9.0.0
HTTP Headerscreated: 9.0.0
HTTP Partscreated: 9.0.0
HTTP Entities and Resourcescreated: 9.0.0
HTTP Responsescreated: 9.0.0
Remote Proxy Interfacescreated: 9.0.0
juneau-rest-serverupdated: 9.0.0
Overviewcreated: 9.0.0
@Rest-Annotated Classesupdated: 8.1.2,9.0.0
Predefined Classesupdated: 9.0.0
Child Resourcesupdated: 9.0.0
Path Variablesupdated: 9.0.0
Deploymentupdated: 9.0.0
Lifecycle Hooksupdated: 9.0.0
@RestOp-Annotated Methodsupdated: 9.0.0
Inferred HTTP Methods and Pathsupdated: 9.0.0
Java Method Parametersupdated: 9.0.0
Java Method Return Typesupdated: 9.0.0
Java Method Throwable Typesupdated: 9.0.0
Path Patternsupdated: 9.0.0
Matchersupdated: 9.0.0
Additional Informationupdated: 9.0.0
HTTP Partsupdated: 9.0.0
Part Marshallersupdated: 8.1.0,9.0.0
HTTP Part Annotationsupdated: 8.1.0,9.0.0
Default Partscreated: 9.0.0
@Request Beansupdated: 8.1.0,9.0.0
@Response Beansupdated: 8.1.0,9.0.0
HTTP Part APIscreated: 9.0.0
Marshallingupdated: 9.0.0
Form Postsupdated: 9.0.0
Guardsupdated: 9.0.0
Convertersupdated: 9.0.0
Localized Messagesupdated: 8.2.0,9.0.0
Encodersupdated: 9.0.0
Configuration Filesupdated: 9.0.0
SVL Variablesupdated: 9.0.0
Static filesupdated: 9.0.0
Client Versioningupdated: 9.0.0
BasicRestServlet/BasicRestObjectupdated: 8.1.0,9.0.0
Basic Swagger Infoupdated: 9.0.0
Parametersupdated: 9.0.0
Modelsupdated: 9.0.0
REST method execution statisticscreated: 8.1.3, updated: 9.0.0
@HtmlDocConfigupdated: 8.1.0,9.0.0
Widgetsupdated: 9.0.0
Predefined Widgetsupdated: 9.0.0
UI Customizationupdated: 9.0.0
Stylesheetsupdated: 8.1.0,9.0.0
Logging / Debuggingcreated: 9.0.0
HTTP Status Codesupdated: 9.0.0
Built-in Parametersupdated: 9.0.0
RestContextcreated: 9.0.0
RestOpContextcreated: 9.0.0
Response Processorscreated: 9.0.0
REST/RPCupdated: 8.0.0,9.0.0
Serializing URIsupdated: 9.0.0
Utility Beanscreated: 9.0.0
Using with HTML Beanscreated: 9.0.0
juneau-rest-server-springbootcreated: 8.0.0, updated: 9.0.0
Overviewcreated: 8.0.0, updated: 9.0.0
juneau-rest-clientupdated: 9.0.0
POJO Marshallingcreated: 8.2.0, updated: 9.0.0
Request Partscreated: 8.2.0, updated: 9.0.0
Request Contentcreated: 8.2.0, updated: 9.0.0
Response Statuscreated: 8.1.0, updated: 9.0.0
Response Headerscreated: 8.2.0, updated: 9.0.0
Response Contentcreated: 8.2.0, updated: 9.0.0
Custom Call Handlerscreated: 8.2.0, updated: 9.0.0
Interceptorscreated: 8.2.0
REST Proxiescreated: 8.2.0, updated: 9.0.0
Logging and Debuggingcreated: 8.2.0, updated: 9.0.0
Customizing HttpClientcreated: 8.2.0, updated: 9.0.0
Extending RestClientcreated: 8.2.0
Authenticationupdated: 8.2.0
juneau-rest-mockcreated: 8.1.0, updated: 8.2.0
MockRestClientcreated: 8.2.0, updated: 9.0.0
juneau-microservice-corecreated: 8.1.0
Microservice Overviewcreated: 8.0.0
Lifecycle Methodscreated: 8.0.0
Argscreated: 8.0.0
Manifestcreated: 8.0.0
Configcreated: 8.0.0
System propertiescreated: 8.0.0
VarResolvercreated: 8.0.0
Console Commandscreated: 8.0.0
Listenerscreated: 8.0.0
juneau-microservice-jettycreated: 8.1.0
Overviewcreated: 8.0.0
Lifecycle Methodscreated: 8.0.0
Resource Classescreated: 8.0.0
Predefined Resource Classescreated: 8.0.0
Configcreated: 8.0.0
Jetty.xml filecreated: 8.0.0
UI Customizationcreated: 8.0.0
Extending JettyMicroservicecreated: 8.0.0
my-jetty-microservicecreated: 8.1.0
Installing in Eclipsecreated: 8.0.0
Running in Eclipsecreated: 8.0.0
Building and Running from Command-Linecreated: 8.0.0
my-springboot-microservicecreated: 8.0.0
Installing in Eclipsecreated: 8.0.0
Running in Eclipsecreated: 8.0.0
Building and Running from Command-Linecreated: 8.0.0
juneau-petstorecreated: 8.2.0, updated: 9.0.0
Running the Pet Store Appcreated: 9.0.0
juneau-petstore-apicreated: 9.0.0
juneau-petstore-clientcreated: 9.0.0
juneau-petstore-servercreated: 9.0.0
juneau-marshallcreated: 8.2.0
juneau-svlcreated: 8.2.0
juneau-rest-servercreated: 8.2.0
Apache Juneau™ is a single cohesive Java ecosystem for marshalling Java objects to a wide variety of language types and creating annotation-based REST end-to-end server and client APIs.
The Juneau ecosystem consists of the following parts:
| Category | Maven Artifacts | Description | Prereqs |
|---|---|---|---|
| juneau-core | juneau-marshall |
|
|
| juneau-marshall-rdf |
|
|
|
| juneau-dto |
|
|
|
| juneau-config |
|
|
|
| juneau-assertions |
|
|
|
| juneau-rest | juneau-rest-common |
|
|
| juneau-rest-server |
|
|
|
| juneau-rest-server-springboot |
|
|
|
| juneau-rest-client |
|
|
|
| juneau-rest-mock |
|
|
|
| my-springboot-microservice |
|
|
|
| juneau-examples | juneau-examples-core |
|
|
| juneau-examples-rest |
|
||
| juneau-all |
Combination of the following:
|
|
The current version of Juneau is
If you would like to work with the bleeding-edge code, you can access the
Each of the components are also packaged as stand-alone OSGi modules.
The juneau-marshall library includes easy-to-use and highly customizable serializers and parsers based around a common API. It allows you to marshall Java POJOs directly to and from a wide variety of language types without the need for intermediate Document Object Models making them extremely efficient.
Supported languages include:
The default serializers can often be used to serialize POJOs in a single line of code:
Parsing back into POJOs is equally simple for any of the supported languages. Language fragments are also supported.
Marshalling support is provided for a wide variety of POJO types including:
Marshallers like the one shown above are pairings of serializers and parsers. Serializers and parsers are builder-based using fluent methods allowing you to quickly create, clone, and modify them in single lines of code.
Many POJOs such as primitives, beans, collections, arrays, and classes with various known constructors and methods are serializable out-of-the-box.
Swaps allow you to replace non-serializable objects with serializable equivalents. The {@link org.apache.juneau.swaps} package contains a variety of predefined swaps.
Any POJO that doesn't fit into the category of a bean/collection/array/primitive and doesn't have a swap associated with it is converted to simple strings. By default, various instance and static methods and constructors on POJO classes are automatically detected and supported for marshalling a POJO to and from a string.
Beans and POJO classes, methods, fields, and constructors can also be annotated with a variety of annotations to customize how they are marshalled:
As a general rule, any capabilities provided by bean annotations can be programmatically specified via the builder APIs. This allows the marshallers to be used equivalently on either your own code that you have access to, or external code where you only have access to binaries.
Serializers and parsers can also be configured using annotations.
Config annotations are extensively used in the REST Servlet APIs to configure how POJOs are marshalled through REST interfaces.
Config variables also support embedded variables for resolving settings at runtime.
Default values for config settings can be overridden via system properties or environment variables. For example, the system property "BeanContext.sortProperties" or environment variable "BEANCONTEXT_SORTPROPERTIES" can be used to set the default value for the sort properties setting.
Bean annotations can also be programmatically attached to POJOs using config annototations like so:
The {@link org.apache.juneau.json.Json5Serializer} class can be used to serialized POJOs into JSON 5 notation.
JSON 5 is similar to JSON except for the following:
JSON 5 is still valid Javascript. 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 JSON 5 and do a simple string comparison.
WriterSerializer
The Marshalling API also supports UON (URL-Encoded Object Notation). It allows JSON-like data structures (OBJECT, ARRAY, NUMBER, BOOLEAN, STRING, NULL) in HTTP constructs (query parameters, form parameters, headers, URL parts) without violating RFC2396. This allows POJOs to be converted directly into these HTTP constructs which is not possible in other languages such as JSON.
(
id=1,
name=
The Marshalling API also supports schema-based OpenAPI serialization. It allows HTTP parts to be marshalled to-and-from POJOs based on OpenAPI schema definitions.
Schema-based serialization and parsing is used heavily in both the server and client REST APIs with built-in schema validations support in various HTTP part annotations.
The {@link org.apache.juneau.collections.JsonMap} and {@link org.apache.juneau.collections.JsonList} collections classes allow you
to programmatically build generic JSON data structures. They are similar in concept to
These classes provide lots of convenience methods including:
{@link org.apache.juneau.serializer.SerializerSet} and {@link org.apache.juneau.parser.ParserSet} classes allow serializers and parsers
to be retrieved by W3C-compliant HTTP Accept
and Content-Type
values:
The {@link org.apache.juneau.svl} package defines an API for a language called "Simple Variable Language".
In a nutshell, Simple Variable Language (or SVL) is text that contains variables of the form
Variables can be recursively nested within the varKey (e.g.
The SVL variables are used widely throughout various annotations defined in Juneau allowing many features to be configured via external sources such as configuration files or environment variables/system properties. The SVL APIs are extensible allowing for the addition of new types of variables.
The juneau-rest-server and juneau-rest-client libraries provide server and client side REST capabilities that can be used by themselves, or together to create simplified yet sophisticated Java-based REST communications layers that completely hide away the complexities of the REST protocol.
A typical pattern is to define a REST API on the server side:
Then define a Java interface that can be provided to consumers of your API to access your REST API:
Note that you may choose to have your service class implement your interface. The REST libraries will happily look for annotations defined on methods of parent classes and interfaces. It's up to you how you want to design it.
Finally, the {@link org.apache.juneau.rest.client.RestClient} class is used to construct a remote proxy to our REST service:
The call above translates to the following REST call:
POST http://localhost:10000/petstore/pets?debug=true HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== E-Tag: 475588d4-0b27-4f56-9296-cc683251d314 { name: 'Fluffy', price: 9.99 }
It looks simplistic but the server and client APIs are highly sophisticated libraries that allow you to perform complex tasks using very little code.
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.servlet.BasicRestServlet}, which itself is simply an extension of {@link jakarta.servlet.http.HttpServlet} which allows it to be deployed as a servlet.
This is what it looks like in a browser.
http://localhost:10000/helloWorld
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.
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
The advantage of using child resources is that they do not need to be declared in the JEE
The servlets in the previous section implemented the {@link org.apache.juneau.rest.config.BasicUniversalConfig} which simply defines a preconfigured set of annotations that get inherited by the child classes:
The {@link org.apache.juneau.rest.config} package contains other basic configurations for use. Annotations are aggregated from child-to-parent order allowing for these basic configurations to be extended and modified, or you can create your own annotations from scratch.
The {@link org.apache.juneau.rest.servlet.BasicRestServletGroup} class provides a default "router" page for child resources when a parent resource is nothing more than a grouping of child resources.
The
When you bring up this resource in a browser, you see the following that provides a list of navigable links to your child resources:
http://localhost:10000
The real power behind the REST server API is the ability to define Java methods as REST endpoints.
Java methods on {@link org.apache.juneau.rest.annotation.Rest @Rest}-annotated classes have the following format:
The various parts require their own topics to fully appreciate the scope of abilities but the following is a summary:
The {@link org.apache.juneau.rest.servlet.BasicRestServlet} class is the entry point for your REST resources.
It extends directly from
When the servlet
Most developers are not going to be using the
The {@link org.apache.juneau.rest.springboot.BasicSpringRestServlet} class is typically entry point for your REST resources when working within a Spring Boot environment. It extends from {@link org.apache.juneau.rest.springboot.SpringRestServlet} which provides additional capabilities including:
Most developers are not going to be using the
Built upon the feature-rich Apache HttpClient library, the Juneau RestClient API adds support for fluent-style REST calls and the ability to perform marshalling of POJOs to and from HTTP parts.
The {@link org.apache.juneau.rest.mock.MockRestClient} class is used for performing serverless unit testing of {@link org.apache.juneau.rest.annotation.Rest @Rest}-annotated and {@link org.apache.juneau.http.remote.Remote @Remote}-annotated classes. It perform full serialization and parsing of the HTTP request and responses, but bypasses the network layer to significantly improve speed while still performing real testing.
The juneau-dto library contains several predefined POJOs for generating commonly-used document types that are designed to be used with the Juneau Marshaller APIs for both serializing and parsing.
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.
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.
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.
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.
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.
The
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:
The juneau-config library contains a powerful API for creating and using INI-style config files.
Config files are accessed through the {@link org.apache.juneau.config.Config} class which
are created through the {@link org.apache.juneau.config.Config.Builder} class.
Builder creator methods are provided on the
The config language may look simple but it is a very powerful feature with many capabilities.
The juneau-assertions module in Juneau is a powerful API for performing fluent style assertions.
Fluent assertions have two types of methods:
Multiple transformations and assertions can be performed per statement.
The Assertions APIs are used throughout the REST client and server APIs for performing inline assertions on REST requests and responses.
The Juneau framework uses the design pattern of builders, context, and session objects:
This is a general design pattern used throughout the framework including the REST client and server APIs.
The following shows the general pattern for creating sessions:
Typically developers will not deal with session objects and will just use convenience methods on the context classes themselves that handle creation of sessions:
Most context objects also have static default instances that can be used in leu of creating new contexts as well:
Most context classes also have the ability to clone and modify existing context objects:
The default values of many context settings can also be set via system properties and environment variables. The javadocs on these settings will identify when this is possible.
The framework makes heavy use of caching of existing context objects with the same builder settings. This is a critical reason why Juneau achieve impressive performance. Using Java reflection to find out all information about a bean type is expensive. By caching context objects, we only need to reflect that bean type once and store that information in the context for reuse by all serializers and parsers that share the same bean context configuration settings.
juneau-marshall-
org.apache.juneau.marshall_
The
{@link org.apache.juneau.marshaller.Marshaller Marshallers} 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.
Juneau comes with the following predefined marshallers:
Each predefined marshaller also includes static convenience from/to methods to make it even easier to perform marshalling on POJOs:
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.
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.
In most cases, you can serialize objects in one line of code by using one of the default serializers:
In addition to the default serializers, customized serializers can be created using various built-in options:
Default serialization support is provided for Java primitives,
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.
Like the serializers, you can often parse objects in one line of code by using one of the default parsers:
The parsers can also be used to populating existing bean and collection objects:
At the heart of the marshalling APIs is the {@link org.apache.juneau.BeanContext Bean Context} API that provides a common framework for marshalling beans and POJOs across all serializers and parsers. All serializers and parsers (and their builders) extend from the bean context API classes.
One important feature of the bean context API is the ability to wrap Java beans inside maps to allow properties to be accessed through a Map layer. Although this is used internally by all the serializers and parsers, it's often useful to use this feature by itself.
The bean context API provides many settings that fine-tune how POJOs should be handled during marshalling.
Out-of-the-box, Juneau supports marshalling of Java beans with standard public getters and setters, public
fields, and fluent setters (e.g.
Several settings exist to allow you to customize how bean properties are handled by serializers and parsers:
Settings and equivalent annotations are also available to control which properties are marshalled and how they are ordered.
It's common to use the {@link org.apache.juneau.annotation.Bean#properties @Bean(properties|p)} annotation to force the ordering of properties during marshalling. IBM JVMs keep the ordering of fields and methods in the compiled bytecodebut Oracle JVMs do not and return fields/methods in random order. The {@link org.apache.juneau.annotation.Bean#properties @Bean(properties|p)} annotation was added to help with this limitation.
The {@link org.apache.juneau.annotation.Bean @Bean} annotation is used to tailor how beans are interpreted by the framework.
Bean property inclusion and ordering on a bean class can be done using the {@link org.apache.juneau.annotation.Bean#properties() @Bean(properties|p)} annotation.
Bean properties can be excluded using the {@link org.apache.juneau.annotation.Bean#excludeProperties() @Bean(excludeProperties|xp)} annotation.
Bean properties can be sorted alphabetically using {@link org.apache.juneau.annotation.Bean#sort() @Bean(sort)}
The {@link org.apache.juneau.annotation.Bean#propertyNamer() @Bean(propertyNamer)} annotation is used to provide customized naming of properties.
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.
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.
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.
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.
For example, in the following class hierarchy, instances of
The {@link org.apache.juneau.annotation.Bean#interceptor() @Bean(interceptor)} annotation and {@link org.apache.juneau.swap.BeanInterceptor} class can be used to perform interception and inline handling of bean getter and setter calls.
The {@link org.apache.juneau.annotation.Bean#on() @Bean(on)} and {@link org.apache.juneau.annotation.Bean#onClass() @Bean(onClass)}
annotations can be used to programmatically attach
The {@link org.apache.juneau.annotation.Beanp @Beanp} annotation is used to tailor how individual bean properties are interpreted by the framework.
The {@link org.apache.juneau.annotation.Beanp#name() @Beanp(name)} annotation is used to override the name of the bean property.
The {@link org.apache.juneau.annotation.Name @Name} annotation is a shortcut for specifying a bean property name:
If the {@link org.apache.juneau.BeanContext.Builder#beanFieldVisibility(Visibility) 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.
The bean property named
The following shows various ways of using dynamic bean properties.
Similar rules apply for value types and swaps. The property values optionally can be any serializable type or use swaps.
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.
The following annotations are equivalent:
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.
This property must denote a concrete class with a no-arg constructor.
The {@link org.apache.juneau.annotation.Beanp#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.
The {@link org.apache.juneau.annotation.Beanp#properties() @Beanp(properties)} 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:
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.
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.
The definition of a read-only bean is a bean with properties with only getters, like shown below:
Beans can also be defined with a combination of read-only and read-write properties.
The {@link org.apache.juneau.annotation.Name @Name} annotation can also be used instead of
If neither
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.
When applied to classes, objects will be converted to strings even though they look like beans.
When applied to fields and getters/setters, they will be ignored as bean properties.
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.
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.
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.
A commonly-used case is when you're parsing beans and a child bean has a reference to a parent bean.
Parsers will automatically set this field for you in the child beans.
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.
A typical builder usage is shown below:
MyBean
The typical code for such a builder using a static inner class is shown below:
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).
Builders require two parts:
The first can be accomplished through any of the following:
The second can be accomplished through any of the following:
Juneau serializers treat instances of
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).
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:
There is a separate set of serializers and parsers for marshalling HTTP parts (query, form-data, headers, path variables, and plain-text request bodies). The distinction is that these are designed to marshall directly to-and-from strings based on Open-API schema information.
The {@link org.apache.juneau.httppart.HttpPartSchema} class also provides convenience static methods for creation of custom schemas. The equivalent to the schema above can be structured like so:
The class hierarchy for the part marshallers are:
Serializers and parsers have a wide variety of configurable settings. Their builders all extend from the {@link org.apache.juneau.BeanContext.Builder} 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:
WriterSerializer
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:
These can be used directly, as follows:
For performance reasons, serializers and parsers are immutable.
However, they can be 'copied' and modified using the
Default values for configurable settings can be set globally using either system properties or environment variables.
For example, the default
All configurable properties described in the previous section have annotation equivalents that can be applied on classes or methods.
In the section on the REST server API, we describe how to configure serializers and parsers using
Config annotations defined on classes and methods can be applied to serializers and parsers using the following methods:
The following example shows how annotations defined on a dummy class can be applied to a serializer:
Config annotations are provided for all serializers and parsers:
Annotations normally applied to bean classes/methods/fields/parameters
can also be programmatically attatched to beans by using the
Annotations can also be applied directly to serializers and parsers using the following method:
The following example shows a concrete implementation of an annotation can be applied to a serializer:
Concrete annotation implementations are provided for all annotations.
Any number of matching config or concrete annotations can be applied. They are applied in the order they are provided to the context. Therefore any values can be overridden. Config and concrete annotations also override any class or method level annotations
The {@link org.apache.juneau.collections.JsonMap} and {@link org.apache.juneau.collections.JsonList} 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.
These classes extend directly from the following JCF classes:
The
These object can be serialized in one of two ways:
Any valid JSON can be parsed into an unstructured model consisting of generic {@link org.apache.juneau.collections.JsonMap} and {@link org.apache.juneau.collections.JsonList} objects. (Any valid XML can also be parsed into an unstructured model)
The
The Juneau parsers have the ability to parse into complex data types that consist of multidimensional arrays and nested maps and collections using the methods below:
Arrays are simple enough and can be constructed using the first method:
String
For data types consisting of nested collections an maps such as
String
The arguments can be arbitrarily long to indicate arbitrarily complex data structures.
Similar methods for converting to complex types can be found on the {@link org.apache.juneau.rest.httppart.RequestContent} and {@link org.apache.juneau.rest.httppart.RequestHttpPart} classes, and the {@link org.apache.juneau.BeanSession#convertToType(Object,Type,Type...)} method.
On top of the serializers and parsers are the {@link org.apache.juneau.serializer.SerializerSet} and
{@link org.apache.juneau.parser.ParserSet} classes.
These classes allow serializers and parsers to be grouped and retrieved by W3C-compliant HTTP
The REST servlet API builds upon the
{@link org.apache.juneau.swap.ObjectSwap Swaps} are a critical component of Juneau. They allow the serializers and parsers to handle Java objects that wouldn't normally be serializable.
Swaps are, simply put, 'object swappers' that swap in serializable objects for
non-serializable ones during serialization, and vis-versa during parsing.
Some examples of non-serializable objects are
In the following example, we introduce a
The swap can then be associated with serializers and parsers like so:
Another example of a
The following example shows the BASE64 swap in use:
The {@link org.apache.juneau.BeanContextable.Builder#swap(Class,Class,ThrowingFunction)} and {@link org.apache.juneau.BeanContextable.Builder#swap(Class,Class,ThrowingFunction,ThrowingFunction)} methods are another way to define swaps by using functions.
By default, all serializers and parsers have built in
Various other swaps are provided in the {@link org.apache.juneau.swaps} package.
Various methods can be defined on a class directly to affect how it gets serialized.
This can often be simpler than using
Objects serialized as
Note that these methods cover conversion from several built-in Java types, meaning the parsers can automatically construct these objects from strings:
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
Serializing to other intermediate objects can be accomplished by defining a swap method directly on the class:
Serializing to and from Maps can be accomplished by defining any of the following methods:
The
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.
Swapped objects can be converted back into their original form by the parsers by specifying one of the following methods:
The following shows how our form template class can be modified to allow the parsers to reconstruct our original object:
Swaps can also be defined per-media-type.
The {@link org.apache.juneau.swap.ObjectSwap#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 object as long as they're differentiated by media type. When multiple swaps are defined, the best-match media type is used.
In the following example, we define 3 swaps against the same object. One for JSON, one for XML, and one for all other types.
When multiple swaps match the same media type, a best-match algorithm is applied to find the correct swap to use.
In later sections we describe how annotations can be used to shorten this syntax:
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 objects 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.
A one-way swap is simply an object transform that only implements the {@code swap()} method. The {@code unswap()} method is simply left unimplemented.
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.
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.
{@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
Multiple swaps can be associated with a class using multiple {@link org.apache.juneau.annotation.Swap @Swap} annotations:
The
When applied to bean properties, the swap annotation need only be applied to either the getter, setter, or field.
The swap annotation can also be applied to the private field of a bean property, like so:
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.
For example, you could pair a template string like so:
The implementation of the FreeMarker swap would look something like this:
Surrogate classes are very similar in concept to
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):
This could be solved with the following
However, the same can be accomplished by using a surrogate class that simply contains a constructor with the non-serializable class as an argument:
The surrogate class is registered in the same way as a
When the serializer encounters the non-serializable class, it will serialize an instance of the surrogate instead.
In the section Swaps, you were introduced to annotations that can be applied to bean classes, methods, fields, and constructors such as {@link org.apache.juneau.annotation.Bean @Bean}:
An alternate way of applying these annotations is to attach them to unrelated classes and methods and then tell your serializer or parser where to find them.
The advantage to this approach is it allows you to use Juneau annotations on classes/methods/fields/constructors where you might not have access to the source code, or when you only want to selectively apply the annotation under certain scenarios instead of globally.
For example, the following shows the
Any Juneau annotation that has an
The valid pattern matches are:
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.
Bean names and dictionaries are used for identifying class types when they cannot be inferred through reflection.
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
On the parsing side, these type names are resolved to classes through the use of bean dictionaries.
For example, if a bean property is of type
When serialized as JSON,
{
x: [
{_type:
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
When serialized as XML, the bean is rendered as:
Bean dictionaries are registered through the following:
The bean dictionary setting can consist of any of the following types:
The
When using the annotation, you'll typically want to define it on an interface class so that it can be inherited by all subclasses.
In addition to the bean type name support described above, simplified support is provided for bean subtypes.
Bean subtypes are similar in concept to bean type names, except for the following differences:
In the following example, the abstract class has two subclasses:
When serialized, the subtype is serialized as a virtual
A1
The following shows what happens when parsing back into the original object.
A
The {@link org.apache.juneau.BeanContext.Builder#disableInterfaceProxies()} setting (enabled by default) allows the Juneau parsers to parse content into virtual beans (bean interfaces without implementation classes).
For example, the following code creates an instance of the specified unimplemented interface:
Getter and setter values can be any parsable values, even other virtual beans.
Under-the-covers, a virtual bean is simply a proxy interface on top of an existing {@link org.apache.juneau.BeanMap} instance. From a programmatic point-of-view, they're indistinguishable from real beans, and can be manipulated and serialized like any other bean.
Virtual beans can also be created programmatically using the {@link org.apache.juneau.BeanContext} class:
Address
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
If you still want to use the Juneau serializers on such models, Juneau provides the {@link org.apache.juneau.BeanTraverseContext.Builder#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.
For example, let's make a POJO model out of the following classes:
Now we create a model with a loop and serialize the results.
What we end up with is the following, which does not serialize the contents of the
{
Without recursion detection enabled, this would cause a stack-overflow error.
Recursion detection introduces a performance penalty of around 20%. For this reason the setting is disabled by default.
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
You can parse into any
When the map or list type is not specified, or is the abstract
For example, given the following JSON:
{
id:
We can parse this into a generic
What we end up with is the exact same output.
Even the numbers and booleans are preserved because they are parsed into
{
id:
Once parsed into a generic model, various convenience methods are provided on the
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.
The following parsers can be configured to read continuous streams of objects from the same input stream:
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.Builder#unbuffered()} setting. This prevents the parsers from using an internal buffer that would read past the end of the currently parsed POJO.
Note that this isn't perfect in all cases since you can't combine two JSON numbers into a single
reader (e.g.
For obvious reasons, do not use the following properties when reading continuous streams:
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.
Juneau serializers have sophisticated support for transforming relative URIs to absolute form.
The following example shows a bean containing URIs of various forms and how they end up serialized.
URI resolution is controlled by the following settings:
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:
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.
The following charts describe equivalent features between the two libraries:
| Jackson | Juneau |
|---|---|
|
|
{@link org.apache.juneau.annotation.Beanp @Beanp} |
|
|
{@link org.apache.juneau.annotation.Beanp#name() @Beanp(name="*")} |
|
|
{@link org.apache.juneau.annotation.BeanIgnore @BeanIgnore} |
| {@link org.apache.juneau.annotation.Bean#excludeProperties @Bean(excludeProperties|xp)} | |
|
No equivalent annotation but can be controlled via:
{@link org.apache.juneau.BeanContext.Builder#beanFieldVisibility(Visibility)} {@link org.apache.juneau.BeanContext.Builder#beanMethodVisibility(Visibility)} |
|
|
|
{@link org.apache.juneau.annotation.Beanc @Beanc} |
| No equivalent. | |
|
|
Juneau uses swaps to convert non-serializable object to serializable forms:
{@link org.apache.juneau.annotation.Swap @Swap} |
|
No equivalent annotation but can be controlled via various settings:
{@link org.apache.juneau.BeanContext} {@link org.apache.juneau.serializer.Serializer} |
|
|
{@link org.apache.juneau.annotation.Bean#properties @Bean(properties="...")}
{@link org.apache.juneau.annotation.Bean#sort @Bean(sort=x)} |
|
|
|
Can be replicated using swaps with |
In general, Juneau allows for marshalling for a wide variety of POJO types including:
The following chart shows POJOs categorized into groups and whether they can be serialized or parsed:
| Group | Description | Examples | Can serialize? | Can parse? |
|---|---|---|---|---|
| 1 | Java primitives and primitive objects |
|
yes | yes |
| 2 | Java Collections Framework objects, Java arrays, Java Optionals | |||
| 2a |
With standard keys/values
Map keys are group [1, 4a, 6a] objects. Map, Collection, Optional, and array values are group [1, 2, 3ac, 4a, 6a] objects. |
|
yes | yes |
| 2b |
With non-standard keys/values
Map keys are group [2, 3, 4b, 5, 6b, 7] objects. Map, Collection, and array values are group [3b, 4b, 5, 6b, 7] objects. |
|
yes | no |
| 3 | Java Beans | |||
| 3a |
With standard properties
These are beans that have one or more properties defined by public getter or public fields. Properties can also be defined as final read-only fields and passed in as constructor args. Property values are group [1, 2, 3ac, 4a, 6a] objects. |
yes | yes | |
| 3b |
With non-standard properties or not true beans
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. 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. |
yes | no | |
| 3c |
Virtual beans
These are unimplemented bean interfaces with properties of type [1, 2, 3ac, 4a, 6a] objects. Parsers will automatically create interface proxies on top of BeanMap instances. |
yes | yes | |
| 3d |
Read-only beans without setters
The same as 3a but without property setters or constructor args. |
yes | no | |
| 4 |
Swapped objects
These are objects that are not directly serializable but have {@link org.apache.juneau.swap.ObjectSwap ObjectSwaps} 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.swaps.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. |
|||
| 4a |
2-way swapped to group [1, 2a, 3ac] objects
For example, a swap that converts a {@code Date} to a {@code String}. |
|
yes | yes |
| 4b |
1-way swapped to group [1, 2, 3] objects
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}. |
|
yes | no |
| 5 |
Readers and InputStreams
Contents are serialized directly to the output stream or writer. Typically used for low-level language-specific replacement of POJOs using per-Media-Type POJO swaps. |
|
yes | no |
| 6 |
Non-serializable objects with standard methods for converting to a serializable form |
|||
| 6a |
Classes with a method that converts it to a serializable form:
|
|
yes | yes |
| 6b |
Classes that only have a method to convert to a serializable form:
|
yes | no | |
| 7 |
All other objects
Anything that doesn't fall into one of the groups above are simply converted to {@code Strings} using the {@code toString()} method. |
yes | no |
A separate category exists for POJOs that can be converted to and from Strings. These are used in places such as:
As a general rule, all POJOs are converted to Strings using the
POJOs are convertible from Strings using any of the following (matched in the specified order):
Exceptions exist for the following classes:
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
POJOs are considered convertible from X if it has any of the following (matched in the specified order):
POJOs are considered convertible from X if any of the reverse of above are true.
The {@link org.apache.juneau.svl} packages defines an API for a language called "Simple Variable Language".
In a nutshell, Simple Variable Language (or SVL) is text that contains variables of the form
Most variables can be recursively nested within the varKey (e.g.
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:
The following logic variables are also provided:
The following shows how variables can be arbitrarily nested...
Variables are defined through the {@link org.apache.juneau.svl.Var} API. The API comes with several predefined variables and is easily extensible.
The following is an example of a variable that performs URL-Encoding on strings.
The following shows the class hierarchy of the {@link org.apache.juneau.svl.Var} class:
The following is the list of default variables defined in all modules:
| Module | Class | Pattern |
|---|---|---|
| juneau-svl | {@link org.apache.juneau.svl.vars.EnvVariablesVar} | $E{key[,default]} |
| {@link org.apache.juneau.svl.vars.SystemPropertiesVar} | $S{key[,default]} | |
| {@link org.apache.juneau.svl.vars.ArgsVar} | $A{key[,default]} | |
| {@link org.apache.juneau.svl.vars.ManifestFileVar} | $MF{key[,default]} | |
| {@link org.apache.juneau.svl.vars.IfVar} | $IF{arg,then[,else]} | |
| {@link org.apache.juneau.svl.vars.SwitchVar} | $SW{arg,pattern1:then1[,pattern2:then2...]} | |
| {@link org.apache.juneau.svl.vars.CoalesceVar} | $CO{arg1[,arg2...]} | |
| {@link org.apache.juneau.svl.vars.PatternMatchVar} | $PM{arg,pattern} | |
| {@link org.apache.juneau.svl.vars.PatternReplaceVar} | $PR{arg,pattern,replace} | |
| {@link org.apache.juneau.svl.vars.PatternExtractVar} | $PE{arg,pattern,groupdIndex} | |
| {@link org.apache.juneau.svl.vars.NotEmptyVar} | $NE{arg} | |
| {@link org.apache.juneau.svl.vars.UpperCaseVar} | $UC{arg} | |
| {@link org.apache.juneau.svl.vars.LowerCaseVar} | $LC{arg} | |
| {@link org.apache.juneau.svl.vars.LenVar} | $LN{arg[,delimiter]} | |
| {@link org.apache.juneau.svl.vars.SubstringVar} | $ST{arg,start[,end]} | |
| {@link org.apache.juneau.html.HtmlWidgetVar} | $W{name} | |
| juneau-config | {@link org.apache.juneau.config.vars.ConfigVar} | $C{key[,default]} |
| juneau-rest-server | {@link org.apache.juneau.rest.vars.FileVar} | $F{path[,default]}} |
| {@link org.apache.juneau.rest.vars.ServletInitParamVar} | $I{name[,default]} | |
| {@link org.apache.juneau.rest.vars.LocalizationVar} | $L{key[,args...]} | |
| {@link org.apache.juneau.rest.vars.RequestAttributeVar} | $RA{key1[,key2...]} | |
| {@link org.apache.juneau.rest.vars.RequestFormDataVar} | $RF{key1[,key2...]} | |
| {@link org.apache.juneau.rest.vars.RequestHeaderVar} | $RH{key1[,key2...]} | |
| {@link org.apache.juneau.rest.vars.RequestPathVar} | $RP{key1[,key2...]} | |
| {@link org.apache.juneau.rest.vars.RequestQueryVar} | $RQ{key1[,key2...]} | |
| {@link org.apache.juneau.rest.vars.RequestSwaggerVar} | $RS{key} | |
| {@link org.apache.juneau.rest.vars.RequestVar} | $R{key1[,key2...]} | |
| {@link org.apache.juneau.rest.vars.SerializedRequestAttrVar} | $SA{contentType,key[,default]} | |
| {@link org.apache.juneau.rest.vars.SwaggerVar} | $SS{key1[,key2...]} | |
| {@link org.apache.juneau.rest.vars.UrlVar} | $U{uri} | |
| {@link org.apache.juneau.rest.vars.UrlEncodeVar} | $UE{uriPart} |
The main class for performing variable resolution is {@link org.apache.juneau.svl.VarResolver}. Two methods are provided for resolving variables:
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 method:
Beans are accessible through the following method:
Var resolvers can be cloned and extended by using the {@link org.apache.juneau.svl.VarResolver#copy()} method. Cloning a resolver will copy it's {@link org.apache.juneau.svl.Var} class names and context objects.
{@link org.apache.juneau.svl.VarResolver#DEFAULT} is a reusable variable resolver with default support for the following variables:
The {@link org.apache.juneau.encoders} package defines an API for handling encoding-based matching
of
The {@link org.apache.juneau.encoders.EncoderSet} class represents the set of {@link org.apache.juneau.encoders.Encoder encoders} keyed by codings.
It maintains a set of encoders and the codings that they can handle.
The {@link org.apache.juneau.encoders.EncoderSet#getEncoderMatch(String) getEncoderMatch(String)} and {@link org.apache.juneau.encoders.EncoderSet#getEncoder(String)}
methods are then used to find appropriate encoders for specific
Encoders are tried in the order they appear in the set. The {@link org.apache.juneau.encoders.EncoderSet.Builder#add(Class...)} / {@link org.apache.juneau.encoders.EncoderSet.Builder#add(Encoder...)} methods prepend the values to the list to allow them the opportunity to override encoders already in the list.
For example, calling builder.add(E1.
will result in the order
The {@link org.apache.juneau.encoders.Encoder} interface is used for enabling decompression on requests and compression on responses, such as support for GZIP compression. It is used to wrap input and output streams within compression/decompression streams.
Encoders are registered with
The {@link org.apache.juneau.objecttools} package defines convenience utility classes for accessing and manipulating POJOs. It consists of the following classes:
The {@link org.apache.juneau.objecttools.ObjectRest} class provides the ability to perform standard REST operations (GET, PUT, POST, DELETE) against nodes in a POJO model. Nodes in the POJO model are addressed using URLs.
A POJO model is defined as a tree model where nodes consist of consisting of the following:
Leaves of the tree can be any type of object.
Use {@link org.apache.juneau.objecttools.ObjectRest#get(String) get()} to retrieve an element from a JSON tree.
Use {@link org.apache.juneau.objecttools.ObjectRest#put(String,Object) put()} to create (or overwrite) an element in a JSON tree.
Use {@link org.apache.juneau.objecttools.ObjectRest#post(String,Object) post()} to add an element to a list in a JSON tree.
Use {@link org.apache.juneau.objecttools.ObjectRest#delete(String) delete()} to remove an element from a JSON tree.
In the special case of collections/arrays of maps/beans, a special XPath-like selector notation can be used in lieu
of index numbers on GET requests to return a map/bean with a specified attribute value.
The syntax is {@code @attr=val}, where attr is the attribute name on the child map, and val is the matching value.
The {@link org.apache.juneau.objecttools.ObjectSearcher} class is designed to provide searches across arrays and collections of maps or beans. It allows you to quickly filter beans and maps using simple yet sophisticated search arguments.
MyBean[]
The tool can be used against the following data types:
The default searcher is configured with the following matcher factories that provides the capabilities of matching against various data types. This list is extensible:
The {@link org.apache.juneau.objecttools.StringMatcherFactory} class provides searching based on the following patterns:
The {@link org.apache.juneau.objecttools.NumberMatcherFactory} class provides searching based on the following patterns:
The {@link org.apache.juneau.objecttools.TimeMatcherFactory} class provides searching based on the following patterns:
The {@link org.apache.juneau.objecttools.ObjectSorter} class is designed to sort arrays and collections of maps or beans.
MyBean[]
The tool can be used against the following data types:
The arguments are a simple comma-delimited list of property names optionally suffixed with
The {@link org.apache.juneau.objecttools.ObjectViewer} class is designed to extract properties from collections of maps or beans.
MyBean[]
The tool can be used against the following data types:
The {@link org.apache.juneau.objecttools.ObjectPaginator} class is designed to extract sublists from arrays/collections of maps or beans.
MyBean[]
The tool can be used against the following data types:
The {@link org.apache.juneau.objecttools.ObjectIntrospector} class is used to invoke methods on {@code Objects} using arguments in serialized form.
String
The arguments passed to the identified method are POJOs serialized in JSON format. Arbitrarily complex arguments can be passed in as arguments.
The {@link org.apache.juneau.objecttools.ObjectMerger} class is used for merging POJOs behind a single interface. This is particularly useful in cases where you want to define beans with 'default' values.
For example, given the following bean classes:
The getters will be called in order until the first non-null value is returned:
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.
The following example shows JSON for a typical bean:
Person
{
{
name:
The JSON data type produced depends on the Java object type being serialized.
| POJO type | JSON type | Example | Serialized form |
|---|---|---|---|
| String | String | ||
| Number | Number | ||
| Boolean | Boolean | ||
| Null | Null | ||
| Beans with properties of any type on this list | Object | ||
| Maps with values of any type on this list | Object | ||
| Collections and arrays of any type on this list | Array |
In addition, swaps can be used to convert non-serializable POJOs into serializable forms, such as converting
The {@link org.apache.juneau.json.JsonSerializer} class is used to serialize POJOs into JSON.
The class hierarchy for the builder of this serializer is:
Refer to the builder javadocs for configurable settings.
The following pre-configured serializers are provided for convenience:
The {@link org.apache.juneau.json.Json5Serializer} class can be used to serialized POJOs into JSON 5 notation.
JSON 5 is similar to JSON except for the following:
The advantage to JSON 5 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 JSON 5 and do a simple string comparison.
WriterSerializer
The {@link org.apache.juneau.json.JsonParser} class is used to parse JSON into POJOs.
The class hierarchy for the builder of this parser is:
Refer to the builder javadocs for configurable settings.
The following pre-configured parsers are provided for convenience:
The JSON parser supports ALL valid JSON, including:
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.
The annotation can be applied to beans as well as other objects serialized to other types (e.g. strings).
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.
The following shows the JSON representation with and without the annotation present:
| Without annotation | With annotation |
|---|---|
|
{
|
{
|
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
The code for creating our POJO model and generating JSON-Schema is shown below:
{
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.
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.
The following example shows XML for a typical bean:
Person
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.
The following examples show how different data types are represented in XML. They mirror how the data structures are represented in JSON.
The representation of loose (not a direct bean property value) simple types are shown below:
| Data type | JSON example | XML |
|---|---|---|
| string | ||
| boolean | ||
| integer | 123 | |
| float | 1.23 | |
| null |
Loose maps and beans use the element
| Data type | JSON example | XML |
|---|---|---|
| Map<String,String> |
{
k1: |
|
| Map<String,Number> |
{
k1: 123,
k2: 1.23,
k3: |
|
| Map<String,Object> |
{
k1: |
Loose collections and arrays use the element
| Data type | JSON example | XML |
|---|---|---|
| String[] |
[
|
|
| Number[] |
[
123,
1.23,
|
|
| Object[] |
[
|
|
| String[][] |
[
[ |
|
|
|
[ 123 ] | |
|
|
[
|
|
| List<String> |
[
|
|
| List<Number> |
[
123,
1.23,
|
|
| List<Object> |
[
|
| Data type | JSON example | XML |
|---|---|---|
|
|
{
|
| Data type | JSON example | XML |
|---|---|---|
|
|
{
|
The {@link org.apache.juneau.xml.XmlSerializer} class is used to serialize POJOs into XML.
The {@link org.apache.juneau.xml.XmlDocSerializer} class is the same but serializes a
The class hierarchy for the builder of this serializer is:
Refer to the builder javadocs for configurable settings.
The following pre-configured serializers are provided for convenience:
The {@link org.apache.juneau.xml.XmlParser} class is used to parse XML into POJOs.
The class hierarchy for the builder of this parser is:
Refer to the builder javadocs for configurable settings.
The following pre-configured parsers are provided for convenience:
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:
| Data type | JSON example | Without annotation | With annotation |
|---|---|---|---|
|
|
{
a: |
On bean properties, a
In the following example, a type attribute is used on property 'b' but not property 'a' since
'b' is of type
| Java | Without annotation | With annotation |
|---|---|---|
|
|
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.
The following examples show how type names are used under various circumstances.
Pay special attention to when
| Java | XML |
|---|---|
|
|
|
|
|
|
|
|
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.
| Java | XML |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
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
| Java | XML |
|---|---|
|
|
|
|
|
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.
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.
| Data type | JSON example | Without annotation | With annotation |
|---|---|---|---|
|
|
{
a: [ |
||
|
|
{ a: [123,456] } |
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.
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).
| Data type | JSON example | Without annotation | With annotation |
|---|---|---|---|
|
|
{
a: |
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.
| Data type | JSON example | Without annotation | With annotation |
|---|---|---|---|
|
|
{
a: |
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.
| Data type | JSON example | Without annotation | With annotation |
|---|---|---|---|
|
|
{
a: |
The {@link org.apache.juneau.xml.annotation.XmlFormat#ATTRS} format can be applied to a single bean
property of type
| Data type | JSON example | Without annotation | With annotation |
|---|---|---|---|
|
|
{
|
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.
| Data type | JSON example | Without annotation | With annotation |
|---|---|---|---|
|
|
{
a: [ |
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.
| Data type | JSON example | With annotation |
|---|---|---|
|
|
{
a: |
|
|
|
{
a: |
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 serializationbut it is needed during parsing to resolve bean types.
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.
| Data type | JSON example | Without annotations | With annotations |
|---|---|---|---|
|
|
{
a: [
|
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.
XML suffers from other deficiencies as well that affect MIXED content.

Any object that can be serialize to a
| Data type | JSON example | Without annotations | With annotations |
|---|---|---|---|
|
|
{
a: |
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
| Data type | JSON example | With TEXT annotation | With XMLTEXT annotation |
|---|---|---|---|
|
|
{
a: |
Let's go back to the example of our original
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:
Person
Now when we run this code, we'll see namespaces added to our output:
Enabling the XmlSerializer.XML_addNamespaceUrisToRootsetting results
in the namespace URLs being added to the root node:
We can simplify the output by setting the default namespace on the serializer so that all the elements do not need to be prefixed:
This produces the following equivalent where the elements don't need prefixes since they're already in the default document namespace:
By default, the XML serializer class will 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 using {@link org.apache.juneau.xml.XmlSerializer.Builder#disableAutoDetectNamespaces()}.
The following code will produce the same output as before but will perform slightly better since it avoids this pre-scan step.
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.
The primary use case for HTML serialization is rendering POJOs in easy-to-read format in REST interfaces.
The following examples show how different data types are represented in HTML. They mirror how the data structures are represented in JSON.
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.
| Data type | JSON example | HTML |
|---|---|---|
| string | ||
| boolean | ||
| integer | 123 | |
| float | 1.23 | |
| null |
Maps and beans are represented as tables.
The
| Data type | JSON example | HTML |
|---|---|---|
| Map<String,String> |
{
k1: |
|
| Map<String,Number> |
{
k1: 123,
k2: 1.23,
k3: |
|
| Map<String,Object> |
{
k1: |
Collections and arrays are represented as ordered lists.
| Data type | JSON example | HTML |
|---|---|---|
| String[] |
[
|
|
| Number[] |
[
123,
1.23,
|
|
| Object[] |
[
|
|
| String[][] |
[
[ |
|
|
|
[ 123 ] | |
|
|
[
|
| Data type | JSON example | HTML |
|---|---|---|
| List<String> |
[
|
|
| List<Number> |
[
123,
1.23,
|
|
| List<Object> |
[
|
| Data type | JSON example | HTML |
|---|---|---|
|
|
{
|
| Data type | JSON example | HTML |
|---|---|---|
|
|
{
|
The {@link org.apache.juneau.html.HtmlSerializer} class is used to serialize POJOs into HTML.
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.
The class hierarchy for the builder of this serializer is:
Refer to the builder javadocs for configurable settings.
The following pre-configured serializers are provided for convenience:
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}.
The class hierarchy for the builder of this parser is:
Refer to the builder javadocs for configurable settings.
The following pre-configured parsers are provided for convenience:
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.
The {@link org.apache.juneau.html.annotation.Html#link @Html(link)} annotation adds a hyperlink to a bean property when rendered as HTML.
The {@link org.apache.juneau.html.annotation.Html#anchorText @Html(anchorText)} annotation is used to specify the anchor text of a hyperlink.
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
The {@link org.apache.juneau.html.annotation.Html#noTableHeaders @Html(noTableHeaders)} annotation is used to prevent beans from being serialized with table headers.
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
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.
The following example shows two render classes that customize the appearance of the
{@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.
The class hierarchy for the builder of this serializer is:
Refer to the builder javadocs for configurable settings.
This class is used extensively in the creation of POJO-based user interfaces in the REST API.
The {@link org.apache.juneau.html.HtmlDocSerializer.Builder#template(Class)} setting defines a template for the HTML page being generated. The default template is described next.
The {@link org.apache.juneau.html.BasicHtmlDocTemplate} class defines a default template for HTML documents created by {@link org.apache.juneau.html.HtmlDocSerializer}.
The HTML document created by this template consists of the following structure:
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.Builder#template(Class)} setting.
The interface implementation is open-ended allowing you to define the contents of the page any way you wish.
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.
The code for creating our POJO model and generating HTML-Schema is shown below:
The result is the HTML table shown below:
| type | object | ||||||||||||||||||||||||||||||||||||||||||
| properties |
|
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.
Juneau uses UON (URL-Encoded Object Notation) for representing POJOs. The UON specification can be found here.
The following example shows JSON for a typical bean:
Person
(
| Java type | JSON equivalent | UON |
|---|---|---|
| Maps/beans | OBJECT |
|
| Collections/arrays | ARRAY |
|
| Booleans | BOOLEAN |
|
| int/float/double/... | NUMBER |
|
| null | NULL |
|
| String | STRING |
|
Refer to the UON specification for a complete set of syntax rules.
The {@link org.apache.juneau.uon.UonSerializer} class is used to serialize POJOs into UON.
The class hierarchy for the builder of this serializer is:
Refer to the builder javadocs for configurable settings.
The following pre-configured serializers are provided for convenience:
The {@link org.apache.juneau.uon.UonParser} class is used to parse UON into POJOs.
The class hierarchy for the builder of this parser is:
Refer to the builder javadocs for configurable settings.
The following pre-configured parsers are provided for convenience:
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.
Juneau uses UON (URL-Encoded Object Notation) for representing POJOs as URL-Encoded values in key-value pairs. The UON specification can be found here.
The following example shows JSON for a typical bean:
Person
| Java type | JSON equivalent | UON |
|---|---|---|
| Maps/beans | OBJECT |
|
| Collections/arrays | ARRAY |
|
| Booleans | BOOLEAN |
|
| int/float/double/... | NUMBER |
|
| null | NULL |
|
| String | STRING |
|
Refer to the UON specification for a complete set of syntax rules.
The {@link org.apache.juneau.urlencoding.UrlEncodingSerializer} class is used to serialize POJOs into URL-Encoding.
The class hierarchy for the builder of this serializer is:
Refer to the builder javadocs for configurable settings.
The following pre-configured serializers are provided for convenience:
The {@link org.apache.juneau.urlencoding.UrlEncodingParser} class is used to parse URL-Encoding into POJOs.
The class hierarchy for the builder of this parser is:
Refer to the builder javadocs for configurable settings.
The following pre-configured parsers are provided for convenience:
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.
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.
Juneau supports converting arbitrary POJOs to and from MessagePack using ultra-efficient serializers and parsers.
MessagePack is a compact binary form of JSON. The serialization support for MessagePack mirrors that of JSON.
The {@link org.apache.juneau.msgpack.MsgPackSerializer} class is used to serialize POJOs into MessagePack.
The class hierarchy for the builder of this serializer is:
Refer to the builder javadocs for configurable settings.
The following pre-configured serializers are provided for convenience:
The {@link org.apache.juneau.msgpack.MsgPackParser} class is used to parse MessagePack into POJOs.
The class hierarchy for the builder of this parser is:
Refer to the builder javadocs for configurable settings.
The following pre-configured parsers are provided for convenience:
Juneau supports converting arbitrary POJOs to and from strings using OpenAPI-based schema rules.
The relevant classes for using OpenAPI-based serialization are:
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.
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:
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
The following table shows the "natural" intermediate type of the object based on the
| Type | Format | Intermediate Java Type |
|---|---|---|
binary binary-spaced |
||
date-time |
{@link java.util.Calendar} | |
| No intermediate type. (serialized directly to/from POJO) |
||
| empty | {@link java.lang.String} | |
| empty | {@link java.lang.Boolean} | |
| {@link java.lang.Integer} | ||
| {@link java.lang.Long} | ||
| {@link java.lang.Float} | ||
| {@link java.lang.Double} | ||
| empty | Arrays of intermediate types on this list. | |
| No intermediate type. (serialized directly to/from POJO) |
||
| empty | ||
| No intermediate type. (serialized directly to/from POJO) |
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.
For example, the following POJO type can be transformed to and from a byte array.
This example shows how that POJO can be converted to a BASE64-encoded string.
In addition to defining format, the schema also allows for validations of the serialized form.
It looks simple but the implementation is highly sophisticated being able to serialize and parse and validate using complex schemas.
The next sections go more into depth on serializing and parsing various POJO types.
The {@link org.apache.juneau.oapi.OpenApiSerializer} class is used to convert POJOs to HTTP parts.
The class hierarchy for the builder of this serializer is:
Refer to the builder javadocs for configurable settings.
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.
Under-the-covers, this gets converted to the following schema object:
HttpPartSchema
Various convenience methods exist for shortening this code.
The following code shows how the schema above can be used to create our pipe+csv list of numbers:
As a general rule, any POJO convertible to the intermediate type for the
| Type | Format | Valid parameter types |
|---|---|---|
binary binary-spaced |
|
|
date-time |
|
|
|
||
| empty |
|
|
| empty |
|
|
|
||
|
||
|
||
|
||
| empty |
|
|
|
||
| empty |
|
|
|
For arrays, an example of "Any POJO transformable to arrays of the default types" is:
In the example above, our POJO class can be used to create our pipe-delimited list of comma-delimited numbers:
The
The following shows an example of a bean with several properties of various types.
We define the following schema:
Then we serialize our bean:
String
The results of this serialization is shown below:
( 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 )
The following is an example of a bean with various array property types:
For this bean, we define the following schema:
Serializing this bean produces the following output:
( 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) )
The {@link org.apache.juneau.oapi.OpenApiParser} class is used to convert HTTP parts back into POJOs.
The class hierarchy for the builder of this parser is:
Refer to the builder javadocs for configurable settings.
The following is the previous example of a schema that defines the format of a pipe-delimited list of comma-delimited numbers (e.g.
The following code shows how the schema above can be used to parse our input into a POJO:
As a general rule, any POJO convertible from the intermediate type for the
| Type | Format | Valid parameter types |
|---|---|---|
binary binary-spaced |
|
|
date-time |
|
|
|
||
| empty |
|
|
| empty |
|
|
|
||
|
||
|
||
|
||
| empty |
|
|
|
||
| empty |
|
|
|
Additionally, any of the type above can also be wrapped as {@link java.util.Optional Optionals}.
For arrays, an example of "Any POJO transformable from arrays of the default types" is:
In the example above, our POJO class can be constructed from our pipe-delimited list of comma-delimited numbers:
Just like serialization, the
The following shows an example of a bean with several properties of various types.
We define the following schema again:
Then we parse our input into our POJO:
String
Note that serializing into generic
We can also parse into Maps as well:
String
juneau-marshall-rdf-
org.apache.juneau.marshaller.rdf_
The
juneau-dto-
org.apache.juneau.dto_
The
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.
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.
The following examples show how to create common HTML DOM objects.
| Java code | HTML |
|---|---|
|
|
|
|
|
|
|
|
Using the HTML5 DTOs, you should be able to construct any valid HTML5 from full document bodies to any possible fragments.
The {@link org.apache.juneau.html.HtmlParser} class can be used convert these HTML documents back into POJOs.
Other serializers and parsers (e.g. {@link org.apache.juneau.json.JsonSerializer}) can be used to represent these POJOs in languages other than HTML.
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.
To serialize this to ATOM, use the {@link org.apache.juneau.xml.XmlSerializer} class:
The {@link org.apache.juneau.xml.XmlParser} class can be used convert these Atom documents back into POJOs.
Other serializers and parsers (e.g. {@link org.apache.juneau.json.JsonSerializer}) can be used to represent these POJOs in languages other than XML.
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.
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.
The following is an example Swagger document from the Swagger website.
{
This document can be generated by the following Java code:
Methods that take in beans and collections of beans can also take in JSON representations of those objects.
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
Swagger docs can be parsed back into Swagger beans using the following code:
Swagger
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.
The
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:
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:
The {@link org.apache.juneau.rest.servlet.BasicRestServlet} class (describe later) shows how this swap is used in the REST interface to generate the Swagger UI shown above:
juneau-config-
org.apache.juneau.config_
The
Config files are accessed through the {@link org.apache.juneau.config.Config} class which
are created through the {@link org.apache.juneau.config.Config.Builder} class.
Builder creator methods are provided on the
Once instantiated, reading values from the config are simple:
The config language may look simple but it is a very powerful feature with many capabilities including:
/ \ [ ] = #
Configuration files can contain entries for anything from primitive types up to complex hierarchies of POJOs consisting of maps, collections, and/or beans.
Entries are accessed via the {@link org.apache.juneau.config.Config#get(String)} method which returns the following bean:
The most common case for configuration values are primitives.
On integers and longs,
Numbers can also use hexadecimal and octal notation:
Strings with newlines are treated as multi-line values that get broken into separate lines:
Typically, multi-line values are started on the next line for clarity like so:
Entries can also be read as POJOs. In theory, any parsable POJO type can be represented as a config value. However in practice, we're typically talking about the following:
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:
Beans are represented as JSON 5 by default:
The default serializer and parser is registered on the Config through the following methods:
The
String[]
String arrays can also be represented in JSON when the registered parser is a JSON parser:
String[]
Primitive arrays can also be retrieved using the
Arrays of POJOs can also be retrieved using the methods as well:
Address[]
Entries can also be read as Java Collection Framework objects.
The
Examples are shown below:
List<Address>
Oftentimes, it might be useful to parse into the {@link org.apache.juneau.collections.JsonList} and {@link org.apache.juneau.collections.JsonMap} classes that provide the various convenience methods for working with JSON-like data structures:
JsonMap
Entries can also be accessed as binary data. Binary data can be represented in 3 formats:
The binary data format is controlled via the following setting:
For example:
Binary lines can be split up into separate lines for readability:
Binary data line wrapping can be controlled via the following setting:
Config files can contain variables that get resolved dynamically using the previously-described {@link org.apache.juneau.svl.VarResolver} API.
Config
By default,
The variable resolver is controlled via the following setting:
Additionally, the following method can be used to retrieve a
The default variable resolver also provides the following logic variables for performing simple logical operations:
The
The
The
The
The following method can be used to associates entry modifiers to a config:
Mods are used to modify values before being persisted. This can be used to
replace or encode sensitive information. They are denoted by a single
character that gets appended between angle brackets on the property name (e.g.
The framework comes built-in with a simple {@link org.apache.juneau.config.mod.XorEncodeMod xor-encode} mod tied
to the
Custom encoders can be used to provide your own encoding support by implementing the {@link org.apache.juneau.config.mod.Mod} class.
Unmodified 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#applyMods()} which can typically be done during JVM startup to immediately encode any unencoded passwords in the file.
Config sections can be retrieved in-bulk using the {@link org.apache.juneau.config.Config#getSection(String)} method. It returns the following bean:
The {@link org.apache.juneau.config.Section#asMap() asMap()} method allows you to access a section as simple key/value pairs.
Maps created this way are snapshot copies of the section at the time of the method call.
Config files can also be used to directly populate beans using {@link org.apache.juneau.config.Section#asBean(Class) asBean()} or {@link org.apache.juneau.config.Section#writeToBean(Object,boolean) writeToBean()}.
Like maps, beans created this way are snapshot copies of the section at the time of the method call.
Config sections can also be accessed via interface proxies using {@link org.apache.juneau.config.Section#asInterface(Class)}.
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.
The following methods allow you to add, remove, and modify entries and sections in a config file:
The method {@link org.apache.juneau.config.Config#set(String,Object,Serializer,String,String,List)} can be used for adding comments and pre-lines to entries, and specifying encoded values.
The last 4 arguments in {@link org.apache.juneau.config.Config#set(String,Object,Serializer,String,String,List)}
are optional in that if you pass
Sections can be added with optional pre-lines using the
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.
Changes can be rolled back using the {@link org.apache.juneau.config.Config#rollback()} method.
In general, external file modifications will be detected immediately in the
The
If the
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).
Setter methods that take in a
The value can then be retrieved using the equivalent parser:
Address
The following methods can be used to bulk-load configuration values:
Changes can then be committed using the {@link org.apache.juneau.config.Config#commit()} method.
Configuration change events can be listened for using the following methods:
The {@link org.apache.juneau.config.event.ConfigEventListener} interface consists of the following method:
The {@link org.apache.juneau.config.event.ConfigEvent} class provides access to all the information about the updated entry:
The listener method is triggered:
In both cases, the listener is triggered after the changes have been committed.
The following methods are used for serializing
Both methods are thread safe.
Configurations can import values from other configurations using the following syntax:
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.
Configuration imports can be nested arbitrarily deep.
Values can be overridden by child configurations.
Config
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
Values can be overwritten in child configurations but the values will only be set in that configuration and not the imported configuration.
Dynamically adding an import will cause change events to be generated for imported values.
Dynamically removing an import has the same effect as removing keys and generates
Note that when dynamically adding or removing imports, overridden keys in the child config will be filtered from the change events.
Configuration files are stored in entities called Stores.
The methods that need to be implemented on a store are:
Read is self-explanatory:
Write is slightly trickier:
The update method is called whenever the stored file gets modified externally:
Two configuration stores are provided by default:
The store is defined on the
The default store used is {@link org.apache.juneau.config.store.FileStore#DEFAULT} which defines the execution directory as the file system directory to store and retrieve files.
The {@link org.apache.juneau.config.store.MemoryStore} class is simply an in-memory storage location for configuration files. There is no hard persistence and is used primarily for testing purposes.
However, the implementation provides a good idea on how stores work (especially the write method):
The {@link org.apache.juneau.config.store.FileStore} is the typical store used for configuration files. It provides the following configurable settings:
The
The example below shows a starting point for an implementation based on polling a relational database. The source can be found here: {@link org.apache.juneau.examples.core.config.store.SqlStore}. Completing it is left as an exercise:
The
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:
This listener is used by the
The following settings can be used to create read-only
This causes all methods that make modifications to throw {@link java.lang.UnsupportedOperationException}.
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.
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:
If you do not specify a system default config, one will be automatically searched for. The search is done in the following order:
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
By default, all properties in the system default configuration are automatically set as system properties.
This can be disabled by setting the system property
juneau-assertions-
org.apache.juneau.assertions_
The {@link org.apache.juneau.assertions} package in Juneau is a powerful API for performing fluent style assertions. It is used to implement built-in assertion methods on both the server and client side APIs. But it can also be used standalone for testing.
The {@link org.apache.juneau.assertions} package in Juneau is a powerful API for performing fluent style assertions. It is used throughout the REST client and server APIs for performing inline assertions on REST requests and responses.
The assertions API is designed to be used in both code (as it's done in the REST APIs) or for standalone use in unit tests.
The {@link org.apache.juneau.assertions.Assertions} class provides various static methods for invoking assertions on a variety of object types for simplified unit testing.
Assertions have 3 categories of methods:
Testing methods (
Transform methods (
Configuration methods (
The following shows the class hierarchy for the {@link org.apache.juneau.assertions.IntegerAssertion IntegerAssertion} class showing the general design pattern for assertion classes:
In the design, the "Fluent" classes (e.g. {@link org.apache.juneau.assertions.FluentIntegerAssertion}) allow you to specify the object
that gets returned when the test method is executed. When used in the
For more information about the capabilities of the Assertions API, refer to the methods on the {@link org.apache.juneau.assertions.Assertions} methods above.
juneau-rest-common-
org.apache.juneau.rest.common_
The {@link org.apache.juneau.http} package contains a slew of useful extensions to the Apache HttpComponents libraries and define APIs used extensively in the REST server and client APIs.
These APIs extend from the Apache HttpComponents libraries and can be used with libraries based on it such as Apache HttpClient. The REST Client API described later is built on top of Apache HttpClient and many of the classes defined in this package make up integral components of that API. Likewise, the APIs defined here are also used in the REST Server APIs also described later.
The {@link org.apache.juneau.http.header} package contains various convenience classes for creating standard HTTP components using static imports.
The {@link org.apache.juneau.http.HttpHeaders} class contains many convenience static methods and fields for working with standard HTTP request and response headers and header lists.
This class is vast in scope and covers all request and response headers defined in RFC2616.
In addition to the predefined headers, various methods are provided for free-form headers. Each accepts either static values or values from {@link java.util.function.Supplier Suppliers}:
The {@link org.apache.juneau.http.HttpHeaders#serializedHeader(String,Object) serializedHeader} methods allows for headers serialized using schema-based serializers such as the OpenAPI serializer.
Static methods are also provided for instantiating {@link org.apache.juneau.http.annotation.Header}-annotated or other HttpComponent-defined header classes:
Lists of headers can be produced with the following methods:
The capabilities of the {@link org.apache.juneau.http.header.HeaderList} class is described later.
The {@link org.apache.juneau.http.HttpParts} class contains convenience static methods for generating query/form-data/path parts and part lists.
The following methods are provided for creating parts. Each accepts either static values or values from {@link java.util.function.Supplier Suppliers}:
The {@link org.apache.juneau.http.HttpParts#serializedPart(String,Object) serializedPart} methods allows for parts serialized using schema-based serializers such as the OpenAPI serializer.
Lists of parts can be produced with the following methods:
The capabilities of the {@link org.apache.juneau.http.part.PartList} class is described later.
The {@link org.apache.juneau.http.HttpEntities} class contains convenience static methods for generating HTTP message entities. Returned objects extend from {@code org.apache.http.HttpEntity} but provides the following additional features:
The following methods are provided for creating entities. Each accepts either static values or values from {@link java.util.function.Supplier Suppliers} and returns builders:
HTTP entities are automatically supported in both the server and client REST APIs for requests and responses.
The {@link org.apache.juneau.http.HttpResources} class contains convenience static methods for generating HTTP message resources. Returned objects extend from {@link org.apache.juneau.http.resource.HttpResource} which extends from {@link org.apache.http.HttpEntity} but with additional arbitrary headers.
The following methods are provided for creating entities. Each accepts either static values or values from {@link java.util.function.Supplier Suppliers} and are in the form of builders.
The most common location where resources are used are as returned types of REST operation methods described later.
The {@link org.apache.juneau.http.HttpResponses} class contains convenience static methods for standard HTTP responses. Returned objects extend from {@code org.apache.http.HttpResponse} and are in the form of builders.
The following methods are provided for creating entities:
The most common location where these responses are used are in REST operation methods described later.
The {@link org.apache.juneau.http.annotation} package contains annotations for defining both server and client side APIs. The server-side APIs also use it for producing auto-generated Swagger documentation through the REST API itself.
These annotations are used in a variety of places in the server and client side REST interfaces, especially for remote proxies. These will be described later in those sections.
The {@link org.apache.juneau.http.header} package contains implementations of
These headers extend from the following classes that provide data-type specific functionality:
These subclasses provide various convenience methods to allow for easy fluent-style coding.
The {@link org.apache.juneau.http.header.HeaderList} class is a list of HTTP headers.
Static methods are provided on {@link org.apache.juneau.http.HttpHeaders} to further simplify creation of header lists.
The builder class supports setting default header values (i.e. add a header to the list if it isn't otherwise in the list).
Note that this is different from simply setting a value twice as using default values will not overwrite existing
headers.
The following example notes the distinction:
Various methods are provided for iterating over the headers in this list to avoid array copies.
In general, try to use these over the {@link org.apache.juneau.http.header.HeaderList#getAll() getAll()} / {@link org.apache.juneau.http.header.HeaderList#getAll(String) getAll(String)} methods that require array copies.
The {@link org.apache.juneau.http.header.HeaderList#get(String) get(String)} method is special in that it will collapse multiple headers with the same name into a single comma-delimited list (see RFC 2616 Section 4.2 for rules).
The {@link org.apache.juneau.http.header.HeaderList#get(Class) get(Class)} and {@link org.apache.juneau.http.header.HeaderList#get(String,Class) get(String,Class)} methods are provided for working with {@link org.apache.juneau.http.annotation.Header}-annotated beans.
HeaderList headers = HeaderList.of(Accept.TEXT_JSON, Accept.TEXT_XML);
By default, header names are treated as case-insensitive. This can be changed using the {@link org.apache.juneau.http.header.HeaderList#caseSensitive(boolean) caseSensitive(boolean)} method.
A {@link org.apache.juneau.svl.VarResolver} can be associated with this builder to create header values with embedded variables that are resolved at runtime.
The {@link org.apache.juneau.http.header.HeaderList} object can be extended to defined pre-packaged lists of headers which can be used in various annotations throughout the framework.
The {@link org.apache.juneau.http.part} package contains implementations of
The {@link org.apache.juneau.http.part.PartList} class is a list of HTTP parts (form-data, query-parameters, path-parameters).
PartList
Convenience creators are provided for creating lists with minimal code:
PartList
Static methods are provided on {@link org.apache.juneau.http.HttpParts} to further simplify creation of part lists.
The builder class supports setting default part values (i.e. add a part to the list if it isn't otherwise in the list).
Note that this is different from simply setting a value twice as using default values will not overwrite existing
parts.
The following example notes the distinction:
Various methods are provided for iterating over the parts in this list to avoid array copies.
In general, try to use these over the {@link org.apache.juneau.http.part.PartList#getAll() getAll()} / {@link org.apache.juneau.http.part.PartList#getAll(String) getAll(String)} methods that require array copies.
Similar to the way multiple headers can be collapsed into a single value, the {@link org.apache.juneau.http.part.PartList#get(String) get(String)} method is special in that it will collapse multiple parts with the same name into a single comma-delimited list.
The {@link org.apache.juneau.http.part.PartList#get(Class) get(Class)} and {@link org.apache.juneau.http.part.PartList#get(String,Class) get(String,Class)} methods are provided for working with {@link org.apache.juneau.http.annotation.FormData} / {@link org.apache.juneau.http.annotation.Query} / {@link org.apache.juneau.http.annotation.Path}-annotated beans.
MyQueryBean
A {@link org.apache.juneau.svl.VarResolver} can be associated with this builder to create part values with embedded variables that are resolved at runtime.
The {@link org.apache.juneau.http.part.PartList} object can be extended to defined pre-packaged lists of parts which can be used in various annotations throughout the framework.
The {@link org.apache.juneau.http.entity} package contains implementations of
The {@link org.apache.juneau.http.resource} package contains implementations of {@link org.apache.juneau.http.resource.HttpResource} which are extensions of
HTTP entities and resources can be used by both the server and client side APIs described in later sections.
The {@link org.apache.juneau.http.response} package contains predefined
These are built upon existing HttpComponents APIs:
The most common location where these responses are used are in REST operation methods described later.
The following classes are also provided for constructing your own custom responses:
The {@link org.apache.juneau.http.remote} package contains the annotations used for defining client-side remote proxies.
See Proxies for more information on use of these annotations.
juneau-rest-server-
org.apache.juneau.rest.server_
The
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
The API builds upon the existing JEE Servlet API. The root class, {@link org.apache.juneau.rest.servlet.RestServlet} is nothing but a specialized {@link jakarta.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 jakarta.servlet.http.HttpServletRequest} and {@link jakarta.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.
Many of the examples in this document are pulled directly from
A REST resource is simply a Java class annotated with {@link org.apache.juneau.rest.annotation.Rest @Rest}. The most common case is a class that extends {@link org.apache.juneau.rest.servlet.BasicRestServlet}, which itself is simply an extension of {@link jakarta.servlet.http.HttpServlet} which allows it to be deployed as a servlet.
Juneau has two sample applications for demonstrating how to use the REST API, one using Jetty and one using Spring Boot:
The
The Jetty application consists of the following application class that registers our top-level servlet:
The root resources class is an example of a router page that is used to attach children to:
This is what it looks like in a browser:
The {@link org.apache.juneau.examples.rest.HelloWorldResource} class is our basic example of a child REST resource:
This is what it looks like in a browser:
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...
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.
The {@link org.apache.juneau.rest.annotation.Rest @Rest} annotation in inheritable from parents and interfaces of resource classes. When multiple annotations are defined at different levels, the annotation values are combined. 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.
The following example represents the bare-minimum needed for deploying a top-level REST endpoint with basic JSON marshalling support:
The {@link org.apache.juneau.rest.servlet.RestServlet} class provides all the logic for starting up your REST application when the servlet container calls {@link org.apache.juneau.rest.servlet.RestServlet#init(ServletConfig) init(ServletConfig)}. On startup, it scans your class for annotations and sets up all of your serializers and parsers. It then does this recursively for all child resources.
Users will typically not extend directly from {@link org.apache.juneau.rest.servlet.RestServlet}. Instead, several classes are provided by the framework to provide additional
functionality and to handle different use-cases. Users will typically extend from one of these
The {@link org.apache.juneau.rest.servlet.RestServlet} class itself is not configured with any serializers or parsers. However, it does provide several convenience methods to be aware of:
The
The
For example, if you want to provide a resource that supports all languages in Juneau, simply add the {@link org.apache.juneau.rest.config.BasicUniversalConfig} interface like so:
The
The
The
The following is a breakdown of which classes you will use in different cases:
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.
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
One advantage of using child resources is that they do not need to be declared in the JEE
As explained earlier, child REST objects typically extend from {@link org.apache.juneau.rest.servlet.BasicRestObject} or {@link org.apache.juneau.rest.servlet.BasicRestObjectGroup} and not from one of the servlet classes. They also technically don't even need to extend from those classes and can instead just be a normal class annotated with the bare-minimum {@link org.apache.juneau.rest.annotation.Rest @Rest} and {@link org.apache.juneau.rest.annotation.RestOp @RestOp} annotations.
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#getPathParams()} method.
Variables can be used on either top-level or child resources and can be defined on multiple levels. Path variables resolved in parent resource paths are also available to the child resources.
REST resources are deployed in the following ways:
When deployed in a J2EE container, you MUST extend from one of the servlet classes.
Deployment in a servlet container is typically done by adding a servlet entry for the top-level resources to the JEE
Deployment in a Spring Boot environment involves defining your top-level resources as Spring Beans. Top-level resources must extend from {@link org.apache.juneau.rest.springboot.BasicSpringRestServlet} or {@link org.apache.juneau.rest.springboot.BasicSpringRestServletGroup} so that Juneau can hook into the injection framework provided by Spring. Child resource CAN be defined as injected Spring Beans as well but it is not a requirement.
Lifecycle hooks allow you to hook into lifecycle events of the servlet/resource creation and REST calls.
For example, if you want to add an initialization method to your resource:
Or if you want to intercept REST calls:
The following lifecycle annotations are provided.
REST Java methods are identified on REST servlets using the {@link org.apache.juneau.rest.annotation.RestOp @RestOp} annotation. The annotation allows the framework to identify the available REST methods through reflection.
The following specialized annotations are also provided for specific HTTP methods:
When the
The HTTP method can be inferred from the Java method by starting the method name with any of the following:
If
If
Java methods can contain any of the following parameters in any order:
In Spring Boot environments, any available Spring Beans can also be passed in as parameters.
Additional parameter types can be defined via the annotation {@link org.apache.juneau.rest.annotation.Rest#restOpArgs()} or by calling {@link org.apache.juneau.rest.RestContext.Builder#restOpArgs(Class...)}.
The return type of the Java method can be any serializable POJO as defined in POJO Categories.
It can also be
In addition to POJOs, the following return types are also supported:
REST Java methods can also generate a response via the following:
Additional parameter types can be defined via the annotation {@link org.apache.juneau.rest.annotation.Rest#responseProcessors()} or by calling {@link org.apache.juneau.rest.RestContext.Builder#responseProcessors(Class...)}.
Annotated Java methods can throw any of the following:
All other throwables get processed as follows:
The {@link org.apache.juneau.rest.annotation.RestOp#path() @RestOp(path)} annotation allows
you to define URL path patterns to match against.
These patterns can contain variables of the form
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...
By default, path patterns are matched using a best-match heuristic. When overlaps occur, URLs are matched from most-specific to most-general order:
Paths that end with
The following example shows the distinction.
{@link org.apache.juneau.rest.matcher.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.
The interface for matchers is simple:
Through the use of the built-in
For example, the URL
To support overloaded methods, the {@link org.apache.juneau.rest.annotation.Rest#allowedMethodParams() @Rest(allowedMethodParams)} setting must be enabled on your servlet.
Refer to the following Javadocs for more information:
In previous examples we showed the ability to pass in annotated parameters on {@link org.apache.juneau.rest.annotation.RestOp}-annotated methods to parse standard HTTP parts:
Annotations are provided for both request and response HTTP parts.
The annotations used for defining the schema for request HTTP parts are:
These annotation can be used on method parameters or on the parameter types themselves, or a combination of both.
Juneau comes with three basic marshaller types for serializing and parsing Header, Query, Form, and Path parts:
By default, the REST API uses the OpenAPI serializer and parser which allows for schema-based marshalling. You also have the option to use UON marshalling which is schema-less but allows for JSON-equivalent data structures (object/array/primitives/...) using URL-encoding notation. This can be done by overriding the part marshallers through the following APIs:
The OpenAPI marshallers themselves also have the ability to support UON notation for individual parts via the schema itself:
The following annotations allow for defining part schemas based on the OpenAPI standard.
The {@link org.apache.juneau.http.annotation.Header @Header}/{@link org.apache.juneau.http.annotation.Query @Query}/ {@link org.apache.juneau.http.annotation.FormData @FormData}/{@link org.apache.juneau.http.annotation.Path @Path} annotations can be used on parameters of {@link org.apache.juneau.rest.annotation.RestOp @RestOp}-annotated methods to get access to request headers, query parameters, form-data parameters, and path parts.
The most typical scenario is to simply use the
This is functionally equivalent to the following code:
The special name
The {@link org.apache.juneau.http.annotation.Content @Content} annotation is used to identify POJOs to be used as the body of an HTTP request.
This is functionally equivalent to the following code:
In addition to {@link org.apache.juneau.http.annotation.Content @Content}-annotated parameters/types, the body of an HTTP request can be retrieved by passing in parameters of the following types (matched in the specified order):
When used in combination with the mutable {@link org.apache.juneau.Value} object, the {@link org.apache.juneau.http.annotation.StatusCode @StatusCode} and {@link org.apache.juneau.http.annotation.Header @Header} annotations can be used on parameters {@link org.apache.juneau.rest.annotation.RestOp @RestOp}-annotated methods to to define to response codes and headers.
This is functionally equivalent to the following code:
The default registered part marshallers, {@link org.apache.juneau.oapi.OpenApiSerializer} and {@link org.apache.juneau.oapi.OpenApiParser}, are used to marshall POJOs using schemas defined via the {@link org.apache.juneau.annotation.Schema @Schema} annotation.
For example, the following shows how a pipe-delimited list of comma-delimited numbers (e.g.
Schema-based marshalling works for both request and response parts.
Input will be converted based on the types and formats defined in the schema definition.
Input validations such as
The part and schema annotations are also used for supplying swagger information about the HTTP part. This information is used to populate the auto-generated Swagger documentation and UI.
SVL Variables (e.g. "$L{my.localized.variable}") are supported on annotation fields as well.
Among other things, this allow for annotation values to be defined externally and the ability to produce localized swagger documents
based on the
The {@link org.apache.juneau.http.annotation.Content @Content} annotation can also be used to parse HTTP request bodies using OpenAPI schemas
when the body content type matches the {@link org.apache.juneau.oapi.OpenApiParser} parser via the header
The following shows the same for a request body:
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
As you can see, the complexity of possible input types expands significantly. For more information about valid parameter types, see OpenAPI Parsers.
By default, HTTP parts that don't have value (such as missing query parameters) end up with null values:
You have several options to provide default values for HTTP parts. The most common is to simply use {@link java.util.Optional} parameters and handle default values programmatically:
You can also specify default values on the annotations:
A third option is to specify default values via the {@link org.apache.juneau.rest.annotation.Rest} and {@link org.apache.juneau.rest.annotation.RestOp} annotations.
Default parts can also be specified programmatically through any of the following methods:
The {@link org.apache.juneau.http.annotation.Request @Request} annotation can used to define proxy interfaces against HTTP requests in combination with the following annotations used on methods:
The example above is identical in behavior to specifying individual annotated parameters on the
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. Part names can either be explicitly specified or automatically inferred from the getter names.
For clarity, the
The {@link org.apache.juneau.http.annotation.Response} annotation can be used to define beans that return HTTP response parts via annotations and methods. They are used in combination with the following annotations:
Response beans can either be returned or thrown from {@link org.apache.juneau.rest.annotation.RestOp @RestOp}-annotated methods.
The following example shows the
Custom exceptions can also extend from one of the predefined HTTP exceptions such as the {@link org.apache.juneau.http.response.Unauthorized} exception: