![JAR search and dependency download from the Maven repository](/logo.png)
org.apache.juneau.httppart.HttpPartSchema Maven / Gradle / Ivy
// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
// * with the License. You may obtain a copy of the License at *
// * *
// * http://www.apache.org/licenses/LICENSE-2.0 *
// * *
// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
// * specific language governing permissions and limitations under the License. *
// ***************************************************************************************************************************
package org.apache.juneau.httppart;
import static java.util.Collections.*;
import static org.apache.juneau.common.internal.StringUtils.*;
import static org.apache.juneau.common.internal.ThrowableUtils.*;
import static org.apache.juneau.httppart.HttpPartDataType.*;
import static org.apache.juneau.httppart.HttpPartFormat.*;
import static org.apache.juneau.internal.ClassUtils.*;
import static org.apache.juneau.internal.CollectionUtils.*;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.math.*;
import java.util.*;
import java.util.concurrent.atomic.*;
import java.util.function.*;
import java.util.regex.*;
import org.apache.juneau.*;
import org.apache.juneau.annotation.*;
import org.apache.juneau.collections.*;
import org.apache.juneau.common.internal.*;
import org.apache.juneau.http.annotation.*;
import org.apache.juneau.internal.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.reflect.*;
/**
* Represents an OpenAPI schema definition.
*
*
* The schema definition can be applied to any HTTP parts such as bodies, headers, query/form parameters, and URL path parts.
*
The API is generic enough to apply to any path part although some attributes may only applicable for certain parts.
*
*
* Schema objects are created via builders instantiated through the {@link #create()} method.
*
*
Notes:
* - This class is thread safe and reusable.
*
*
* See Also:
* - OpenAPI Details
*
*/
public class HttpPartSchema {
//-------------------------------------------------------------------------------------------------------------------
// Static
//-------------------------------------------------------------------------------------------------------------------
/** Reusable instance of this object, all default settings. */
public static final HttpPartSchema DEFAULT = HttpPartSchema.create().allowEmptyValue(true).build();
/** Boolean type */
public static final HttpPartSchema T_BOOLEAN = HttpPartSchema.tBoolean().build();
/** File type */
public static final HttpPartSchema T_FILE = HttpPartSchema.tFile().build();
/** Integer type */
public static final HttpPartSchema T_INTEGER = HttpPartSchema.tInteger().build();
/** Int32 type */
public static final HttpPartSchema T_INT32 = HttpPartSchema.tInt32().build();
/** Int64 type */
public static final HttpPartSchema T_INT64 = HttpPartSchema.tInt64().build();
/** No type */
public static final HttpPartSchema T_NONE = HttpPartSchema.tNone().build();
/** Number type */
public static final HttpPartSchema T_NUMBER = HttpPartSchema.tNumber().build();
/** Float type */
public static final HttpPartSchema T_FLOAT = HttpPartSchema.tFloat().build();
/** Double type */
public static final HttpPartSchema T_DOUBLE = HttpPartSchema.tDouble().build();
/** String type */
public static final HttpPartSchema T_STRING = HttpPartSchema.tString().build();
/** Byte type */
public static final HttpPartSchema T_BYTE = HttpPartSchema.tByte().build();
/** Binary type */
public static final HttpPartSchema T_BINARY = HttpPartSchema.tBinary().build();
/** Spaced binary type */
public static final HttpPartSchema T_BINARY_SPACED = HttpPartSchema.tBinarySpaced().build();
/** Date type */
public static final HttpPartSchema T_DATE = HttpPartSchema.tDate().build();
/** Date-time type */
public static final HttpPartSchema T_DATETIME = HttpPartSchema.tDateTime().build();
/** UON-formated simple type */
public static final HttpPartSchema T_UON = HttpPartSchema.tUon().build();
/** Array type */
public static final HttpPartSchema T_ARRAY = HttpPartSchema.tArray().build();
/** Comma-delimited array type */
public static final HttpPartSchema T_ARRAY_CSV = HttpPartSchema.tArrayCsv().build();
/** Pipe-delimited array type */
public static final HttpPartSchema T_ARRAY_PIPES = HttpPartSchema.tArrayPipes().build();
/** Space-delimited array type */
public static final HttpPartSchema T_ARRAY_SSV = HttpPartSchema.tArraySsv().build();
/** Tab-delimited array type */
public static final HttpPartSchema T_ARRAY_TSV = HttpPartSchema.tArrayTsv().build();
/** UON-formatted array type */
public static final HttpPartSchema T_ARRAY_UON = HttpPartSchema.tArrayUon().build();
/** Multi-part array type */
public static final HttpPartSchema T_ARRAY_MULTI = HttpPartSchema.tArrayMulti().build();
/** Object type */
public static final HttpPartSchema T_OBJECT = HttpPartSchema.tObject().build();
/** Comma-delimited object type */
public static final HttpPartSchema T_OBJECT_CSV = HttpPartSchema.tObjectCsv().build();
/** Pipe-delimited object type */
public static final HttpPartSchema T_OBJECT_PIPES = HttpPartSchema.tObjectPipes().build();
/** Space-delimited object type */
public static final HttpPartSchema T_OBJECT_SSV = HttpPartSchema.tObjectSsv().build();
/** Tab-delimited object type */
public static final HttpPartSchema T_OBJECT_TSV = HttpPartSchema.tObjectTsv().build();
/** UON-formated object type */
public static final HttpPartSchema T_OBJECT_UON = HttpPartSchema.tObjectUon().build();
/**
* Instantiates a new builder for this object.
*
* @return A new builder for this object.
*/
public static Builder create() {
return new Builder();
}
/**
* Shortcut for create ().type(HttpPartDataType.BOOLEAN ) .
*
* @return A new builder for this object.
*/
public static Builder tBoolean() {
return create().tBoolean();
}
/**
* Shortcut for create ().type(HttpPartDataType.FILE ) .
*
* @return A new builder for this object.
*/
public static Builder tFile() {
return create().tFile();
}
/**
* Shortcut for create ().type(HttpPartDataType.INTEGER ) .
*
* @return A new builder for this object.
*/
public static Builder tInteger() {
return create().tInteger();
}
/**
* Shortcut for create ().type(HttpPartDataType.INTEGER ).format(HttpPartFormat.INT32 ) .
*
* @return A new builder for this object.
*/
public static Builder tInt32() {
return create().tInteger().fInt32();
}
/**
* Shortcut for create ().type(HttpPartDataType.INTEGER ).format(HttpPartFormat.INT64 ) .
*
* @return A new builder for this object.
*/
public static Builder tInt64() {
return create().tInteger().fInt64();
}
/**
* Shortcut for create ().type(HttpPartDataType.NONE ) .
*
* @return A new builder for this object.
*/
public static Builder tNone() {
return create().tNone();
}
/**
* Shortcut for create ().type(HttpPartDataType.NUMBER ) .
*
* @return A new builder for this object.
*/
public static Builder tNumber() {
return create().tNumber();
}
/**
* Shortcut for create ().type(HttpPartDataType.NUMBER ).format(HttpPartFormat.FLOAT ) .
*
* @return A new builder for this object.
*/
public static Builder tFloat() {
return create().tNumber().fFloat();
}
/**
* Shortcut for create ().type(HttpPartDataType.NUMBER ).format(HttpPartFormat.DOUBLE ) .
*
* @return A new builder for this object.
*/
public static Builder tDouble() {
return create().tNumber().fDouble();
}
/**
* Shortcut for create ().type(HttpPartDataType.STRING ) .
*
* @return A new builder for this object.
*/
public static Builder tString() {
return create().tString();
}
/**
* Shortcut for create ().type(HttpPartDataType.STRING ).format(HttpPartFormat.BYTE ) .
*
* @return A new builder for this object.
*/
public static Builder tByte() {
return create().tString().fByte();
}
/**
* Shortcut for create ().type(HttpPartDataType.STRING ).format(HttpPartFormat.BINARY ) .
*
* @return A new builder for this object.
*/
public static Builder tBinary() {
return create().tString().fBinary();
}
/**
* Shortcut for create ().type(HttpPartDataType.STRING ).format(HttpPartFormat.BINARY_SPACED ) .
*
* @return A new builder for this object.
*/
public static Builder tBinarySpaced() {
return create().tString().fBinarySpaced();
}
/**
* Shortcut for create ().type(HttpPartDataType.STRING ).format(HttpPartFormat.DATE ) .
*
* @return A new builder for this object.
*/
public static Builder tDate() {
return create().tString().fDate();
}
/**
* Shortcut for create ().type(HttpPartDataType.STRING ).format(HttpPartFormat.DATE_TIME ) .
*
* @return A new builder for this object.
*/
public static Builder tDateTime() {
return create().tString().fDateTime();
}
/**
* Shortcut for create ().type(HttpPartDataType.STRING ).format(HttpPartFormat.UON ) .
*
* @return A new builder for this object.
*/
public static Builder tUon() {
return create().tString().fUon();
}
/**
* Shortcut for create ().type(HttpPartDataType.ARRAY ) .
*
* @return A new builder for this object.
*/
public static Builder tArray() {
return create().tArray();
}
/**
* Shortcut for create ().type(HttpPartDataType.ARRAY ).items(items) .
*
* @param items The schema of the array items.
* @return A new builder for this object.
*/
public static Builder tArray(Builder items) {
return create().tArray().items(items);
}
/**
* Shortcut for create ().type(HttpPartDataType.ARRAY ).collectionFormat(HttpPartCollectionFormat.CSV ) .
*
* @return A new builder for this object.
*/
public static Builder tArrayCsv() {
return create().tArray().cfCsv();
}
/**
* Shortcut for create ().type(HttpPartDataType.ARRAY ).collectionFormat(HttpPartCollectionFormat.CSV ).items(items) .
*
* @param items The schema of the array items.
* @return A new builder for this object.
*/
public static Builder tArrayCsv(Builder items) {
return create().tArray().cfCsv().items(items);
}
/**
* Shortcut for create ().type(HttpPartDataType.ARRAY ).collectionFormat(HttpPartCollectionFormat.PIPES ) .
*
* @return A new builder for this object.
*/
public static Builder tArrayPipes() {
return create().tArray().cfPipes();
}
/**
* Shortcut for create ().type(HttpPartDataType.ARRAY ).collectionFormat(HttpPartCollectionFormat.PIPES ).items(items) .
*
* @param items The schema of the array items.
* @return A new builder for this object.
*/
public static Builder tArrayPipes(Builder items) {
return create().tArray().cfPipes().items(items);
}
/**
* Shortcut for create ().type(HttpPartDataType.ARRAY ).collectionFormat(HttpPartCollectionFormat.SSV ) .
*
* @return A new builder for this object.
*/
public static Builder tArraySsv() {
return create().tArray().cfSsv();
}
/**
* Shortcut for create ().type(HttpPartDataType.ARRAY ).collectionFormat(HttpPartCollectionFormat.SSV ).items(items) .
*
* @param items The schema of the array items.
* @return A new builder for this object.
*/
public static Builder tArraySsv(Builder items) {
return create().tArray().cfSsv().items(items);
}
/**
* Shortcut for create ().type(HttpPartDataType.ARRAY ).collectionFormat(HttpPartCollectionFormat.TSV ) .
*
* @return A new builder for this object.
*/
public static Builder tArrayTsv() {
return create().tArray().cfTsv();
}
/**
* Shortcut for create ().type(HttpPartDataType.ARRAY ).collectionFormat(HttpPartCollectionFormat.TSV ).items(items) .
*
* @param items The schema of the array items.
* @return A new builder for this object.
*/
public static Builder tArrayTsv(Builder items) {
return create().tArray().cfTsv().items(items);
}
/**
* Shortcut for create ().type(HttpPartDataType.ARRAY ).collectionFormat(HttpPartCollectionFormat.UONC ) .
*
* @return A new builder for this object.
*/
public static Builder tArrayUon() {
return create().tArray().cfUon();
}
/**
* Shortcut for create ().type(HttpPartDataType.ARRAY ).collectionFormat(HttpPartCollectionFormat.UONC ).items(items) .
*
* @param items The schema of the array items.
* @return A new builder for this object.
*/
public static Builder tArrayUon(Builder items) {
return create().tArray().cfUon().items(items);
}
/**
* Shortcut for create ().type(HttpPartDataType.ARRAY ).collectionFormat(HttpPartCollectionFormat.MULTI ) .
*
* @return A new builder for this object.
*/
public static Builder tArrayMulti() {
return create().tArray().cfMulti();
}
/**
* Shortcut for create ().type(HttpPartDataType.ARRAY ).collectionFormat(HttpPartCollectionFormat.MULTI ).items(items) .
*
* @param items The schema of the array items.
* @return A new builder for this object.
*/
public static Builder tArrayMulti(Builder items) {
return create().tArray().cfMulti().items(items);
}
/**
* Shortcut for create ().type(HttpPartDataType.OBJECT ) .
*
* @return A new builder for this object.
*/
public static Builder tObject() {
return create().tObject();
}
/**
* Shortcut for create ().type(HttpPartDataType.OBJECT ).collectionFormat(HttpPartCollectionFormat.CSV ) .
*
* @return A new builder for this object.
*/
public static Builder tObjectCsv() {
return create().tObject().cfCsv();
}
/**
* Shortcut for create ().type(HttpPartDataType.OBJECT ).collectionFormat(HttpPartCollectionFormat.PIPES ) .
*
* @return A new builder for this object.
*/
public static Builder tObjectPipes() {
return create().tObject().cfPipes();
}
/**
* Shortcut for create ().type(HttpPartDataType.OBJECT ).collectionFormat(HttpPartCollectionFormat.SSV ) .
*
* @return A new builder for this object.
*/
public static Builder tObjectSsv() {
return create().tObject().cfSsv();
}
/**
* Shortcut for create ().type(HttpPartDataType.OBJECT ).collectionFormat(HttpPartCollectionFormat.TSV ) .
*
* @return A new builder for this object.
*/
public static Builder tObjectTsv() {
return create().tObject().cfTsv();
}
/**
* Shortcut for create ().type(HttpPartDataType.OBJECT ).collectionFormat(HttpPartCollectionFormat.UON ) .
*
* @return A new builder for this object.
*/
public static Builder tObjectUon() {
return create().tObject().cfUon();
}
/**
* Finds the schema information for the specified method parameter.
*
*
* This method will gather all the schema information from the annotations at the following locations:
*
* - The method parameter.
*
- The method parameter class.
*
- The method parameter parent classes and interfaces.
*
*
* @param c
* The annotation to look for.
*
Valid values:
*
* - {@link Content}
*
- {@link Header}
*
- {@link Query}
*
- {@link FormData}
*
- {@link Path}
*
- {@link Response}
*
- {@link HasQuery}
*
- {@link HasFormData}
*
* @param mpi The Java method parameter.
* @return The schema information about the parameter.
*/
public static HttpPartSchema create(Class extends Annotation> c, ParamInfo mpi) {
return create().applyAll(c, mpi).build();
}
/**
* Finds the schema information for the specified method return.
*
*
* This method will gather all the schema information from the annotations at the following locations:
*
* - The method.
*
- The method return class.
*
- The method return parent classes and interfaces.
*
*
* @param c
* The annotation to look for.
*
Valid values:
*
* - {@link Content}
*
- {@link Header}
*
- {@link Query}
*
- {@link FormData}
*
- {@link Path}
*
- {@link Response}
*
- {@link HasQuery}
*
- {@link HasFormData}
*
* @param m
* The Java method with the return type being checked.
* @return The schema information about the parameter.
*/
public static HttpPartSchema create(Class extends Annotation> c, Method m) {
return create().applyAll(c, m).build();
}
/**
* Finds the schema information for the specified class.
*
*
* This method will gather all the schema information from the annotations on the class and all parent classes/interfaces.
*
* @param c
* The annotation to look for.
*
Valid values:
*
* - {@link Content}
*
- {@link Header}
*
- {@link Query}
*
- {@link FormData}
*
- {@link Path}
*
- {@link Response}
*
- {@link HasQuery}
*
- {@link HasFormData}
*
* @param t
* The class containing the parameter.
* @return The schema information about the parameter.
*/
public static HttpPartSchema create(Class extends Annotation> c, java.lang.reflect.Type t) {
return create().applyAll(c, t).build();
}
/**
* Shortcut for calling create().type(type);
*
* @param type The schema type value.
* @return A new builder.
*/
public static Builder create(String type) {
return create().type(type);
}
/**
* Shortcut for calling create().type(type).format(format);
*
* @param type The schema type value.
* @param format The schema format value.
* @return A new builder.
*/
public static Builder create(String type, String format) {
return create().type(type).format(format);
}
/**
* Finds the schema information on the specified annotation.
*
* @param a
* The annotation to find the schema information on..
* @return The schema information found on the annotation.
*/
public static HttpPartSchema create(Annotation a) {
return create().apply(a).build();
}
/**
* Finds the schema information on the specified annotation.
*
* @param a
* The annotation to find the schema information on..
* @param defaultName The default part name if not specified on the annotation.
* @return The schema information found on the annotation.
*/
public static HttpPartSchema create(Annotation a, String defaultName) {
return create().name(defaultName).apply(a).build();
}
//-------------------------------------------------------------------------------------------------------------------
// Builder
//-------------------------------------------------------------------------------------------------------------------
/**
* Builder class.
*/
public static class Builder {
String name, _default;
Set codes;
Set _enum;
Boolean allowEmptyValue, exclusiveMaximum, exclusiveMinimum, required, uniqueItems, skipIfEmpty;
HttpPartCollectionFormat collectionFormat = HttpPartCollectionFormat.NO_COLLECTION_FORMAT;
HttpPartDataType type = HttpPartDataType.NO_TYPE;
HttpPartFormat format = HttpPartFormat.NO_FORMAT;
Pattern pattern;
Number maximum, minimum, multipleOf;
Long maxLength, minLength, maxItems, minItems, maxProperties, minProperties;
Map properties;
Object items, additionalProperties;
boolean noValidate;
Class extends HttpPartParser> parser;
Class extends HttpPartSerializer> serializer;
/**
* Instantiates a new {@link HttpPartSchema} object based on the configuration of this builder.
*
*
* This method can be called multiple times to produce new schema objects.
*
* @return
* A new {@link HttpPartSchema} object.
*
Never null .
*/
public HttpPartSchema build() {
return new HttpPartSchema(this);
}
Builder apply(Class extends Annotation> c, ParamInfo mpi) {
apply(c, mpi.getParameterType().innerType());
mpi.forEachDeclaredAnnotation(c, x -> true, this::apply);
return this;
}
Builder applyAll(Class extends Annotation> c, ParamInfo mpi) {
return apply(Schema.class, mpi).apply(c, mpi);
}
Builder apply(Class extends Annotation> c, Method m) {
apply(c, m.getGenericReturnType());
Annotation a = m.getAnnotation(c);
if (a != null)
return apply(a);
return this;
}
Builder applyAll(Class extends Annotation> c, Method m) {
return apply(Schema.class, m).apply(c, m);
}
Builder apply(Class extends Annotation> c, java.lang.reflect.Type t) {
if (t instanceof Class>) {
ClassInfo.of((Class>)t).forEachAnnotation(c, x -> true, this::apply);
} else if (Value.isType(t)) {
apply(c, Value.getParameterType(t));
}
return this;
}
Builder applyAll(Class extends Annotation> c, java.lang.reflect.Type t) {
return apply(Schema.class, t).apply(c, t);
}
/**
* Apply the specified annotation to this schema.
*
* @param a The annotation to apply.
* @return This object.
*/
public Builder apply(Annotation a) {
if (a instanceof Content)
apply((Content)a);
else if (a instanceof Header)
apply((Header)a);
else if (a instanceof FormData)
apply((FormData)a);
else if (a instanceof Query)
apply((Query)a);
else if (a instanceof Path)
apply((Path)a);
else if (a instanceof Response)
apply((Response)a);
else if (a instanceof StatusCode)
apply((StatusCode)a);
else if (a instanceof HasQuery)
apply((HasQuery)a);
else if (a instanceof HasFormData)
apply((HasFormData)a);
else if (a instanceof Schema)
apply((Schema)a);
else
throw new BasicRuntimeException("Builder.apply(@{0}) not defined", className(a));
return this;
}
Builder apply(Content a) {
if (! SchemaAnnotation.empty(a.schema()))
apply(a.schema());
return this;
}
Builder apply(Header a) {
if (! SchemaAnnotation.empty(a.schema()))
apply(a.schema());
name(firstNonEmpty(a.name(), a.value()));
parser(a.parser());
serializer(a.serializer());
return this;
}
Builder apply(FormData a) {
if (! SchemaAnnotation.empty(a.schema()))
apply(a.schema());
name(firstNonEmpty(a.name(), a.value()));
parser(a.parser());
serializer(a.serializer());
return this;
}
Builder apply(Query a) {
if (! SchemaAnnotation.empty(a.schema()))
apply(a.schema());
name(firstNonEmpty(a.name(), a.value()));
parser(a.parser());
serializer(a.serializer());
return this;
}
Builder apply(Path a) {
if (! SchemaAnnotation.empty(a.schema()))
apply(a.schema());
name(firstNonEmpty(a.name(), a.value()));
parser(a.parser());
serializer(a.serializer());
// Path remainder always allows empty value.
if (startsWith(name, '/')) {
allowEmptyValue();
required(false);
} else if (required == null) {
required(true);
}
return this;
}
Builder apply(Response a) {
allowEmptyValue(true);
apply(a.schema());
parser(a.parser());
required(false);
serializer(a.serializer());
return this;
}
Builder apply(StatusCode a) {
codes(a.value());
return this;
}
Builder apply(Items a) {
_default(joinnlOrNull(a._default(), a.df()));
_enum(toSet(a._enum(), a.e()));
collectionFormat(firstNonEmpty(a.collectionFormat(), a.cf()));
exclusiveMaximum(a.exclusiveMaximum() || a.emax());
exclusiveMinimum(a.exclusiveMinimum() || a.emin());
format(firstNonEmpty(a.format(), a.f()));
items(a.items());
maximum(toNumber(a.maximum(), a.max()));
maxItems(firstNmo(a.maxItems(), a.maxi()));
maxLength(firstNmo(a.maxLength(), a.maxl()));
minimum(toNumber(a.minimum(), a.min()));
minItems(firstNmo(a.minItems(), a.mini()));
minLength(firstNmo(a.minLength(), a.minl()));
multipleOf(toNumber(a.multipleOf(), a.mo()));
pattern(firstNonEmpty(a.pattern(), a.p()));
type(firstNonEmpty(a.type(), a.t()));
uniqueItems(a.uniqueItems() || a.ui()); return this;
}
Builder apply(SubItems a) {
_default(joinnlOrNull(a._default(), a.df()));
_enum(toSet(a._enum(), a.e()));
collectionFormat(firstNonEmpty(a.collectionFormat(), a.cf()));
exclusiveMaximum(a.exclusiveMaximum() || a.emax());
exclusiveMinimum(a.exclusiveMinimum() || a.emin());
format(firstNonEmpty(a.format(), a.f()));
items(HttpPartSchema.toJsonMap(a.items()));
maximum(toNumber(a.maximum(), a.max()));
maxItems(firstNmo(a.maxItems(), a.maxi()));
maxLength(firstNmo(a.maxLength(), a.maxl()));
minimum(toNumber(a.minimum(), a.min()));
minItems(firstNmo(a.minItems(), a.mini()));
minLength(firstNmo(a.minLength(), a.minl()));
multipleOf(toNumber(a.multipleOf(), a.mo()));
pattern(firstNonEmpty(a.pattern(), a.p()));
type(firstNonEmpty(a.type(), a.t()));
uniqueItems(a.uniqueItems() || a.ui()); return this;
}
Builder apply(Schema a) {
_default(joinnlOrNull(a._default(), a.df()));
_enum(toSet(a._enum(), a.e()));
additionalProperties(HttpPartSchema.toJsonMap(a.additionalProperties()));
allowEmptyValue(a.allowEmptyValue() || a.aev());
collectionFormat(firstNonEmpty(a.collectionFormat(), a.cf()));
exclusiveMaximum(a.exclusiveMaximum() || a.emax());
exclusiveMinimum(a.exclusiveMinimum() || a.emin());
format(firstNonEmpty(a.format(), a.f()));
items(a.items());
maximum(toNumber(a.maximum(), a.max()));
maxItems(firstNmo(a.maxItems(), a.maxi()));
maxLength(firstNmo(a.maxLength(), a.maxl()));
maxProperties(firstNmo(a.maxProperties(), a.maxp()));
minimum(toNumber(a.minimum(), a.min()));
minItems(firstNmo(a.minItems(), a.mini()));
minLength(firstNmo(a.minLength(), a.minl()));
minProperties(firstNmo(a.minProperties(), a.minp()));
multipleOf(toNumber(a.multipleOf(), a.mo()));
pattern(firstNonEmpty(a.pattern(), a.p()));
properties(HttpPartSchema.toJsonMap(a.properties()));
required(a.required() || a.r());
skipIfEmpty(a.skipIfEmpty() || a.sie());
type(firstNonEmpty(a.type(), a.t()));
uniqueItems(a.uniqueItems() || a.ui());
return this;
}
Builder apply(HasQuery a) {
name(firstNonEmpty(a.name(), a.value()));
return this;
}
Builder apply(HasFormData a) {
name(firstNonEmpty(a.name(), a.value()));
return this;
}
Builder apply(JsonMap m) {
if (m != null && ! m.isEmpty()) {
_default(m.getString("default"));
_enum(HttpPartSchema.toSet(m.getString("enum")));
allowEmptyValue(m.getBoolean("allowEmptyValue"));
exclusiveMaximum(m.getBoolean("exclusiveMaximum"));
exclusiveMinimum(m.getBoolean("exclusiveMinimum"));
required(m.getBoolean("required"));
uniqueItems(m.getBoolean("uniqueItems"));
collectionFormat(m.getString("collectionFormat"));
type(m.getString("type"));
format(m.getString("format"));
pattern(m.getString("pattern"));
maximum(m.get("maximum", Number.class));
minimum(m.get("minimum", Number.class));
multipleOf(m.get("multipleOf", Number.class));
maxItems(m.get("maxItems", Long.class));
maxLength(m.get("maxLength", Long.class));
maxProperties(m.get("maxProperties", Long.class));
minItems(m.get("minItems", Long.class));
minLength(m.get("minLength", Long.class));
minProperties(m.get("minProperties", Long.class));
items(m.getMap("items"));
properties(m.getMap("properties"));
additionalProperties(m.getMap("additionalProperties"));
apply(m.getMap("schema", null));
}
return this;
}
/**
* name field.
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder name(String value) {
if (isNotEmpty(value))
name = value;
return this;
}
/**
* Synonym for {@link #name(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder n(String value) {
return name(value);
}
/**
* httpStatusCode key.
*
*
* Applicable to the following Swagger schema objects:
*
* - Responses
*
*
* @param value
* The new value for this property.
*
Ignored if null or an empty array.
* @return This object.
*/
public Builder codes(int[] value) {
if (value != null && value.length != 0)
for (int v : value)
code(v);
return this;
}
/**
* httpStatusCode key.
*
*
* Applicable to the following Swagger schema objects:
*
* - Responses
*
*
* @param value
* The new value for this property.
*
Ignored if value is 0 .
* @return This object.
*/
public Builder code(int value) {
if (value != 0) {
if (codes == null)
codes = new TreeSet<>();
codes.add(value);
}
return this;
}
/**
* required field.
*
*
* Determines whether the parameter is mandatory.
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder required(Boolean value) {
required = resolve(value, required);
return this;
}
/**
* Synonym for {@link #required(Boolean)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder r(Boolean value) {
return required(value);
}
/**
* required field.
*
*
* Determines whether the parameter is mandatory.
*
*
* Same as {@link #required(Boolean)} but takes in a boolean value as a string.
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder required(String value) {
required = resolve(value, required);
return this;
}
/**
* Synonym for {@link #required(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder r(String value) {
return required(value);
}
/**
* required field.
*
*
* Shortcut for calling required(true );
.
*
* @return This object.
*/
public Builder required() {
return required(true);
}
/**
* Synonym for {@link #required()}.
*
* @return This object.
*/
public Builder r() {
return required();
}
/**
* type field.
*
*
* The type of the parameter.
*
*
* If the type is not specified, it will be auto-detected based on the parameter class type.
*
*
* Applicable to the following Swagger schema objects:
*
* - Parameter
*
- Schema
*
- Items
*
- SecurityScheme
*
*
*
* -
*
"string"
*
Parameter must be a string or a POJO convertible from a string.
* -
*
"number"
*
Parameter must be a number primitive or number object.
*
If parameter is Object , creates either a Float or Double depending on the size of the number.
* -
*
"integer"
*
Parameter must be a integer/long primitive or integer/long object.
*
If parameter is Object , creates either a Short , Integer , or Long depending on the size of the number.
* -
*
"boolean"
*
Parameter must be a boolean primitive or object.
* -
*
"array"
*
Parameter must be an array or collection.
*
Elements must be strings or POJOs convertible from strings.
*
If parameter is Object , creates an {@link JsonList}.
* -
*
"object"
*
Parameter must be a map or bean.
*
If parameter is Object , creates an {@link JsonMap}.
*
Note that this is an extension of the OpenAPI schema as Juneau allows for arbitrarily-complex POJOs to be serialized as HTTP parts.
* -
*
"file"
*
This type is currently not supported.
*
*
* See Also:
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder type(String value) {
try {
if (isNotEmpty(value))
type = HttpPartDataType.fromString(value);
} catch (Exception e) {
throw new ContextRuntimeException("Invalid value ''{0}'' passed in as type value. Valid values: {1}", value, HttpPartDataType.values());
}
return this;
}
/**
* Synonym for {@link #type(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder t(String value) {
return type(value);
}
/**
* Shortcut for type(HttpPartDataType.STRING) .
*
* @return This object.
*/
public Builder tString() {
type = HttpPartDataType.STRING;
return this;
}
/**
* Shortcut for type(HttpPartDataType.NUMBER) .
*
* @return This object.
*/
public Builder tNumber() {
type = HttpPartDataType.NUMBER;
return this;
}
/**
* Shortcut for type(HttpPartDataType.INTEGER) .
*
* @return This object.
*/
public Builder tInteger() {
type = HttpPartDataType.INTEGER;
return this;
}
/**
* Shortcut for type(HttpPartDataType.BOOLEAN) .
*
* @return This object.
*/
public Builder tBoolean() {
type = HttpPartDataType.BOOLEAN;
return this;
}
/**
* Shortcut for type(HttpPartDataType.ARRAY) .
*
* @return This object.
*/
public Builder tArray() {
type = HttpPartDataType.ARRAY;
return this;
}
/**
* Shortcut for type(HttpPartDataType.OBJECT) .
*
* @return This object.
*/
public Builder tObject() {
type = HttpPartDataType.OBJECT;
return this;
}
/**
* Shortcut for type(HttpPartDataType.FILE) .
*
* @return This object.
*/
public Builder tFile() {
type = HttpPartDataType.FILE;
return this;
}
/**
* Shortcut for type(HttpPartDataType.NO_TYPE) .
*
* @return This object.
*/
public Builder tNone() {
type = HttpPartDataType.NO_TYPE;
return this;
}
/**
* type field.
*
*
* The type of the parameter.
*
*
* If the type is not specified, it will be auto-detected based on the parameter class type.
*
*
* Applicable to the following Swagger schema objects:
*
* - Parameter
*
- Schema
*
- Items
*
- SecurityScheme
*
*
*
* - {@link HttpPartDataType}
*
* -
* {@link HttpPartDataType#STRING STRING}
*
Parameter must be a string or a POJO convertible from a string.
* -
* {@link HttpPartDataType#NUMBER NUMBER}
*
Parameter must be a number primitive or number object.
*
If parameter is Object , creates either a Float or Double depending on the size of the number.
* -
* {@link HttpPartDataType#INTEGER INTEGER}
*
Parameter must be a integer/long primitive or integer/long object.
*
If parameter is Object , creates either a Short , Integer , or Long depending on the size of the number.
* -
* {@link HttpPartDataType#BOOLEAN BOOLEAN}
*
Parameter must be a boolean primitive or object.
* -
* {@link HttpPartDataType#ARRAY ARRAY}
*
Parameter must be an array or collection.
*
Elements must be strings or POJOs convertible from strings.
*
If parameter is Object , creates an {@link JsonList}.
* -
* {@link HttpPartDataType#OBJECT OBJECT}
*
Parameter must be a map or bean.
*
If parameter is Object , creates an {@link JsonMap}.
*
Note that this is an extension of the OpenAPI schema as Juneau allows for arbitrarily-complex POJOs to be serialized as HTTP parts.
* -
* {@link HttpPartDataType#FILE FILE}
*
This type is currently not supported.
*
*
*
* See Also:
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder type(HttpPartDataType value) {
this.type = value;
return this;
}
/**
* Synonym for {@link #type(HttpPartDataType)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder t(HttpPartDataType value) {
return type(value);
}
/**
* format field.
*
*
* The extending format for the previously mentioned parameter type.
*
*
* Applicable to the following Swagger schema objects:
*
*
*
* -
*
"int32" - Signed 32 bits.
*
Only valid with type "integer" .
* -
*
"int64" - Signed 64 bits.
*
Only valid with type "integer" .
* -
*
"float" - 32-bit floating point number.
*
Only valid with type "number" .
* -
*
"double" - 64-bit floating point number.
*
Only valid with type "number" .
* -
*
"byte" - BASE-64 encoded characters.
*
Only valid with type "string" .
*
Parameters of type POJO convertible from string are converted after the string has been decoded.
* -
*
"binary" - Hexadecimal encoded octets (e.g. "00FF" ).
*
Only valid with type "string" .
*
Parameters of type POJO convertible from string are converted after the string has been decoded.
* -
*
"binary-spaced" - Hexadecimal encoded octets, spaced (e.g. "00 FF" ).
*
Only valid with type "string" .
*
Parameters of type POJO convertible from string are converted after the string has been decoded.
* -
*
"date" - An RFC3339 full-date.
*
Only valid with type "string" .
* -
*
"date-time" - An RFC3339 date-time.
*
Only valid with type "string" .
* -
*
"password" - Used to hint UIs the input needs to be obscured.
*
This format does not affect the serialization or parsing of the parameter.
* -
*
"uon" - UON notation (e.g. "(foo=bar,baz=@(qux,123))" ).
*
Only valid with type "object" .
*
If not specified, then the input is interpreted as plain-text and is converted to a POJO directly.
*
*
* See Also:
*
* @param value
* The new value for this property.
*
Ignored if value is null or an empty string.
* @return This object.
*/
public Builder format(String value) {
try {
if (isNotEmpty(value))
format = HttpPartFormat.fromString(value);
} catch (Exception e) {
throw new ContextRuntimeException("Invalid value ''{0}'' passed in as format value. Valid values: {1}", value, HttpPartFormat.values());
}
return this;
}
/**
* Synonym for {@link #format(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder f(String value) {
return format(value);
}
/**
* format field.
*
*
* The extending format for the previously mentioned parameter type.
*
*
* Applicable to the following Swagger schema objects:
*
*
*
* {@link HttpPartFormat}
*
* -
* {@link HttpPartFormat#INT32 INT32} - Signed 32 bits.
*
Only valid with type "integer" .
* -
* {@link HttpPartFormat#INT64 INT64} - Signed 64 bits.
*
Only valid with type "integer" .
* -
* {@link HttpPartFormat#FLOAT FLOAT} - 32-bit floating point number.
*
Only valid with type "number" .
* -
* {@link HttpPartFormat#DOUBLE DOUBLE} - 64-bit floating point number.
*
Only valid with type "number" .
* -
* {@link HttpPartFormat#BYTE BYTE} - BASE-64 encoded characters.
*
Only valid with type "string" .
*
Parameters of type POJO convertible from string are converted after the string has been decoded.
* -
* {@link HttpPartFormat#BINARY BINARY} - Hexadecimal encoded octets (e.g.
"00FF" ).
*
Only valid with type "string" .
*
Parameters of type POJO convertible from string are converted after the string has been decoded.
* -
* {@link HttpPartFormat#BINARY_SPACED BINARY_SPACED} - Hexadecimal encoded octets, spaced (e.g.
"00 FF" ).
*
Only valid with type "string" .
*
Parameters of type POJO convertible from string are converted after the string has been decoded.
* -
* {@link HttpPartFormat#DATE DATE} - An RFC3339 full-date.
*
Only valid with type "string" .
* -
* {@link HttpPartFormat#DATE_TIME DATE_TIME} - An RFC3339 date-time.
*
Only valid with type "string" .
* -
* {@link HttpPartFormat#PASSWORD PASSWORD} - Used to hint UIs the input needs to be obscured.
*
This format does not affect the serialization or parsing of the parameter.
* -
* {@link HttpPartFormat#UON UON} - UON notation (e.g.
"(foo=bar,baz=@(qux,123))" ).
*
Only valid with type "object" .
*
If not specified, then the input is interpreted as plain-text and is converted to a POJO directly.
*
*
*
* See Also:
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder format(HttpPartFormat value) {
format = value;
return this;
}
/**
* Synonym for {@link #format(HttpPartFormat)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder f(HttpPartFormat value) {
return format(value);
}
/**
* Shortcut for format(HttpPartFormat.INT32) .
*
* @return This object.
*/
public Builder fInt32() {
format = HttpPartFormat.INT32;
return this;
}
/**
* Shortcut for format(HttpPartFormat.INT64) .
*
* @return This object.
*/
public Builder fInt64() {
format = HttpPartFormat.INT64;
return this;
}
/**
* Shortcut for format(HttpPartFormat.FLOAT) .
*
* @return This object.
*/
public Builder fFloat() {
format = HttpPartFormat.FLOAT;
return this;
}
/**
* Shortcut for format(HttpPartFormat.DOUBLE) .
*
* @return This object.
*/
public Builder fDouble() {
format = HttpPartFormat.DOUBLE;
return this;
}
/**
* Shortcut for format(HttpPartFormat.BYTE) .
*
* @return This object.
*/
public Builder fByte() {
format = HttpPartFormat.BYTE;
return this;
}
/**
* Shortcut for format(HttpPartFormat.BINARY) .
*
* @return This object.
*/
public Builder fBinary() {
format = HttpPartFormat.BINARY;
return this;
}
/**
* Shortcut for format(HttpPartFormat.BINARY_SPACED) .
*
* @return This object.
*/
public Builder fBinarySpaced() {
format = HttpPartFormat.BINARY_SPACED;
return this;
}
/**
* Shortcut for format(HttpPartFormat.DATE) .
*
* @return This object.
*/
public Builder fDate() {
format = HttpPartFormat.DATE;
return this;
}
/**
* Shortcut for format(HttpPartFormat.DATE_TIME) .
*
* @return This object.
*/
public Builder fDateTime() {
format = HttpPartFormat.DATE_TIME;
return this;
}
/**
* Shortcut for format(HttpPartFormat.PASSWORD) .
*
* @return This object.
*/
public Builder fPassword() {
format = HttpPartFormat.PASSWORD;
return this;
}
/**
* Shortcut for format(HttpPartFormat.UON) .
*
* @return This object.
*/
public Builder fUon() {
format = HttpPartFormat.UON;
return this;
}
/**
* Shortcut for format(HttpPartFormat.NO_FORMAT) .
*
* @return This object.
*/
public Builder fNone() {
format = HttpPartFormat.NO_FORMAT;
return this;
}
/**
* allowEmptyValue field.
*
*
* Sets the ability to pass empty-valued parameters.
*
This is valid only for either query or formData parameters and allows you to send a parameter with a name only or an empty value.
*
The default value is false .
*
*
* Applicable to the following Swagger schema objects:
*
* - Parameter
*
*
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder allowEmptyValue(Boolean value) {
allowEmptyValue = resolve(value, allowEmptyValue);
return this;
}
/**
* Synonym for {@link #allowEmptyValue(Boolean)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder aev(Boolean value) {
return allowEmptyValue(value);
}
/**
* allowEmptyValue field.
*
*
* Same as {@link #allowEmptyValue(Boolean)} but takes in a string boolean value.
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder allowEmptyValue(String value) {
allowEmptyValue = resolve(value, allowEmptyValue);
return this;
}
/**
* Synonym for {@link #allowEmptyValue(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder aev(String value) {
return allowEmptyValue(value);
}
/**
* allowEmptyValue field.
*
*
* Shortcut for calling allowEmptyValue(true );
.
*
* @return This object.
*/
public Builder allowEmptyValue() {
return allowEmptyValue(true);
}
/**
* Synonym for {@link #allowEmptyValue()}.
*
* @return This object.
*/
public Builder aev() {
return allowEmptyValue(true);
}
/**
* items field.
*
*
* Describes the type of items in the array.
*
* Required if type is "array" .
*
Can only be used if type is "array" .
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder items(Builder value) {
if (value != null)
this.items = value;
return this;
}
/**
* Synonym for {@link #items(HttpPartSchema.Builder)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder i(Builder value) {
return items(value);
}
/**
* items field.
*
*
* Describes the type of items in the array.
*
* Required if type is "array" .
*
Can only be used if type is "array" .
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder items(HttpPartSchema value) {
if (value != null)
this.items = value;
return this;
}
/**
* Synonym for {@link #items(HttpPartSchema)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder i(HttpPartSchema value) {
return items(value);
}
Builder items(JsonMap value) {
if (value != null && ! value.isEmpty())
items = HttpPartSchema.create().apply(value);
return this;
}
Builder items(Items value) {
if (! ItemsAnnotation.empty(value))
items = HttpPartSchema.create().apply(value);
return this;
}
Builder items(SubItems value) {
if (! SubItemsAnnotation.empty(value))
items = HttpPartSchema.create().apply(value);
return this;
}
/**
* collectionFormat field.
*
*
* Determines the format of the array if type "array" is used.
*
Can only be used if type is "array" .
*
*
* Applicable to the following Swagger schema objects:
*
*
*
* Note that for collections/arrays parameters with POJO element types, the input is broken into a string array before being converted into POJO elements.
*
*
* -
*
"csv" (default) - Comma-separated values (e.g. "foo,bar" ).
* -
*
"ssv" - Space-separated values (e.g. "foo bar" ).
* -
*
"tsv" - Tab-separated values (e.g. "foo\tbar" ).
* -
*
"pipes - Pipe-separated values (e.g. "foo|bar" ).
* -
*
"multi" - Corresponds to multiple parameter instances instead of multiple values for a single instance (e.g. "foo=bar&foo=baz" ).
* -
*
"uon" - UON notation (e.g. "@(foo,bar)" ).
* -
*
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder collectionFormat(String value) {
try {
if (isNotEmpty(value))
this.collectionFormat = HttpPartCollectionFormat.fromString(value);
} catch (Exception e) {
throw new ContextRuntimeException("Invalid value ''{0}'' passed in as collectionFormat value. Valid values: {1}", value, HttpPartCollectionFormat.values());
}
return this;
}
/**
* Synonym for {@link #collectionFormat(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder cf(String value) {
return collectionFormat(value);
}
/**
* collectionFormat field.
*
*
* Determines the format of the array if type "array" is used.
*
Can only be used if type is "array" .
*
*
* Applicable to the following Swagger schema objects:
*
*
*
* Note that for collections/arrays parameters with POJO element types, the input is broken into a string array before being converted into POJO elements.
*
*
* {@link HttpPartCollectionFormat}
*
* -
* {@link HttpPartCollectionFormat#CSV CSV} (default) - Comma-separated values (e.g.
"foo,bar" ).
* -
* {@link HttpPartCollectionFormat#SSV SSV} - Space-separated values (e.g.
"foo bar" ).
* -
* {@link HttpPartCollectionFormat#TSV TSV} - Tab-separated values (e.g.
"foo\tbar" ).
* -
* {@link HttpPartCollectionFormat#PIPES PIPES} - Pipe-separated values (e.g.
"foo|bar" ).
* -
* {@link HttpPartCollectionFormat#MULTI MULTI} - Corresponds to multiple parameter instances instead of multiple values for a single instance (e.g.
"foo=bar&foo=baz" ).
* -
* {@link HttpPartCollectionFormat#UONC UONC} - UON collection notation (e.g.
"@(foo,bar)" ).
*
*
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder collectionFormat(HttpPartCollectionFormat value) {
collectionFormat = value;
return this;
}
/**
* Synonym for {@link #collectionFormat(HttpPartCollectionFormat)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder cf(HttpPartCollectionFormat value) {
return collectionFormat(value);
}
/**
* Shortcut for collectionFormat(HttpPartCollectionFormat.CSV) .
*
* @return This object.
*/
public Builder cfCsv() {
return collectionFormat(HttpPartCollectionFormat.CSV);
}
/**
* Shortcut for collectionFormat(HttpPartCollectionFormat.SSV) .
*
* @return This object.
*/
public Builder cfSsv() {
return collectionFormat(HttpPartCollectionFormat.SSV);
}
/**
* Shortcut for collectionFormat(HttpPartCollectionFormat.TSV) .
*
* @return This object.
*/
public Builder cfTsv() {
return collectionFormat(HttpPartCollectionFormat.TSV);
}
/**
* Shortcut for collectionFormat(HttpPartCollectionFormat.PIPES) .
*
* @return This object.
*/
public Builder cfPipes() {
return collectionFormat(HttpPartCollectionFormat.PIPES);
}
/**
* Shortcut for collectionFormat(HttpPartCollectionFormat.MULTI) .
*
* @return This object.
*/
public Builder cfMulti() {
return collectionFormat(HttpPartCollectionFormat.MULTI);
}
/**
* Shortcut for collectionFormat(HttpPartCollectionFormat.UONC) .
*
* @return This object.
*/
public Builder cfUon() {
return collectionFormat(HttpPartCollectionFormat.UONC);
}
/**
* Shortcut for collectionFormat(HttpPartCollectionFormat.NO_COLLECTION_FORMAT) .
*
* @return This object.
*/
public Builder cfNone() {
return collectionFormat(HttpPartCollectionFormat.NO_COLLECTION_FORMAT);
}
/**
* default field.
*
*
* Declares the value of the parameter that the server will use if none is provided, for example a "count" to control the number of results per page might default to 100 if not supplied by the client in the request.
*
(Note: "default" has no meaning for required parameters.)
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder _default(String value) {
if (value != null)
this._default = value;
return this;
}
/**
* Synonym for {@link #_default(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder df(String value) {
return _default(value);
}
/**
* maximum field.
*
*
* Defines the maximum value for a parameter of numeric types.
*
*
* Only allowed for the following types: "integer" , "number" .
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder maximum(Number value) {
if (value != null)
this.maximum = value;
return this;
}
/**
* Synonym for {@link #maximum(Number)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder max(Number value) {
return maximum(value);
}
/**
* exclusiveMaximum field.
*
*
* Defines whether the maximum is matched exclusively.
*
*
* Only allowed for the following types: "integer" , "number" .
*
If true , must be accompanied with maximum .
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder exclusiveMaximum(Boolean value) {
exclusiveMaximum = resolve(value, exclusiveMaximum);
return this;
}
/**
* Synonym for {@link #exclusiveMaximum(Boolean)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder emax(Boolean value) {
return exclusiveMaximum(value);
}
/**
* exclusiveMaximum field.
*
*
* Same as {@link #exclusiveMaximum(Boolean)} but takes in a string boolean value.
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder exclusiveMaximum(String value) {
exclusiveMaximum = resolve(value, exclusiveMaximum);
return this;
}
/**
* Synonym for {@link #exclusiveMaximum(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder emax(String value) {
return exclusiveMaximum(value);
}
/**
* exclusiveMaximum field.
*
*
* Shortcut for calling exclusiveMaximum(true );
.
*
* @return This object.
*/
public Builder exclusiveMaximum() {
return exclusiveMaximum(true);
}
/**
* Synonym for {@link #exclusiveMaximum()}.
*
* @return This object.
*/
public Builder emax() {
return exclusiveMaximum();
}
/**
* minimum field.
*
*
* Defines the minimum value for a parameter of numeric types.
*
*
* Only allowed for the following types: "integer" , "number" .
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder minimum(Number value) {
if (value != null)
this.minimum = value;
return this;
}
/**
* Synonym for {@link #minimum(Number)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder min(Number value) {
return minimum(value);
}
/**
* exclusiveMinimum field.
*
*
* Defines whether the minimum is matched exclusively.
*
*
* Only allowed for the following types: "integer" , "number" .
*
If true , must be accompanied with minimum .
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder exclusiveMinimum(Boolean value) {
exclusiveMinimum = resolve(value, exclusiveMinimum);
return this;
}
/**
* Synonym for {@link #exclusiveMinimum(Boolean)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder emin(Boolean value) {
return exclusiveMinimum(value);
}
/**
* exclusiveMinimum field.
*
*
* Same as {@link #exclusiveMinimum(Boolean)} but takes in a string boolean value.
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder exclusiveMinimum(String value) {
exclusiveMinimum = resolve(value, exclusiveMinimum);
return this;
}
/**
* Synonym for {@link #exclusiveMinimum(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder emin(String value) {
return exclusiveMinimum(value);
}
/**
* exclusiveMinimum field.
*
*
* Shortcut for calling exclusiveMinimum(true );
.
*
* @return This object.
*/
public Builder exclusiveMinimum() {
return exclusiveMinimum(true);
}
/**
* Synonym for {@link #exclusiveMinimum()}.
*
* @return This object.
*/
public Builder emin() {
return exclusiveMinimum();
}
/**
* maxLength field.
*
*
* A string instance is valid against this keyword if its length is less than, or equal to, the value of this keyword.
*
The length of a string instance is defined as the number of its characters as defined by RFC 4627.
*
*
* Only allowed for the following types: "string" .
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null or -1 .
* @return This object.
*/
public Builder maxLength(Long value) {
maxLength = resolve(value, maxLength);
return this;
}
/**
* Synonym for {@link #maxLength(Long)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder maxl(Long value) {
return maxLength(value);
}
/**
* maxLength field.
*
*
* Same as {@link #maxLength(Long)} but takes in a string number.
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder maxLength(String value) {
maxLength = resolve(value, maxLength);
return this;
}
/**
* Synonym for {@link #maxLength(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder maxl(String value) {
return maxLength(value);
}
/**
* minLength field.
*
*
* A string instance is valid against this keyword if its length is greater than, or equal to, the value of this keyword.
*
The length of a string instance is defined as the number of its characters as defined by RFC 4627.
*
*
* Only allowed for the following types: "string" .
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null or -1 .
* @return This object.
*/
public Builder minLength(Long value) {
minLength = resolve(value, minLength);
return this;
}
/**
* Synonym for {@link #minLength(Long)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder minl(Long value) {
return minLength(value);
}
/**
* minLength field.
*
*
* Same as {@link #minLength(Long)} but takes in a string number.
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder minLength(String value) {
minLength = resolve(value, minLength);
return this;
}
/**
* Synonym for {@link #minLength(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder minl(String value) {
return minLength(value);
}
/**
* pattern field.
*
*
* A string input is valid if it matches the specified regular expression pattern.
*
*
* Only allowed for the following types: "string" .
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder pattern(String value) {
try {
if (isNotEmpty(value))
this.pattern = Pattern.compile(value);
} catch (Exception e) {
throw new ContextRuntimeException(e, "Invalid value {0} passed in as pattern value. Must be a valid regular expression.", value);
}
return this;
}
/**
* Synonym for {@link #pattern(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder p(String value) {
return pattern(value);
}
/**
* maxItems field.
*
*
* An array or collection is valid if its size is less than, or equal to, the value of this keyword.
*
*
* Only allowed for the following types: "array" .
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null or -1 .
* @return This object.
*/
public Builder maxItems(Long value) {
maxItems = resolve(value, maxItems);
return this;
}
/**
* Synonym for {@link #maxItems(Long)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder maxi(Long value) {
return maxItems(value);
}
/**
* maxItems field.
*
*
* Same as {@link #maxItems(Long)} but takes in a string number.
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder maxItems(String value) {
maxItems = resolve(value, maxItems);
return this;
}
/**
* Synonym for {@link #maxItems(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder maxi(String value) {
return maxItems(value);
}
/**
* minItems field.
*
*
* An array or collection is valid if its size is greater than, or equal to, the value of this keyword.
*
*
* Only allowed for the following types: "array" .
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null or -1 .
* @return This object.
*/
public Builder minItems(Long value) {
minItems = resolve(value, minItems);
return this;
}
/**
* Synonym for {@link #minItems(Long)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder mini(Long value) {
return minItems(value);
}
/**
* minItems field.
*
*
* Same as {@link #minItems(Long)} but takes in a string number.
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder minItems(String value) {
minItems = resolve(value, minItems);
return this;
}
/**
* Synonym for {@link #minItems(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder mini(String value) {
return minItems(value);
}
/**
* uniqueItems field.
*
*
* If true , the input validates successfully if all of its elements are unique.
*
*
*
If the parameter type is a subclass of {@link Set}, this validation is skipped (since a set can only contain unique items anyway).
*
Otherwise, the collection or array is checked for duplicate items.
*
*
* Only allowed for the following types: "array" .
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder uniqueItems(Boolean value) {
uniqueItems = resolve(value, uniqueItems);
return this;
}
/**
* Synonym for {@link #uniqueItems(Boolean)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder ui(Boolean value) {
return uniqueItems(value);
}
/**
* uniqueItems field.
*
*
* Same as {@link #uniqueItems(Boolean)} but takes in a string boolean.
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty..
* @return This object.
*/
public Builder uniqueItems(String value) {
uniqueItems = resolve(value, uniqueItems);
return this;
}
/**
* Synonym for {@link #uniqueItems(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder ui(String value) {
return uniqueItems(value);
}
/**
* uniqueItems field.
*
*
* Shortcut for calling uniqueItems(true );
.
*
* @return This object.
*/
public Builder uniqueItems() {
return uniqueItems(true);
}
/**
* Synonym for {@link #uniqueItems()}.
*
* @return This object.
*/
public Builder ui() {
return uniqueItems();
}
/**
* skipIfEmpty field.
*
*
* Identifies whether an item should be skipped during serialization if it's empty.
*
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder skipIfEmpty(Boolean value) {
skipIfEmpty = resolve(value, skipIfEmpty);
return this;
}
/**
* Synonym for {@link #skipIfEmpty(Boolean)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder sie(Boolean value) {
return skipIfEmpty(value);
}
/**
* skipIfEmpty field.
*
*
* Same as {@link #skipIfEmpty(Boolean)} but takes in a string boolean.
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder skipIfEmpty(String value) {
skipIfEmpty = resolve(value, skipIfEmpty);
return this;
}
/**
* Synonym for {@link #skipIfEmpty(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder sie(String value) {
return skipIfEmpty(value);
}
/**
* Identifies whether an item should be skipped if it's empty.
*
*
* Shortcut for calling skipIfEmpty(true );
.
*
* @return This object.
*/
public Builder skipIfEmpty() {
return skipIfEmpty(true);
}
/**
* Synonym for {@link #skipIfEmpty()}.
*
* @return This object.
*/
public Builder sie() {
return skipIfEmpty();
}
/**
* enum field.
*
*
* If specified, the input validates successfully if it is equal to one of the elements in this array.
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null or an empty set.
* @return This object.
*/
public Builder _enum(Set value) {
if (value != null && ! value.isEmpty())
this._enum = value;
return this;
}
/**
* Synonym for {@link #_enum(Set)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder e(Set value) {
return _enum(value);
}
/**
* _enum field.
*
*
* Same as {@link #_enum(Set)} but takes in a var-args array.
*
* @param values
* The new values for this property.
*
Ignored if value is empty.
* @return This object.
*/
public Builder _enum(String...values) {
return _enum(set(values));
}
/**
* Synonym for {@link #_enum(String...)}.
*
* @param values
* The new values for this property.
* @return This object.
*/
public Builder e(String...values) {
return _enum(values);
}
/**
* multipleOf field.
*
*
* A numeric instance is valid if the result of the division of the instance by this keyword's value is an integer.
*
*
* Only allowed for the following types: "integer" , "number" .
*
*
* Applicable to the following Swagger schema objects:
*
*
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder multipleOf(Number value) {
if (value != null)
this.multipleOf = value;
return this;
}
/**
* Synonym for {@link #multipleOf(Number)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder mo(Number value) {
return multipleOf(value);
}
/**
* mapProperties field.
*
*
* Applicable to the following Swagger schema objects:
*
* - Schema
*
*
* @param value
* The new value for this property.
*
Ignored if value is null or -1 .
* @return This object.
*/
public Builder maxProperties(Long value) {
maxProperties = resolve(value, maxProperties);
return this;
}
/**
* Synonym for {@link #maxProperties(Long)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder maxp(Long value) {
return maxProperties(value);
}
/**
* mapProperties field.
*
*
* Same as {@link #maxProperties(Long)} but takes in a string number.
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder maxProperties(String value) {
maxProperties = resolve(value, maxProperties);
return this;
}
/**
* Synonym for {@link #maxProperties(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder maxp(String value) {
return maxProperties(value);
}
/**
* minProperties field.
*
*
* Applicable to the following Swagger schema objects:
*
* - Schema
*
*
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder minProperties(Long value) {
minProperties = resolve(value, minProperties);
return this;
}
/**
* Synonym for {@link #minProperties(Long)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder minp(Long value) {
return minProperties(value);
}
/**
* minProperties field.
*
*
* Same as {@link #minProperties(Long)} but takes in a string boolean.
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder minProperties(String value) {
minProperties = resolve(value, minProperties);
return this;
}
/**
* Synonym for {@link #minProperties(String)}.
*
* @param value
* The new value for this property.
* @return This object.
*/
public Builder minp(String value) {
return minProperties(value);
}
/**
* properties field.
*
*
* Applicable to the following Swagger schema objects:
*
* - Schema
*
*
* @param key
* The property name.
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder property(String key, Builder value) {
if ( key != null && value != null) {
if (properties == null)
properties = map();
properties.put(key, value);
}
return this;
}
/**
* properties field.
*
*
* Applicable to the following Swagger schema objects:
*
* - Schema
*
*
* @param key
* The property name.
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder property(String key, HttpPartSchema value) {
if ( key != null && value != null) {
if (properties == null)
properties = map();
properties.put(key, value);
}
return this;
}
/**
* Shortcut for property(key, value) .
*
*
* Applicable to the following Swagger schema objects:
*
* - Schema
*
*
* @param key
* The property name.
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder p(String key, Builder value) {
return property(key, value);
}
/**
* Shortcut for property(key, value) .
*
*
* Applicable to the following Swagger schema objects:
*
* - Schema
*
*
* @param key
* The property name.
* @param value
* The new value for this property.
*
Ignored if value is null .
* @return This object.
*/
public Builder p(String key, HttpPartSchema value) {
return property(key, value);
}
private Builder properties(JsonMap value) {
if (value != null)
value.forEach((k,v) -> property(k, HttpPartSchema.create().apply((JsonMap)v)));
return this;
}
/**
* additionalProperties field.
*
*
* Applicable to the following Swagger schema objects:
*
* - Schema
*
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder additionalProperties(Builder value) {
if (value != null)
additionalProperties = value;
return this;
}
/**
* additionalProperties field.
*
*
* Applicable to the following Swagger schema objects:
*
* - Schema
*
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder additionalProperties(HttpPartSchema value) {
if (value != null)
additionalProperties = value;
return this;
}
/**
* Shortcut for additionalProperties(value)
*
*
* Applicable to the following Swagger schema objects:
*
* - Schema
*
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder ap(Builder value) {
return additionalProperties(value);
}
/**
* Shortcut for additionalProperties(value)
*
*
* Applicable to the following Swagger schema objects:
*
* - Schema
*
*
* @param value
* The new value for this property.
*
Ignored if value is null or empty.
* @return This object.
*/
public Builder ap(HttpPartSchema value) {
return additionalProperties(value);
}
private Builder additionalProperties(JsonMap value) {
if (value != null && ! value.isEmpty())
additionalProperties = HttpPartSchema.create().apply(value);
return this;
}
/**
* Identifies the part serializer to use for serializing this part.
*
* @param value
* The new value for this property.
*
Ignored if value is null or {@link HttpPartSerializer.Void}.
* @return This object.
*/
public Builder serializer(Class extends HttpPartSerializer> value) {
if (isNotVoid(value))
serializer = value;
return this;
}
/**
* Identifies the part parser to use for parsing this part.
*
* @param value
* The new value for this property.
*
Ignored if value is null or {@link HttpPartParser.Void}.
* @return This object.
*/
public Builder parser(Class extends HttpPartParser> value) {
if (isNotVoid(value))
parser = value;
return this;
}
/**
* Disables Swagger schema usage validation checking.
*
* @param value Specify true to prevent {@link ContextRuntimeException} from being thrown if invalid Swagger usage was detected.
* @return This object.
*/
public Builder noValidate(Boolean value) {
if (value != null)
this.noValidate = value;
return this;
}
/**
* Disables Swagger schema usage validation checking.
*
*
* Shortcut for calling noValidate(true );
.
*
* @return This object.
*/
public Builder noValidate() {
return noValidate(true);
}
private Boolean resolve(String newValue, Boolean oldValue) {
return isEmpty(newValue) ? oldValue : Boolean.valueOf(newValue);
}
private Boolean resolve(Boolean newValue, Boolean oldValue) {
return newValue == null ? oldValue : newValue;
}
private Long resolve(String newValue, Long oldValue) {
return isEmpty(newValue) ? oldValue : Long.parseLong(newValue);
}
private Long resolve(Long newValue, Long oldValue) {
return (newValue == null || newValue == -1) ? oldValue : newValue;
}
private Set toSet(String[]...s) {
return HttpPartSchema.toSet(s);
}
private Number toNumber(String...s) {
return HttpPartSchema.toNumber(s);
}
private Long firstNmo(Long...l) {
for (Long ll : l)
if (ll != null && ll != -1)
return ll;
return null;
}
private String joinnlOrNull(String[]...s) {
for (String[] ss : s)
if (ss.length > 0)
return joinnl(ss);
return null;
}
}
//-------------------------------------------------------------------------------------------------------------------
// Instance
//-------------------------------------------------------------------------------------------------------------------
final String name;
final String _default;
final Set _enum;
final Map properties;
final boolean allowEmptyValue, exclusiveMaximum, exclusiveMinimum, required, uniqueItems, skipIfEmpty;
final HttpPartCollectionFormat collectionFormat;
final HttpPartDataType type;
final HttpPartFormat format;
final Pattern pattern;
final HttpPartSchema items, additionalProperties;
final Number maximum, minimum, multipleOf;
final Long maxLength, minLength, maxItems, minItems, maxProperties, minProperties;
final Class extends HttpPartParser> parser;
final Class extends HttpPartSerializer> serializer;
final ClassMeta> parsedType;
HttpPartSchema(Builder b) {
this.name = b.name;
this._default = b._default;
this._enum = copy(b._enum);
this.properties = build(b.properties, b.noValidate);
this.allowEmptyValue = resolve(b.allowEmptyValue);
this.exclusiveMaximum = resolve(b.exclusiveMaximum);
this.exclusiveMinimum = resolve(b.exclusiveMinimum);
this.required = resolve(b.required);
this.uniqueItems = resolve(b.uniqueItems);
this.skipIfEmpty = resolve(b.skipIfEmpty);
this.collectionFormat = b.collectionFormat;
this.type = b.type;
this.format = b.format;
this.pattern = b.pattern;
this.items = build(b.items, b.noValidate);
this.additionalProperties = build(b.additionalProperties, b.noValidate);
this.maximum = b.maximum;
this.minimum = b.minimum;
this.multipleOf = b.multipleOf;
this.maxItems = b.maxItems;
this.maxLength = b.maxLength;
this.maxProperties = b.maxProperties;
this.minItems = b.minItems;
this.minLength = b.minLength;
this.minProperties = b.minProperties;
this.parser = b.parser;
this.serializer = b.serializer;
// Calculate parse type
Class> parsedType = Object.class;
if (type == ARRAY) {
if (items != null)
parsedType = Array.newInstance(items.parsedType.getInnerClass(), 0).getClass();
} else if (type == BOOLEAN) {
parsedType = Boolean.class;
} else if (type == INTEGER) {
if (format == INT64)
parsedType = Long.class;
else
parsedType = Integer.class;
} else if (type == NUMBER) {
if (format == DOUBLE)
parsedType = Double.class;
else
parsedType = Float.class;
} else if (type == STRING) {
if (format == BYTE || format == BINARY || format == BINARY_SPACED)
parsedType = byte[].class;
else if (format == DATE || format == DATE_TIME)
parsedType = Calendar.class;
else
parsedType = String.class;
}
this.parsedType = BeanContext.DEFAULT.getClassMeta(parsedType);
if (b.noValidate)
return;
// Validation.
List errors = list();
ListBuilder notAllowed = listBuilder(String.class);
boolean invalidFormat = false;
switch (type) {
case STRING: {
notAllowed
.addIf(properties != null, "properties")
.addIf(additionalProperties != null, "additionalProperties")
.addIf(exclusiveMaximum, "exclusiveMaximum")
.addIf(exclusiveMinimum, "exclusiveMinimum")
.addIf(uniqueItems, "uniqueItems")
.addIf(collectionFormat != HttpPartCollectionFormat.NO_COLLECTION_FORMAT, "collectionFormat")
.addIf(items != null, "items")
.addIf(maximum != null, "maximum")
.addIf(minimum != null, "minimum")
.addIf(multipleOf != null, "multipleOf")
.addIf(maxItems != null, "maxItems")
.addIf(minItems != null, "minItems")
.addIf(minProperties != null, "minProperties");
invalidFormat = ! format.isOneOf(HttpPartFormat.BYTE, HttpPartFormat.BINARY, HttpPartFormat.BINARY_SPACED, HttpPartFormat.DATE, HttpPartFormat.DATE_TIME, HttpPartFormat.PASSWORD, HttpPartFormat.UON, HttpPartFormat.NO_FORMAT);
break;
}
case ARRAY: {
notAllowed.addIf(properties != null, "properties")
.addIf(additionalProperties != null, "additionalProperties")
.addIf(exclusiveMaximum, "exclusiveMaximum")
.addIf(exclusiveMinimum, "exclusiveMinimum")
.addIf(pattern != null, "pattern")
.addIf(maximum != null, "maximum")
.addIf(minimum != null, "minimum")
.addIf(multipleOf != null, "multipleOf")
.addIf(maxLength != null, "maxLength")
.addIf(minLength != null, "minLength")
.addIf(maxProperties != null, "maxProperties")
.addIf(minProperties != null, "minProperties");
invalidFormat = ! format.isOneOf(HttpPartFormat.NO_FORMAT, HttpPartFormat.UON);
break;
}
case BOOLEAN: {
notAllowed.addIf(! _enum.isEmpty(), "_enum")
.addIf(properties != null, "properties")
.addIf(additionalProperties != null, "additionalProperties")
.addIf(exclusiveMaximum, "exclusiveMaximum")
.addIf(exclusiveMinimum, "exclusiveMinimum")
.addIf(uniqueItems, "uniqueItems")
.addIf(collectionFormat != HttpPartCollectionFormat.NO_COLLECTION_FORMAT, "collectionFormat")
.addIf(pattern != null, "pattern")
.addIf(items != null, "items")
.addIf(maximum != null, "maximum")
.addIf(minimum != null, "minimum")
.addIf(multipleOf != null, "multipleOf")
.addIf(maxItems != null, "maxItems")
.addIf(maxLength != null, "maxLength")
.addIf(maxProperties != null, "maxProperties")
.addIf(minItems != null, "minItems")
.addIf(minLength != null, "minLength")
.addIf(minProperties != null, "minProperties");
invalidFormat = ! format.isOneOf(HttpPartFormat.NO_FORMAT, HttpPartFormat.UON);
break;
}
case FILE: {
break;
}
case INTEGER: {
notAllowed.addIf(properties != null, "properties")
.addIf(additionalProperties != null, "additionalProperties")
.addIf(uniqueItems, "uniqueItems")
.addIf(collectionFormat != HttpPartCollectionFormat.NO_COLLECTION_FORMAT, "collectionFormat")
.addIf(pattern != null, "pattern")
.addIf(items != null, "items")
.addIf(maxItems != null, "maxItems")
.addIf(maxLength != null, "maxLength")
.addIf(maxProperties != null, "maxProperties")
.addIf(minItems != null, "minItems")
.addIf(minLength != null, "minLength")
.addIf(minProperties != null, "minProperties");
invalidFormat = ! format.isOneOf(HttpPartFormat.NO_FORMAT, HttpPartFormat.UON, HttpPartFormat.INT32, HttpPartFormat.INT64);
break;
}
case NUMBER: {
notAllowed.addIf(properties != null, "properties")
.addIf(additionalProperties != null, "additionalProperties")
.addIf(uniqueItems, "uniqueItems")
.addIf(collectionFormat != HttpPartCollectionFormat.NO_COLLECTION_FORMAT, "collectionFormat")
.addIf(pattern != null, "pattern")
.addIf(items != null, "items")
.addIf(maxItems != null, "maxItems")
.addIf(maxLength != null, "maxLength")
.addIf(maxProperties != null, "maxProperties")
.addIf(minItems != null, "minItems")
.addIf(minLength != null, "minLength")
.addIf(minProperties != null, "minProperties");
invalidFormat = ! format.isOneOf(HttpPartFormat.NO_FORMAT, HttpPartFormat.UON, HttpPartFormat.FLOAT, HttpPartFormat.DOUBLE);
break;
}
case OBJECT: {
notAllowed.addIf(exclusiveMaximum, "exclusiveMaximum")
.addIf(exclusiveMinimum, "exclusiveMinimum")
.addIf(uniqueItems, "uniqueItems")
.addIf(pattern != null, "pattern")
.addIf(items != null, "items")
.addIf(maximum != null, "maximum")
.addIf(minimum != null, "minimum")
.addIf(multipleOf != null, "multipleOf")
.addIf(maxItems != null, "maxItems")
.addIf(maxLength != null, "maxLength")
.addIf(minItems != null, "minItems")
.addIf(minLength != null, "minLength");
invalidFormat = ! format.isOneOf(HttpPartFormat.NO_FORMAT);
break;
}
default:
break;
}
List notAllowed2 = notAllowed.build();
if (! notAllowed2.isEmpty())
errors.add("Attributes not allow for type='"+type+"': " + StringUtils.join(notAllowed2, ","));
if (invalidFormat)
errors.add("Invalid format for type='"+type+"': '"+format+"'");
if (exclusiveMaximum && maximum == null)
errors.add("Cannot specify exclusiveMaximum with maximum.");
if (exclusiveMinimum && minimum == null)
errors.add("Cannot specify exclusiveMinimum with minimum.");
if (required && _default != null)
errors.add("Cannot specify a default value on a required value.");
if (minLength != null && maxLength != null && maxLength < minLength)
errors.add("maxLength cannot be less than minLength.");
if (minimum != null && maximum != null && maximum.doubleValue() < minimum.doubleValue())
errors.add("maximum cannot be less than minimum.");
if (minItems != null && maxItems != null && maxItems < minItems)
errors.add("maxItems cannot be less than minItems.");
if (minProperties != null && maxProperties != null && maxProperties < minProperties)
errors.add("maxProperties cannot be less than minProperties.");
if (minLength != null && minLength < 0)
errors.add("minLength cannot be less than zero.");
if (maxLength != null && maxLength < 0)
errors.add("maxLength cannot be less than zero.");
if (minItems != null && minItems < 0)
errors.add("minItems cannot be less than zero.");
if (maxItems != null && maxItems < 0)
errors.add("maxItems cannot be less than zero.");
if (minProperties != null && minProperties < 0)
errors.add("minProperties cannot be less than zero.");
if (maxProperties != null && maxProperties < 0)
errors.add("maxProperties cannot be less than zero.");
if (type == ARRAY && items != null && items.getType() == OBJECT && (format != UON && format != HttpPartFormat.NO_FORMAT))
errors.add("Cannot define an array of objects unless array format is 'uon'.");
if (! errors.isEmpty())
throw new ContextRuntimeException("Schema specification errors: \n\t" + join(errors, "\n\t"), new Object[0]);
}
/**
* Returns the default parsed type for this schema.
*
* @return The default parsed type for this schema. Never null .
*/
public ClassMeta> getParsedType() {
return parsedType;
}
/**
* Returns the name of the object described by this schema, for example the query or form parameter name.
*
* @return The name, or null if not specified.
* @see HttpPartSchema.Builder#name(String)
*/
public String getName() {
return name;
}
/**
* Returns the type field of this schema.
*
* @return The type field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#type(String)
*/
public HttpPartDataType getType() {
return type;
}
/**
* Returns the type field of this schema.
*
* @param cm
* The class meta of the object.
*
Used to auto-detect the type if the type was not specified.
* @return The format field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#format(String)
*/
public HttpPartDataType getType(ClassMeta> cm) {
if (type != HttpPartDataType.NO_TYPE)
return type;
if (cm.isTemporal() || cm.isDateOrCalendar())
return HttpPartDataType.STRING;
if (cm.isNumber()) {
if (cm.isDecimal())
return HttpPartDataType.NUMBER;
return HttpPartDataType.INTEGER;
}
if (cm.isBoolean())
return HttpPartDataType.BOOLEAN;
if (cm.isMapOrBean())
return HttpPartDataType.OBJECT;
if (cm.isCollectionOrArray())
return HttpPartDataType.ARRAY;
return HttpPartDataType.STRING;
}
/**
* Returns the default field of this schema.
*
* @return The default value for this schema, or null if not specified.
* @see HttpPartSchema.Builder#_default(String)
*/
public String getDefault() {
return _default;
}
/**
* Returns the collectionFormat field of this schema.
*
* @return The collectionFormat field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#collectionFormat(String)
*/
public HttpPartCollectionFormat getCollectionFormat() {
return collectionFormat;
}
/**
* Returns the format field of this schema.
*
* @see HttpPartSchema.Builder#format(String)
* @return The format field of this schema, or null if not specified.
*/
public HttpPartFormat getFormat() {
return format;
}
/**
* Returns the format field of this schema.
*
* @param cm
* The class meta of the object.
*
Used to auto-detect the format if the format was not specified.
* @return The format field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#format(String)
*/
public HttpPartFormat getFormat(ClassMeta> cm) {
if (format != HttpPartFormat.NO_FORMAT)
return format;
if (cm.isNumber()) {
if (cm.isDecimal()) {
if (cm.isDouble())
return HttpPartFormat.DOUBLE;
return HttpPartFormat.FLOAT;
}
if (cm.isLong())
return HttpPartFormat.INT64;
return HttpPartFormat.INT32;
}
return format;
}
/**
* Returns the maximum field of this schema.
*
* @return The schema for child items of the object represented by this schema, or null if not defined.
* @see HttpPartSchema.Builder#items(HttpPartSchema.Builder)
*/
public HttpPartSchema getItems() {
return items;
}
/**
* Returns the maximum field of this schema.
*
* @return The maximum field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#maximum(Number)
*/
public Number getMaximum() {
return maximum;
}
/**
* Returns the minimum field of this schema.
*
* @return The minimum field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#minimum(Number)
*/
public Number getMinimum() {
return minimum;
}
/**
* Returns the xxx field of this schema.
*
* @return The xxx field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#multipleOf(Number)
*/
public Number getMultipleOf() {
return multipleOf;
}
/**
* Returns the xxx field of this schema.
*
* @return The xxx field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#pattern(String)
*/
public Pattern getPattern() {
return pattern;
}
/**
* Returns the xxx field of this schema.
*
* @return The xxx field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#maxLength(Long)
*/
public Long getMaxLength() {
return maxLength;
}
/**
* Returns the xxx field of this schema.
*
* @return The xxx field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#minLength(Long)
*/
public Long getMinLength() {
return minLength;
}
/**
* Returns the xxx field of this schema.
*
* @return The xxx field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#maxItems(Long)
*/
public Long getMaxItems() {
return maxItems;
}
/**
* Returns the xxx field of this schema.
*
* @return The xxx field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#minItems(Long)
*/
public Long getMinItems() {
return minItems;
}
/**
* Returns the xxx field of this schema.
*
* @return The xxx field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#maxProperties(Long)
*/
public Long getMaxProperties() {
return maxProperties;
}
/**
* Returns the xxx field of this schema.
*
* @return The xxx field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#minProperties(Long)
*/
public Long getMinProperties() {
return minProperties;
}
/**
* Returns the exclusiveMaximum field of this schema.
*
* @return The exclusiveMaximum field of this schema.
* @see HttpPartSchema.Builder#exclusiveMaximum(Boolean)
*/
public boolean isExclusiveMaximum() {
return exclusiveMaximum;
}
/**
* Returns the exclusiveMinimum field of this schema.
*
* @return The exclusiveMinimum field of this schema.
* @see HttpPartSchema.Builder#exclusiveMinimum(Boolean)
*/
public boolean isExclusiveMinimum() {
return exclusiveMinimum;
}
/**
* Returns the uniqueItems field of this schema.
*
* @return The uniqueItems field of this schema.
* @see HttpPartSchema.Builder#uniqueItems(Boolean)
*/
public boolean isUniqueItems() {
return uniqueItems;
}
/**
* Returns the required field of this schema.
*
* @return The required field of this schema.
* @see HttpPartSchema.Builder#required(Boolean)
*/
public boolean isRequired() {
return required;
}
/**
* Returns the skipIfEmpty field of this schema.
*
* @return The skipIfEmpty field of this schema.
* @see HttpPartSchema.Builder#skipIfEmpty(Boolean)
*/
public boolean isSkipIfEmpty() {
return skipIfEmpty;
}
/**
* Returns the allowEmptyValue field of this schema.
*
* @return The skipIfEmpty field of this schema.
* @see HttpPartSchema.Builder#skipIfEmpty(Boolean)
*/
public boolean isAllowEmptyValue() {
return allowEmptyValue;
}
/**
* Returns the enum field of this schema.
*
* @return The enum field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#_enum(Set)
*/
public Set getEnum() {
return _enum;
}
/**
* Returns the parser field of this schema.
*
* @return The parser field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#parser(Class)
*/
public Class extends HttpPartParser> getParser() {
return parser;
}
/**
* Returns the serializer field of this schema.
*
* @return The serializer field of this schema, or null if not specified.
* @see HttpPartSchema.Builder#serializer(Class)
*/
public Class extends HttpPartSerializer> getSerializer() {
return serializer;
}
/**
* Throws a {@link ParseException} if the specified pre-parsed input does not validate against this schema.
*
* @param in The input.
* @return The same object passed in.
* @throws SchemaValidationException if the specified pre-parsed input does not validate against this schema.
*/
public String validateInput(String in) throws SchemaValidationException {
if (! isValidRequired(in))
throw new SchemaValidationException("No value specified.");
if (in != null) {
if (! isValidAllowEmpty(in))
throw new SchemaValidationException("Empty value not allowed.");
if (! isValidPattern(in))
throw new SchemaValidationException("Value does not match expected pattern. Must match pattern: {0}", pattern.pattern());
if (! isValidEnum(in))
throw new SchemaValidationException("Value does not match one of the expected values. Must be one of the following: {0}", cdl(_enum));
if (! isValidMaxLength(in))
throw new SchemaValidationException("Maximum length of value exceeded.");
if (! isValidMinLength(in))
throw new SchemaValidationException("Minimum length of value not met.");
}
return in;
}
/**
* Throws a {@link ParseException} if the specified parsed output does not validate against this schema.
*
* @param The return type.
* @param o The parsed output.
* @param bc The bean context used to detect POJO types.
* @return The same object passed in.
* @throws SchemaValidationException if the specified parsed output does not validate against this schema.
*/
public T validateOutput(T o, BeanContext bc) throws SchemaValidationException {
if (o == null) {
if (! isValidRequired(o))
throw new SchemaValidationException("Required value not provided.");
return o;
}
ClassMeta> cm = bc.getClassMetaForObject(o);
switch (getType(cm)) {
case ARRAY: {
if (cm.isArray()) {
if (! isValidMinItems(o))
throw new SchemaValidationException("Minimum number of items not met.");
if (! isValidMaxItems(o))
throw new SchemaValidationException("Maximum number of items exceeded.");
if (! isValidUniqueItems(o))
throw new SchemaValidationException("Duplicate items not allowed.");
HttpPartSchema items = getItems();
if (items != null)
for (int i = 0; i < Array.getLength(o); i++)
items.validateOutput(Array.get(o, i), bc);
} else if (cm.isCollection()) {
Collection> c = (Collection>)o;
if (! isValidMinItems(c))
throw new SchemaValidationException("Minimum number of items not met.");
if (! isValidMaxItems(c))
throw new SchemaValidationException("Maximum number of items exceeded.");
if (! isValidUniqueItems(c))
throw new SchemaValidationException("Duplicate items not allowed.");
HttpPartSchema items = getItems();
if (items != null)
c.forEach(x -> items.validateOutput(x, bc));
}
break;
}
case INTEGER: {
if (cm.isNumber()) {
Number n = (Number)o;
if (! isValidMinimum(n))
throw new SchemaValidationException("Minimum value not met.");
if (! isValidMaximum(n))
throw new SchemaValidationException("Maximum value exceeded.");
if (! isValidMultipleOf(n))
throw new SchemaValidationException("Multiple-of not met.");
}
break;
}
case NUMBER: {
if (cm.isNumber()) {
Number n = (Number)o;
if (! isValidMinimum(n))
throw new SchemaValidationException("Minimum value not met.");
if (! isValidMaximum(n))
throw new SchemaValidationException("Maximum value exceeded.");
if (! isValidMultipleOf(n))
throw new SchemaValidationException("Multiple-of not met.");
}
break;
}
case OBJECT: {
if (cm.isMapOrBean()) {
Map,?> m = cm.isMap() ? (Map,?>)o : bc.toBeanMap(o);
if (! isValidMinProperties(m))
throw new SchemaValidationException("Minimum number of properties not met.");
if (! isValidMaxProperties(m))
throw new SchemaValidationException("Maximum number of properties exceeded.");
m.forEach((k,v) -> {
String key = k.toString();
HttpPartSchema s2 = getProperty(key);
if (s2 != null)
s2.validateOutput(v, bc);
});
} else if (cm.isBean()) {
}
break;
}
case BOOLEAN:
case FILE:
case STRING:
case NO_TYPE:
break;
}
return o;
}
//-----------------------------------------------------------------------------------------------------------------
// Helper methods.
//-----------------------------------------------------------------------------------------------------------------
private boolean isValidRequired(Object x) {
return x != null || ! required;
}
private boolean isValidMinProperties(Map,?> x) {
return minProperties == null || x.size() >= minProperties;
}
private boolean isValidMaxProperties(Map,?> x) {
return maxProperties == null || x.size() <= maxProperties;
}
private boolean isValidMinimum(Number x) {
if (x instanceof Integer || x instanceof AtomicInteger)
return minimum == null || x.intValue() > minimum.intValue() || (x.intValue() == minimum.intValue() && (! exclusiveMinimum));
if (x instanceof Short || x instanceof Byte)
return minimum == null || x.shortValue() > minimum.shortValue() || (x.intValue() == minimum.shortValue() && (! exclusiveMinimum));
if (x instanceof Long || x instanceof AtomicLong || x instanceof BigInteger)
return minimum == null || x.longValue() > minimum.longValue() || (x.intValue() == minimum.longValue() && (! exclusiveMinimum));
if (x instanceof Float)
return minimum == null || x.floatValue() > minimum.floatValue() || (x.floatValue() == minimum.floatValue() && (! exclusiveMinimum));
if (x instanceof Double || x instanceof BigDecimal)
return minimum == null || x.doubleValue() > minimum.doubleValue() || (x.doubleValue() == minimum.doubleValue() && (! exclusiveMinimum));
return true;
}
private boolean isValidMaximum(Number x) {
if (x instanceof Integer || x instanceof AtomicInteger)
return maximum == null || x.intValue() < maximum.intValue() || (x.intValue() == maximum.intValue() && (! exclusiveMaximum));
if (x instanceof Short || x instanceof Byte)
return maximum == null || x.shortValue() < maximum.shortValue() || (x.intValue() == maximum.shortValue() && (! exclusiveMaximum));
if (x instanceof Long || x instanceof AtomicLong || x instanceof BigInteger)
return maximum == null || x.longValue() < maximum.longValue() || (x.intValue() == maximum.longValue() && (! exclusiveMaximum));
if (x instanceof Float)
return maximum == null || x.floatValue() < maximum.floatValue() || (x.floatValue() == maximum.floatValue() && (! exclusiveMaximum));
if (x instanceof Double || x instanceof BigDecimal)
return maximum == null || x.doubleValue() < maximum.doubleValue() || (x.doubleValue() == maximum.doubleValue() && (! exclusiveMaximum));
return true;
}
private boolean isValidMultipleOf(Number x) {
if (x instanceof Integer || x instanceof AtomicInteger)
return multipleOf == null || x.intValue() % multipleOf.intValue() == 0;
if (x instanceof Short || x instanceof Byte)
return multipleOf == null || x.shortValue() % multipleOf.shortValue() == 0;
if (x instanceof Long || x instanceof AtomicLong || x instanceof BigInteger)
return multipleOf == null || x.longValue() % multipleOf.longValue() == 0;
if (x instanceof Float)
return multipleOf == null || x.floatValue() % multipleOf.floatValue() == 0;
if (x instanceof Double || x instanceof BigDecimal)
return multipleOf == null || x.doubleValue() % multipleOf.doubleValue() == 0;
return true;
}
private boolean isValidAllowEmpty(String x) {
return allowEmptyValue || isNotEmpty(x);
}
private boolean isValidPattern(String x) {
return pattern == null || pattern.matcher(x).matches();
}
private boolean isValidEnum(String x) {
return _enum.isEmpty() || _enum.contains(x);
}
private boolean isValidMinLength(String x) {
return minLength == null || x.length() >= minLength;
}
private boolean isValidMaxLength(String x) {
return maxLength == null || x.length() <= maxLength;
}
private boolean isValidMinItems(Object x) {
return minItems == null || Array.getLength(x) >= minItems;
}
private boolean isValidMaxItems(Object x) {
return maxItems == null || Array.getLength(x) <= maxItems;
}
private boolean isValidUniqueItems(Object x) {
if (uniqueItems) {
Set