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

hydraql.shaded.fastjson2.schema.ArraySchema Maven / Gradle / Ivy

package hydraql.shaded.fastjson2.schema;

import hydraql.shaded.fastjson2.JSONArray;
import hydraql.shaded.fastjson2.JSONException;
import hydraql.shaded.fastjson2.JSONObject;

import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.util.*;

public final class ArraySchema
        extends JSONSchema {
    final Map definitions;
    final Map defs;

    final boolean typed;

    final int maxLength;
    final int minLength;
    final JSONSchema itemSchema;
    final JSONSchema[] prefixItems;
    final boolean additionalItems;
    final JSONSchema additionalItem;
    final JSONSchema contains;
    final int minContains;
    final int maxContains;
    final boolean uniqueItems;

    final AllOf allOf;
    final AnyOf anyOf;
    final OneOf oneOf;

    public ArraySchema(JSONObject input, JSONSchema root) {
        super(input);

        this.typed = "array".equals(input.get("type"));
        this.definitions = new LinkedHashMap<>();
        this.defs = new LinkedHashMap<>();

        JSONObject definitions = input.getJSONObject("definitions");
        if (definitions != null) {
            for (Iterator> it = definitions.entrySet().iterator(); it.hasNext(); ) {
                Map.Entry entry = it.next();
                String entryKey = entry.getKey();
                JSONObject entryValue = (JSONObject) entry.getValue();
                JSONSchema schema = JSONSchema.of(entryValue, root == null ? this : root);
                this.definitions.put(entryKey, schema);
            }
        }

        JSONObject defs = input.getJSONObject("$defs");
        if (defs != null) {
            for (Iterator> it = defs.entrySet().iterator(); it.hasNext(); ) {
                Map.Entry entry = it.next();
                String entryKey = entry.getKey();
                JSONObject entryValue = (JSONObject) entry.getValue();
                JSONSchema schema = JSONSchema.of(entryValue, root == null ? this : root);
                this.defs.put(entryKey, schema);
            }
        }

        this.minLength = input.getIntValue("minItems", -1);
        this.maxLength = input.getIntValue("maxItems", -1);

        Object items = input.get("items");
        Object additionalItems = input.get("additionalItems");
        JSONArray prefixItems = input.getJSONArray("prefixItems");

        boolean additionalItemsSupport;
        if (items == null) {
            additionalItemsSupport = true;
            this.itemSchema = null;
        } else if (items instanceof Boolean) {
            additionalItemsSupport = ((Boolean) items).booleanValue();
            this.itemSchema = null;
        } else if (items instanceof JSONArray) {
            if (prefixItems == null) {
                prefixItems = (JSONArray) items;
            } else {
                throw new JSONException("schema error, items : " + items);
            }
            this.itemSchema = null;
            additionalItemsSupport = true;
        } else {
            additionalItemsSupport = true;
            this.itemSchema = JSONSchema.of((JSONObject) items, root);
        }

        if (additionalItems instanceof JSONObject) {
            additionalItem = JSONSchema.of((JSONObject) additionalItems, root == null ? this : root);
            additionalItemsSupport = true;
        } else if (additionalItems instanceof Boolean) {
            additionalItemsSupport = ((Boolean) additionalItems).booleanValue();
            this.additionalItem = null;
        } else {
            this.additionalItem = null;
        }
//        ((itemSchema != null && !(itemSchema instanceof Any))
//                || this.prefixItems.length > 0)
        if (itemSchema != null && !(itemSchema instanceof Any)) {
            additionalItemsSupport = true;
        } else if (prefixItems == null && !(items instanceof Boolean)) {
            additionalItemsSupport = true;
        }
        this.additionalItems = additionalItemsSupport;

        if (prefixItems == null) {
            this.prefixItems = new JSONSchema[0];
        } else {
            this.prefixItems = new JSONSchema[prefixItems.size()];
            for (int i = 0; i < prefixItems.size(); i++) {
                JSONSchema schema;

                Object prefixItem = prefixItems.get(i);
                if (prefixItem instanceof Boolean) {
                    schema = ((Boolean) prefixItem).booleanValue() ? Any.INSTANCE : Any.NOT_ANY;
                } else {
                    JSONObject jsonObject = (JSONObject) prefixItem;
                    schema = JSONSchema.of(jsonObject, root == null ? this : root);
                }

                this.prefixItems[i] = schema;
            }
        }

        this.contains = input.getObject("contains", JSONSchema::of);
        this.minContains = input.getIntValue("minContains", -1);
        this.maxContains = input.getIntValue("maxContains", -1);

        this.uniqueItems = input.getBooleanValue("uniqueItems");

        allOf = allOf(input, null);
        anyOf = anyOf(input, null);
        oneOf = oneOf(input, null);
    }

    @Override
    public Type getType() {
        return Type.Array;
    }

    @Override
    public ValidateResult validate(Object value) {
        if (value == null) {
            return typed ? FAIL_INPUT_NULL : SUCCESS;
        }

        Set uniqueItemsSet = null;

        if (value instanceof Object[]) {
            Object[] array = (Object[]) value;
            final int size = array.length;

            if (minLength >= 0 && size < minLength) {
                return new ValidateResult(false, "minLength not match, expect >= %s, but %s", minLength, size);
            }

            if (maxLength >= 0) {
                if (maxLength >= 0 && size > maxLength) {
                    return new ValidateResult(false, "maxLength not match, expect <= %s, but %s", maxLength, size);
                }
            }

            int containsCount = 0;
            for (int index = 0; index < array.length; index++) {
                Object item = array[index];

                boolean prefixMatch = false;
                if (index < prefixItems.length) {
                    ValidateResult result = prefixItems[index].validate(item);
                    if (!result.isSuccess()) {
                        return result;
                    }
                    prefixMatch = true;
                }

                if (!prefixMatch && itemSchema != null) {
                    ValidateResult result = itemSchema.validate(item);
                    if (!result.isSuccess()) {
                        return result;
                    }
                }

                if (this.contains != null && (minContains > 0 || maxContains > 0 || containsCount == 0)) {
                    ValidateResult result = this.contains.validate(item);
                    if (result == SUCCESS) {
                        containsCount++;
                    }
                }

                if (uniqueItems) {
                    if (uniqueItemsSet == null) {
                        uniqueItemsSet = new HashSet(size);
                    }

                    if (item instanceof BigDecimal) {
                        item = ((BigDecimal) item).stripTrailingZeros();
                    }

                    if (!uniqueItemsSet.add(item)) {
                        return UNIQUE_ITEMS_NOT_MATCH;
                    }
                }
            }

            if (this.contains != null && containsCount == 0) {
                return CONTAINS_NOT_MATCH;
            }

            if (minContains >= 0 && containsCount < minContains) {
                return new ValidateResult(false, "minContains not match, expect %s, but %s", minContains, containsCount);
            }

            if (maxContains >= 0 && containsCount > maxContains) {
                return new ValidateResult(false, "maxContains not match, expect %s, but %s", maxContains, containsCount);
            }

            if (!additionalItems) {
                if (size > prefixItems.length) {
                    return new ValidateResult(false, "additional items not match, max size %s, but %s", prefixItems.length, size);
                }
            }

            if (allOf != null) {
                ValidateResult result = allOf.validate(value);
                if (!result.isSuccess()) {
                    return result;
                }
            }

            if (anyOf != null) {
                ValidateResult result = anyOf.validate(value);
                if (!result.isSuccess()) {
                    return result;
                }
            }

            if (oneOf != null) {
                ValidateResult result = oneOf.validate(value);
                if (!result.isSuccess()) {
                    return result;
                }
            }

            return SUCCESS;
        }

        if (value.getClass().isArray()) {
            final int size = Array.getLength(value);

            if (minLength >= 0 && size < minLength) {
                return new ValidateResult(false, "minLength not match, expect >= %s, but %s", minLength, size);
            }

            if (maxLength >= 0) {
                if (maxLength >= 0 && size > maxLength) {
                    return new ValidateResult(false, "maxLength not match, expect <= %s, but %s", maxLength, size);
                }
            }

            int containsCount = 0;
            for (int index = 0; index < size; index++) {
                Object item = Array.get(value, index);

                boolean prefixMatch = false;
                if (index < prefixItems.length) {
                    ValidateResult result = prefixItems[index].validate(item);
                    if (!result.isSuccess()) {
                        return result;
                    }
                    prefixMatch = true;
                }

                if (!prefixMatch && itemSchema != null) {
                    ValidateResult result = itemSchema.validate(item);
                    if (!result.isSuccess()) {
                        return result;
                    }
                }

                if (this.contains != null && (minContains > 0 || maxContains > 0 || containsCount == 0)) {
                    ValidateResult result = this.contains.validate(item);
                    if (result == SUCCESS) {
                        containsCount++;
                    }
                }

                if (uniqueItems) {
                    if (uniqueItemsSet == null) {
                        uniqueItemsSet = new HashSet(size);
                    }

                    if (item instanceof BigDecimal) {
                        item = ((BigDecimal) item).stripTrailingZeros();
                    }

                    if (!uniqueItemsSet.add(item)) {
                        return UNIQUE_ITEMS_NOT_MATCH;
                    }
                }
            }
            if (this.contains != null && containsCount == 0) {
                return CONTAINS_NOT_MATCH;
            }

            if (minContains >= 0 && containsCount < minContains) {
                return new ValidateResult(false, "minContains not match, expect %s, but %s", minContains, containsCount);
            }

            if (maxContains >= 0 && containsCount > maxContains) {
                return new ValidateResult(false, "maxContains not match, expect %s, but %s", maxContains, containsCount);
            }

            if (!additionalItems) {
                if (size > prefixItems.length) {
                    return new ValidateResult(false, "additional items not match, max size %s, but %s", prefixItems.length, size);
                }
            }

            if (allOf != null) {
                ValidateResult result = allOf.validate(value);
                if (!result.isSuccess()) {
                    return result;
                }
            }

            if (anyOf != null) {
                ValidateResult result = anyOf.validate(value);
                if (!result.isSuccess()) {
                    return result;
                }
            }

            if (oneOf != null) {
                ValidateResult result = oneOf.validate(value);
                if (!result.isSuccess()) {
                    return result;
                }
            }

            return SUCCESS;
        }

        if (value instanceof Collection) {
            int size = ((Collection) value).size();
            if (minLength >= 0 && size < minLength) {
                return new ValidateResult(false, "minLength not match, expect >= %s, but %s", minLength, size);
            }

            if (maxLength >= 0) {
                if (maxLength >= 0 && size > maxLength) {
                    return new ValidateResult(false, "maxLength not match, expect <= %s, but %s", maxLength, size);
                }
            }

            if (!additionalItems) {
                if (size > prefixItems.length) {
                    return new ValidateResult(false, "additional items not match, max size %s, but %s", prefixItems.length, size);
                }
            }

            int index = 0;
            int containsCount = 0;
            for (Iterator it = ((Iterable) value).iterator(); it.hasNext(); index++) {
                Object item = it.next();

                boolean prefixMatch = false;
                if (index < prefixItems.length) {
                    ValidateResult result = prefixItems[index].validate(item);
                    if (!result.isSuccess()) {
                        return result;
                    }
                    prefixMatch = true;
                } else if (itemSchema == null && additionalItem != null) {
                    ValidateResult result = additionalItem.validate(item);
                    if (!result.isSuccess()) {
                        return result;
                    }
                }

                if (!prefixMatch && itemSchema != null) {
                    ValidateResult result = itemSchema.validate(item);
                    if (!result.isSuccess()) {
                        return result;
                    }
                }

                if (this.contains != null && (minContains > 0 || maxContains > 0 || containsCount == 0)) {
                    ValidateResult result = this.contains.validate(item);
                    if (result == SUCCESS) {
                        containsCount++;
                    }
                }

                if (uniqueItems) {
                    if (uniqueItemsSet == null) {
                        uniqueItemsSet = new HashSet();
                    }

                    if (item instanceof BigDecimal) {
                        item = ((BigDecimal) item).stripTrailingZeros();
                    }

                    if (!uniqueItemsSet.add(item)) {
                        return UNIQUE_ITEMS_NOT_MATCH;
                    }
                }
            }

            if (this.contains != null) {
                if (minContains >= 0 && containsCount < minContains) {
                    return new ValidateResult(false, "minContains not match, expect %s, but %s", minContains, containsCount);
                } else {
                    if (containsCount == 0 && minContains != 0) {
                        return CONTAINS_NOT_MATCH;
                    }
                }

                if (maxContains >= 0 && containsCount > maxContains) {
                    return new ValidateResult(false, "maxContains not match, expect %s, but %s", maxContains, containsCount);
                }
            }

            if (allOf != null) {
                ValidateResult result = allOf.validate(value);
                if (!result.isSuccess()) {
                    return result;
                }
            }

            if (anyOf != null) {
                ValidateResult result = anyOf.validate(value);
                if (!result.isSuccess()) {
                    return result;
                }
            }

            if (oneOf != null) {
                ValidateResult result = oneOf.validate(value);
                if (!result.isSuccess()) {
                    return result;
                }
            }

            return SUCCESS;
        }

        return typed ? FAIL_TYPE_NOT_MATCH : SUCCESS;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        hydraql.shaded.fastjson2.schema.ArraySchema that = (hydraql.shaded.fastjson2.schema.ArraySchema) o;
        return Objects.equals(title, that.title) && Objects.equals(description, that.description);
    }

    @Override
    public int hashCode() {
        return Objects.hash(title, description);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy