All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.zuunr.json.schema.generation.BasicSchemaPerceptor Maven / Gradle / Ivy

The newest version!
package com.zuunr.json.schema.generation;

import com.zuunr.json.*;
import com.zuunr.json.schema.Keywords;
import com.zuunr.json.schema.Schemas;

/**
 * @author Niklas Eldberger
 */
public class BasicSchemaPerceptor implements SchemaPerceptor {

    public final KeywordMapper keywordMapper;

    public BasicSchemaPerceptor(KeywordMapper keywordMapper) {
        this.keywordMapper = keywordMapper;
    }

    public BasicSchemaPerceptor() {
        this(new KeywordMapper());
    }

    @Override
    public JsonObject generateProperties(JsonValue rootValue, JsonArray path, JsonObject jsonObject, JsonObject pathsPerValue) {
        return null;
    }

    @Override
    public JsonObject generateStringSchema(JsonValue rootValue, JsonArray path, String stringValue, JsonObject pathsPerValue) {
        KeywordMapperAndMatcher mapperAndMatcher = keywordMapper.chooseMapper(rootValue, path, JsonValue.of(stringValue), pathsPerValue);
        JsonObjectBuilder builder = generateCommonKeywords(rootValue, path, JsonValue.of(stringValue), pathsPerValue, mapperAndMatcher, Schemas.STRING.builder());

        int stringLength = stringValue.length();

        applyKeyword(Keywords.MAX_LENGTH, JsonValue.of(stringLength), mapperAndMatcher, builder);
        applyKeyword(Keywords.MIN_LENGTH, JsonValue.of(stringLength), mapperAndMatcher, builder);

        // TODO: pattern
        return KeywordMapper.applyRef(mapperAndMatcher, builder.build()); // applyRef must be last

    }

    public JsonObjectBuilder generateCommonKeywords(JsonValue rootValue, JsonArray path, JsonValue value, JsonObject pathsPerValue, KeywordMapperAndMatcher keywordMapperAndMatcher, JsonObjectBuilder schemaBuilder) {
        applyKeyword(Keywords.CONST, value, keywordMapperAndMatcher, schemaBuilder);
        return schemaBuilder;
    }

    @Override
    public JsonObject generateNumericSchema(JsonValue rootValue, JsonArray path, JsonNumber numberValue, JsonObject pathsPerValue) {
        JsonObjectBuilder builder;
        KeywordMapperAndMatcher mapperAndMatcher = keywordMapper.chooseMapper(rootValue, path, numberValue.jsonValue(), pathsPerValue);
        if (numberValue.isJsonInteger()) {
            builder = generateCommonKeywords(rootValue, path, numberValue.jsonValue(), pathsPerValue, mapperAndMatcher, Schemas.INTEGER.builder());
        } else {
            builder = generateCommonKeywords(rootValue, path, numberValue.jsonValue(), pathsPerValue, mapperAndMatcher, Schemas.NUMBER.builder());
        }
        applyKeyword(Keywords.MAXIMUM, numberValue.jsonValue(), mapperAndMatcher, builder);
        applyKeyword(Keywords.MINIMUM, numberValue.jsonValue(), mapperAndMatcher, builder);
        return KeywordMapper.applyRef(mapperAndMatcher, builder.build());

    }

    @Override
    public JsonObject generateObjectSchema(JsonValue rootValue, JsonArray path, JsonObject jsonObject, JsonObject pathsPerValue, KeywordMapperAndMatcher keywordMapperAndMatcher) {

        KeywordMapperAndMatcher mapperAndMatcher = keywordMapper.chooseMapper(rootValue, path, jsonObject.jsonValue(), pathsPerValue);
        JsonObjectBuilder builder = generateCommonKeywords(rootValue, path, jsonObject.jsonValue(), pathsPerValue, mapperAndMatcher, Schemas.OBJECT.builder());
        applyKeyword(Keywords.REQUIRED, jsonObject.keys().sort().jsonValue(), mapperAndMatcher, builder);
        JsonValue size = JsonValue.of(jsonObject.size());
        applyKeyword(Keywords.MAX_PROPERTIES, size, mapperAndMatcher, builder);
        applyKeyword(Keywords.MIN_PROPERTIES, size, mapperAndMatcher, builder);
        return builder.build();
    }

    @Override
    public JsonObject generateArraySchema(JsonValue rootValue, JsonArray path, JsonArray jsonArray, JsonObject pathsPerValue) {
        KeywordMapperAndMatcher mapperAndMatcher = keywordMapper.chooseMapper(rootValue, path, jsonArray.jsonValue(), pathsPerValue);

        JsonObjectBuilder schemaBuilder = generateCommonKeywords(rootValue, path, jsonArray.jsonValue(), pathsPerValue, mapperAndMatcher, Schemas.ARRAY.builder());

        if (jsonArray.asSet().size() == jsonArray.size()) {
            applyKeyword(Keywords.UNIQUE_ITEMS, JsonValue.TRUE, mapperAndMatcher, schemaBuilder);
        }

        JsonValue size = JsonValue.of(jsonArray.size());
        applyKeyword(Keywords.MAX_ITEMS, size, mapperAndMatcher, schemaBuilder);
        applyKeyword(Keywords.MIN_ITEMS, size, mapperAndMatcher, schemaBuilder);

        return KeywordMapper.applyRef(mapperAndMatcher, schemaBuilder.build());
    }

    @Override
    public JsonValue generateItemsSchema(JsonValue rootValue, JsonArray path, JsonArray jsonArrayInstance, JsonObject pathsPerValue) {
        return null;
    }

    @Override
    public JsonObject generateBooleanSchema(JsonValue rootValue, JsonArray path, Boolean value, JsonObject pathsPerValue) {
        KeywordMapperAndMatcher mapperAndMatcher = keywordMapper.chooseMapper(rootValue, path, JsonValue.of(value), pathsPerValue);

        return generateCommonKeywords(rootValue, path, JsonValue.of(value), pathsPerValue, mapperAndMatcher, Schemas.BOOLEAN.builder()).build();
    }

    private void applyKeyword(String keyword, JsonValue constraintFromExampleValue, KeywordMapperAndMatcher keywordMapperAndMatcher, JsonObjectBuilder schemaBuilder) {
        JsonValue constraint = keywordMapperAndMatcher.keywordMapper.get("keywords", JsonObject.EMPTY).get(keyword);

        if (constraint != null && !JsonValue.NULL.equals(constraint) && !JsonValue.FALSE.equals(constraint)) {
            schemaBuilder.put(keyword, chooseConstraintValue(keyword, constraintFromExampleValue, constraint));
        }
    }

    private JsonValue chooseConstraintValue(String keyword, JsonValue constraintFromExampleValue, JsonValue constraintFromMapper) {

        if (!constraintFromMapper.isJsonArray()) {
            return constraintFromExampleValue;
        }

        switch (keyword) {
            case Keywords.MAX_LENGTH, Keywords.MAXIMUM, Keywords.MAX_ITEMS, Keywords.MAX_PROPERTIES: {
                return firstConstraintGteExample(constraintFromExampleValue, constraintFromMapper.getJsonArray());
            }
            case Keywords.MIN_LENGTH, Keywords.MINIMUM, Keywords.MIN_ITEMS, Keywords.MIN_PROPERTIES: {
                return firstConstraintLteExample(constraintFromExampleValue, constraintFromMapper.getJsonArray());
            }
            default:
        }
        return constraintFromExampleValue;
    }

    private JsonValue firstConstraintGteExample(JsonValue constraintFromExampleValue, JsonArray predefinedLimits) {
        for (int i = 0; i < predefinedLimits.size(); i++) {
            JsonValue limit = predefinedLimits.get(i);
            if (limit.getJsonNumber().longValue() >= constraintFromExampleValue.getJsonNumber().longValue()) {
                return limit;
            }
        }
        return constraintFromExampleValue;
    }

    private JsonValue firstConstraintLteExample(JsonValue constraintFromExampleValue, JsonArray predefinedLimits) {
        for (int i = 0; i < predefinedLimits.size(); i++) {
            JsonValue limit = predefinedLimits.get(i);
            if (limit.getJsonNumber().longValue() <= constraintFromExampleValue.getJsonNumber().longValue()) {
                return limit;
            }
        }
        return constraintFromExampleValue;
    }


    @Override
    public JsonObject generateNullSchema(JsonValue rootValue, JsonArray path, JsonObject pathsPerValue) {
        KeywordMapperAndMatcher mapperAndMatcher = keywordMapper.chooseMapper(rootValue, path, JsonValue.NULL, pathsPerValue);
        JsonObjectBuilder builder = generateCommonKeywords(rootValue, path, JsonValue.NULL, pathsPerValue, mapperAndMatcher, Schemas.NULL.builder());
        return builder.build();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy