{title:'Marshalling', created:'9.0.0'}

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:

| // A simple bean | public class Person { | public String name = "John Smith"; | public int age = 21; | } | | // Produces: | // "{"name":"John Smith","age":21}" | String json = Json.of(new Person());

Parsing back into POJOs is equally simple for any of the supported languages. Language fragments are also supported.

| // Parse a JSON object as a bean. | String json = "{\"name\":\"John Smith\","\age\":21}"; | Person person = Json.to(json, Person.class);

Marshalling support is provided for a wide variety of POJO types including:

Serializer/Parser Builders

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.

| // Create a serializer from scratch programmatically using a builder. | JsonSerializer serializer = JsonSerializer | .create() | .simple() // Simple mode | .sq() // Use single quotes | .timeZone(TimeZone.GMT) // For timezone-specific serialization | .locale(Locale.JAPAN) // For locale-specific serialization | .sortCollections() | .sortProperties() | .keepNullProperties() | .trimStrings() | .beanMethodVisibility(PROTECTED) // Control which fields/methods are serialized | .beanDictionary( // Adds type variables for resolution during parsing | MyBeanA.class, | MyBeanB.class | ) | .debug() // Debug mode | .build();

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 oaj.swaps} package contains a variety of predefined swaps.

| // Create a serializer from scratch programmatically using a builder. | JsonSerializer serializer = JsonSerializer | .create() | .swaps( // Swap unserializable classes with surrogate POJOs | IteratorSwap.class, // Iterators swapped with lists | ByteArrayBase64Swap.class, // byte[] swapped with base-64 encoded strings | CalendarSwap.ISO8601DT.class // Calendars swapped with ISO8601-compliant strings | ) | .build();

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.

Bean Annotations

Beans and POJO classes, methods, fields, and constructors can also be annotated with a variety of annotations to customize how they are marshalled:

| // Sort bean properties by name. | // Exclude city/state from marshalling. | @Bean(sort=true, excludeProperties="city,state") | public class Address { ... } | | // Specify an implementation class for an interface. | @Marshalled(implClass=AutomobileImpl.class) | public interface Automobile { ... }

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.

Configuration Annotations

Serializers and parsers can also be configured using annotations.

| @BeanConfig(sortProperties="true") | @SerializerConfig(quoteChar="'") | @RdfConfig(rdfxml_tab="5", addRootProperty="true") | public class MyAnnotatedClass {...} | | // Create a serializer configured using annotations. | JsonSerializer serializer = JsonSerializer | .create() | .applyAnnotations(MyAnnotatedClass.class) | .build();

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.

| // Sort properties depending on value of system property "sortProperties". | @BeanConfig(sortProperties="$S{sortProperties,false}")

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:

| @Bean(onClass=Address.class, sort=true, excludeProperties="city,state") | public class MyAnnotatedClass {...}

JSON 5 Marshalling

The {@link oaj.json.Json5Serializer} class can be used to serialized POJOs into JSON 5 notation.

JSON 5 is similar to JSON except for the following:

Examples:

| // Some free-form JSON. | Map map = JsonMap.of( | "foo", "x1", | "_bar", "x2", | " baz ", "x3", | "123", "x4", | "return", "x5", | "", "x6" | );

| // Serialized to standard JSON | { | "foo": "x1", | "_bar": "x2", | " baz ": "x3", | "123": "x4", | "return": "x5", | "": "x6" | }

// Serialized to JSON 5 | { | foo: 'x1', | _bar: 'x2', | ' baz ': 'x3', // Quoted due to embedded spaces. | '123': 'x4', // Quoted to prevent confusion with number. | 'return': 'x5', // Quoted because it's a keyword. | '': 'x6' // Quoted because it's an empty string. | }

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 serializer = Json5Serializer.DEFAULT; | assertString(serializer.toString(myPojo)).is("{foo:'bar',baz:123}");

UON Marshalling

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='John+Smith', | uri=http://sample/addressBook/person/1, | addressBookUri=http://sample/addressBook, | birthDate=1946-08-12T00:00:00Z, | addresses=@( | ( | uri=http://sample/addressBook/address/1, | personUri=http://sample/addressBook/person/1, | id=1, | street='100+Main+Street', | city=Anywhereville, | state=NY, | zip=12345, | isCurrent=true | ) | ) | )

OpenAPI Marshalling

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.

| import static org.apache.juneau.httpart.HttpPartSchema.*; | | // Schema - Pipe-delimited list of comma-delimited longs. | HttpPartSchema schema = tArrayPipes().items( | tArrayCsv().items( | tInt64() | ) | ).build(); | | // Our value to serialize | Object value = new long[][]{{1,2,3},{4,5,6},{7,8,9}}; | | // Produces "1,2,3|4,5,6|7,8,9" | String output = OpenApi.of(schema, value);

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.

| // REST server method with HTTP parts using schema validation. | @RestGet | public void doGet( | @Query(name="myParam", schema=@Schema(min=1, max=32)) int myParam, | @Header("MyHeader", schema=@Schema(pattern="foo.*")) String p2 | ) {...}

JsonMap/JsonList

The {@link oaj.collections.JsonMap} and {@link oaj.collections.JsonList} collections classes allow you to programmatically build generic JSON data structures. They are similar in concept to JSONObject and JSONArray that you find in other JSON marshalling APIs but can be used to generate DOMs in any of the supported languages.

| // Create JSON strings from scratch using fluent-style code. | String myMap = JsonMap.create().append("foo","bar").asJson(); | String myList = JsonList.of("foo", 123, null, jsonObject).asJson(); | | // Parse directly from JSON into generic DOMs. | Map<String,Object> myMap = JsonMap.ofJson("{foo:'bar'}"); | List<Object> myList = JsonList.ofJson("['foo',123,null]");

These classes provide lots of convenience methods including:

Serializer and Parser Sets

{@link oaj.serializer.SerializerSet} and {@link oaj.parser.ParserSet} classes allow serializers and parsers to be retrieved by W3C-compliant HTTP Accept and Content-Type values:

| // Construct a new serializer group with configuration parameters that get applied | // to all serializers. | SerializerSet serializerSet = SerializerSet | .create() | .add(JsonSerializer.class, UrlEncodingSerializer.class); | .forEach(x -> x.swaps(CalendarSwap.ISO8601DT.class)) | .forEachWS(x -> x.useWhitespace()) | .build(); | | // Find the appropriate serializer by Accept type and serialize our POJO to the specified writer. | // Fully RFC2616 compliant. | serializerSet | .getSerializer("text/invalid, text/json;q=0.8, text/*;q:0.6, *\/*;q=0.0") | .serialize(person, myWriter); | | // Construct a new parser group with configuration parameters that get applied to all parsers. | ParserSet parserSet = ParserSet | .create() | .add(JsonParser.class, UrlEncodingParser.class); | .forEach(x -> x.swaps(CalendarSwap.ISO8601DT.class)) | .build(); | | Person person = parserSet | .getParser("text/json") | .parse(myReader, Person.class);

SVL Variables

The {@link oaj.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 "$varName{varKey}".

Variables can be recursively nested within the varKey (e.g. "$FOO{$BAR{xxx},$BAZ{xxx}}"). Variables can also return values that themselves contain more variables.

| // Use the default variable resolver to resolve a string that | // contains $S (system property) variables | String myProperty = VarResolver.DEFAULT.resolve("The Java home directory is $S{java.home}");

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.