Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.muserver.openapi.SchemaObjectBuilder Maven / Gradle / Ivy
package io.muserver.openapi;
import io.muserver.UploadedFile;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.time.Instant;
import java.time.LocalDate;
import java.time.temporal.Temporal;
import java.util.*;
import java.util.regex.Pattern;
import static io.muserver.openapi.OpenApiUtils.immutable;
import static java.util.Arrays.asList;
/**
* The Schema Object allows the definition of input and output data types. These types can be objects, but also
* primitives and arrays. This object is an extended subset of the JSON Schema
* Specification Wright Draft 00 .
* For more information about the properties, see JSON
* Schema Core and JSON Schema Validation .
* Unless stated otherwise, the property definitions follow the JSON Schema.
*/
public class SchemaObjectBuilder {
private String title;
private Double multipleOf;
private Double maximum;
private Boolean exclusiveMaximum;
private Double minimum;
private Boolean exclusiveMinimum;
private Integer maxLength;
private Integer minLength;
private Pattern pattern;
private Integer maxItems;
private Integer minItems;
private Boolean uniqueItems;
private Integer maxProperties;
private Integer minProperties;
private List required;
private List enumValue;
private String type;
private List allOf;
private List oneOf;
private List anyOf;
private List not;
private SchemaObject items;
private Map properties;
private Object additionalProperties;
private String description;
private String format;
private Object defaultValue;
private Boolean nullable;
private DiscriminatorObject discriminator;
private Boolean readOnly;
private Boolean writeOnly;
private XmlObject xml;
private ExternalDocumentationObject externalDocs;
private Object example;
private Boolean deprecated;
/**
* @return the value set by {@link #withTitle}
*/
public String title() {
return title;
}
/**
* @return the value set by {@link #withMultipleOf}
*/
public Double multipleOf() {
return multipleOf;
}
/**
* @return the value set by {@link #withMaximum}
*/
public Double maximum() {
return maximum;
}
/**
* @return the value set by {@link #withExclusiveMaximum}
*/
public Boolean exclusiveMaximum() {
return exclusiveMaximum;
}
/**
* @return the value set by {@link #withMinimum}
*/
public Double minimum() {
return minimum;
}
/**
* @return the value set by {@link #withExclusiveMinimum}
*/
public Boolean exclusiveMinimum() {
return exclusiveMinimum;
}
/**
* @return the value set by {@link #withMaxLength}
*/
public Integer maxLength() {
return maxLength;
}
/**
* @return the value set by {@link #withMinLength}
*/
public Integer minLength() {
return minLength;
}
/**
* @return the value set by {@link #withPattern}
*/
public Pattern pattern() {
return pattern;
}
/**
* @return the value set by {@link #withMaxItems}
*/
public Integer maxItems() {
return maxItems;
}
/**
* @return the value set by {@link #withMinItems}
*/
public Integer minItems() {
return minItems;
}
/**
* @return the value set by {@link #withUniqueItems}
*/
public Boolean uniqueItems() {
return uniqueItems;
}
/**
* @return the value set by {@link #withMaxProperties}
*/
public Integer maxProperties() {
return maxProperties;
}
/**
* @return the value set by {@link #withMinProperties}
*/
public Integer minProperties() {
return minProperties;
}
/**
* @return the value set by {@link #withRequired}
*/
public List required() {
return required;
}
/**
* @return the value set by {@link #withEnumValue}
*/
public List enumValue() {
return enumValue;
}
/**
* @return the value set by {@link #withType}
*/
public String type() {
return type;
}
/**
* @return the value set by {@link #withAllOf}
*/
public List allOf() {
return allOf;
}
/**
* @return the value set by {@link #withOneOf}
*/
public List oneOf() {
return oneOf;
}
/**
* @return the value set by {@link #withAnyOf}
*/
public List anyOf() {
return anyOf;
}
/**
* @return the value set by {@link #withNot}
*/
public List not() {
return not;
}
/**
* @return the value set by {@link #withItems}
*/
public SchemaObject items() {
return items;
}
/**
* @return the value set by {@link #withProperties}
*/
public Map properties() {
return properties;
}
/**
* @return the value set by {@link #withAdditionalProperties}
*/
public Object additionalProperties() {
return additionalProperties;
}
/**
* @return the value set by {@link #withDescription}
*/
public String description() {
return description;
}
/**
* @return the value set by {@link #withFormat}
*/
public String format() {
return format;
}
/**
* @return the value set by {@link #withDefaultValue}
*/
public Object defaultValue() {
return defaultValue;
}
/**
* @return the value set by {@link #withNullable}
*/
public Boolean nullable() {
return nullable;
}
/**
* @return the value set by {@link #withDiscriminator}
*/
public DiscriminatorObject discriminator() {
return discriminator;
}
/**
* @return the value set by {@link #withReadOnly}
*/
public Boolean readOnly() {
return readOnly;
}
/**
* @return the value set by {@link #withWriteOnly}
*/
public Boolean writeOnly() {
return writeOnly;
}
/**
* @return the value set by {@link #withXml}
*/
public XmlObject xml() {
return xml;
}
/**
* @return the value set by {@link #withExternalDocs}
*/
public ExternalDocumentationObject externalDocs() {
return externalDocs;
}
/**
* @return the value set by {@link #withExample}
*/
public Object example() {
return example;
}
/**
* @return the value set by {@link #withDeprecated}
*/
public Boolean deprecated() {
return deprecated;
}
/**
* @param title the name of this object type
* @return this builder
*/
public SchemaObjectBuilder withTitle(String title) {
this.title = title;
return this;
}
/**
* Restricts numeric values to be a multiple of the given value
* @param multipleOf the multiple
* @return this builder
*/
public SchemaObjectBuilder withMultipleOf(Double multipleOf) {
this.multipleOf = multipleOf;
return this;
}
/**
* @param maximum The maximum allowed value for numeric values
* @return this builder
* @see #withExclusiveMaximum(Boolean)
*/
public SchemaObjectBuilder withMaximum(Double maximum) {
this.maximum = maximum;
return this;
}
/**
* @param exclusiveMaximum true
if the value specified with {@link #withMaximum(Double)} is exclusive;
* otherwise the default false
means it is an inclusive number.
* @return this builder
* @see #withMaximum(Double)
*/
public SchemaObjectBuilder withExclusiveMaximum(Boolean exclusiveMaximum) {
this.exclusiveMaximum = exclusiveMaximum;
return this;
}
/**
* @param minimum The minimum allowed value for numeric values
* @return this builder
* @see #withExclusiveMinimum(Boolean)
*/
public SchemaObjectBuilder withMinimum(Double minimum) {
this.minimum = minimum;
return this;
}
/**
* @param exclusiveMinimum true
if the value specified with {@link #withMinimum(Double)} is exclusive;
* otherwise the default false
means it is an inclusive number.
* @return this builder
* @see #withMinimum(Double)
*/
public SchemaObjectBuilder withExclusiveMinimum(Boolean exclusiveMinimum) {
this.exclusiveMinimum = exclusiveMinimum;
return this;
}
/**
* @param maxLength the maximum allowed length of string values
* @return this builder
*/
public SchemaObjectBuilder withMaxLength(Integer maxLength) {
this.maxLength = maxLength;
return this;
}
/**
* @param minLength the minimum allowed length of string values
* @return this builder
*/
public SchemaObjectBuilder withMinLength(Integer minLength) {
this.minLength = minLength;
return this;
}
/**
* @param pattern a regular expression that string values must match against
* @return this builder
*/
public SchemaObjectBuilder withPattern(Pattern pattern) {
this.pattern = pattern;
return this;
}
/**
* @param maxItems the maximum number of items allowed in an array value
* @return this builder
*/
public SchemaObjectBuilder withMaxItems(Integer maxItems) {
this.maxItems = maxItems;
return this;
}
/**
* @param minItems the minimum number of items allowed in an array value
* @return this builder
*/
public SchemaObjectBuilder withMinItems(Integer minItems) {
this.minItems = minItems;
return this;
}
/**
* @param uniqueItems if true, then all items in an array value must be unique
* @return this builder
*/
public SchemaObjectBuilder withUniqueItems(Boolean uniqueItems) {
this.uniqueItems = uniqueItems;
return this;
}
/**
* @param maxProperties the maximum number of properties allowed for an "object" type.
* @return this builder
*/
public SchemaObjectBuilder withMaxProperties(Integer maxProperties) {
this.maxProperties = maxProperties;
return this;
}
/**
* @param minProperties the minimum number of properties allowed for an "object" type.
* @return this builder
*/
public SchemaObjectBuilder withMinProperties(Integer minProperties) {
this.minProperties = minProperties;
return this;
}
/**
* @param required the list of properties that are required to have a value for an "object" type.
* @return this builder
*/
public SchemaObjectBuilder withRequired(List required) {
this.required = required;
return this;
}
/**
* @param enumValue the allowed values for an "enum" type
* @return this builder
*/
public SchemaObjectBuilder withEnumValue(List enumValue) {
this.enumValue = enumValue;
return this;
}
/**
* @param type the type of this schema object. One of string
, number
, integer
, boolean
, array
or object
* @return this builder
*/
public SchemaObjectBuilder withType(String type) {
this.type = type;
return this;
}
/**
* @param allOf the schemas that the value must match
* @return this builder
*/
public SchemaObjectBuilder withAllOf(List allOf) {
this.allOf = allOf;
return this;
}
/**
* Forces a value to be one of several different schemas
* @param oneOf the schemas the validate against
* @return this builder
* @see #withAnyOf(List)
*/
public SchemaObjectBuilder withOneOf(List oneOf) {
this.oneOf = oneOf;
return this;
}
/**
* Forces a value to be any of a number of different schemas
* @param anyOf the schemas the validate against
* @return this builder
* @see #withOneOf(List)
*/
public SchemaObjectBuilder withAnyOf(List anyOf) {
this.anyOf = anyOf;
return this;
}
/**
* @param not schemas the value must not validate against
* @return this builder
*/
public SchemaObjectBuilder withNot(List not) {
this.not = not;
return this;
}
/**
* @param items the schema that items in an array object must validate against
* @return this builder
*/
public SchemaObjectBuilder withItems(SchemaObject items) {
this.items = items;
return this;
}
/**
* @param properties the schema objects of each property for an object
type
* @return this builder
*/
public SchemaObjectBuilder withProperties(Map properties) {
this.properties = properties;
return this;
}
/**
* Defines how properties not covered by {@link #withProperties(Map)} are handled when the
* type is object
* @param additionalProperties If false
then extra properties are not allowed.
* If it is a schema object then any extra properties must validate
* against this schema.
* @return this builder
*/
public SchemaObjectBuilder withAdditionalProperties(Object additionalProperties) {
this.additionalProperties = additionalProperties;
return this;
}
/**
* @param description a description of this type
* @return this builder
* @see #withTitle(String)
*/
public SchemaObjectBuilder withDescription(String description) {
this.description = description;
return this;
}
/**
* This is used to further specify the format of string
types.
*
* Example type/format combos
*
*
* Type
* Format
* Description
*
*
*
*
* number
*
* Any numbers.
*
*
* number
* float
* Floating-point numbers.
*
*
* number
* double
* Floating-point numbers with double precision.
*
*
* integer
*
* Integer numbers.
*
*
* integer
* in32
* Signed 32-bit integers (commonly used integer type).
*
*
* integer
* int64
* Signed 64-bit integers (long type).
*
*
* string
* date
* full-date notation as defined by RFC 3339, section 5.6, for example, 2021-02-12
*
*
* string
* date-time
* the date-time notation as defined by RFC 3339, section 5.6, for example, 2021-02-12T15:33:28Z
*
*
* string
* password
* a hint to UIs to mask the input
*
*
* string
* byte
* base64-encoded characters, for example, U3dhZ2dlciByb2Nrcw==
*
*
* string
* binary
* binary data, used to describe files (not text)
*
*
* string
* email
* email addresses
*
*
* string
* uuid
* UUIDs such as 93d35de9-0083-4765-8b60-822258e8ffad
*
*
* string
* uri
* URIs, for example https://muserver.io/
*
*
* string
* hostname
* A server hostname
*
*
* string
* ipv4
* An IP4 address
*
*
* string
* ipv6
* An IP6 address
*
*
*
* Custom formats may be specified too.
* @param format the format of the type specified by {@link #withType(String)}
* @return this builder
*/
public SchemaObjectBuilder withFormat(String format) {
this.format = format;
return this;
}
/**
* @param defaultValue The default value to use when none is specified
* @return this builder
*/
public SchemaObjectBuilder withDefaultValue(Object defaultValue) {
this.defaultValue = defaultValue;
return this;
}
/**
* @param nullable A true
value adds "null"
to the allowed type specified by the
* type
keyword, only if type
is explicitly defined within the same Schema
* Object. Other Schema Object constraints retain their defined behavior, and therefore may disallow
* the use of null
as a value. A false
value leaves the specified or default
* type
unmodified. The default value is false
.
* @return The current builder
*/
public SchemaObjectBuilder withNullable(Boolean nullable) {
this.nullable = nullable;
return this;
}
/**
* @param discriminator Adds support for polymorphism. The discriminator is an object name that is used to differentiate between other schemas which may satisfy the payload description.
* @return The current builder
*/
public SchemaObjectBuilder withDiscriminator(DiscriminatorObject discriminator) {
this.discriminator = discriminator;
return this;
}
/**
* @param readOnly Relevant only for Schema "properties"
definitions. Declares the property as "read only".
* This means that it MAY be sent as part of a response but SHOULD NOT be sent as part of the request.
* If the property is marked as readOnly
being true
and is in the required
* list, the required
will take effect on the response only. A property MUST NOT be marked
* as both readOnly
and writeOnly
being true
. Default value is false
.
* @return The current builder
*/
public SchemaObjectBuilder withReadOnly(Boolean readOnly) {
this.readOnly = readOnly;
return this;
}
/**
* @param writeOnly Relevant only for Schema "properties"
definitions. Declares the property as "write only".
* Therefore, it MAY be sent as part of a request but SHOULD NOT be sent as part of the response. If
* the property is marked as writeOnly
being true
and is in the
* required
list, the required
will take effect on the request only. A property
* MUST NOT be marked as both readOnly
and writeOnly
being true
.
* Default value is false
.
* @return The current builder
*/
public SchemaObjectBuilder withWriteOnly(Boolean writeOnly) {
this.writeOnly = writeOnly;
return this;
}
/**
* @param xml This MAY be used only on properties schemas. It has no effect on root schemas. Adds additional metadata
* to describe the XML representation of this property.
* @return The current builder
*/
public SchemaObjectBuilder withXml(XmlObject xml) {
this.xml = xml;
return this;
}
/**
* @param externalDocs Additional external documentation for this schema.
* @return The current builder
*/
public SchemaObjectBuilder withExternalDocs(ExternalDocumentationObject externalDocs) {
this.externalDocs = externalDocs;
return this;
}
/**
* @param example A free-form property to include an example of an instance for this schema. To represent examples
* that cannot be naturally represented in JSON or YAML, a string value can be used to contain the
* example with escaping where necessary.
* @return The current builder
*/
public SchemaObjectBuilder withExample(Object example) {
this.example = example;
return this;
}
/**
* @param deprecated Specifies that a schema is deprecated and SHOULD be transitioned out of usage. Default value is false
.
* @return The current builder
*/
public SchemaObjectBuilder withDeprecated(Boolean deprecated) {
this.deprecated = deprecated;
return this;
}
/**
* @return A new object
*/
public SchemaObject build() {
return new SchemaObject(title, multipleOf, maximum, exclusiveMaximum, minimum, exclusiveMinimum, maxLength,
minLength, pattern, maxItems, minItems, uniqueItems, maxProperties, minProperties, immutable(required),
immutable(enumValue), type, immutable(allOf), immutable(oneOf), immutable(anyOf), immutable(not),
items, immutable(properties), additionalProperties, description, format, defaultValue, nullable,
discriminator, readOnly, writeOnly, xml, externalDocs, example, deprecated);
}
/**
* Creates a builder for a {@link SchemaObject}
*
* @return A new builder
*/
public static SchemaObjectBuilder schemaObject() {
return new SchemaObjectBuilder();
}
/**
* Creates a builder for a {@link SchemaObject} with the type and format based on the given class
* @param from Type type to build from, e.g. if the type is String.class
then the type
will
* be set as string
.
* @return A new builder
*/
public static SchemaObjectBuilder schemaObjectFrom(Class> from) {
return schemaObjectFrom(from, null, false);
}
/**
* Creates a builder for a {@link SchemaObject} with the type and format based on the given class and generic type.
* @param from Type type to build from, e.g. if the type is List.class
then the type
will
* be set as array
.
* @param parameterizedType The generic type of the class, e.g. a String if the type is List<String>
* @param required True if it's a required value
* @return A new builder
*/
public static SchemaObjectBuilder schemaObjectFrom(Class> from, Type parameterizedType, boolean required) {
Objects.requireNonNull(from, "from");
if (from.equals(void.class) || from.equals(Void.class)) {
return schemaObject();
}
parameterizedType = getUpperBound(parameterizedType);
String jsonType = jsonType(from);
SchemaObjectBuilder schemaObjectBuilder = schemaObject()
.withType(jsonType)
.withFormat(jsonFormat(from))
.withExample(example(from))
.withNullable((!from.isPrimitive() && !required) ? true : null)
.withItems(itemsFor(from, parameterizedType, "array".equals(jsonType)));
if (from.equals(UUID.class)) {
schemaObjectBuilder
.withPattern(Pattern.compile("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]"));
} else if (from.isEnum()) {
Object[] enumConstants = from.getEnumConstants();
schemaObjectBuilder.withEnumValue(asList(enumConstants));
}
return schemaObjectBuilder;
}
private static Object example(Class> clazz) {
if (clazz.equals(UUID.class)) {
return UUID.randomUUID();
} else if (Temporal.class.isAssignableFrom(clazz)) {
try {
return clazz.getDeclaredMethod("now").invoke(null);
} catch (Exception ignored) { }
}
return null;
}
private static Type getUpperBound(Type parameterizedType) {
if (parameterizedType instanceof WildcardType && ((WildcardType)parameterizedType).getUpperBounds().length > 0) {
parameterizedType = ((WildcardType)parameterizedType).getUpperBounds()[0];
}
return parameterizedType;
}
private static SchemaObject itemsFor(Class> from, Type parameterizedType, boolean isJsonArray) {
Class> componentType = from.getComponentType();
if (componentType == null) {
if (isJsonArray) {
SchemaObjectBuilder schemaObjectBuilder = schemaObject().withType("object");
if (parameterizedType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) parameterizedType).getActualTypeArguments();
if (actualTypeArguments.length == 1) {
Type argType = getUpperBound(actualTypeArguments[0]);
if (argType instanceof Class>) {
Class> argClass = (Class>) argType;
schemaObjectBuilder = schemaObjectFrom(argClass, null, true);
}
}
}
return schemaObjectBuilder.build();
} else {
return null;
}
}
return schemaObjectFrom(componentType).build();
}
private static String jsonType(Class> type) {
if (CharSequence.class.isAssignableFrom(type) || type.equals(byte.class) || type.equals(Byte.class)
|| type.isAssignableFrom(Date.class) || Temporal.class.isAssignableFrom(type) || isBinaryClass(type)
|| type.isAssignableFrom(UUID.class) || type.isEnum()) {
return "string";
} else if (type.equals(boolean.class) || type.equals(Boolean.class)) {
return "boolean";
} else if (type.equals(int.class) || type.equals(Integer.class) || type.equals(long.class) || type.equals(Long.class)) {
return "integer";
} else if (Number.class.isAssignableFrom(type) || type.equals(float.class) || type.equals(double.class)) {
return "number";
} else if (Collection.class.isAssignableFrom(type) || type.isArray()) {
return "array";
}
return "object";
}
private static String jsonFormat(Class> type) {
if (type.equals(int.class) || type.equals(Integer.class)) {
return "int32";
} else if (type.equals(long.class) || type.equals(Long.class)) {
return "int64";
} else if (type.equals(float.class) || type.equals(Float.class)) {
return "float";
} else if (type.equals(double.class) || type.equals(Double.class)) {
return "double";
} else if (type.equals(byte.class) || type.equals(Byte.class)) {
return "byte";
} else if (type.equals(Date.class) || type.equals(Instant.class)) {
return "date-time";
} else if (type.equals(LocalDate.class)) {
return "date";
} else if (isBinaryClass(type)) {
return "binary";
} else if (type.equals(UUID.class)) {
return "uuid";
}
return null;
}
private static boolean isBinaryClass(Class> type) {
return UploadedFile.class.isAssignableFrom(type) || File.class.isAssignableFrom(type)
|| InputStream.class.isAssignableFrom(type) || (type.isArray() && type.getComponentType().equals(byte.class));
}
@Override
public String toString() {
return "SchemaObjectBuilder{" +
"title='" + title + '\'' +
", multipleOf=" + multipleOf +
", maximum=" + maximum +
", exclusiveMaximum=" + exclusiveMaximum +
", minimum=" + minimum +
", exclusiveMinimum=" + exclusiveMinimum +
", maxLength=" + maxLength +
", minLength=" + minLength +
", pattern=" + pattern +
", maxItems=" + maxItems +
", minItems=" + minItems +
", uniqueItems=" + uniqueItems +
", maxProperties=" + maxProperties +
", minProperties=" + minProperties +
", required=" + required +
", enumValue=" + enumValue +
", type='" + type + '\'' +
", allOf=" + allOf +
", oneOf=" + oneOf +
", anyOf=" + anyOf +
", not=" + not +
", items=" + items +
", properties=" + properties +
", additionalProperties=" + additionalProperties +
", description='" + description + '\'' +
", format='" + format + '\'' +
", defaultValue=" + defaultValue +
", nullable=" + nullable +
", discriminator=" + discriminator +
", readOnly=" + readOnly +
", writeOnly=" + writeOnly +
", xml=" + xml +
", externalDocs=" + externalDocs +
", example=" + example +
", deprecated=" + deprecated +
'}';
}
}