Skip to content

Commit 2f973dd

Browse files
authored
Introduce abstraction for validated elements (#191)
Make validation abstracted from the `JsonElement` Related to #190 Resolves #193
1 parent 66d118a commit 2f973dd

File tree

74 files changed

+718
-218
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+718
-218
lines changed

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ org.gradle.jvmargs=-Xmx1G
44
org.gradle.java.installations.auto-download=false
55
org.gradle.daemon=false
66

7-
version=0.2.4-SNAPSHOT
7+
version=0.3.0-SNAPSHOT
88
group=io.github.optimumcode

json-schema-validator/api/json-schema-validator.api

+34-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public abstract interface class io/github/optimumcode/json/schema/FormatValidato
9494
public static final field Companion Lio/github/optimumcode/json/schema/FormatValidator$Companion;
9595
public static fun Invalid ()Lio/github/optimumcode/json/schema/FormatValidationResult;
9696
public static fun Valid ()Lio/github/optimumcode/json/schema/FormatValidationResult;
97-
public abstract fun validate (Lkotlinx/serialization/json/JsonElement;)Lio/github/optimumcode/json/schema/FormatValidationResult;
97+
public abstract fun validate (Lio/github/optimumcode/json/schema/model/AbstractElement;)Lio/github/optimumcode/json/schema/FormatValidationResult;
9898
}
9999

100100
public final class io/github/optimumcode/json/schema/FormatValidator$Companion {
@@ -108,6 +108,8 @@ public final class io/github/optimumcode/json/schema/JsonSchema {
108108
public static final fun fromDefinition (Ljava/lang/String;Lio/github/optimumcode/json/schema/SchemaType;)Lio/github/optimumcode/json/schema/JsonSchema;
109109
public static final fun fromJsonElement (Lkotlinx/serialization/json/JsonElement;)Lio/github/optimumcode/json/schema/JsonSchema;
110110
public static final fun fromJsonElement (Lkotlinx/serialization/json/JsonElement;Lio/github/optimumcode/json/schema/SchemaType;)Lio/github/optimumcode/json/schema/JsonSchema;
111+
public final fun validate (Lio/github/optimumcode/json/schema/model/AbstractElement;Lio/github/optimumcode/json/schema/ErrorCollector;)Z
112+
public final fun validate (Lio/github/optimumcode/json/schema/model/AbstractElement;Lio/github/optimumcode/json/schema/OutputCollector$Provider;)Ljava/lang/Object;
111113
public final fun validate (Lkotlinx/serialization/json/JsonElement;Lio/github/optimumcode/json/schema/ErrorCollector;)Z
112114
public final fun validate (Lkotlinx/serialization/json/JsonElement;Lio/github/optimumcode/json/schema/OutputCollector$Provider;)Ljava/lang/Object;
113115
}
@@ -337,9 +339,15 @@ public abstract interface class io/github/optimumcode/json/schema/extension/Exte
337339
}
338340

339341
public abstract interface class io/github/optimumcode/json/schema/extension/ExternalAssertion {
342+
public abstract fun validate (Lio/github/optimumcode/json/schema/model/AbstractElement;Lio/github/optimumcode/json/schema/extension/ExternalAssertionContext;Lio/github/optimumcode/json/schema/ErrorCollector;)Z
340343
public abstract fun validate (Lkotlinx/serialization/json/JsonElement;Lio/github/optimumcode/json/schema/extension/ExternalAssertionContext;Lio/github/optimumcode/json/schema/ErrorCollector;)Z
341344
}
342345

346+
public final class io/github/optimumcode/json/schema/extension/ExternalAssertion$DefaultImpls {
347+
public static fun validate (Lio/github/optimumcode/json/schema/extension/ExternalAssertion;Lio/github/optimumcode/json/schema/model/AbstractElement;Lio/github/optimumcode/json/schema/extension/ExternalAssertionContext;Lio/github/optimumcode/json/schema/ErrorCollector;)Z
348+
public static fun validate (Lio/github/optimumcode/json/schema/extension/ExternalAssertion;Lkotlinx/serialization/json/JsonElement;Lio/github/optimumcode/json/schema/extension/ExternalAssertionContext;Lio/github/optimumcode/json/schema/ErrorCollector;)Z
349+
}
350+
343351
public abstract interface class io/github/optimumcode/json/schema/extension/ExternalAssertionContext {
344352
public abstract fun getAnnotationCollector ()Lio/github/optimumcode/json/schema/extension/ExternalAnnotationCollector;
345353
public abstract fun getObjectPath ()Lio/github/optimumcode/json/pointer/JsonPointer;
@@ -354,3 +362,28 @@ public abstract interface class io/github/optimumcode/json/schema/extension/Exte
354362
public abstract fun getSchemaPath ()Lio/github/optimumcode/json/pointer/JsonPointer;
355363
}
356364

365+
public abstract interface class io/github/optimumcode/json/schema/model/AbstractElement {
366+
public abstract fun toString ()Ljava/lang/String;
367+
}
368+
369+
public abstract interface class io/github/optimumcode/json/schema/model/ArrayElement : io/github/optimumcode/json/schema/model/AbstractElement, kotlin/sequences/Sequence {
370+
public abstract fun get (I)Lio/github/optimumcode/json/schema/model/AbstractElement;
371+
public abstract fun getSize ()I
372+
}
373+
374+
public abstract interface class io/github/optimumcode/json/schema/model/ObjectElement : io/github/optimumcode/json/schema/model/AbstractElement, kotlin/sequences/Sequence {
375+
public abstract fun contains (Ljava/lang/String;)Z
376+
public abstract fun get (Ljava/lang/String;)Lio/github/optimumcode/json/schema/model/AbstractElement;
377+
public abstract fun getKeys ()Ljava/util/Set;
378+
public abstract fun getSize ()I
379+
}
380+
381+
public abstract interface class io/github/optimumcode/json/schema/model/PrimitiveElement : io/github/optimumcode/json/schema/model/AbstractElement {
382+
public abstract fun getContent ()Ljava/lang/String;
383+
public abstract fun getNumber ()Ljava/lang/Number;
384+
public abstract fun isBoolean ()Z
385+
public abstract fun isNull ()Z
386+
public abstract fun isNumber ()Z
387+
public abstract fun isString ()Z
388+
}
389+

json-schema-validator/src/commonMain/kotlin/io/github/optimumcode/json/schema/FormatValidator.kt

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package io.github.optimumcode.json.schema
22

3-
import kotlinx.serialization.json.JsonElement
3+
import io.github.optimumcode.json.schema.model.AbstractElement
44
import kotlin.jvm.JvmStatic
55

66
/**
7-
* The [FormatValidator] is used to check whether the [JsonElement] matches the expected format.
8-
* If the [JsonElement] is not of the required type (e.g. validator expects string but the [JsonElement] is an object)
7+
* The [FormatValidator] is used to check whether the [AbstractElement] matches the expected format.
8+
* If the [AbstractElement] is not of the required type
9+
* (e.g. validator expects string but the [AbstractElement] is an object)
910
* the validator **MUST** return [FormatValidator.Valid] result
1011
*/
1112
@ExperimentalApi
@@ -16,7 +17,7 @@ public interface FormatValidator {
1617
* @param element JSON element to validate against the expected format
1718
* @return the result of the validation
1819
*/
19-
public fun validate(element: JsonElement): FormatValidationResult
20+
public fun validate(element: AbstractElement): FormatValidationResult
2021

2122
public companion object {
2223
@Suppress("ktlint:standard:function-naming", "FunctionName")

json-schema-validator/src/commonMain/kotlin/io/github/optimumcode/json/schema/JsonSchema.kt

+29-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import io.github.optimumcode.json.schema.internal.DefaultAssertionContext
66
import io.github.optimumcode.json.schema.internal.DefaultReferenceResolver
77
import io.github.optimumcode.json.schema.internal.IsolatedLoader
88
import io.github.optimumcode.json.schema.internal.JsonSchemaAssertion
9+
import io.github.optimumcode.json.schema.internal.wrapper.wrap
10+
import io.github.optimumcode.json.schema.model.AbstractElement
911
import kotlinx.serialization.json.JsonElement
1012
import kotlin.jvm.JvmOverloads
1113
import kotlin.jvm.JvmStatic
@@ -28,6 +30,31 @@ public class JsonSchema internal constructor(
2830
public fun validate(
2931
value: JsonElement,
3032
errorCollector: ErrorCollector,
33+
): Boolean = validate(value.wrap(), errorCollector)
34+
35+
/**
36+
* Validates [value] against this [JsonSchema].
37+
* The provided [outputCollectorProvider] will be used to create [OutputCollector]
38+
* which collects the validation result.
39+
*
40+
* @return validation result depending on [outputCollectorProvider]
41+
*/
42+
public fun <T> validate(
43+
value: JsonElement,
44+
outputCollectorProvider: OutputCollector.Provider<T>,
45+
): T = validate(value.wrap(), outputCollectorProvider)
46+
47+
/**
48+
* Validates [value] against this [JsonSchema].
49+
* If the [value] is valid against the schema the function returns `true`.
50+
* Otherwise, it returns `false`.
51+
*
52+
* All reported errors will be reported to [ErrorCollector.onError]
53+
*/
54+
@ExperimentalApi
55+
public fun validate(
56+
value: AbstractElement,
57+
errorCollector: ErrorCollector,
3158
): Boolean {
3259
val context = DefaultAssertionContext(JsonPointer.ROOT, referenceResolver)
3360
return DelegateOutputCollector(errorCollector).use {
@@ -42,8 +69,9 @@ public class JsonSchema internal constructor(
4269
*
4370
* @return validation result depending on [outputCollectorProvider]
4471
*/
72+
@ExperimentalApi
4573
public fun <T> validate(
46-
value: JsonElement,
74+
value: AbstractElement,
4775
outputCollectorProvider: OutputCollector.Provider<T>,
4876
): T {
4977
val context = DefaultAssertionContext(JsonPointer.ROOT, referenceResolver)

json-schema-validator/src/commonMain/kotlin/io/github/optimumcode/json/schema/extension/ExternalAnnotationCollector.kt

+2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package io.github.optimumcode.json.schema.extension
22

33
import io.github.optimumcode.json.schema.AnnotationKey
4+
import io.github.optimumcode.json.schema.ExperimentalApi
45

6+
@ExperimentalApi
57
public interface ExternalAnnotationCollector {
68
/**
79
* Adds annotation with provided [key]

json-schema-validator/src/commonMain/kotlin/io/github/optimumcode/json/schema/extension/ExternalAssertion.kt

+26-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
package io.github.optimumcode.json.schema.extension
22

33
import io.github.optimumcode.json.schema.ErrorCollector
4+
import io.github.optimumcode.json.schema.ExperimentalApi
5+
import io.github.optimumcode.json.schema.internal.wrapper.JsonWrapper
6+
import io.github.optimumcode.json.schema.model.AbstractElement
47
import kotlinx.serialization.json.JsonElement
58

69
/**
710
* This interface allows you to implement your own schema assertion.
811
* This interface **does not** allow implementing custom applicators.
912
* Only simple assertions (like: _format_, _type_) can be implemented.
1013
*/
14+
@Suppress("detekt:ForbiddenComment")
15+
@ExperimentalApi
1116
public interface ExternalAssertion {
1217
/**
1318
* Validates passes [element].
@@ -24,9 +29,28 @@ public interface ExternalAssertion {
2429
* @param errorCollector handler for [io.github.optimumcode.json.schema.ValidationError] produced by assertion
2530
* @return `true` if element is valid against assertion. Otherwise, returns `false`
2631
*/
32+
public fun validate(
33+
element: AbstractElement,
34+
context: ExternalAssertionContext,
35+
errorCollector: ErrorCollector,
36+
): Boolean =
37+
// TODO: remove it after two minor/major release
38+
validate(element.unwrap(), context, errorCollector)
39+
40+
// TODO: increase level to error in the next release
41+
@Deprecated(
42+
message = "override validate(AbstractElement, ExternalAssertionContext, ErrorCollector) instead",
43+
level = DeprecationLevel.WARNING,
44+
)
2745
public fun validate(
2846
element: JsonElement,
2947
context: ExternalAssertionContext,
3048
errorCollector: ErrorCollector,
31-
): Boolean
32-
}
49+
): Boolean = throw UnsupportedOperationException()
50+
}
51+
52+
internal fun AbstractElement.unwrap(): JsonElement =
53+
when (this) {
54+
is JsonWrapper -> unwrap()
55+
else -> error("unsupported element type: ${this::class.simpleName}")
56+
}

json-schema-validator/src/commonMain/kotlin/io/github/optimumcode/json/schema/extension/ExternalAssertionContext.kt

+2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package io.github.optimumcode.json.schema.extension
22

33
import io.github.optimumcode.json.pointer.JsonPointer
4+
import io.github.optimumcode.json.schema.ExperimentalApi
45

6+
@ExperimentalApi
57
public interface ExternalAssertionContext {
68
/**
79
* A JSON pointer to the currently validating element in the object that is being validated

json-schema-validator/src/commonMain/kotlin/io/github/optimumcode/json/schema/extension/ExternalAssertionFactory.kt

+2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package io.github.optimumcode.json.schema.extension
22

3+
import io.github.optimumcode.json.schema.ExperimentalApi
34
import kotlinx.serialization.json.JsonElement
45

6+
@ExperimentalApi
57
public interface ExternalAssertionFactory {
68
/**
79
* A keyword that is associated with the [ExternalAssertion] created by this factory.

json-schema-validator/src/commonMain/kotlin/io/github/optimumcode/json/schema/extension/ExternalLoadingContext.kt

+2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package io.github.optimumcode.json.schema.extension
22

33
import io.github.optimumcode.json.pointer.JsonPointer
4+
import io.github.optimumcode.json.schema.ExperimentalApi
45

6+
@ExperimentalApi
57
public interface ExternalLoadingContext {
68
/**
79
* A JSON pointer to the current position in schema associated with currently processing element

json-schema-validator/src/commonMain/kotlin/io/github/optimumcode/json/schema/internal/BooleanSchemaAssertion.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ package io.github.optimumcode.json.schema.internal
33
import io.github.optimumcode.json.pointer.JsonPointer
44
import io.github.optimumcode.json.schema.OutputCollector
55
import io.github.optimumcode.json.schema.ValidationError
6-
import kotlinx.serialization.json.JsonElement
6+
import io.github.optimumcode.json.schema.model.AbstractElement
77

88
internal class FalseSchemaAssertion(
99
private val path: JsonPointer,
1010
) : JsonSchemaAssertion {
1111
override fun validate(
12-
element: JsonElement,
12+
element: AbstractElement,
1313
context: AssertionContext,
1414
errorCollector: OutputCollector<*>,
1515
): Boolean {
@@ -28,7 +28,7 @@ internal class FalseSchemaAssertion(
2828

2929
internal object TrueSchemaAssertion : JsonSchemaAssertion {
3030
override fun validate(
31-
element: JsonElement,
31+
element: AbstractElement,
3232
context: AssertionContext,
3333
errorCollector: OutputCollector<*>,
3434
): Boolean {

json-schema-validator/src/commonMain/kotlin/io/github/optimumcode/json/schema/internal/JsonSchemaAssertion.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package io.github.optimumcode.json.schema.internal
22

33
import io.github.optimumcode.json.schema.OutputCollector
4-
import kotlinx.serialization.json.JsonElement
4+
import io.github.optimumcode.json.schema.model.AbstractElement
55

66
internal interface JsonSchemaAssertion {
77
/**
@@ -20,7 +20,7 @@ internal interface JsonSchemaAssertion {
2020
* @return `true` if element is valid against assertion. Otherwise, returns `false`
2121
*/
2222
fun validate(
23-
element: JsonElement,
23+
element: AbstractElement,
2424
context: AssertionContext,
2525
errorCollector: OutputCollector<*>,
2626
): Boolean

json-schema-validator/src/commonMain/kotlin/io/github/optimumcode/json/schema/internal/JsonSchemaRoot.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package io.github.optimumcode.json.schema.internal
33
import com.eygraber.uri.Uri
44
import io.github.optimumcode.json.pointer.JsonPointer
55
import io.github.optimumcode.json.schema.OutputCollector
6-
import kotlinx.serialization.json.JsonElement
6+
import io.github.optimumcode.json.schema.model.AbstractElement
77

88
internal class JsonSchemaRoot(
99
private val scopeId: Uri,
@@ -12,7 +12,7 @@ internal class JsonSchemaRoot(
1212
private val canBeReferencedRecursively: Boolean,
1313
) : JsonSchemaAssertion {
1414
override fun validate(
15-
element: JsonElement,
15+
element: AbstractElement,
1616
context: AssertionContext,
1717
errorCollector: OutputCollector<*>,
1818
): Boolean {

json-schema-validator/src/commonMain/kotlin/io/github/optimumcode/json/schema/internal/RecursiveRefSchemaAssertion.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import io.github.optimumcode.json.pointer.plus
55
import io.github.optimumcode.json.pointer.relative
66
import io.github.optimumcode.json.schema.AbsoluteLocation
77
import io.github.optimumcode.json.schema.OutputCollector
8-
import kotlinx.serialization.json.JsonElement
8+
import io.github.optimumcode.json.schema.model.AbstractElement
99

1010
internal class RecursiveRefSchemaAssertion(
1111
private val basePath: JsonPointer,
1212
private val refId: RefId,
1313
) : JsonSchemaAssertion {
1414
override fun validate(
15-
element: JsonElement,
15+
element: AbstractElement,
1616
context: AssertionContext,
1717
errorCollector: OutputCollector<*>,
1818
): Boolean {

json-schema-validator/src/commonMain/kotlin/io/github/optimumcode/json/schema/internal/RefSchemaAssertion.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import io.github.optimumcode.json.pointer.plus
66
import io.github.optimumcode.json.pointer.relative
77
import io.github.optimumcode.json.schema.AbsoluteLocation
88
import io.github.optimumcode.json.schema.OutputCollector
9-
import kotlinx.serialization.json.JsonElement
9+
import io.github.optimumcode.json.schema.model.AbstractElement
1010

1111
internal class RefSchemaAssertion(
1212
private val basePath: JsonPointer,
@@ -17,7 +17,7 @@ internal class RefSchemaAssertion(
1717
private lateinit var refAbsolutePath: Uri
1818

1919
override fun validate(
20-
element: JsonElement,
20+
element: AbstractElement,
2121
context: AssertionContext,
2222
errorCollector: OutputCollector<*>,
2323
): Boolean {

json-schema-validator/src/commonMain/kotlin/io/github/optimumcode/json/schema/internal/factories/ExternalAssertionFactoryAdapter.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import io.github.optimumcode.json.schema.extension.ExternalAssertionFactory
77
import io.github.optimumcode.json.schema.internal.AssertionContext
88
import io.github.optimumcode.json.schema.internal.JsonSchemaAssertion
99
import io.github.optimumcode.json.schema.internal.LoadingContext
10+
import io.github.optimumcode.json.schema.model.AbstractElement
1011
import kotlinx.serialization.json.JsonElement
1112

1213
internal class ExternalAssertionFactoryAdapter(
@@ -25,7 +26,7 @@ private class ExternalAssertionAdapter(
2526
private val externalAssertion: ExternalAssertion,
2627
) : JsonSchemaAssertion {
2728
override fun validate(
28-
element: JsonElement,
29+
element: AbstractElement,
2930
context: AssertionContext,
3031
errorCollector: OutputCollector<*>,
3132
): Boolean =

json-schema-validator/src/commonMain/kotlin/io/github/optimumcode/json/schema/internal/factories/array/AdditionalItemsAssertion.kt

+5-4
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import io.github.optimumcode.json.schema.AnnotationKey
55
import io.github.optimumcode.json.schema.OutputCollector
66
import io.github.optimumcode.json.schema.internal.AssertionContext
77
import io.github.optimumcode.json.schema.internal.JsonSchemaAssertion
8-
import kotlinx.serialization.json.JsonArray
9-
import kotlinx.serialization.json.JsonElement
8+
import io.github.optimumcode.json.schema.model.AbstractElement
9+
import io.github.optimumcode.json.schema.model.ArrayElement
10+
import io.github.optimumcode.json.schema.model.lastIndex
1011

1112
internal class AdditionalItemsAssertion(
1213
private val location: JsonPointer,
@@ -16,12 +17,12 @@ internal class AdditionalItemsAssertion(
1617
private val returnIfNoIndex: Boolean,
1718
) : JsonSchemaAssertion {
1819
override fun validate(
19-
element: JsonElement,
20+
element: AbstractElement,
2021
context: AssertionContext,
2122
errorCollector: OutputCollector<*>,
2223
): Boolean {
2324
return errorCollector.updateKeywordLocation(location).use {
24-
if (element !is JsonArray) {
25+
if (element !is ArrayElement) {
2526
return@use true
2627
}
2728
val lastProcessedIndex: Int =

0 commit comments

Comments
 (0)