juneau-marshall
juneau.version is 10.0.0-SNAPSHOT for these docs (the latest release on Maven Central is 9.2.0); see Install Juneau for the property and the snapshots repository.
| Maven | |
|---|---|
| Jar | juneau-marshall-10.0.0.jar |
| OSGi | org.apache.juneau.marshall_10.0.0.jar |
| Links | Maven Central · Javadocs · Source |
Contents/Features
- Foundation for all serializers and parsers.
- Implementations for all serializers and parsers except RDF languages.
- Various reusable utilities used throughout the framework.
Overview
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:
These are the 38 formats the docs count; see Counting formats.
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 JSON5 fragment (unquoted keys, single-quoted values) as a bean.
String json5 = "{name:'John Smith',age:21}";
Person person = Json5.to(json5, Person.class);
Marshalling support is provided for a wide variety of POJO types including:
- Primitives and primitive wrappers (
int,Integer,boolean,Boolean, etc.) - Java beans (standard getters/setters)
- Java Records
- Enums
- Java Collections Framework objects (
List,Set,Map,Queue,Deque, etc.) - Arrays (including multi-dimensional)
OptionalandOptionalInt/OptionalLong/OptionalDouble- Date/time types (
Calendar,Date,Temporalsubtypes,Duration,Period) IteratorandStream(serialization only — consumed lazily without buffering)- Classes with
toString()/fromString()orvalueOf(String)methods - Classes with constructors taking a single
Stringargument - Interfaces (when an implementation class is specified via
@Marshalled(implClass=...)) - Any other type via pluggable Swaps
- Pojo Categories for an exhaustive list of categories supported out-of-the-box.
Counting formats
These docs count 38 formats (26 in juneau-marshall, 12 RDF in juneau-marshall-rdf). One format is one
marshaller class that both serializes and parses: a public class in the marshaller package of either module that
extends CharMarshaller or StreamMarshaller, such as Json or Turtle. The 12 RDF formats live in
juneau-marshall-rdf and need Apache Jena. SOAP is not counted: SoapXmlSerializer writes SOAP envelopes but has
no parser. JsonPatchMarshaller (in juneau-bean-jsonpatch) is not counted either: it is JSON pre-wired for JSON
Patch, not a separate format.
Token and Record Streaming
For large datasets, the marshalling API supports O(1)-memory streaming via RecordReader and RecordWriter cursors.
Records are produced or consumed one at a time without buffering the entire document.
JSON5L (line-delimited JSON5) is a natural fit — each line is an independent record:
// Write a large dataset line-by-line to an OutputStream.
try (RecordWriter w = Json5l.DEFAULT.toRecords(myOutputStream)) {
for (Person p : millionsOfPeople)
w.write(p);
}
// Read it back record-by-record — constant memory regardless of dataset size.
try (RecordReader r = Json5l.DEFAULT.fromRecords(myInputStream)) {
Person p;
while ((p = r.read(Person.class)) != null)
process(p);
}
Formats like JSON and CBOR additionally expose a structural TokenReader/TokenWriter cursor that streams
individual tokens (OBJECT_START, KEY, VALUE, OBJECT_END, …) for use cases such as schema validation,
transformation pipelines, and custom serialization logic.
- Token Streaming Basics for the full streaming API reference.
- Record Streaming for record-cursor details and per-format capability matrix.
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 = Json5Serializer // Simple mode, single quotes
.create()
.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();
Swaps allow you to replace non-serializable objects with serializable equivalents or to override the default serialization format for types that already have built-in support. The org.apache.juneau.marshall.swaps package contains a variety of predefined swaps.
// Create a serializer from scratch programmatically using a builder.
JsonSerializer serializer = JsonSerializer
.create()
.binaryFormat(BinaryFormat.BASE64) // byte[] serialized as base-64 encoded strings
.calendarFormat(CalendarFormat.RFC_1123_DATE_TIME) // Override default ISO 8601 format for Calendars
.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:
// Disable alphabetical sorting of bean properties (bean properties are sorted by default).
// Exclude city/state from marshalling.
@BeanType(unsorted=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.
- Java Beans Support for more information.
Configuration Annotations
Serializers and parsers can also be configured using annotations.
@MarshalledConfig(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".
@MarshalledConfig(sortProperties="$S{sortProperties,false}")
Default values for config settings can be overridden via system properties or environment variables. For example, the system property "MarshallingContext.sortProperties" or environment variable "MARSHALLINGCONTEXT_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 annotations like so:
@BeanTypeApply(onClass=Address.class, value=@BeanType(unsorted=true, excludeProperties="city,state"))
public class MyAnnotatedClass {...}
- Context Annotations for more information.
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.marshall.httppart.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 = OpenApiSerializer.DEFAULT.write(HttpPartType.QUERY, 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
) {...}
- OpenAPI Details for more information.
Bean Property Schema Validation
Parsers and serializers can also enforce JSON-Schema constraints declared via
@Schema
on bean properties, independent of HTTP parts. Validation is opt-in via
MarshallingContext.Builder.validateSchema() and is powered by
JsonSchemaValidator
in juneau-bean-jsonschema.
public class MyBean {
@Schema(minLength=2, maxLength=10) public String name;
@Schema(minimum="0", maximum="150") public int age;
}
ReaderParser p = JsonParser.create().validateSchema().build();
p.read("{\"name\":\"a\",\"age\":42}", MyBean.class); // throws ParseException - minLength
The flag flows through @BeanConfig(validateSchema="true") and every builder subclass (parsers,
serializers, REST clients). Failures surface as ParseException on the parse side and
SerializeException on the serialize side. When juneau-bean-jsonschema is not on the classpath
the flag becomes a silent no-op.
- JSON-Schema Support for the marshalling-side schema details.
- juneau-bean-jsonschema for the full validator reference and supported keywords.
JsonMap/JsonList
The JsonMap and 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 = Json5Map.create().append("foo","bar").toJson5();
String myList = Json5List.of("foo", 123, null, jsonObject).toJson5();
// Parse directly from JSON5 into generic DOMs.
Map myMap = Json5Map.ofString("{foo:'bar'}");
List myList = Json5List.ofString("['foo',123,null]");
Both pairs sit on top of a new neutral MarshalledMap / MarshalledList base introduced in v10.0; JsonMap / JsonList carry the strict RFC 8259 JSON flavor, and Json5Map / Json5List carry the JSON5 flavor used in the examples above.
These classes provide lots of convenience methods including:
- Methods for direct marshalling to/from any of the other supported languages.
- Methods for quick conversions to other data types including collections, beans, arrays, etc...
- JsonMap and JsonList for more information.
Serializer and Parser Sets
SerializerSet and 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)
.forEachWS(x -> x.useWhitespace())
.build();
// Find the appropriate serializer by Accept type and serialize our POJO to the specified writer.
// Fully RFC2616 compliant. The lookup returns an Optional - a missing match on the
// Accept header maps to HTTP 406 (Not Acceptable).
serializerSet
.getSerializer("text/invalid, text/json;q=0.8, text/*;q:0.6, *\/*;q=0.0")
.orElseThrow(NotAcceptable::new) // HTTP 406 - no serializer matched the Accept header
.write(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);
.build();
// The lookup returns an Optional - a missing match on the Content-Type maps to
// HTTP 415 (Unsupported Media Type).
Person person = parserSet
.getParser("text/json")
.orElseThrow(UnsupportedMediaType::new) // HTTP 415 - no parser matched the Content-Type
.read(myReader, Person.class);
- SerializerSets and ParserSets for more information.
SVL Variables
Juneau includes built-in support for Simple Variable Language (SVL) — a text-template engine that resolves variables of
the form $varName{varKey} against sources such as system properties, environment variables, config files, and more.
SVL is used widely throughout Juneau annotations and configuration settings.
See Simple Variable Language for the built-in variable reference,
#{...} function-call syntax, compiled-template API, and more.
In This Section
🗃️ Core Concepts
12 items
🗃️ Customization and Advanced Types
12 items
🗃️ Data Formats
22 items
🗃️ Streaming
2 items
📄️ 2.2.49. Best Practices
The following guidelines help you get the most out of the Juneau marshalling APIs in terms of