OpenAPI Parsers

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

The following is the previous example of a schema that defines the format of a pipe-delimited list of comma-delimited numbers (e.g. "1,2,3|4,5,6|7,8,9"):

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 parse our input into a POJO:

// Our input being parsed. String input = "1,2,3|4,5,6|7,8,9" // The parser to use. HttpPartParser p = OpenApiParser.DEFAULT; // Convert string to a POJO. try { Long[][] pojo = p.parse(schema, input, Long[][].class); } catch (SchemaValidationException e) { // Oops, one of the restrictions were not met. }

As a general rule, any POJO convertible from the intermediate type for the `type/format` of the schema can be parsed using the OpenAPI parser.
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} - Returns a {@link java.io.ByteArrayInputStream}. {@link java.io.Reader} - Returns a {@link java.io.InputStreamReader} wrapped around a {@link java.io.ByteArrayInputStream}. {@link java.lang.String} - Constructed using {@link java.lang.String#String(byte[])}. {@link java.lang.Object} - Returns the default `byte[]`. Any POJO transformable from a `byte[]` (via constructors or static create methods).
`date date-time` | {@link java.util.Calendar} (default) {@link java.util.Date} {@link java.util.GregorianCalendar} {@link java.lang.String} - Converted using {@link java.util.Calendar#toString()}. {@link java.lang.Object} - Returns the default {@link java.util.Calendar}. Any POJO transformable from a {@link java.util.Calendar} (via constructors or static create methods).
`uon` | Any {@doc PojoCategories Parsable POJO} type.
empty | {@link java.lang.String} (default) {@link java.lang.Object} - Returns the default {@link java.lang.String}. Any POJO transformable from a {@link java.lang.String} (via constructors, static create methods, or swaps).
`boolean` | empty | {@link java.lang.Boolean} (default) boolean {@link java.lang.String} {@link java.lang.Object} - Returns the default {@link java.lang.Boolean}. Any POJO transformable from a {@link java.lang.Boolean} (via constructors, static create methods, or swaps).
`integer` | `int32` | {@link java.lang.Integer} (default) Any subclass of {@link java.lang.Number} Any primitive number: (e.g int, float...) {@link java.lang.String} {@link java.lang.Object} - Returns the default {@link java.lang.Integer}. Any POJO transformable from an {@link java.lang.Integer} (via constructors, static create methods, or swaps).
`int64` | {@link java.lang.Long} (default) Any subclass of {@link java.lang.Number} Any primitive number: (e.g int, float...) {@link java.lang.String} {@link java.lang.Object} - Returns the default {@link java.lang.Long}. Any POJO transformable from an {@link java.lang.Long} (via constructors, static create methods, or swaps).
`number` | `float` | {@link java.lang.Float} (default) Any subclass of {@link java.lang.Number} Any primitive number: (e.g int, float...) {@link java.lang.String} {@link java.lang.Object} - Returns the default {@link java.lang.Float}. Any POJO transformable from an {@link java.lang.Float} (via constructors, static create methods, or swaps).
`double` | {@link java.lang.Double} (default) Any subclass of {@link java.lang.Number} Any primitive number: (e.g int, float...) {@link java.lang.String} {@link java.lang.Object} - Returns the default {@link java.lang.Double}. Any POJO transformable from an {@link java.lang.Double} (via constructors, static create methods, or swaps).
`array` | empty | Arrays or Collections of anything on this list. Any POJO transformable from arrays of the default types (e.g. `Integer[]`, `Boolean[][]`, etc...).
`uon` | Any {@doc PojoCategories Parsable POJO} type.
`object` | empty | `Map<String,Object>` (default) Beans with properties of anything on this list. Maps with string keys.
`uon` | Any {@doc PojoCategories Parsable POJO} type.

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

// Sample POJO class convertable from a Long[][]. public class MyPojo { // Constructor used by parser. public MyPojo(Long[][] from2dLongs) {...} }

In the example above, our POJO class can be constructed from our pipe-delimited list of comma-delimited numbers:

// Our input being parsed. String input = "1,2,3|4,5,6|7,8,9" // The parser to use. HttpPartParser p = OpenApiParser.DEFAULT; // Convert string to a POJO. try { MyPojo pojo = p.parse(schema, input, MyPojo.class); } catch (SchemaValidationException e) { // Oops, one of the restrictions were not met. }

Just like serialization, the `object` type is not officially part of the OpenAPI standard, but Juneau supports parsing HTTP parts in UON notation to Maps and beans.

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

public class MyBean { public String f1; public byte[] f2; public byte[] f3; public byte[] f4; public Calendar f5; public String f6; public int f7; public Long f8; public float f9; public Double f10; public Boolean f11; public Object fExtra; }

We define the following schema again:

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 parse our input into our POJO:

String input = "(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)"; HttpPartParser p = OpenApiParser.DEFAULT; MyBean b = p.parse(schema, input, MyBean.class);

Note that serializing into generic `Object` properties would have produced similar results:

public class MyBean { public Object f1; public Object f2; public Object f3; public Object f4; public Object f5; public Object f6; public Object f7; public Object f8; public Object f9; public Object f10; public Object f11; public Object fExtra; }

We can also parse into Maps as well:

String input = "(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)"; HttpPartParser p = OpenApiParser.DEFAULT; ObjectMap m = p.parse(schema, input, ObjectMap.class);

##### 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 output to the matching type. However, you will get `ParseExceptions` if you attempt an impossible conversion. (e.g. trying to parse the string "foo" into a boolean).