dhis2 / json-tree

A lazily parsed JSON object tree library
BSD 3-Clause "New" or "Revised" License
4 stars 2 forks source link

feat: JSON to POJO mapping [DHIS2-13378] #12

Closed jbee closed 2 years ago

jbee commented 2 years ago

Summary

Adds a lazy version of "POJO mapping" to the library.

Sticking with the lazy "virtual" concept of the JSON tree the way JSON can be mapped to a Java representation is exploiting the already existing features of the virtual tree.

A JSON object graph can be mapped to its Java form by declaring a Java interface representation of it using common JDK types.

interface POJO extends JsonValue {
  int getAge();
  List<String> getNames();
  boolean isEager();
}

A suitable JSON document would look like this:

{
  "age": 42,
  "names": ["Ringo", "Star"],
  "eager": true
}

To "map" the JSON to Java one simply does:

POJO obj = JsonValue.of("...").as( POJO.class );

So far this is again just a view, a way of looking at the the underlying tree. First if a property is accessed it will be parsed and mapped individually. The POJO object is never really created as an independent object instance. Instead every time a property is accessed the value found in the JSON document is attempted to map to the Java type expected by the methods return type.

Type Support

This mapping on access is configured via the new JsonTypedAccessStore. The default implementation JsonTypedAccess comes with a wide support JDK types common for modelling data. This includes:

Further type accessors can be added by the user if needed. All types can be mixed without limitation. This includes mixing these types with the JsonValue tree types.

A new object type can either inherit from JsonValue or JsonObject depending on if the author wants their methods being inherited by the new POJO object.

Names

The getters can use prefixes get/is or not. The member name is the getter name without potential prefix starting with a lower case letter.

Undefined Values

The behaviour in case a value is not defined in the JSON document depends on the way it is accessed and is consistent with the behaviour of the JsonValue API (as it is used internally).

In essence this means

Any accessor method can get a default value parameter. This has to be of the same type as the return type of the method. If a value is undefined in the JSON document and a default parameter is provided the default is returned.

Automatic Testing

The mapping is tested fairly extensive in newly added test class.