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

com.github.erosb.jsonsKema.ValidationFailure.kt Maven / Gradle / Ivy

package com.github.erosb.jsonsKema

abstract class ValidationFailure(
    open val message: String,
    open val schema: Schema,
    open val instance: IJsonValue,
    val keyword: Keyword? = null,
    open val causes: Set = setOf()
) {

    private fun appendTo(sb: StringBuilder, linePrefix: String) {
        sb.append("${linePrefix}${instance.location.getLocation()}: $message\n" +
                "${linePrefix}Keyword: ${keyword?.value}\n"  +
                "${linePrefix}Schema pointer: ${schema.location.pointer}\n" +
                "${linePrefix}Schema location: Line ${schema.location.lineNumber}, character ${schema.location.position}\n" +
                "${linePrefix}Instance pointer: ${instance.location.pointer}\n" +
                "${linePrefix}Instance location: ${instance.location.getLocation()}")
        if (causes.isNotEmpty()) {
            sb.append("\nCauses:")
            for (cause in causes) {
                sb.append("\n\n")
                cause.appendTo(sb, linePrefix + "\t")
            }
        }
    }
    final override fun toString(): String {
        val sb = StringBuilder()
        appendTo(sb, "")
        return sb.toString()
    }

    fun toJSON(): JsonObject {
        val instanceRef = JsonString(instance.location.pointer.toString())
        val json = mutableMapOf(
            JsonString("instanceRef") to instanceRef,
            JsonString("schemaRef") to JsonString(schema.location.pointer.toString()),
            JsonString("message") to JsonString(message)
        )
        keyword?.let { json[JsonString("keyword")] = JsonString(it.value) }
        if (causes.isNotEmpty()) {
            json[JsonString("causes")] = JsonArray(causes.map { failure -> failure.toJSON() })
        }
        return JsonObject(
            properties = json.toMap()
        )
    }

    internal open fun join(parent: Schema, instance: IJsonValue, other: ValidationFailure): ValidationFailure {
        return AggregatingValidationFailure(parent, instance, setOf(this, other))
    }
}

data class MinimumValidationFailure(
    override val schema: MinimumSchema,
    override val instance: IJsonNumber
) : ValidationFailure("${instance.value} is lower than minimum ${schema.minimum}", schema, instance, Keyword.MINIMUM)

data class MaximumValidationFailure(
    override val schema: MaximumSchema,
    override val instance: IJsonNumber
) : ValidationFailure("${instance.value} is greater than maximum ${schema.maximum}", schema, instance, Keyword.MAXIMUM)

data class ExclusiveMinimumValidationFailure(
    override val schema: ExclusiveMinimumSchema,
    override val instance: IJsonNumber
) : ValidationFailure("${instance.value} is lower than or equal to minimum ${schema.minimum}", schema, instance, Keyword.EXCLUSIVE_MINIMUM)

data class ExclusiveMaximumValidationFailure(
    override val schema: ExclusiveMaximumSchema,
    override val instance: IJsonNumber
) : ValidationFailure("${instance.value} is greater than or equal to maximum ${schema.maximum}", schema, instance, Keyword.EXCLUSIVE_MAXIMUM)

data class MultipleOfValidationFailure(
    override val schema: MultipleOfSchema,
    override val instance: IJsonNumber
) : ValidationFailure("${instance.value} is not a multiple of ${schema.denominator}", schema, instance, Keyword.MULTIPLE_OF)

data class TypeValidationFailure(
    val actualInstanceType: String,
    override val schema: TypeSchema,
    override val instance: IJsonValue
) : ValidationFailure("expected type: ${schema.type.value}, actual: $actualInstanceType", schema, instance, Keyword.TYPE)

data class MultiTypeValidationFailure(
    val actualInstanceType: String,
    override val schema: MultiTypeSchema,
    override val instance: IJsonValue
) : ValidationFailure(
    "expected type: one of ${schema.types.elements.joinToString { ", " }}, actual: $actualInstanceType",
    schema,
    instance,
    Keyword.TYPE
)

data class FalseValidationFailure(
    override val schema: FalseSchema,
    override val instance: IJsonValue
) : ValidationFailure("false schema always fails", schema, instance, Keyword.FALSE)

data class RequiredValidationFailure(
    val missingProperties: List,
    override val schema: RequiredSchema,
    override val instance: IJsonObj
) : ValidationFailure(
    "required properties are missing: " + missingProperties.joinToString(),
    schema,
    instance,
    Keyword.REQUIRED
)

data class NotValidationFailure(
    override val schema: Schema,
    override val instance: IJsonValue
) : ValidationFailure("negated subschema did not fail", schema, instance, Keyword.NOT)

data class MaxLengthValidationFailure(
    override val schema: MaxLengthSchema,
    override val instance: IJsonString
) : ValidationFailure(
    "actual string length ${instance.value.length} exceeds maxLength ${schema.maxLength}",
    schema,
    instance,
    Keyword.MAX_LENGTH
)

data class MinLengthValidationFailure(
    override val schema: MinLengthSchema,
    override val instance: IJsonString
) : ValidationFailure(
    "actual string length ${instance.value.length} is lower than minLength ${schema.minLength}",
    schema,
    instance,
    Keyword.MIN_LENGTH
)

data class ConstValidationFailure(
    override val schema: ConstSchema,
    override val instance: IJsonValue
) : ValidationFailure(
    "actual instance is not the same as expected constant value",
    schema,
    instance,
    Keyword.CONST
)

data class UniqueItemsValidationFailure(
    val arrayPositions: List,
    override val schema: UniqueItemsSchema,
    override val instance: IJsonArray<*>
) : ValidationFailure("the same array element occurs at positions " + arrayPositions.joinToString(", "), schema, instance, Keyword.UNIQUE_ITEMS)

data class ItemsValidationFailure(
    val itemFailures: Map,
    override val schema: ItemsSchema,
    override val instance: IJsonArray<*>
) : ValidationFailure(
    "array items ${itemFailures.keys.joinToString(", ")} failed to validate against \"items\" subschema",
    schema,
    instance,
    Keyword.ITEMS,
    itemFailures.values.toSet()
)

data class PrefixItemsValidationFailure(
    val itemFailures: Map,
    override val schema: PrefixItemsSchema,
    override val instance: IJsonArray<*>
) : ValidationFailure(
    "array items ${itemFailures.keys.joinToString(", ")} failed to validate against \"prefixItems\" subschema",
    schema,
    instance,
    Keyword.PREFIX_ITEMS,
    itemFailures.values.toSet()
)

data class UnevaluatedItemsValidationFailure(
    val itemFailures: Map,
    override val schema: UnevaluatedItemsSchema,
    override val instance: IJsonArray<*>
) : ValidationFailure(
    "array items ${itemFailures.keys.joinToString(", ")} failed to validate against \"unevaluatedItems\" subschema",
    schema,
    instance,
    Keyword.UNEVALUATED_ITEMS,
    itemFailures.values.toSet()
)

data class UnevaluatedPropertiesValidationFailure(
    val propertyFailures: Map,
    override val schema: UnevaluatedPropertiesSchema,
    override val instance: IJsonObj
) : ValidationFailure(
    "object properties ${propertyFailures.keys.joinToString(", ")} failed to validate against \"unevaluatedProperties\" subschema",
    schema,
    instance,
    Keyword.UNEVALUATED_ITEMS,
    propertyFailures.values.toSet()
)

data class ContainsValidationFailure(
    override val message: String,
    override val schema: ContainsSchema,
    override val instance: IJsonArray<*>
) : ValidationFailure(
    message,
    schema,
    instance,
    Keyword.CONTAINS
)

data class AllOfValidationFailure(
    override val schema: AllOfSchema,
    override val instance: IJsonValue,
    override val causes: Set
) : ValidationFailure(
    message = "${causes.size} subschemas out of ${schema.subschemas.size} failed to validate",
    schema = schema,
    instance = instance,
    causes = causes,
    keyword = Keyword.ALL_OF
)

data class AnyOfValidationFailure(
    override val schema: AnyOfSchema,
    override val instance: IJsonValue,
    override val causes: Set
) : ValidationFailure(
    message = "no subschema out of ${schema.subschemas.size} matched",
    schema = schema,
    instance = instance,
    causes = causes,
    keyword = Keyword.ANY_OF
)

data class OneOfValidationFailure(
    override val schema: OneOfSchema,
    override val instance: IJsonValue,
    override val causes: Set
) : ValidationFailure(
    message = "expected 1 subschema to match out of ${schema.subschemas.size}, ${schema.subschemas.size - causes.size} matched",
    schema = schema,
    instance = instance,
    causes = causes,
    keyword = Keyword.ONE_OF
)

data class DependentSchemasValidationFailure(
    override val schema: DependentSchemasSchema,
    override val instance: IJsonValue,
    val causesByProperty: Map
) : ValidationFailure(
    message = "some dependent subschemas did not match",
    schema = schema,
    instance = instance,
    keyword = Keyword.DEPENDENT_SCHEMAS,
    causes = causesByProperty.values.toSet()
)

data class PatternValidationFailure(
    override val schema: PatternSchema,
    override val instance: IJsonValue,
) : ValidationFailure(
    message = "some dependent subschemas did not match",
    schema = schema,
    instance = instance,
    keyword = Keyword.PATTERN
)

data class PropertyNamesValidationFailure(
    override val schema: PropertyNamesSchema,
    override val instance: IJsonObj,
    val causesByProperties: Map
) : ValidationFailure(
    message = "",
    schema = schema,
    instance = instance,
    keyword = Keyword.PROPERTY_NAMES,
    causes = causesByProperties.values.toSet()
)

internal class AggregatingValidationFailure(
    schema: Schema,
    instance: IJsonValue,
    causes: Set
) : ValidationFailure("multiple validation failures", schema, instance, null, causes) {

    private var _causes = causes.toMutableSet()
    override val causes: Set
        get() {
            return _causes
        }

    override fun join(parent: Schema, instance: IJsonValue, other: ValidationFailure): ValidationFailure {
        if (parent != schema) {
            TODO("something went wrong")
        }
        if (instance != this.instance) {
            TODO("something went wrong: $instance vs ${this.instance}")
        }
        _causes.add(other)
        return this
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy