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( items=@Items( collectionFormat="pipes", items=@SubItems( collectionFormat="csv", type="integer", format="int64", minimum="0", maximum="100" minLength=1, maxLength=10 ) ) minLength=1, maxLength=10 ) ) Long[][] body ) {...}

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

import static org.apache.juneau.httppart.HttpPartSchema.*; HttpPartSchema schema = create() .items( create() .collectionFormat("pipes") .items( create() .collectionFormat("csv") .type("integer") .format("int64") .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 s = OpenApiSerializer.DEFAULT; // Convert POJO to a string. try { String httpPart = s.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 s = OpenApiSerializer.DEFAULT; // Convert POJO to a string. try { String httpPart = s.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 ps = schema("object") .property("f1", schema("string")) .property("f2", schema("string", "byte")) .property("f3", schema("string", "binary")) .property("f4", schema("string", "binary-spaced")) .property("f5", schema("string", "date-time")) .property("f6", schema("string", "uon")) .property("f7", schema("integer")) .property("f8", schema("integer", "int64")) .property("f9", schema("number")) .property("f10", schema("number", "double")) .property("f11", schema("boolean")) .additionalProperties(schema("integer")) .build();

Then we serialize our bean:

HttpPartSerializer s = OpenApiSerializer.DEFAULT; String httpPart = s.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 = new String[]{"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 = new String[]{"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:

HttpPartSchema ps = schema("object") .property("f1", schema("array").items(schema("string"))) .property("f2", schema("array").items(schema("string", "byte"))) .property("f3", schema("array").items(schema("string", "binary"))) .property("f4", schema("array").items(schema("string", "binary-spaced"))) .property("f5", schema("array").items(schema("string", "date-time"))) .property("f6", schema("array").items(schema("string", "uon"))) .property("f7", schema("array").items(schema("integer"))) .property("f8", schema("array").items(schema("integer", "int64"))) .property("f9", schema("array").items(schema("number"))) .property("f10", schema("array").items(schema("number", "double"))) .property("f11", schema("array").items(schema("boolean"))) .additionalProperties(schema("array").items(schema("integer"))) .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) )

##### Other Notes:

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