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:

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