Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating the version for com.networknt json-schema-validator from 1.0.74 to 1.3.2 runs into error for : Reference /definitions/testDocument cannot be resolved #964

Closed
Aravinda93 opened this issue Feb 9, 2024 · 5 comments

Comments

@Aravinda93
Copy link

I was previously using the following version of the JSON Schema Validator and everything was working fine when I was validating the JSON against the respective JSON Schema:

com.networknt
json-schema-validator
1.0.74

Following is the code I have for 1.0.74 version:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.JsonSchema;
import com.networknt.schema.JsonSchemaFactory;
import jakarta.enterprise.context.ApplicationScoped;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

@Slf4j
@ApplicationScoped
@RequiredArgsConstructor
public class JsonSchemaValidator {
  private final ObjectMapper objectMapper = new ObjectMapper();
  private final JsonSchemaFactory validatorFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)).objectMapper(objectMapper).build();
  private JsonSchema captureJsonSchema;

  @PostConstruct
  public void postConstruct() {
    captureJsonSchema = loadSchema("/myJsonSchema.json");
  }

  private JsonSchema loadSchema(final String path) {
    final InputStream inputStream = JsonSchemaValidator.class.getResourceAsStream(path);
    return validatorFactory.getSchema(inputStream);
  }

  public void captureTest(final InputStream inputData) {
    try {
      final Set<ValidationMessage> captureErrors = captureJsonSchema.validate(objectMapper.readValue(inputData, JsonNode.class));
      if (!captureErrors.isEmpty()) {
        throw new CaptureValidationException(ValidationMessageFormatter.format(captureErrors));
      }

    } catch (Exception exception) {
      System.out.println(exception.getMessage());
      throw new CaptureValidationException("Exception occurred during validation against JSON Capture schema : " + exception.getMessage(), exception);

    }
  }
}

With its test case:

    @Test
    public void Tes1() throws Exception {
        final InputStream inputStream = getClass().getResourceAsStream("/SampleJSON.json");
        final JsonSchemaValidator jsonSchemaValidator = new JsonSchemaValidator();
        jsonSchemaValidator.postConstruct();
        jsonSchemaValidator.captureTest(inputStream);
    }

The above-provided code works perfectly fine and is able to identify any issues that may be present in JSON by validating against the JSON Schema.

Now I only changed the version from 1.0.74 to latest version 1.3.2 for the Schema validator:

<dependency>
    <groupId>com.networknt</groupId>
    <artifactId>json-schema-validator</artifactId>
    <version>1.3.2</version>
</dependency>

Based on this change I had to change the objectMapper to jsonMapper while creating the instance of the factory:

private final JsonSchemaFactory validatorFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)).jsonMapper(objectMapper).build();

Apart from this everything remains the same including the JSON document provided as input and JSON schema but when I run this test then I get the following error:

: Reference /definitions/testDocument cannot be resolved

CaptureValidationException: Exception occurred during validation against JSON Capture schema : : Reference /definitions/testDocument cannot be resolved

Can anyone please let me know what needs to be modified based on the version update? I am unable to find anything on the web.

@justin-tay
Copy link
Contributor

It's hard to say since you didn't show your schema.

If /definitions/testDocument is really a file relative to your schema then you should load your schema using a SchemaLocation so that it knows the base IRI to resolve it to.

If /definitions/testDocument is supposed to be in the same schema document, then it should be #/definitions/testDocument.

@xinw3
Copy link

xinw3 commented Mar 26, 2024

@justin-tay I'm trying to upgrade from 1.0.64 to 1.4.0 and seeing the same issue. My schema is like the follows:

{
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "$id": "https://json-schema.org/draft/2019-09/schema",
  "title": "test schema",
  "type": "object",
  "properties": {
    "fields": {
      "type": "object",
      "properties": {
        "ids": {
          "$ref": "#/$defs/fruits"
        }
      }
    }
  },
  "$defs": {
    "fruits": {
      "$id": "/fruits/id",
      "type": "object",
      "properties": {
        "berries": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Berry"
          }
        }
      }
    },
    "Berry": {
      "$id": "/berry-id",
      "type": "object",
      "properties": {
        "type": {
          "type": "string"
        }
      }
    }
  }
}

The json schema validator complains: com.networknt.schema.InvalidSchemaRefException: : Reference /$defs/Berry cannot be resolved. How was 1.0.64 able to resolve it?

If I paste the schema to an online json schema validator, I receive errors as well. Was it a bug in 1.0.64?

@justin-tay
Copy link
Contributor

There are plenty of issues in 1.0.64 that were fixed particularly for ref resolution and embedded schema resources.

Putting $id in a subschema makes it schema resource which makes any $ref that references the document # resolve to that schema resource.

In your example, all your $id entries make no sense and you should just remove all of them. You shouldn't use https://json-schema.org/draft/2019-09/schema for your $id as this is for the metaschema. It is intended to use your own identifier. In subschemas the $id is used for embedded schema resources and it doesn't appear to be your intent as you don't reference them.

@xinw3
Copy link

xinw3 commented Mar 27, 2024

Thanks for the answer @justin-tay. The upper level $id was just an example. The actual id is like classpath:schemas/test. I got past that error by not referencing the subschemas under the same $defs document since that could cause infinite loop and is not allowed based on the documentation.

However, I encountered another error. I have some json schema documents defined under a common folder so they can be shared by different schemas. I'm seeing this error after upgrade com.networknt.schema.JsonSchemaFactory - Failed to load json schema from classpath:schemas/common/child2.json. The files would be something like:

main.json

{
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "$id": "classpath:schemas/main",
  "title": "main schema",
  "type": "object",
  "properties": {
    "fields": {
      "type": "object",
      "properties": {
        "ids": {
          "$ref": "../common/child.json"
        }
      }
    }
  }
}

child.json

{
    "$id": "/common/child",
    "title": "child schema",
    "type": "object",
    "properties": {
        "value": {
            "$ref": "./child2.json"
        }
    }
}

child2.json

{
    "$id": "/common/child2",
    "title": "child2 schema",
    "type": "object",
    "properties": {
        "value": {
            "type": "string",
            "$comment": "child value."
        }
    }
}

Folder structure:

| -- main
|      | -- main.json
| -- common
|      | -- child.json
|      | -- child2.json
         

Is there something wrong with the way how I load the schemas? I use the following:

  JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909);
  return factory.getSchema(getClass().getResourceAsStream(name));

@justin-tay
Copy link
Contributor

Your $id entries used are very confusing. They should be absolute IRIs. Here your $id entries look like the retrieval IRI, but aren't as they aren't placed in the correct structure, nor have the correct extension. You would be better off just removing them. The error says it can't find classpath:schemas/common/child2.json probably because it's not there.

After removing all your $id entries you can try the following.

        JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V201909);
        JsonSchema schema = factory.getSchema(SchemaLocation.of("classpath:/main/main.json"));
        String inputData = "{\r\n"
                + "  \"fields\": {\r\n"
                + "    \"ids\": {\r\n"
                + "      \"value\": {\r\n"
                + "        \"value\": 1\r\n"
                + "      }\r\n"
                + "    }\r\n"
                + "  }\r\n"
                + "}";
        System.out.println(schema.validate(inputData, InputFormat.JSON, OutputFormat.HIERARCHICAL));

@stevehu stevehu closed this as completed May 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants