networknt / json-schema-validator

A fast Java JSON schema validator that supports draft V4, V6, V7, V2019-09 and V2020-12
Apache License 2.0
822 stars 323 forks source link

Schema Validation for property from other schmea #978

Closed gourav157537 closed 6 months ago

gourav157537 commented 6 months ago

I want to do of property referring to property of other schema. I am getting below error while trying

Error: Exception in thread "main" com.networknt.schema.JsonSchemaException: #/properties/id/$ref: Reference abcuri:ref.json/#id cannot be resolved

Library version

com.networknt json-schema-validator 1.0.87

Example to retry.

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.*;
import com.networknt.schema.uri.URIFactory;
import com.networknt.schema.uri.URIFetcher;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Main {

    static Map<String,String> schemaLoader(){
        Map<String,String> jsonSchemaResolver = new HashMap<>();
        jsonSchemaResolver.put("main.json", """
                {
                  "$schema": "http://json-schema.org/draft/2019-09/schema",
                  "additionalProperties": false,
                  "type": "object",

                  "properties": {
                    "id": {
                      "$ref": "abcuri:ref.json/#id"

                    },
                    "effectiveTime": {
                      "$ref": "abcuri:ref.json/#date-time"

                    },
                    "idType": {
                      "type": "string",

                      "enum": [
                        "Internal",
                        "External"
                      ]
                    }
                  }
                }
                """);
        jsonSchemaResolver.put("ref.json", """
                {
                  "$schema": "http://json-schema.org/draft/2019-09/schema",
                  "additionalProperties": false,
                  "type": "object",
                  "$defs": {
                    "id": {

                      "type": "string",
                      "minLength": 5,
                      "maxLength": 100

                    },
                    "date-time": {
                      "type": "string",
                      "pattern": "date-time"
                    }
                  }
                }

                """);
        return jsonSchemaResolver;
    }

    public static void main(String[] args) throws JsonProcessingException {
        String data= """
        {"id":"abcde","idType":"Explicit","effectiveTime":"2022-02-02T13:00:00Z"}
        """;
        Map<String,String> jsonSchemaResolver = schemaLoader();
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode jsonNode = objectMapper.readTree(data);
        JsonSchemaFactory localFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909))
                .uriFetcher(new ValidatorUriFetcher(jsonSchemaResolver), "abcuri")
                  .uriFactory(new ValidatorUriFactory(), "abcuri")
                .build();
        SchemaValidatorsConfig schemaValidatorsConfig = new SchemaValidatorsConfig();
        schemaValidatorsConfig.setFailFast(false);
        schemaValidatorsConfig.setPathType(PathType.JSON_POINTER);
        JsonSchema schema = localFactory.getSchema(jsonSchemaResolver
                .get("main.json"), schemaValidatorsConfig);
        schema.initializeValidators();

        Set<ValidationMessage> errors = schema.validate(jsonNode);
        if (!errors.isEmpty()) {
            System.out.println(errors.toString());
        }
        System.out.println(errors);
    }
}
class ValidatorUriFactory implements URIFactory {

    @Override
    public URI create(String uri) {
        try {
            return new URI(uri);
        } catch (URISyntaxException | NullPointerException e) {
            // this is the scenario that one of the $ref URI is invalid
            var errMsg = String.format("Invalid metadata uri - [%s]", uri);

            try {
                throw e;
            } catch (URISyntaxException ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    @Override
    public URI create(URI baseURI, String segment) {
        return null;
    }

}
class ValidatorUriFetcher implements URIFetcher {
    private final Map<String ,String > jsonSchemaResolver;

    ValidatorUriFetcher(Map<String, String> jsonSchemaResolver) {
        this.jsonSchemaResolver = jsonSchemaResolver;
    }

    /**
     * @param uri
     * @return InputStream
     * @throws IOException
     */
    @Override
    public InputStream fetch(final URI uri) throws IOException {

        String schema = uri.toString().replace("abcuri:", "").replace("/","");

        String schemaString = jsonSchemaResolver.get(schema);
        return new ByteArrayInputStream(schemaString.getBytes(StandardCharsets.UTF_8));
    }
}
stevehu commented 6 months ago

A lot of issues have been resolved in the recent updates. I encourage you to try the 1.3.3 version instead.

justin-tay commented 6 months ago

You are getting the error Reference abcuri:ref.json/#id cannot be resolved because your reference is incorrect and there is nothing at that reference.

Given how you have defined your schema in ref.json.

The reference abcuri:ref.json/#id should be abcuri:ref.json/#/$defs/id.

The reference abcuri:ref.json/#date-time should be abcuri:ref.json/#/$defs/date-time.

justin-tay commented 6 months ago

Closing as given the correct $ref this cannot be reproduced.

package com.networknt.schema;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.junit.jupiter.api.Test;

import com.networknt.schema.SpecVersion.VersionFlag;

public class Issue978Test {
    @Test
    void test() {
        SchemaValidatorsConfig config = new SchemaValidatorsConfig();
        config.setFormatAssertionsEnabled(true);
        config.setPathType(PathType.JSON_POINTER);
        String mainSchemaData = "{\r\n"
                + "                  \"$schema\": \"http://json-schema.org/draft/2019-09/schema\",\r\n"
                + "                  \"additionalProperties\": false,\r\n"
                + "                  \"type\": \"object\",\r\n"
                + "                                \r\n"
                + "                  \"properties\": {\r\n"
                + "                    \"id\": {\r\n"
                + "                      \"$ref\": \"abcuri:ref.json#/$defs/id\"\r\n"
                + "                                \r\n"
                + "                    },\r\n"
                + "                    \"effectiveTime\": {\r\n"
                + "                      \"$ref\": \"abcuri:ref.json#/$defs/date-time\"\r\n"
                + "                                \r\n"
                + "                    },\r\n"
                + "                    \"idType\": {\r\n"
                + "                      \"type\": \"string\",\r\n"
                + "                                \r\n"
                + "                      \"enum\": [\r\n"
                + "                        \"Internal\",\r\n"
                + "                        \"External\"\r\n"
                + "                      ]\r\n"
                + "                    }\r\n"
                + "                  }\r\n"
                + "                }";
        String refSchemaData = "{\r\n"
                + "                  \"$schema\": \"http://json-schema.org/draft/2019-09/schema\",\r\n"
                + "                  \"additionalProperties\": false,\r\n"
                + "                  \"type\": \"object\",\r\n"
                + "                  \"$defs\": {\r\n"
                + "                    \"id\": {\r\n"
                + "                                \r\n"
                + "                      \"type\": \"string\",\r\n"
                + "                      \"minLength\": 5,\r\n"
                + "                      \"maxLength\": 100\r\n"
                + "                                \r\n"
                + "                    },\r\n"
                + "                    \"date-time\": {\r\n"
                + "                      \"type\": \"string\",\r\n"
                + "                      \"pattern\": \"date-time\"\r\n"
                + "                    }\r\n"
                + "                  }\r\n"
                + "                }";
        Map<String, String> schemas = new HashMap<>();
        schemas.put("abcuri:main.json", mainSchemaData);
        schemas.put("abcuri:ref.json", refSchemaData);

        JsonSchema schema = JsonSchemaFactory
                .getInstance(VersionFlag.V201909,
                        builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(schemas)))
                .getSchema(SchemaLocation.of("abcuri:main.json"), config);

        String inputData = "{\"id\":\"abcde\",\"idType\":\"Explicit\",\"effectiveTime\":\"2022-02-02T13:00:00Z\"}";
        Set<ValidationMessage> messages = schema.validate(inputData, InputFormat.JSON);
        System.out.println(messages);
    }
}