Skip to main content

POJO Categories

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:

General POJO serialization/parsing support​

TypeDescriptionCan
serialize?
Can
parse?
Java primitives and primitive objects
  • String
  • Integer
  • Float
  • Boolean
  • All primitive types and boxed equivalents

Standard Java primitive types (int, long, float, double, boolean, byte, short, char) and their boxed equivalents, plus String.

yesyes
Java Collections Framework objects, Java arrays, Java Optionals
  • HashSet<String,Integer>
  • TreeMap<Integer,Bean>
  • List<int[][]>
  • Bean[]
  • Optional<Bean>
  • OptionalInt
  • OptionalLong
  • OptionalDouble

With standard keys/values
Map keys are primitive/string, swapped, or bean types.
Map, Collection, Optional, and array values are primitive/string, collection, bean, or swapped types.
OptionalInt, OptionalLong, and OptionalDouble are treated as first-class optional primitive types and serialize/parse identically to Optional<Integer>, Optional<Long>, and Optional<Double> respectively.

yesyes
  • HashSet<Bean,Integer>
  • TreeMap<Integer,Reader>
  • Optional<Reader>

With non-standard keys/values
Map keys are collection, non-standard bean, raw-streamed, or otherwise non-string types.
Map, Collection, and array values are non-standard bean, raw-streamed, or toString-only types.

yesno
  • Iterator<String>
  • Stream<Bean>
  • Iterable<Integer>
  • Enumeration<String>

Streamable sequence types
Iterator, Iterable (non-Collection), Enumeration, and java.util.stream.Stream.
These are serialized directly as arrays. Elements are written lazily for text-based formats (JSON, XML, UON, URL Encoding, OpenAPI). MsgPack, HTML, and CSV may materialize to a list internally due to format constraints.
Parsing is not supported since these are inherently one-way consumption types.

yesno
  • Instant
  • ZonedDateTime
  • Calendar
  • Date
  • Duration
  • Period
  • XMLGregorianCalendar

Date/time and duration types
Calendar, Date, Temporal subtypes (Instant, ZonedDateTime, LocalDate, etc.), XMLGregorianCalendar, java.time.Duration, and java.time.Period.
These are serialized and parsed natively as ISO 8601 strings without requiring swaps. Swap classes remain available as override mechanisms for custom formats.

yesyes
Java Beans
Standard beans

Beans with one or more properties defined by public getters or public fields.
Properties can also be defined as final read-only fields and passed in as constructor args, or populated via a builder class (see Builder-based beans below).
Property values must be other standard, collection, or swapped types.

yesyes
Non-standard or partial beans

True beans that have one or more properties defined by getter and setter methods but whose property types include non-standard, raw-streamed, or toString-only values.
Also includes classes that look like beans but aren't: getters without setters, or classes without no-arg constructors and no recognized constructor-arg mapping.

yesno
Virtual beans

Unimplemented bean interfaces with properties of standard, collection, or swapped types.
Parsers automatically create interface proxies on top of BeanMap instances.

yesyes
Read-only beans

Beans with readable properties but no setters and no constructor-arg mapping. Equivalent to standard beans but parse-only via a swapped form is not recoverable.

yesno
Java Records

Java record classes (record Foo(String bar, int baz) {}). Record components are treated as bean properties. The canonical all-args constructor is used for parsing, so all record components are round-trip capable without any additional annotations.
The @BeanType, @BeanProp, @MarshalledIgnore, and @BeanCtor annotations are supported on record classes and their components.

yesyes
Builder-based beans

Classes that are constructed via a separate builder class. The framework auto-detects a builder when the object class has a public static create() method returning a builder (that implements the Builder interface), and the builder has a build() method returning the target type, or when the object class has a constructor that accepts a Builder-typed argument. The @Builder annotation can also explicitly name the builder class.
During parsing, the builder is instantiated, properties are populated on it, and build() is called to produce the final object.

yesyes
Swapped objects

Objects that are not directly serializable but have 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.
Note: As of 10.0.0, date/time types (Calendar, Date, Temporal subtypes, XMLGregorianCalendar, Duration, Period) are handled natively and no longer require swaps. Swap classes remain available as override mechanisms.

2-way swapped

Swapped to a primitive/string, standard collection, or standard bean form — reconstruction from the wire form is possible.

  • Custom user-defined swaps
yesyes
1-way swapped

Swapped to a simpler form where reconstruction from the wire form is not possible.
Note: As of 10.0.0, Iterator and Enumeration are handled natively and no longer require swaps.

yesno
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.

  • FileInputStream
  • StringReader
Raw Reader and InputStream objects. Contents are written directly; no structural wrapping.yesno
Non-serializable objects with standard methods for converting to a serializable form
2-way convertible

Classes with a method that converts it to a serializable form:

  • public X swap(MarshallingSession); where X is a primitive/string, standard collection, or standard bean.
  • public String toString(); where the string is any meaningful data.

And a method that converts it back:

  • public static T fromString(String);
  • public static T valueOf(String);
  • public static T parse(String);
  • public static T parseString(String);
  • public static T forName(String);
  • public static T forString(String);
  • public T(X); where X is a primitive/string, standard collection, or standard bean.
  • public static T unswap(MarshallingSession,X); where X is a primitive/string, standard collection, or standard bean.

Examples:

  • java.lang.Class
  • java.sql.Time
  • java.sql.Timestamp
  • java.text.MessageFormat
  • java.text.NumberFormat
  • java.util.UUID
  • java.util.logging.Level
  • javax.xml.bind.DatatypeConverter
yesyes
1-way convertible

Classes that only have a method to convert to a serializable form:

  • public X swap(MarshallingSession); where X is any collection or bean type.
  • public String toString(); where the string is any meaningful data.
yesno
All other objects

Anything that doesn't fall into one of the groups above is simply converted to Strings using the toString() method.

yesno
info

Serializers are designed to work on tree-shaped POJO models. These are models where there are no referential loops (e.g. leaves with references to nodes, or nodes in one branch referencing nodes in another branch). There is a serializer setting detectRecursions to look for and handle these kinds of loops (by setting these references to null) but it is not enabled by default since it introduces a moderate performance penalty.

POJOs convertible to/from Strings​

A separate category exists for POJOs that can be converted to and from Strings. These are used in places such as:

  • Serializing of POJOs to Strings in the REST client API when no serializers are registered.
  • Parsing of POJOs from Strings in the REST server API for text/plain requests where text/plain is not already mapped to an existing serializer.

As a general rule, all POJOs are converted to Strings using the toString() method. However, there is one exception:

TimeZone - Uses TimeZone.getID()

POJOs are convertible from Strings using any of the following (matched in the specified order):

  • Any of the following public static non-deprecated methods:
    • create(String)
    • fromString(String)
    • fromValue(String)
    • valueOf(String)
    • parse(String)
    • parseString(String)
    • forName(String)
    • forString(String)
  • Has a public constructor that takes in a String.

Exceptions exist for the following classes:

TimeZone - Uses TimeZone.getTimeZone(String)Locale - Uses Locale.forLanguageTag(String) after replacing _ with -.Boolean - Blank and "null" are interpreted as null values.Primitives (except for void.class) - Uses the primitive wrapper classes for instantiating from Strings.

POJOs convertible to/from other types​

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 X.

POJOs are considered convertible from X if it has any of the following (matched in the specified order):

  • Any any of the following public static non-deprecated methods:
    • create(X)
    • from*(X)
  • Has a public constructor that takes in an X.
  • The X class has a public non-static no-arg non-deprecated method called to*().

POJOs are considered convertible from X if any of the reverse of above are true.