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.

Additionally, any of the type above can also be wrapped as {@link java.util.Optional Optionals}.

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

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