Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.zuunr.jsonschema.ValueFormatConverter Maven / Gradle / Ivy
/*
* Copyright 2020 Zuunr AB
*
* Licensed 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 com.zuunr.jsonschema;
import com.zuunr.forms.Form;
import com.zuunr.forms.FormField;
import com.zuunr.forms.FormFields;
import com.zuunr.forms.ValueFormat;
import com.zuunr.forms.formfield.Type;
import com.zuunr.json.JsonArray;
import com.zuunr.json.JsonObject;
import com.zuunr.json.JsonObjectBuilder;
import com.zuunr.json.JsonValue;
import java.util.Iterator;
import java.util.function.Function;
/**
* @author Niklas Eldberger
*/
public class ValueFormatConverter {
public static final JsonObject TYPE_MAPPING = JsonObject.EMPTY.builder()
.put(Type.STRING.toString(), JsonObject.EMPTY.put("type", JsonArray.of("string")))
.put(Type.OBJECT.toString(), JsonObject.EMPTY.put("type", JsonArray.of("object")))
.put(Type.ARRAY.toString(), JsonObject.EMPTY.put("type", JsonArray.of("array")))
.put(Type.BOOLEAN.toString(), JsonObject.EMPTY.put("type", JsonArray.of("boolean")))
.put(Type.SET.toString(), JsonObject.EMPTY.put("type", JsonArray.of("array")))
.put(Type.DATE.toString(), JsonObject.EMPTY.put("type", JsonArray.of("date")))
.put(Type.DATETIME.toString(), JsonObject.EMPTY.put("type", JsonArray.of("dateTime")))
.put(Type.INTEGER.toString(), JsonObject.EMPTY.put("type", JsonArray.of("integer")))
.put(Type.UNDEFINED.toString(), JsonObject.EMPTY)
.build();
private static final JsonObject NULLABLE_TYPE_MAPPING = JsonObject.EMPTY.builder()
.put(Type.STRING.toString(), JsonObject.EMPTY.put("type", JsonArray.of("string", "null")))
.put(Type.OBJECT.toString(), JsonObject.EMPTY.put("type", JsonArray.of("object", "null")))
.put(Type.ARRAY.toString(), JsonObject.EMPTY.put("type", JsonArray.of("array", "null")))
.put(Type.BOOLEAN.toString(), JsonObject.EMPTY.put("type", JsonArray.of("boolean", "null")))
.put(Type.SET.toString(), JsonObject.EMPTY.put("type", JsonArray.of("array", "null")))
.put(Type.DATE.toString(), JsonObject.EMPTY.put("type", JsonArray.of("date", "null")))
.put(Type.DATETIME.toString(), JsonObject.EMPTY.put("type", JsonArray.of("dateTime", "null")))
.put(Type.INTEGER.toString(), JsonObject.EMPTY.put("type", JsonArray.of("integer", "null")))
.put(Type.UNDEFINED.toString(), JsonObject.EMPTY)
.build();
// VALUE_FORMAT_VALIDATION_KEY_MAPPINGS - when value has same meaning and format in JsonSchema and ValueFormat
private static final JsonObject VALUE_FORMAT_VALIDATION_KEY_MAPPINGS = JsonObject.EMPTY.builder()
.put("max", "maximum")
.put("exclusiveMaximum", "exclusiveMaximum")
.put("exclusiveMinimum", "exclusiveMinimum")
.put("maxsize", "maxItems")
.put("maxlength", "maxLength")
.put("min", "minimum")
.put("minsize", "minItems")
.put("minlength", "minLength")
.put("pattern", "pattern")
.put("desc", "description")
.put("enum", "enum")
.put("const", "const")
.put("typeFormat", "format")
.build();
private JsonObject convertTypeAndNullable(ValueFormat valueFormat) {
ValueFormat explicitValueFormat = valueFormat.asExplicitValueFormat();
JsonObject mapping = explicitValueFormat.nullable().booleanValue() ? NULLABLE_TYPE_MAPPING : TYPE_MAPPING;
JsonObject jsonObject = mapping.get(explicitValueFormat.type().toString(), JsonValue.NULL).getValue(JsonObject.class);
if (jsonObject == null) {
throw new ConversionException("Type not supported: " + valueFormat.type());
}
return jsonObject;
}
private Function schemaStyleFormatter;
public ValueFormatConverter(Function schemaStyleFormatter) {
this.schemaStyleFormatter = schemaStyleFormatter;
}
public ValueFormatConverter() {
schemaStyleFormatter = valueFormatAndSchemaTuple -> valueFormatAndSchemaTuple.jsonSchema;
}
public JsonObject translate(ValueFormat valueFormat) {
ValueFormat explicitValueFormat = valueFormat.asExplicitValueFormat();
JsonObjectBuilder jsonSchemaBuilder = convertTypeAndNullable(valueFormat).builder();
translateSimpleMappings(valueFormat, jsonSchemaBuilder);
translateOpenApiStyle(valueFormat, jsonSchemaBuilder);
if (explicitValueFormat.type().isStringTypeOrSubtypeOfString()) {
translateStringType(valueFormat, jsonSchemaBuilder);
} else if (explicitValueFormat.type().isObject()) {
translateObjectType(valueFormat, jsonSchemaBuilder);
} else if (explicitValueFormat.type().isArrayOrSet()) {
translateArrayType(valueFormat, jsonSchemaBuilder);
}
return schemaStyleFormatter.apply(new ValueFormatAndSchemaTuple(valueFormat, jsonSchemaBuilder.build()));
}
private void translateOpenApiStyle(ValueFormat valueFormat, JsonObjectBuilder jsonSchemaBuilder) {
if (valueFormat.asExplicitValueFormat().constant() != null){
jsonSchemaBuilder.put("enum", JsonArray.of(valueFormat.constant()));
jsonSchemaBuilder.remove("const");
}
if (valueFormat.asExplicitValueFormat().type().isStringTypeOrSubtypeOfString()) {
jsonSchemaBuilder.remove("maximum");
jsonSchemaBuilder.remove("minimum");
}
}
private void translateSimpleMappings(ValueFormat valueFormat, JsonObjectBuilder jsonSchemaBuilder) {
JsonObject compactValueFormat = valueFormat.asCompactValueFormat().asJsonValue().getJsonObject();
JsonArray keys = compactValueFormat.keys();
Iterator values = compactValueFormat.values().iterator();
for (String key : keys.asList(String.class)) {
JsonValue value = values.next();
JsonValue mappedKeyword = VALUE_FORMAT_VALIDATION_KEY_MAPPINGS.get(key);
if (mappedKeyword != null) {
jsonSchemaBuilder.put(mappedKeyword.getString(), value);
}
}
}
private void translateStringType(ValueFormat valueFormat, JsonObjectBuilder jsonSchemaBuilder) {
// subtypes of strings should be handled here
}
private void translateObjectType(ValueFormat valueFormat, JsonObjectBuilder jsonSchemaBuilder) {
translateExclusive(valueFormat, jsonSchemaBuilder);
translateRequired(valueFormat, jsonSchemaBuilder);
translateForm(valueFormat, jsonSchemaBuilder);
}
private void translateArrayType(ValueFormat valueFormat, JsonObjectBuilder jsonSchemaBuilder) {
JsonObject itemsSchema = translate(valueFormat.asExplicitValueFormat().element());
jsonSchemaBuilder.put("items", itemsSchema);
}
private void translateForm(ValueFormat valueFormat, JsonObjectBuilder jsonSchemaBuilder) {
JsonObjectBuilder propertiesBuilder = JsonObject.EMPTY.builder();
Form form = valueFormat.form();
if (form != null) {
FormFields formFields = form.formFields();
for (FormField formField : formFields.asList()) {
propertiesBuilder.put(formField.name(), translate(formField.asValueFormat()));
}
}
jsonSchemaBuilder.put("properties", propertiesBuilder.build());
}
private void translateExclusive(ValueFormat valueFormat, JsonObjectBuilder jsonSchemaBuilder) {
Form form = valueFormat.form();
if (form == null) {
jsonSchemaBuilder.put("additionalProperties", true);
} else if (form.exclusive() == null) {
jsonSchemaBuilder.remove("additionalProperties");
} else {
jsonSchemaBuilder.put("additionalProperties", !form.exclusive());
}
}
private void translateRequired(ValueFormat valueFormat, JsonObjectBuilder jsonSchemaBuilder) {
if (valueFormat.form() != null) {
JsonArray required = valueFormat.form().requiredFormFields().keys().sort();
if (!required.isEmpty()) {
jsonSchemaBuilder.put("required", required);
}
}
}
public class ValueFormatAndSchemaTuple {
public final ValueFormat valueFormat;
public final JsonObject jsonSchema;
public ValueFormatAndSchemaTuple(ValueFormat valueFormat, JsonObject jsonSchema) {
this.valueFormat = valueFormat;
this.jsonSchema = jsonSchema;
}
}
}