How to validate JSON with schema which contains a reference to another schema?

2.2k views Asked by At

I want to validate a JSON file with a JSON schema file, which contains a reference to another JSON schema file.

I added a JSON Schema Validator for my Apache Camel route. Because I use JSON schema version draft-07 and the default version is draft-04, I exposed a JsonSchemaLoader, see also https://stackoverflow.com/a/63417253/5277820.

The first schema test-schema-1 is loaded from class path, but the second test-schema-2 is loaded from internet. The used ID http://mycompany/test-schema2.json is only an ID not a real resource, therefore I get an exception.

Is there any way to load the second JSON schema also from class path?

Spring Boot application

@SpringBootApplication
public class TestApplication {
  public static void main(String[] args) {
    SpringApplication.run(TestApplication.class, args);
  }

  @Bean
  public JsonSchemaLoader mySchemaLoader() {
    return (camelContext, schemaStream) -> 
        JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7).getSchema(schemaStream);
  }

  @Bean
  public EndpointRouteBuilder routeBuilder() {
    return new EndpointRouteBuilder() {
      @Override
      public void configure() throws Exception {
        from(file("d:/tmp/camel/"))
            .to(jsonValidator("/test/test-schema1.json").advanced().schemaLoader(mySchemaLoader())).stop();
      }
    };
  }
}

JSON schema

test-schema-1:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "http://mycompany/test-schema1.json",
    "type": "object",
    "properties": {
        "obj": {
            "$ref": "test-schema2.json"
        }
    },
    "required": [
        "target"
    ]
}

test-schema-2:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "http://mycompany/test-schema2.json",
    "type": "object",
    "properties": {
        "value": {
            "type": "string"
        }
    }
}

Logs

Message History (complete message history is disabled)
---------------------------------------------------------------------------------------------------------------------------------------
RouteId              ProcessorId          Processor                                                                        Elapsed (ms)
[route1            ] [route1            ] [from[file://d:/tmp/camel/]                                                    ] [         5]
...
[route1            ] [to1               ] [json-validator:///test/test-schema1.json?hash=93f27f49                        ] [         0]

Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------

com.networknt.schema.JsonSchemaException: java.net.UnknownHostException: mycompany
    at com.networknt.schema.JsonSchemaFactory.getSchema(JsonSchemaFactory.java:348) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.RefValidator.getRefSchema(RefValidator.java:76) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.RefValidator.<init>(RefValidator.java:41) ~[json-schema-validator-1.0.43.jar:na]
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:na]
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490) ~[na:na]
    at com.networknt.schema.ValidatorTypeCode.newValidator(ValidatorTypeCode.java:131) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.JsonMetaSchema.newValidator(JsonMetaSchema.java:342) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.ValidationContext.newValidator(ValidationContext.java:53) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.JsonSchema.read(JsonSchema.java:198) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.JsonSchema.initialize(JsonSchema.java:76) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.PropertiesValidator.<init>(PropertiesValidator.java:36) ~[json-schema-validator-1.0.43.jar:na]
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:na]
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490) ~[na:na]
    at com.networknt.schema.ValidatorTypeCode.newValidator(ValidatorTypeCode.java:131) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.JsonMetaSchema.newValidator(JsonMetaSchema.java:342) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.ValidationContext.newValidator(ValidationContext.java:53) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.JsonSchema.read(JsonSchema.java:198) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.JsonSchema.initialize(JsonSchema.java:76) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.JsonSchemaFactory.newJsonSchema(JsonSchemaFactory.java:254) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.JsonSchemaFactory.getSchema(JsonSchemaFactory.java:296) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.JsonSchemaFactory.getSchema(JsonSchemaFactory.java:304) ~[json-schema-validator-1.0.43.jar:na]
    at test.TestApplication.lambda$0(TestApplication.java:22) ~[classes/:na]
    at org.apache.camel.component.jsonvalidator.JsonValidatorEndpoint.getOrCreateSchema(JsonValidatorEndpoint.java:162) ~[camel-json-validator-3.5.0.jar:3.5.0]
    at org.apache.camel.component.jsonvalidator.JsonValidatorEndpoint.onExchange(JsonValidatorEndpoint.java:94) ~[camel-json-validator-3.5.0.jar:3.5.0]
    at org.apache.camel.support.ProcessorEndpoint$1.process(ProcessorEndpoint.java:61) ~[camel-support-3.5.0.jar:3.5.0]
    at org.apache.camel.support.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:66) ~[camel-support-3.5.0.jar:3.5.0]
    at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:169) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:404) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:60) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:147) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:287) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.component.file.GenericFileConsumer.processExchange(GenericFileConsumer.java:483) ~[camel-file-3.5.0.jar:3.5.0]
    at org.apache.camel.component.file.GenericFileConsumer.processBatch(GenericFileConsumer.java:237) ~[camel-file-3.5.0.jar:3.5.0]
    at org.apache.camel.component.file.GenericFileConsumer.poll(GenericFileConsumer.java:198) ~[camel-file-3.5.0.jar:3.5.0]
    at org.apache.camel.support.ScheduledPollConsumer.doRun(ScheduledPollConsumer.java:190) ~[camel-support-3.5.0.jar:3.5.0]
    at org.apache.camel.support.ScheduledPollConsumer.run(ScheduledPollConsumer.java:107) ~[camel-support-3.5.0.jar:3.5.0]
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[na:na]
    at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305) ~[na:na]
    at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
    at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Caused by: java.net.UnknownHostException: mycompany
    at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:220) ~[na:na]
    at java.base/java.net.Socket.connect(Socket.java:608) ~[na:na]
    at java.base/java.net.Socket.connect(Socket.java:557) ~[na:na]
    at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:182) ~[na:na]
    at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:474) ~[na:na]
    at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:569) ~[na:na]
    at java.base/sun.net.www.http.HttpClient.<init>(HttpClient.java:242) ~[na:na]
    at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:341) ~[na:na]
    at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:362) ~[na:na]
    at java.base/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1253) ~[na:na]
    at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1187) ~[na:na]
    at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1081) ~[na:na]
    at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:1015) ~[na:na]
    at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1592) ~[na:na]
    at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1520) ~[na:na]
    at com.networknt.schema.uri.URLFetcher.openConnectionCheckRedirects(URLFetcher.java:57) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.uri.URLFetcher.fetch(URLFetcher.java:43) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.uri.URISchemeFetcher.fetch(URISchemeFetcher.java:50) ~[json-schema-validator-1.0.43.jar:na]
    at com.networknt.schema.JsonSchemaFactory.getSchema(JsonSchemaFactory.java:325) ~[json-schema-validator-1.0.43.jar:na]
    ... 46 common frames omitted
1

There are 1 answers

2
dur On BEST ANSWER

There is a configuration property for URI mappings, see Configuration:

  • uriMappings

Map of public, typically internet-accessible schema URLs to alternate locations; this allows for offline validation of schemas that refer to public URLs. This is merged with any mappings the sonSchemaFactory may have been built.

The type for this variable is Map<String, String>.

Modified code:

@Bean
public JsonSchemaLoader mySchemaLoader() {

  final SchemaValidatorsConfig config = new SchemaValidatorsConfig();
  config.setUriMappings(
      Map.of("http://mycompany/test-schema2.json", "resource:/test/test-schema2.json"));

  return (camelContext, schemaStream) ->
      JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7).getSchema(schemaStream, config);
}