in core/src/main/java/com/alibaba/fastjson2/schema/JSONSchema.java [375:640]
public static JSONSchema of(JSONObject input, JSONSchema parent) {
if (input.size() == 1 && input.isArray("type")) {
JSONArray types = input.getJSONArray("type");
JSONSchema[] items = new JSONSchema[types.size()];
for (int i = 0; i < types.size(); i++) {
items[i] = JSONSchema.of(JSONObject.of("type", types.get(i)));
}
return new AnyOf(items);
}
Type type = Type.of(
input.getString("type")
);
if (type == null) {
Object[] enums = input.getObject("enum", Object[].class);
if (enums != null) {
boolean nonString = false;
for (Object anEnum : enums) {
if (!(anEnum instanceof String)) {
nonString = true;
break;
}
}
if (!nonString) {
return new StringSchema(input);
}
return new EnumSchema(enums);
}
Object constValue = input.get("const");
if (constValue instanceof String) {
return new StringSchema(input);
} else if (constValue instanceof Integer || constValue instanceof Long) {
return new IntegerSchema(input);
}
if (input.size() == 1) {
String ref = input.getString("$ref");
if (ref != null && !ref.isEmpty()) {
if ("http://json-schema.org/draft-04/schema#".equals(ref)) {
JSONSchema schema = CACHE.get(ref);
if (schema == null) {
URL draf4Resource = JSONSchema.class.getClassLoader().getResource("schema/draft-04.json");
schema = JSONSchema.of(
JSON.parseObject(draf4Resource),
(JSONSchema) null
);
JSONSchema origin = CACHE.putIfAbsent(ref, schema);
if (origin != null) {
schema = origin;
}
}
return schema;
}
if ("#".equals(ref)) {
return parent;
}
Map<String, JSONSchema> definitions = null, defs = null, properties = null;
if (parent instanceof ObjectSchema) {
ObjectSchema objectSchema = (ObjectSchema) parent;
definitions = objectSchema.definitions;
defs = objectSchema.defs;
properties = objectSchema.properties;
} else if (parent instanceof ArraySchema) {
definitions = ((ArraySchema) parent).definitions;
defs = ((ArraySchema) parent).defs;
}
if (definitions != null) {
if (ref.startsWith("#/definitions/")) {
final int PREFIX_LEN = 14; // "#/definitions/".length();
String refName = ref.substring(PREFIX_LEN);
return definitions.get(refName);
}
}
if (defs != null) {
if (ref.startsWith("#/$defs/")) {
final int PREFIX_LEN = 8; // "#/$defs/".length();
String refName = ref.substring(PREFIX_LEN);
refName = URLDecoder.decode(refName);
JSONSchema refSchema = defs.get(refName);
if (refSchema == null) {
refSchema = new UnresolvedReference(refName);
}
return refSchema;
}
}
if (properties != null) {
if (ref.startsWith("#/properties/")) {
final int PREFIX_LEN = 13; // "#/properties/".length();
String refName = ref.substring(PREFIX_LEN);
return properties.get(refName);
}
}
if (ref.startsWith("#/prefixItems/") && parent instanceof ArraySchema) {
final int PREFIX_LEN = 14; // "#/properties/".length();
int index = Integer.parseInt(ref.substring(PREFIX_LEN));
return ((ArraySchema) parent).prefixItems[index];
}
}
Object exclusiveMaximum = input.get("exclusiveMaximum");
Object exclusiveMinimum = input.get("exclusiveMinimum");
if (exclusiveMaximum instanceof Integer
|| exclusiveMinimum instanceof Integer
|| exclusiveMaximum instanceof Long
|| exclusiveMinimum instanceof Long) {
return new IntegerSchema(input);
}
if (exclusiveMaximum instanceof Number || exclusiveMinimum instanceof Number) {
return new NumberSchema(input);
}
}
if (input.containsKey("properties")
|| input.containsKey("dependentSchemas")
|| input.containsKey("if")
|| input.containsKey("required")
|| input.containsKey("patternProperties")
|| input.containsKey("additionalProperties")
|| input.containsKey("minProperties")
|| input.containsKey("maxProperties")
|| input.containsKey("propertyNames")
|| input.containsKey("$ref")
) {
return new ObjectSchema(input, parent);
}
if (input.containsKey("maxItems")
|| input.containsKey("minItems")
|| input.containsKey("additionalItems")
|| input.containsKey("items")
|| input.containsKey("prefixItems")
|| input.containsKey("uniqueItems")
|| input.containsKey("maxContains")
|| input.containsKey("minContains")
) {
return new ArraySchema(input, parent);
}
if (input.containsKey("pattern")
|| input.containsKey("format")
|| input.containsKey("minLength")
|| input.containsKey("maxLength")
) {
return new StringSchema(input);
}
boolean allOf = input.containsKey("allOf");
boolean anyOf = input.containsKey("anyOf");
boolean oneOf = input.containsKey("oneOf");
if (allOf || anyOf || oneOf) {
int count = (allOf ? 1 : 0) + (anyOf ? 1 : 0) + (oneOf ? 1 : 0);
if (count == 1) {
if (allOf) {
return new AllOf(input, parent);
}
if (anyOf) {
return new AnyOf(input, parent);
}
return new OneOf(input, parent);
}
JSONSchema[] items = new JSONSchema[count];
int index = 0;
if (allOf) {
items[index++] = new AllOf(input, parent);
}
if (anyOf) {
items[index++] = new AnyOf(input, parent);
}
if (oneOf) {
items[index++] = new OneOf(input, parent);
}
return new AllOf(items);
}
if (input.containsKey("not")) {
return ofNot(input, null);
}
if (input.get("maximum") instanceof Number
|| input.get("minimum") instanceof Number
|| input.containsKey("multipleOf")
) {
return new NumberSchema(input);
}
if (input.isEmpty()) {
return Any.INSTANCE;
}
if (input.size() == 1) {
Object propertyType = input.get("type");
if (propertyType instanceof JSONArray) {
JSONArray array = (JSONArray) propertyType;
JSONSchema[] typeSchemas = new JSONSchema[array.size()];
for (int i = 0; i < array.size(); i++) {
Type itemType = Type.of(array.getString(i));
switch (itemType) {
case String:
typeSchemas[i] = new StringSchema(JSONObject.of("type", "string"));
break;
case Integer:
typeSchemas[i] = new IntegerSchema(JSONObject.of("type", "integer"));
break;
case Number:
typeSchemas[i] = new NumberSchema(JSONObject.of("type", "number"));
break;
case Boolean:
typeSchemas[i] = new BooleanSchema(JSONObject.of("type", "boolean"));
break;
case Null:
typeSchemas[i] = new NullSchema(JSONObject.of("type", "null"));
break;
case Object:
typeSchemas[i] = new ObjectSchema(JSONObject.of("type", "object"));
break;
case Array:
typeSchemas[i] = new ArraySchema(JSONObject.of("type", "array"), null);
break;
default:
throw new JSONSchemaValidException("not support type : " + itemType);
}
}
return new AnyOf(typeSchemas);
}
}
if (input.getString("type") == null) {
throw new JSONSchemaValidException("type required");
} else {
throw new JSONSchemaValidException("not support type : " + input.getString("type"));
}
}
switch (type) {
case String:
return new StringSchema(input);
case Integer:
return new IntegerSchema(input);
case Number:
return new NumberSchema(input);
case Boolean:
return new BooleanSchema(input);
case Null:
return new NullSchema(input);
case Object:
return new ObjectSchema(input, parent);
case Array:
return new ArraySchema(input, parent);
default:
throw new JSONSchemaValidException("not support type : " + type);
}
}