Skip to content

Commit

Permalink
implemented $dynamicRef / $dynamicAnchor (from 2020-12)
Browse files Browse the repository at this point in the history
  • Loading branch information
redmitry committed Mar 15, 2024
1 parent 563cfec commit 9588194
Show file tree
Hide file tree
Showing 153 changed files with 13,467 additions and 748 deletions.
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<groupId>es.elixir.bsc.json.schema</groupId>
<artifactId>jaronuinga</artifactId>
<version>0.5.2</version>
<version>0.5.3</version>
<packaging>jar</packaging>

<organization>
Expand All @@ -33,8 +33,8 @@
</developers>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>

<dependencies>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* *****************************************************************************
* Copyright (C) 2023 ELIXIR ES, Spanish National Bioinformatics Institute (INB)
* 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
Expand Down Expand Up @@ -35,7 +35,8 @@ public enum JsonSchemaVersion {
SCHEMA_DRAFT_04("http://json-schema.org/draft-04/schema#"),
SCHEMA_DRAFT_06("http://json-schema.org/draft-06/schema#"),
SCHEMA_DRAFT_07("http://json-schema.org/draft-07/schema#"),
SCHEMA_DRAFT_2019_09("https://json-schema.org/draft/2019-09/schema");
SCHEMA_DRAFT_2019_09("https://json-schema.org/draft/2019-09/schema"),
SCHEMA_DRAFT_2020_12("https://json-schema.org/draft/2020-12/schema");

public final String VALUE;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,33 +84,43 @@ public JsonValue getSchema(URI uri, String jsonPointer)

JsonValue schema = schemas.get(uri);
if (schema == null) {
final InputStream in;
final String scheme = uri.getScheme();
if ("http".equals(scheme) || "https".equals(scheme)) {
try {
final HttpResponse<InputStream> response =
http_client.send(HttpRequest.newBuilder(uri).build(),
HttpResponse.BodyHandlers.ofInputStream());
if (response == null) {
throw new IOException(String.format("no respnse from %s", uri));
try {
uri = new URI(uri.getScheme(), uri.getSchemeSpecificPart(), null);
schema = schemas.get(uri);
if (schema == null) {
InputStream in = null;
final String scheme = uri.getScheme();
if ("http".equals(scheme) || "https".equals(scheme)) {
try {
final HttpResponse<InputStream> response =
http_client.send(HttpRequest.newBuilder(uri).build(),
HttpResponse.BodyHandlers.ofInputStream());
if (response == null) {
throw new IOException(String.format("no respnse from %s", uri));
}

if (response.statusCode() >= 300) {
throw new IOException(String.format("error reading from %s %d", uri, response.statusCode()));
}
in = response.body();
} catch (InterruptedException ex) {
throw new IOException(String.format("no respnse from %s", uri));
}
} else {
// not http schemas like "file" etc...
in = uri.toURL().openStream();
}

if (response.statusCode() >= 300) {
throw new IOException(String.format("error reading from %s %d", uri, response.statusCode()));
try {
final JsonReaderFactory factory = Json.createReaderFactory(Collections.EMPTY_MAP);
final JsonReader reader = factory.createReader(in);
schema = reader.readValue();
setSchema(schema);
} finally {
in.close();
}
in = response.body();
} catch (InterruptedException ex) {
throw new IOException(String.format("no respnse from %s", uri));
}
} else {
// not http schemas like "file" etc...
in = uri.toURL().openStream();
}

final JsonReaderFactory factory = Json.createReaderFactory(Collections.EMPTY_MAP);
final JsonReader reader = factory.createReader(in);
schema = reader.readValue();
setSchema(schema);
} catch (URISyntaxException ex) {}
}

if ("/".endsWith(jsonPointer)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* *****************************************************************************
* Copyright (C) 2023 ELIXIR ES, Spanish National Bioinformatics Institute (INB)
* 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
Expand Down Expand Up @@ -33,7 +33,6 @@
import es.elixir.bsc.json.schema.ParsingMessage;
import static es.elixir.bsc.json.schema.model.JsonEnum.ENUM;
import es.elixir.bsc.json.schema.model.JsonType;
import es.elixir.bsc.json.schema.model.impl.JsonAnyOfImpl;
import es.elixir.bsc.json.schema.model.impl.JsonArraySchemaImpl;
import es.elixir.bsc.json.schema.model.impl.JsonBooleanSchemaImpl;
import es.elixir.bsc.json.schema.model.impl.JsonEnumImpl;
Expand All @@ -52,6 +51,7 @@
import es.elixir.bsc.json.schema.model.impl.JsonConstImpl;
import es.elixir.bsc.json.schema.model.impl.JsonReferenceImpl;
import es.elixir.bsc.json.schema.model.impl.AbstractJsonSchemaElement;
import es.elixir.bsc.json.schema.model.impl.JsonMultitypeSchemaWrapper;
import java.util.Map;
import javax.json.JsonArray;
import javax.json.JsonObject;
Expand Down Expand Up @@ -87,8 +87,8 @@ public AbstractJsonSchema parse(JsonSchemaLocator locator, AbstractJsonSchemaEle
}

if (value.getValueType() != ValueType.OBJECT) {
throw new JsonSchemaException(new ParsingError(ParsingMessage.SCHEMA_OBJECT_ERROR,
new Object[] {value.getValueType()}));
throw new JsonSchemaException(new ParsingError(
ParsingMessage.SCHEMA_OBJECT_ERROR, value.getValueType()));
}

final JsonObject object = value.asJsonObject();
Expand All @@ -97,7 +97,7 @@ public AbstractJsonSchema parse(JsonSchemaLocator locator, AbstractJsonSchemaEle
if (jref != null) {
if (JsonValue.ValueType.STRING != jref.getValueType()) {
throw new JsonSchemaException(new ParsingError(ParsingMessage.INVALID_ATTRIBUTE_TYPE,
new Object[] {JsonReference.REF, jref.getValueType().name(), JsonValue.ValueType.STRING.name()}));
JsonReference.REF, jref.getValueType().name(), JsonValue.ValueType.STRING.name()));
}

// before draft 2019-09 $ref ignored any other properties
Expand All @@ -110,22 +110,22 @@ public AbstractJsonSchema parse(JsonSchemaLocator locator, AbstractJsonSchemaEle
final ValueType vtype;
if (type_value == null) {
vtype = null;
} else {
} else {
vtype = type_value.getValueType();
switch(vtype) {
case STRING:
try {
try {
type = JsonType.fromValue(((JsonString)type_value).getString());
} catch(IllegalArgumentException ex) {
throw new JsonSchemaException(new ParsingError(ParsingMessage.UNKNOWN_OBJECT_TYPE,
new Object[] {((JsonString)type_value).getString()}));
}
} catch(IllegalArgumentException ex) {
throw new JsonSchemaException(new ParsingError(
ParsingMessage.UNKNOWN_OBJECT_TYPE, ((JsonString)type_value).getString()));
}
case ARRAY: break;
default:
default:
throw new JsonSchemaException(new ParsingError(
ParsingMessage.INVALID_ATTRIBUTE_TYPE,
new Object[] {"type", type_value.getValueType().name(),
"either a string or an array"}));
ParsingMessage.INVALID_ATTRIBUTE_TYPE,
"type", type_value.getValueType().name(),
"either a string or an array"));
}
}

Expand All @@ -143,7 +143,8 @@ public AbstractJsonSchema parse(JsonSchemaLocator locator, AbstractJsonSchemaEle
}

if (type == null) {
return new JsonAnyOfImpl(parent, locator, jsonPointer, vtype == ValueType.ARRAY ? type_value.asJsonArray() : null)
return new JsonMultitypeSchemaWrapper(parent, locator, jsonPointer,
vtype == ValueType.ARRAY ? type_value.asJsonArray() : null)
.read(this, object, null);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* *****************************************************************************
* Copyright (C) 2023 ELIXIR ES, Spanish National Bioinformatics Institute (INB)
* 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
Expand Down Expand Up @@ -65,8 +65,8 @@ public JsonSchema read(URL url) throws JsonSchemaException {
try {
return read(new DefaultJsonSchemaLocator(url.toURI()));
} catch (URISyntaxException ex) {
throw new JsonSchemaException(new ParsingError(ParsingMessage.INVALID_REFERENCE,
new Object[] {url.toString()}));
throw new JsonSchemaException(
new ParsingError(ParsingMessage.INVALID_REFERENCE, url.toString()));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* *****************************************************************************
* 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.model;

/**
* @author Dmitry Repchevsky
*/

public interface JsonDynamicReference extends JsonReference {

public final static String DYNAMIC_REF = "$dynamicRef";
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* *****************************************************************************
* Copyright (C) 2023 ELIXIR ES, Spanish National Bioinformatics Institute (INB)
* 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
Expand Down Expand Up @@ -43,6 +43,7 @@ public interface JsonSchema extends JsonSchemaElement {
public final static String DEFS = "$defs";
public final static String ANCHOR = "$anchor";
public final static String RECURSIVE_ANCHOR = "$recursiveAnchor";
public final static String DYNAMIC_ANCHOR = "$dynamicAnchor";
public final static String VOCABULARY = "$vocabulary";

boolean validate(JsonValue value, List<ValidationError> errors, JsonSchemaValidationCallback<JsonValue> callback) throws ValidationException;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* *****************************************************************************
* Copyright (C) 2023 ELIXIR ES, Spanish National Bioinformatics Institute (INB)
* Copyright (C) 2022 ELIXIR ES, Spanish National Bioinformatics Institute (INB)
* and Barcelona Supercomputing Center (BSC)
*
* Modifications to the initial code base are copyright of their respective
Expand Down Expand Up @@ -61,5 +61,5 @@ public interface JsonSchemaElement {
*
* @return stream of child schemas
*/
public abstract <T extends JsonSchemaElement> Stream<T> getChildren();
<T extends JsonSchemaElement> Stream<T> getChildren();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* *****************************************************************************
* Copyright (C) 2023 ELIXIR ES, Spanish National Bioinformatics Institute (INB)
* 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
Expand Down Expand Up @@ -60,12 +60,4 @@ public interface PrimitiveSchema<T extends JsonSchema> extends JsonSchema {
<T extends JsonSchema> T getElse();

JsonReference getReference();

/**
* $RecursiveAnchor property
* @see https://json-schema.org/draft/2019-09/json-schema-core.html#recursive-ref
*
* @return TRUE when "recursiveAnchor": true
*/
boolean isRecursiveAnchor();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* *****************************************************************************
* Copyright (C) 2023 ELIXIR ES, Spanish National Bioinformatics Institute (INB)
* 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
Expand Down Expand Up @@ -28,12 +28,20 @@
import es.elixir.bsc.json.schema.JsonSchemaException;
import es.elixir.bsc.json.schema.JsonSchemaLocator;
import es.elixir.bsc.json.schema.JsonSchemaValidationCallback;
import es.elixir.bsc.json.schema.ParsingError;
import es.elixir.bsc.json.schema.ParsingMessage;
import es.elixir.bsc.json.schema.ValidationError;
import es.elixir.bsc.json.schema.ValidationException;
import es.elixir.bsc.json.schema.impl.JsonSubschemaParser;
import es.elixir.bsc.json.schema.model.JsonReference;
import es.elixir.bsc.json.schema.model.JsonSchemaElement;
import es.elixir.bsc.json.schema.model.JsonType;
import javax.json.JsonException;
import java.util.List;
import javax.json.JsonObject;
import javax.json.JsonValue;
import java.net.URI;
import java.net.URISyntaxException;

/**
* @author Dmitry Repchevsky
Expand All @@ -42,11 +50,51 @@
public abstract class AbstractJsonReferenceImpl extends AbstractJsonSchema<JsonObject>
implements JsonReference {

protected JsonSchemaElement schema;

protected URI ref;
protected String ref_pointer;
protected JsonSchemaLocator ref_locator;
protected JsonSubschemaParser parser;

public AbstractJsonReferenceImpl(AbstractJsonSchemaElement parent, JsonSchemaLocator locator,
String jsonPointer) {
super(parent, locator, jsonPointer);
}

protected void read(JsonSubschemaParser parser, JsonObject object,
JsonType type, String tag) throws JsonSchemaException {

this.parser = parser;

final String jref = object.getString(tag);
try {
ref = URI.create(jref);
final String fragment = ref.getFragment();
if (fragment == null) {
ref_pointer = "/";
ref_locator = getScope().resolve(ref);
} else if ("#".equals(jref)) {
ref_pointer = "/";
ref_locator = getScope();
} else if (fragment.startsWith("/")) {
ref_pointer = fragment;
if (jref.startsWith("#")) {
ref_locator = getScope();
} else {
ref_locator = getScope().resolve(
new URI(ref.getScheme(), ref.getSchemeSpecificPart(), null));
}
} else {
ref_pointer = "/";
ref_locator = getScope().resolve(ref);
}
} catch(JsonException | IllegalArgumentException | URISyntaxException ex) {
throw new JsonSchemaException(
new ParsingError(ParsingMessage.INVALID_REFERENCE, ref));
}
}

@Override
public boolean validate(String jsonPointer, JsonValue value, JsonValue parent,
List evaluated, List<ValidationError> errors,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,14 @@ public AbstractJsonSchema<T> read(JsonSubschemaParser parser, T value,
}

public abstract boolean validate(String jsonPointer, JsonValue value, JsonValue parent,
List evaluated, List<ValidationError> errors,
JsonSchemaValidationCallback<JsonValue> callback)
List evaluated, List<ValidationError> errors,
JsonSchemaValidationCallback<JsonValue> callback)
throws ValidationException;

@Override
public boolean validate(JsonValue value, List<ValidationError> errors,
JsonSchemaValidationCallback<JsonValue> callback)
throws ValidationException {
return validate("", value, null, new ArrayList(), errors, callback);
return validate("/", value, null, new ArrayList(), errors, callback);
}
}
Loading

0 comments on commit 9588194

Please sign in to comment.