POJO Categories

The following chart shows POJOs categorized into groups and whether they can be serialized or parsed:

##### General POJO serialization/parsing support

Group | Description | Examples | Can serialize? | Can parse?
--- | --- | --- | --- | ---
1 | Java primitives and primitive objects | {@code String} {@code Integer} {@code Float} {@code Boolean} | yes | yes
2 | Java Collections Framework objects and Java arrays |  |  |
2a | With standard keys/values Map keys are group [1, 4a, 6a] objects. Map, Collection, and array values are group [1, 2, 3ac, 4a, 6a] objects. | HashSet<String,Integer> TreeMap<Integer,Bean> List<int[][]> Bean[] | 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. | HashSet<Bean,Integer> TreeMap<Integer,Reader> | 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 oaj.transform.PojoSwap PojoSwaps} associated with them. The purpose of a POJO swap is to convert an object to another object that is easier to serialize and parse. For example, the {@link oaj.transforms.TemporalDateSwap.IsoLocalDateTime} class can be used to serialize {@link java.util.Date} objects to ISO8601 strings, and parse them back into {@link java.util.Date} objects. |  |  |
4a | 2-way swapped to group [1, 2a, 3ac] objects For example, a swap that converts a {@code Date} to a {@code String}. | java.util.Date java.util.GregorianCalendar | 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}. | java.util.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. | {@code FileInputStream} {@code StringReader} | 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: public X swap(BeanSession); where X is in groups [1, 2a, 3ac]. public String toString(); where the string is any meaningful data. And a method that converts it back into the original object: 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 in groups [1, 2a, 3ac]. public static T unswap(BeanSession,X); where X is in groups [1, 2a, 3ac]. | java.lang.Class java.sql.Time java.sql.Timestamp java.text.MessageFormat java.text.NumberFormat java.util.Date java.util.UUID java.util.logging.Level javax.xml.bind.DatatypeConverter | yes | yes
6b | Classes that only have a method to convert to a serializable form: public X swap(BeanSession); where X is in groups [1, 2, 3]. public String toString(); where the string is any meaningful data. |  | 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

Serializers are designed to work on tree-shaped POJO models. These are models where there are no referential loops (e.g. leaves with references to nodes, or nodes in one branch referencing nodes in another branch). There is a serializer setting {@code detectRecursions} to look for and handle these kinds of loops (by setting these references to 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:

- {@link java.util.TimeZone} - Uses {@link java.util.TimeZone#getID()}

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

- Any 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:

- {@link java.util.TimeZone} - Uses {@link java.util.TimeZone#getTimeZone(String)}
- {@link java.util.Locale} - Uses {@link java.util.Locale#forLanguageTag(String)} after replacing '_' with '-'.
- {@link java.lang.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.