{8.2.0-updated} OpenAPI Serializers

The {@link oaj.oapi.OpenApiSerializer} class is used to convert POJOs to HTTP parts.

Later we'll describe how to use HTTP-Part annotations to define OpenAPI schemas for serialization and parsing of HTTP parts. The following example is a preview showing an HTTP body defined as pipe-delimited list of comma-delimited numbers (e.g. "1,2,3|4,5,6|7,8,9"):

@RestMethod(method="POST", path="/2dLongArray") public void post2dLongArray( @Body( schema=@Schema( type="array", collectionFormat="pipes", items=@Items( type="array", collectionFormat="csv", items=@SubItems( type="integer", format="int64", minimum="0", maximum="100" minLength=1, maxLength=10 ) ) minLength=1, maxLength=10 ) ) Long[][] body ) {...} // Alternate shortened format. @RestMethod(method="POST", path="/2dLongArray") public void post2dLongArray( @Body( schema=@Schema( t="array", cf="pipes", i=@Items( t="array", cf="csv", i=@SubItems( t="integer", f="int64", min="0", max="100" minl=1, maxl=10 ) ) minl=1, maxl=10 ) ) Long[][] body ) {...}

Under-the-covers, this gets converted to the following schema object:

HttpPartSchema schema = HttpPartSchema.create() .items( HttpPartSchema.create() .type("array") .collectionFormat("pipes") .items( HttpPartSchema.create() .type("array") .collectionFormat("csv") .items( HttpPartSchema.create() .type("integer") .format("int64") .minimum(0) .maximum(100) .minLength(1) .maxLength(10) ) ) ) .build();

Various convenience methods exist for shortening this code.

HttpPartSchema schema = HttpPartSchema.tArrayPipes( tArrayCsv( tInt64().minimum(0).maximum(100).minLength(1).maxLength(10) ) ).build();

The following code shows how the schema above can be used to create our pipe+csv list of numbers:

// Our POJO being serialized. Long[][] input = .... // The serializer to use. HttpPartSerializer serializer = OpenApiSerializer.DEFAULT; // Convert POJO to a string. try { String httpPart = serializer.serialize(schema, input); } catch (SchemaValidationException e) { // Oops, one of the restrictions were not met. }

As a general rule, any POJO convertible to the intermediate type for the type/format of the schema can be serialized using the OpenAPI serializer. Here are the rules of POJO types allowed for various type/format combinations:

Type | Format | Valid parameter types
--- | --- | ---
string or empty | byte binary binary-spaced | byte[] (default) {@link java.io.InputStream} {@link java.io.Reader} - Read into String and then converted using {@link java.lang.String#getBytes()}. {@link java.lang.Object} - Converted to String and then converted using {@link java.lang.String#getBytes()}. Any POJO transformable to a byte[] via the following methods: public byte[] toBytes() {...} public byte[] toFoo() {...} (any method name starting with "to") Any POJO transformable to a byte[] via a {@link oaj.transform.PojoSwap}.
date date-time | {@link java.util.Calendar} (default) {@link java.util.Date} Any POJO transformable to a {@link java.util.Calendar} via the following methods: public Calendar toCalendar() {...} public Calendar toFoo() {...} (any method name starting with "to") Any POJO transformable to a {@link java.util.Calendar} via a {@link oaj.transform.PojoSwap}.
uon | Any {@doc PojoCategories Serializable POJO} type.
empty | {@link java.lang.String} (default) Any POJO transformable to a {@link java.lang.String} via the following methods: public String toString() {...} Any POJO transformable to a {@link java.lang.String} via a {@link oaj.transform.PojoSwap}.
boolean | empty | {@link java.lang.Boolean} (default) boolean {@link java.lang.String} - Converted to a {@link java.lang.Boolean}. Any POJO transformable to a {@link java.lang.Boolean} via the following methods: public Boolean toBoolean() {...} public Boolean toFoo() {...} (any method name starting with "to") Any POJO transformable to a {@link java.lang.Boolean} via a {@link oaj.transform.PojoSwap}.
integer | int32 | {@link java.lang.Integer} (default) int {@link java.lang.String} - Converted to an {@link java.lang.String}. Any POJO transformable to an {@link java.lang.Integer} via the following methods: public Integer toInteger() {...} public Integer toFoo() {...} (any method name starting with "to") Any POJO transformable to an {@link java.lang.Integer} via a {@link oaj.transform.PojoSwap}.
int64 | {@link java.lang.Long} (default) long {@link java.lang.String} - Converted to a {@link java.lang.Long}. Any POJO transformable to a {@link java.lang.Long} via the following methods: public Long toLong() {...} public Long toFoo() {...} (any method name starting with "to") Any POJO transformable to a {@link java.lang.Long} via a {@link oaj.transform.PojoSwap}.
number | float | {@link java.lang.Float} (default) float {@link java.lang.String} - Converted to a {@link java.lang.Float}. Any POJO transformable to a {@link java.lang.Float} via the following methods: public Float toFloat() {...} public Float toFoo() {...} (any method name starting with "to") Any POJO transformable to a {@link java.lang.Float} via a {@link oaj.transform.PojoSwap}.
double | {@link java.lang.Double} (default) double {@link java.lang.String} - Converted to a {@link java.lang.Double}. Any POJO transformable to a {@link java.lang.Double} via the following methods: public Double toDouble() {...} public Double toFoo() {...} (any method name starting with "to") Any POJO transformable to a {@link java.lang.Double} via a {@link oaj.transform.PojoSwap}.
array | empty | Arrays or Collections of any defaults on this list. Any POJO transformable to arrays of the default types (e.g. Integer[], Boolean[][], etc...). For example: public Boolean[][] toFoo() {...} (any method name starting with "to") Any POJO transformable to arrays of the default types via a {@link oaj.transform.PojoSwap}
uon | Any {@doc PojoCategories Serializable POJO} type.
object | empty | Map<String,Object> (default) Beans with properties of anything on this list. Any POJO transformable to a map via a {@link oaj.transform.PojoSwap}
uon | Any {@doc PojoCategories Serializable POJO} type.

For arrays, an example of "Any POJO transformable to arrays of the default types" is:

// Sample POJO class convertable to a Long[][]. public class MyPojo { // toX method used by serializer. public Long[][] to2dLongs() {...} }

In the example above, our POJO class can be used to create our pipe-delimited list of comma-delimited numbers:

// Our POJO being serialized. MyPojo input = .... // The serializer to use. HttpPartSerializer serializer = OpenApiSerializer.DEFAULT; // Convert POJO to a string. try { String httpPart = serializer.serialize(schema, input); } catch (SchemaValidationException e) { // Oops, one of the restrictions were not met. }

The object type is not officially part of the OpenAPI standard. However, Juneau supports serializing Maps and beans to HTTP parts using UON notation.

The following shows an example of a bean with several properties of various types.

public class MyBean { private static byte[] FOOB = "foo".getBytes(); public String f1 = "foo"; public byte[] f2 = FOOB; public byte[] f3 = FOOB; public byte[] f4 = FOOB; public Calendar f5 = parseIsoCalendar("2012-12-21T12:34:56Z"); public String f6 = "foo"; public int f7 = 1; public Long f8 = 2l; public float f9 = 1.0; public Double f10 = 1.0; public Boolean f11 = true; public Object fExtra = "1"; }

We define the following schema:

import static org.apache.juneau.httppart.HttpPartSchema.*; HttpPartSchema schema = tObject() .prop("f1", tString()) .prop("f2", tByte()) .prop("f3", tBinary()) .prop("f4", tBinarySpaced()) .prop("f5", tDateTime(>)) .prop("f6", tUon()) .prop("f7", tInteger()) .prop("f8", tInt64()) .prop("f9", tNumber()) .prop("f10", tDouble()) .prop("f11", tBoolean()) .ap(tInteger()) .build();

Then we serialize our bean:

HttpPartSerializer serializer = OpenApiSerializer.DEFAULT; String httpPart = serializer.serialize(schema, new MyBean());

The results of this serialization is shown below:

( f1=foo, f2=Zm9v, f3=666F6F, f4='66 6F 6F', f5=2012-12-21T12:34:56Z, f6=foo, f7=1, f8=2, f9=1.0, f10=1.0, f11=true, fExtra=1 )

The following is an example of a bean with various array property types:

public class MyBean { private static byte[] FOOB = "foo".getBytes(); public String[] f1 = {"a,b",null}, public byte[][] f2 = new byte[][]{FOOB,null}, public byte[][] f3 = new byte[][]{FOOB,null}, public byte[][] f4 = new byte[][]{FOOB,null}, public Calendar[] f5 = new Calendar[]{parseIsoCalendar("2012-12-21T12:34:56Z"),null}, public String[] f6 = {"a","b",null}, public int[] f7 = new int[]{1,2,null}, public Integer[] f8 = new Integer[]{3,4,null}, public float[] f9 = new float[]{1f,2f,null}, public Float[] f10 = new Float[]{3f,4f,null}, public Boolean[] f11 = new Boolean[]{true,false,null}, public Object[] fExtra = new Object[]{1,"2",null}; }

For this bean, we define the following schema:

import static org.apache.juneau.httppart.HttpPartSchema.*; HttpPartSchema schema = tObject() .prop("f1", tArray(tString())) .prop("f2", tArray(tByte())) .prop("f3", tArray(tBinary())) .prop("f4", tArray(tBinarySpaced())) .prop("f5", tArray(tDateTime())) .prop("f6", tArray(tUon())) .prop("f7", tArray(tInteger())) .prop("f8", tArray(tInt64())) .prop("f9", tArray(tNumber())) .prop("f10", tArray(tDouble())) .prop("f11", tArray(tBoolean())) .ap(tArray(tInteger())) .build();

Serializing this bean produces the following output:

( f1=@('a,b',null), f2=@(Zm9v,null), f4=@(2012-12-21T12:34:56Z,null), f5=@(666F6F,null), f6=@('66 6F 6F',null), f7=@(a,b,null), f8=@(1,2,null), f9=@(3,4,null), f10=@(1.0,2.0,null), f11=@(3.0,4.0,null), f12=@(true,false,null), fExtra=@(1,2,null) )

- Array properties can also use CSV/SSV/PIPES for array notation.
  Various notations can be mixed throughout.
- Schemas and POJOs can be defined arbitrarily deep.
- Schemas are optional. They can be skipped or partially defined.
- We make our best attempt to convert the input to the matching type. However, you will get SerializeExceptions if you attempt an impossible conversion. (e.g. trying to serialize the string "foo" as a boolean).