OpenAPI Serializers
The OpenApiSerializer class is used to convert POJOs to HTTP parts.
Class hierarchy
The class hierarchy for the builder of this serializer is:
Refer to the builder javadocs for configurable settings.
Defining a schema
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"):
@RestPost("/2dLongArray")
public void post2dLongArray(
@Content(
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.
@RestPost("/2dLongArray")
public void post2dLongArray(
@Content(
schema=@Schema(
t="array",
cf="pipes",
items=@Items(
t="array",
cf="csv",
items=@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)
)
)
)
.build();
Various convenience methods exist for shortening this code.
import static org.apache.juneau.marshall.httppart.HttpPartSchema.*;
HttpPartSchema schema = tArrayPipes(
tArrayCsv(
tInt64().minimum(0).maximum(100)
)
).build();
The following program uses the schema above to create our pipe+csv list of numbers:
import static org.apache.juneau.marshall.httppart.HttpPartSchema.*;
import org.apache.juneau.commons.httppart.*;
import org.apache.juneau.marshall.httppart.*;
import org.apache.juneau.marshall.oapi.*;
public class PipeCsvSerializeExample {
public static void main(String[] args) throws Exception {
HttpPartSchema schema = tArrayPipes(
tArrayCsv(
tInt64().min(0).max(100)
)
).build();
// Our POJO being serialized.
Long[][] input = { {1L, 2L, 3L}, {4L, 5L, 6L}, {7L, 8L, 9L} };
// Convert POJO to a string.
try {
String httpPart = OpenApiSerializer.DEFAULT.write(HttpPartType.QUERY, schema, input);
System.out.println(httpPart);
} catch (SchemaValidationException e) {
// Oops, one of the restrictions were not met.
System.out.println("rejected: " + e.getMessage());
}
}
}
The program prints 1,2,3|4,5,6|7,8,9.
Allowed POJO types
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 | bytebinarybinary-spaced | •
|
datedate-time | • Calendar (default)
| |
uon | • Any Serializable POJO type | |
| empty | • String (default)
| |
boolean | empty | • Boolean (default)
|
integer | int32 | • Integer (default)
|
int64 | • Long (default)
| |
number | float | • Float (default)
|
double | • Double (default)
| |
array | empty | • Arrays or |
uon | • Any Serializable POJO type | |
object | empty | • |
uon | • Any 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[][] toLongArrayArray() {...}
}
The method name must be to followed by the readable name of the target type (matched case-insensitively), which for Long[][] is toLongArrayArray.
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 = ....
// Convert POJO to a string.
try {
String httpPart = OpenApiSerializer.DEFAULT.write(HttpPartType.QUERY, schema, input);
} catch (SchemaValidationException e) {
// Oops, one of the restrictions were not met.
}
For a MyPojo whose toLongArrayArray() returns {{1,2},{3,4}} and a schema of tArrayPipes(tArrayCsv(tInt64())), the serialized output is:
1,2|3,4
Object types
The object type is not officially part of the OpenAPI standard.
However, Juneau supports serializing Maps and beans to HTTP parts as comma-delimited name=value pairs.
The following shows an example of a bean with several properties of various types.
import java.util.*;
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 = new GregorianCalendar(2012, Calendar.DECEMBER, 21, 12, 34, 56);
public String f6 = "foo";
public int f7 = 1;
public Long f8 = 2l;
public float f9 = 1.0f;
public Double f10 = 1.0;
public Boolean f11 = true;
public Object fExtra = "1";
}
We define the following schema:
import static org.apache.juneau.marshall.httppart.HttpPartSchema.*;
HttpPartSchema schema = tObject()
.p("f1", tString())
.p("f2", tByte())
.p("f3", tBinary())
.p("f4", tBinarySpaced())
.p("f5", tDateTime())
.p("f6", tUon())
.p("f7", tInteger())
.p("f8", tInt64())
.p("f9", tNumber())
.p("f10", tDouble())
.p("f11", tBoolean())
.ap(tInteger())
.build();
Then we serialize our bean. The complete program:
import static org.apache.juneau.marshall.httppart.HttpPartSchema.*;
import java.util.*;
import org.apache.juneau.commons.httppart.*;
import org.apache.juneau.marshall.httppart.*;
import org.apache.juneau.marshall.oapi.*;
public class MyBeanSerializeExample {
public static 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 = new GregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.US);
public String f6 = "foo";
public int f7 = 1;
public Long f8 = 2l;
public float f9 = 1.0f;
public Double f10 = 1.0;
public Boolean f11 = true;
public Object fExtra = "1";
public MyBean() {
f5.clear();
f5.set(2012, Calendar.DECEMBER, 21, 12, 34, 56);
}
}
public static void main(String[] args) throws Exception {
HttpPartSchema schema = tObject()
.p("f1", tString())
.p("f2", tByte())
.p("f3", tBinary())
.p("f4", tBinarySpaced())
.p("f5", tDateTime())
.p("f6", tUon())
.p("f7", tInteger())
.p("f8", tInt64())
.p("f9", tNumber())
.p("f10", tDouble())
.p("f11", tBoolean())
.ap(tInteger())
.build();
String httpPart = OpenApiSerializer.DEFAULT.write(HttpPartType.QUERY, schema, new MyBean());
System.out.println(httpPart);
}
}
The results of this serialization is shown below. Properties are written in alphabetical order:
f1=foo,f10=1.0,f11=true,f2=Zm9v,f3=666F6F,f4=66 6F 6F,f5=2012-12-21T12:34:56Z,f6=foo,f7=1,f8=2,f9=1.0,fExtra=1
Beans with array properties
The following is an example of a bean with various array property types:
import java.util.*;
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[]{new GregorianCalendar(2012, Calendar.DECEMBER, 21, 12, 34, 56),null};
public String[] f6 = {"a","b",null};
public Integer[] f7 = new Integer[]{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.marshall.httppart.HttpPartSchema.*;
HttpPartSchema schema = tObject()
.p("f1", tArray(tString()))
.p("f2", tArray(tByte()))
.p("f3", tArray(tBinary()))
.p("f4", tArray(tBinarySpaced()))
.p("f5", tArray(tDateTime()))
.p("f6", tArray(tUon()))
.p("f7", tArray(tInteger()))
.p("f8", tArray(tInt64()))
.p("f9", tArray(tNumber()))
.p("f10", tArray(tDouble()))
.p("f11", tArray(tBoolean()))
.ap(tArray(tInteger()))
.build();
The following program serializes this bean. Items within an array property are comma-delimited, and the commas
are escaped by a backslash so they survive inside the enclosing name=value list:
import static org.apache.juneau.marshall.httppart.HttpPartSchema.*;
import java.util.*;
import org.apache.juneau.commons.httppart.*;
import org.apache.juneau.marshall.httppart.*;
import org.apache.juneau.marshall.oapi.*;
public class MyArrayBeanSerializeExample {
public static class MyBean {
private static byte[] FOOB = "foo".getBytes();
private static Calendar utc(int y, int m, int d, int h, int mi, int sec) {
var c = new GregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.US);
c.clear();
c.set(y, m, d, h, mi, sec);
return c;
}
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[]{utc(2012, Calendar.DECEMBER, 21, 12, 34, 56),null};
public String[] f6 = {"a","b",null};
public Integer[] f7 = new Integer[]{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};
}
public static void main(String[] args) throws Exception {
HttpPartSchema schema = tObject()
.p("f1", tArray(tString()))
.p("f2", tArray(tByte()))
.p("f3", tArray(tBinary()))
.p("f4", tArray(tBinarySpaced()))
.p("f5", tArray(tDateTime()))
.p("f6", tArray(tUon()))
.p("f7", tArray(tInteger()))
.p("f8", tArray(tInt64()))
.p("f9", tArray(tNumber()))
.p("f10", tArray(tDouble()))
.p("f11", tArray(tBoolean()))
.ap(tArray(tInteger()))
.build();
System.out.println(OpenApiSerializer.DEFAULT.write(HttpPartType.QUERY, schema, new MyBean()));
}
}
The output is:
f1=a\\\,b\,null,f10=3.0\,4.0\,null,f11=true\,false\,null,f2=Zm9v\,null,f3=666F6F\,null,f4=66 6F 6F\,null,f5=2012-12-21T12:34:56Z\,null,f6=a\,b\,null,f7=1\,2\,null,f8=3\,4\,null,f9=1.0\,2.0\,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).