diff --git a/src/main/java/es/elixir/bsc/json/schema/model/JsonArraySchema.java b/src/main/java/es/elixir/bsc/json/schema/model/JsonArraySchema.java
index e86e841..c0b1852 100644
--- a/src/main/java/es/elixir/bsc/json/schema/model/JsonArraySchema.java
+++ b/src/main/java/es/elixir/bsc/json/schema/model/JsonArraySchema.java
@@ -36,6 +36,7 @@
public interface JsonArraySchema extends JsonSchema {
public final static String ITEMS = "items";
+ public final static String PREFIX_ITEMS = "prefixItems";
public final static String UNIQUE_ITEMS = "uniqueItems";
public final static String ADDITIONAL_ITEMS = "additionalItems";
public final static String UNEVALUATED_ITEMS = "unevaluatedItems";
@@ -54,19 +55,33 @@ public interface JsonArraySchema extends JsonSchema {
void setMaxItems(Long maxItems);
/**
+ * returns a list that contain one or more schemas.
+ *
+ * In 2020-12 returns immutable list with just one schema.
+ * In 2019-09 and before the list may contain more schemas.
+ *
* In a case where there is only one schema in the list it is
- * either {...} or [{...}].Setting 'additionalItems' to NULL
- * means there is a single schema and not an array with only one schema defined.
- *
- * @param
+ * either {...} or [{...}].
+ *
+ * @param any implementation specific class that implements JsonSchema
*
* @return list of schemas
*/
List getItems();
+ /**
+ * Returns 2020-12 'prefixItems'
+ *
+ * @param any implementation specific class that implements JsonSchema
+ * @return
+ */
+ List getPrefixItems();
+
Boolean isUniqueItems();
/**
+ * Returns 'additionalSchema' or 'items' in the 2020-09
+ *
* @param
*
* @return 'additionalSchema' JsonSchema, NULL if FALSE (or not set),
diff --git a/src/main/java/es/elixir/bsc/json/schema/model/impl/JsonArraySchemaImpl.java b/src/main/java/es/elixir/bsc/json/schema/model/impl/JsonArraySchemaImpl.java
index fb3460e..c5351ff 100644
--- a/src/main/java/es/elixir/bsc/json/schema/model/impl/JsonArraySchemaImpl.java
+++ b/src/main/java/es/elixir/bsc/json/schema/model/impl/JsonArraySchemaImpl.java
@@ -56,7 +56,11 @@
public class JsonArraySchemaImpl extends PrimitiveSchemaImpl
implements JsonArraySchema {
- private List items;
+ private final List items;
+
+ // the items are actually a 'prefixItems'
+ private boolean prefixItems;
+
private Boolean additionalItems;
private Boolean uniqueItems;
private AbstractJsonSchema additionalItemsSchema;
@@ -74,6 +78,8 @@ public class JsonArraySchemaImpl extends PrimitiveSchemaImpl
public JsonArraySchemaImpl(AbstractJsonSchemaElement parent,
JsonSchemaLocator locator, String jsonPointer) {
super(parent, locator, jsonPointer);
+
+ items = new ArrayList();
}
@Override
@@ -93,11 +99,15 @@ public Stream getChildren() {
@Override
public List getItems() {
- if (items == null) {
- items = new ArrayList<>();
- }
-
- return items;
+ // in 2020-12 'items' is a schema
+ return prefixItems ? additionalItemsSchema != null ? List.of(additionalItemsSchema) : null : items;
+ }
+
+ @Override
+ public List getPrefixItems() {
+ // 2019-09 'items' == 2020-12 'prefixItems'
+ // 2019-09 'additionalItemsSchema' == 2020-12 'items'
+ return prefixItems ? items : null;
}
@Override
@@ -155,7 +165,7 @@ public JsonArraySchemaImpl read(JsonSubschemaParser parser, JsonObject object)
throws JsonSchemaException {
super.read(parser, object);
-
+
final JsonNumber min = JsonSchemaUtil.check(object.getJsonNumber(MIN_ITEMS), JsonValue.ValueType.NUMBER);
if (min != null) {
minItems = min.longValue();
@@ -192,47 +202,59 @@ public JsonArraySchemaImpl read(JsonSubschemaParser parser, JsonObject object)
}
JsonValue jitems = object.get(ITEMS);
- if (jitems != null) {
+ JsonValue jadditionalItems = object.get(ADDITIONAL_ITEMS);
+
+ JsonArray jprefixitems = JsonSchemaUtil.check(object.get(PREFIX_ITEMS), JsonValue.ValueType.ARRAY);
+ if (jprefixitems != null) {
+ // in 2020-12 when 'prefixItems' is defined 'items' are 'additionalItems'
+ prefixItems = true;
+ jadditionalItems = jitems;
+ } else if (jitems != null) {
switch(jitems.getValueType()) {
case OBJECT:
case TRUE:
case FALSE: final AbstractJsonSchema schema = parser.parse(locator, this, getJsonPointer() + "/" + ITEMS, jitems, null);
- getItems().add(schema);
+ items.add(schema);
break;
- case ARRAY: additionalItems = true;
- for (int i = 0, n = jitems.asJsonArray().size(); i < n; i++) {
- final JsonValue value = jitems.asJsonArray().get(i);
- switch(value.getValueType()) {
- case OBJECT:
- case TRUE:
- case FALSE: final AbstractJsonSchema arr = parser.parse(locator, this, getJsonPointer() + "/" + ITEMS + "/" + i, value, null);
- getItems().add(arr);
- break;
- default: throw new JsonSchemaException(new ParsingError(ParsingMessage.INVALID_ATTRIBUTE_TYPE,
- ITEMS + "/" + i, value.getValueType().name(), "either an object or boolean"));
- }
- }
+ case ARRAY: jprefixitems = jitems.asJsonArray();
break;
default: throw new JsonSchemaException(new ParsingError(ParsingMessage.INVALID_ATTRIBUTE_TYPE,
ITEMS, jitems.getValueType().name(), "either an object, boolean or an array"));
-
}
}
-
- if (additionalItems != null) {
- final JsonValue jadditionalItems = object.get(ADDITIONAL_ITEMS);
- if (jadditionalItems != null) {
- switch(jadditionalItems.getValueType()) {
- case OBJECT: additionalItems = null; break;
- case FALSE: additionalItems = false;
- case TRUE: break;
- default: throw new JsonSchemaException(new ParsingError(ParsingMessage.INVALID_ATTRIBUTE_TYPE,
- ADDITIONAL_ITEMS, jadditionalItems.getValueType().name(), "either object or boolean"));
+
+ if (jprefixitems != null) {
+ additionalItems = true;
+
+ final String propertyName = prefixItems ? PREFIX_ITEMS : ITEMS;
+
+ for (int i = 0, n = jprefixitems.size(); i < n; i++) {
+ final JsonValue value = jprefixitems.get(i);
+ switch(value.getValueType()) {
+ case OBJECT:
+ case TRUE:
+ case FALSE: final AbstractJsonSchema arr = parser.parse(locator, this, getJsonPointer() + "/" + propertyName + "/" + i, value, null);
+ items.add(arr);
+ break;
+ default: throw new JsonSchemaException(new ParsingError(ParsingMessage.INVALID_ATTRIBUTE_TYPE,
+ propertyName + "/" + i, value.getValueType().name(), "either an object or boolean"));
}
- additionalItemsSchema = parser.parse(locator, this, getJsonPointer() + "/" + ADDITIONAL_ITEMS, jadditionalItems, null);
}
}
+ if (additionalItems != null && jadditionalItems != null) {
+ final String propertyName = jadditionalItems == jitems ? ITEMS : ADDITIONAL_ITEMS;
+
+ switch(jadditionalItems.getValueType()) {
+ case OBJECT: break;
+ case FALSE: additionalItems = false;
+ case TRUE: break;
+ default: throw new JsonSchemaException(new ParsingError(ParsingMessage.INVALID_ATTRIBUTE_TYPE,
+ propertyName, jadditionalItems.getValueType().name(), "either object or boolean"));
+ }
+ additionalItemsSchema = parser.parse(locator, this, getJsonPointer() + "/" + propertyName, jadditionalItems, null);
+ }
+
final JsonValue junevaluatedItems = object.get(UNEVALUATED_ITEMS);
if (junevaluatedItems != null) {
switch(junevaluatedItems.getValueType()) {
diff --git a/src/test/java/es/elixir/bsc/json/schema/org/tests/JsonSchemaItemsTest.java b/src/test/java/es/elixir/bsc/json/schema/org/tests/JsonSchemaItemsTest.java
index 0b478b3..08d4063 100644
--- a/src/test/java/es/elixir/bsc/json/schema/org/tests/JsonSchemaItemsTest.java
+++ b/src/test/java/es/elixir/bsc/json/schema/org/tests/JsonSchemaItemsTest.java
@@ -59,8 +59,8 @@ public void test_draft201909() {
test(JSON_DRAFT201909_TEST_FILE);
}
-// @Test
-// public void test_draft202012() {
-// test(JSON_DRAFT202012_TEST_FILE);
-// }
+ @Test
+ public void test_draft202012() {
+ test(JSON_DRAFT202012_TEST_FILE);
+ }
}
diff --git a/src/test/java/es/elixir/bsc/json/schema/org/tests/JsonSchemaPrefixItemsTest.java b/src/test/java/es/elixir/bsc/json/schema/org/tests/JsonSchemaPrefixItemsTest.java
new file mode 100644
index 0000000..94d7a4b
--- /dev/null
+++ b/src/test/java/es/elixir/bsc/json/schema/org/tests/JsonSchemaPrefixItemsTest.java
@@ -0,0 +1,42 @@
+/**
+ * *****************************************************************************
+ * Copyright (C) 2024 ELIXIR ES, Spanish National Bioinformatics Institute (INB)
+ * and Barcelona Supercomputing Center (BSC)
+ *
+ * Modifications to the initial code base are copyright of their respective
+ * authors, or their employers as appropriate.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *****************************************************************************
+ */
+
+package es.elixir.bsc.json.schema.org.tests;
+
+import org.junit.Test;
+
+/**
+ * @author Dmitry Repchevsky
+ */
+
+public class JsonSchemaPrefixItemsTest extends JsonSchemaOrgTest {
+
+ private final static String JSON_DRAFT202012_TEST_FILE = "json-schema-org/tests/draft2020-12/prefixItems.json";
+
+ @Test
+ public void test_draft202012() {
+ test(JSON_DRAFT202012_TEST_FILE);
+ }
+}