Giter VIP home page Giter VIP logo

jsonschemafriend's Introduction

jsonschemafriend

jsonschemafriend is a JSON Schema-based data validator, delivered as a Java library.

As well as offering standards-compliant validation, it can provide JSON Schema loading services to tools, allowing them to explore a correctly built schema structure using typed accessors.

About

An online demonstration is here.

It is written by [email protected] and offered under an Apache 2.0 license.

It is compatible with the following versions of the standard.

Including in a project

The library is live on JitPack.

Gradle

To include in a Gradle project, ensure jitpack repository is specified in your base build.gradle file. For example:

repositories {
    maven {
        url 'https://jitpack.io'
    }
    // ...
}

Add the project as a dependency in the module's build.gradle.

dependencies {
    implementation 'net.jimblackler.jsonschemafriend:core:0.12.3'
    // ...
}

Maven

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>
<dependency>
    <groupId>net.jimblackler.jsonschemafriend</groupId>
    <artifactId>core</artifactId>
    <version>0.12.3</version>
</dependency>

Usage

Javadocs can be found here.

Basic example using JSON strings

import net.jimblackler.jsonschemafriend.Schema;
import net.jimblackler.jsonschemafriend.SchemaException;
import net.jimblackler.jsonschemafriend.SchemaStore;
import net.jimblackler.jsonschemafriend.Validator;

public class Main {
  public static void main(String[] args) {
    // Create a new schema in a JSON string.
    String schemaString = "{"
        + "  \"$schema\": \"http://json-schema.org/draft-07/schema#\","
        + "  \"type\": \"integer\""
        + "}";

    try {
      SchemaStore schemaStore = new SchemaStore(); // Initialize a SchemaStore.
      Schema schema = schemaStore.loadSchemaJson(schemaString); // Load the schema.
      Validator validator = new Validator(); // Create a validator.
      validator.validateJson(schema, "1"); // Will not throw an exception.
      validator.validateJson(schema, "true"); // Will throw a ValidationException.
    } catch (SchemaException e) {
      e.printStackTrace();
    }
  }
}

Via a Map

Schemas and objects can be provided in the form of standard Java objects. This enables the selection of a JSON parser by the client based on preferences such as speed, handling of numbers, and handling of key order, all of which vary between libraries. Clients can also chose to construct these document directly or on import from different formats such as JSON5 and YAML. It also makes it easier to validate documents before serialization.

The parser takes documents and schemas as a tree of objects, typed as follows:

JSON value Java class
object java.util.Map<String, Object>
array java.util.List<Object>
number java.lang.Number
string java.lang.String
true/false java.lang.Boolean
null null

Documents arranged this way can be created by all major JSON libraries for Java, including:

  • org.json

    new JSONObject(jsonString).toMap()

  • gson

    new Gson().fromJson(jsonString, Map.class);

  • Jackson

    new ObjectMapper().readValue(jsonString, Map.class);

  • usejson

    new Json5Parser().parse(jsonString);

This is an example of loading a schema in a Map.

import net.jimblackler.jsonschemafriend.Schema;
import net.jimblackler.jsonschemafriend.SchemaException;
import net.jimblackler.jsonschemafriend.SchemaStore;
import net.jimblackler.jsonschemafriend.Validator;

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

public class Main {
  public static void main(String[] args) {
    // Create a new schema in a map.
    Map<String, Object> schemaMap = new HashMap<>();
    schemaMap.put("$schema", "http://json-schema.org/draft-07/schema#");
    schemaMap.put("type", "integer");

    try {
      SchemaStore schemaStore = new SchemaStore(); // Initialize a SchemaStore.
      Schema schema = schemaStore.loadSchema(schemaMap); // Load the schema.
      Validator validator = new Validator(); // Create a validator.
      validator.validate(schema, 1); // Will not throw an exception.
      validator.validate(schema, "x"); // Will throw a ValidationException.
    } catch (SchemaException e) {
      e.printStackTrace();
    }
  }
}

Via a JSONObject

This is an example of loading a schema in a JSONObject using JSONObject.toMap().

import net.jimblackler.jsonschemafriend.Schema;
import net.jimblackler.jsonschemafriend.SchemaException;
import net.jimblackler.jsonschemafriend.SchemaStore;
import net.jimblackler.jsonschemafriend.Validator;
import org.json.JSONObject;

public class Main {
  public static void main(String[] args) {
    // Create a new schema in a JSON object.
    JSONObject schemaJson = new JSONObject();
    schemaJson.put("$schema", "http://json-schema.org/draft-07/schema#");
    schemaJson.put("type", "integer");

    try {
      SchemaStore schemaStore = new SchemaStore(); // Initialize a SchemaStore.
      Schema schema = schemaStore.loadSchema(schemaJson.toMap()); // Load the schema.
      Validator validator = new Validator(); // Create a validator.
      validator.validate(schema, 1); // Will not throw an exception.
      validator.validate(schema, "x"); // Will throw a ValidationException.
    } catch (SchemaException e) {
      e.printStackTrace();
    }
  }
}

Via Java Resources

This example loads a schema in the resources folder and validates data in the resources folder.

schema.json

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "name": {
      "type": "string",
      "minLength": 2
    }
  }
}

data1.json

{
  "name": "Bill"
}

data2.json

{
  "name": ""
}

Main.java

import java.io.IOException;
import net.jimblackler.jsonschemafriend.Schema;
import net.jimblackler.jsonschemafriend.SchemaException;
import net.jimblackler.jsonschemafriend.SchemaStore;
import net.jimblackler.jsonschemafriend.Validator;

public class Main {
  public static void main(String[] args) {
    try {
      SchemaStore schemaStore = new SchemaStore(); // Initialize a SchemaStore.
      // Load the schema.
      Schema schema = schemaStore.loadSchema(Main.class.getResource("/schema.json"));

      Validator validator = new Validator();

      // Will not throw an exception.
      validator.validate(schema, Main.class.getResourceAsStream("/data1.json"));

      // Will throw a ValidationException.
      validator.validate(schema, Main.class.getResourceAsStream("/data2.json"));
    } catch (SchemaException | IOException e) {
      e.printStackTrace();
    }
  }
}

From URIs or URLs

This example loads both the schema, and the data to test from the internet, via URIs (URLs can also be used).

import java.io.IOException;
import java.net.URI;
import net.jimblackler.jsonschemafriend.Schema;
import net.jimblackler.jsonschemafriend.SchemaException;
import net.jimblackler.jsonschemafriend.SchemaStore;
import net.jimblackler.jsonschemafriend.Validator;

public class Main {
  public static void main(String[] args) {
    try {
      SchemaStore schemaStore = new SchemaStore(); // Initialize a SchemaStore.
      // Load the schema.
      Schema schema = schemaStore.loadSchema(URI.create("https://json.schemastore.org/resume"));

      URI resume = URI.create(
          "https://gist.githubusercontent.com/thomasdavis/c9dcfa1b37dec07fb2ee7f36d7278105/raw");
      // Will not throw an exception; document passes the schema.
      new Validator().validate(schema, resume);

    } catch (SchemaException | IOException e) {
      e.printStackTrace();
    }
  }
}

From files

Both schemas and test data can be specified as a java.io.File. For example:

Schema schema = schemaStore.loadSchema(new File("/tmp/schema.json"));
new Validator().validate(schema, new File("/tmp/test.json"));

Custom validation handling

A custom Consumer can be passed to the validator to collect validation errors, rather than triggering a ValidationException.

import java.net.URI;
import java.util.HashMap;
import java.util.Map;

import net.jimblackler.jsonschemafriend.MissingPropertyError;
import net.jimblackler.jsonschemafriend.Schema;
import net.jimblackler.jsonschemafriend.SchemaException;
import net.jimblackler.jsonschemafriend.SchemaStore;
import net.jimblackler.jsonschemafriend.Validator;

public class Main {
  public static void main(String[] args) {
    try {
      SchemaStore schemaStore = new SchemaStore(); // Initialize a SchemaStore.
      // Load the schema.
      Schema schema =
          schemaStore.loadSchema(URI.create("https://json.schemastore.org/chrome-manifest"));

      // Send an object that won't validate, and collect the validation errors.
      Map<String, Object> document = new HashMap<>();
      new Validator().validate(schema, document, validationError -> {
        if (validationError instanceof MissingPropertyError) {
          MissingPropertyError missingPropertyError = (MissingPropertyError) validationError;
          System.out.println("A missing property was: " + missingPropertyError.getProperty());
        }
      });
    } catch (SchemaException e) {
      e.printStackTrace();
    }
  }
}

Validating formats

Starting with Json Schema Draft 2019-09 validation of formats is an optional feature. Pass a true boolean to the Validator constructor to enable format validation.

import net.jimblackler.jsonschemafriend.Schema;
import net.jimblackler.jsonschemafriend.SchemaException;
import net.jimblackler.jsonschemafriend.SchemaStore;
import net.jimblackler.jsonschemafriend.Validator;

public class Main {
  public static void main(String[] args) {
    // Create a new schema in a JSON string.
    String schemaString = "{"
        + "  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\","
        + "  \"format\": \"uri\""
        + "}";

    try {
      SchemaStore schemaStore = new SchemaStore(); // Initialize a SchemaStore.
      Schema schema = schemaStore.loadSchemaJson(schemaString); // Load the schema.
      Validator validator = new Validator(true); // Create a validator for validating formats.
      validator.validateJson(schema, "\"https://foo.bar/?baz=qux#quux\""); // Will not throw an exception.
      validator.validateJson(schema, "\"bar,baz:foo\""); // Will throw a ValidationException.
    } catch (SchemaException e) {
      e.printStackTrace();
    }
  }
}

Custom schema loading

By default the SchemaStore will use a class CacheLoader to resolve a schema URI. For http/https URIs this will download the schema and cache it locally for future use. A custom Loader can be passed to the SchemaStore to allow alternative methods for retrieving schemas.

import java.net.URI;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;

import net.jimblackler.jsonschemafriend.Loader;
import net.jimblackler.jsonschemafriend.MissingPropertyError;
import net.jimblackler.jsonschemafriend.Schema;
import net.jimblackler.jsonschemafriend.SchemaException;
import net.jimblackler.jsonschemafriend.SchemaStore;
import net.jimblackler.jsonschemafriend.Validator;

public class Main {
  public static void main(String[] args) {
    try {
       // An inefficient example that connects to and loads a schema from a database.
      Loader databaseLoader = new Loader() {
        public String load(URI uri, boolean cacheSchema) throws IOException {
          try (
            Connection con = DriverManager.getConnection("...", "user", "pass");
            Statement stmt = con.createStatement();
            ResultSet resultSet = stmt.executeQuery("..."); // some query that uses the uri
          ) {
            resultSet.first();
            return resultSet.getString("schema");
          } catch (SQLException e) {
            throw new IOException("Unable to retrieve schema", e);
          }
        }
      };
    
      SchemaStore schemaStore = new SchemaStore(databaseLoader);
      // Load the schema.
      Schema schema =
          schemaStore.loadSchema(URI.create("https://json.schemastore.org/chrome-manifest"));
    } catch (SchemaException e) {
      e.printStackTrace();
    }
  }
}

As a parser

The library can act as a parser for applications that need to work with JSON Schemas. For example; code creation tools, test data generators, schema converters or visualizers.

It offers typed accessors for Schema keywords but the main value it offers is to build a correctly connected Schema tree. Although JSON Schemas are plain JSON objects, locating subschemas from $ref is not trivial. Keywords $id, $anchor and $ref require careful handling, and requirements differ across JSON Schema standard versions. The library can shield clients from these details.

Once a Schema has been loaded, it can be evaluated with accessors in the Schema class, for example:

import net.jimblackler.jsonschemafriend.GenerationException;
import net.jimblackler.jsonschemafriend.Schema;
import net.jimblackler.jsonschemafriend.SchemaStore;

import java.net.URI;
import java.util.Map;

public class Main {
  public static void main(String[] args) throws GenerationException {
    SchemaStore schemaStore = new SchemaStore(); // Initialize a SchemaStore.
    // Load the schema.
    Schema schema =
        schemaStore.loadSchema(URI.create("https://json.schemastore.org/mocharc.json"));

    // Display the metaschema, for example http://json-schema.org/draft-07/schema#
    URI metaSchema = schema.getMetaSchema();
    System.out.println(metaSchema);

    // Get the 'color' property and print its canonical URI and its resource URI (where it can be
    // found in the schema document).
    Schema color = schema.getProperties().get("color");
    System.out.println(color.getExplicitTypes());  // [boolean]
    System.out.println(color.getUri());  // https://json.schemastore.org/mocharc#/definitions/bool
    System.out.println(
        color.getResourceUri());  // https://json.schemastore.org/mocharc.json#/definitions/bool

    // Display the URIs of all the subschemas (immediate dependents of the schema).
    Map<URI, Schema> subSchemas = schema.getSubSchemas();
    for (URI uri: subSchemas.keySet()) {
      System.out.println(uri);
    }
  }
}

jsonschemafriend's People

Contributors

big-andy-coates avatar dependabot[bot] avatar elisherer avatar gareth-robinson avatar jimblackler avatar jimblacklercorp avatar jt-siege avatar kool79 avatar olegshtch avatar robbielamb-wf avatar zak905 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

jsonschemafriend's Issues

string date-time format

Hi , i tried tried the following .. in your online version

SChema:

"$schema": "https://json-schema.org/draft/2020-12/schema",

    "Erstellt": {
        "type": "string",
        "format": "date-time"
    },

Json:
"Erstellt": "2004-06-14T23:34:30.322",

So here the timezone is missing in the json
https://json-schema.org/understanding-json-schema/reference/string.html says in the sample that there has to be a timezone

https://github.com/networknt/json-schema-validator this lib marks that as invalid .. your online version says that it is valid ..
sry im not that deeply in the spec . but ... is there a bug in your implementation or is the spec not that precise?
Greets André

Failing to load draft-07 type schemas (probably lower ones too)

Using SchemaStore::loadSchema(Object document) get stuck in an infinite loop trying to fetch the meta-schema of draft-07.
Getting logs:

net.jimblackler.jsonschemafriend.SchemaStore: Was not valid JSON: http://json-schema.org/draft-07/schema

It began today (2023-10-02) and probably is related to a change made at https://json-schema.org/blog/posts/new-website.

Issue

  • It seems that the issue is with the http stream not following 301 redirects.
  • Also getting into an infinite loop instead of failing fast makes the service unresponsive.

Reproduce

  • I think any piece of code (like the one in the README.md) which loads draft-07 schema will fail.

Workaround

Workaround 1:

Using a url rewriter (a bit dangerous)

public class SchemaForceHttpsUrlRewriter implements UrlRewriter {
    @Override
    public URI rewrite(URI in) {
        if (in.toString().startsWith("http:")) {
            return URI.create(in.toString().replaceFirst("http:", "https:"));
        }
        return in;
    }
}

Initialize store with store = new SchemaStore(new SchemaForceHttpsUrlRewriter());

Workaround 2:

not using a validator when using loadSchema

store.loadSchema(obj, null);

Workaround 3:

Storing the meta schemas as resources in the module and pre-loading them before calling loadSchema
Using SchemaStore::store(URI uri, Object document)
or SchemaStore::register(URI path, Schema schema)

(Maybe as a premanent solution it would be best to bundle all meta-schema draft-03+ with the library and prevent even trying to download them)

Support $refs with implicit url base

When loading the following schema I get a warning:

Aug 06, 2021 12:31:26 PM net.jimblackler.jsonschemafriend.Schema <init>
WARNING: No match for #/$defs/reference
{
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "$id": "urn:defs-test",
  "title": "TEST",
  "type": "object",
  "properties": {
    "testReference": {
      "$ref": "#/$defs/reference",
    }
  },
  "$defs": {
    "reference": {
      "type": "string"
    }
  }
}

type: integer does not match specification

Specifications (since draft-6) say (https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-01#name-mathematical-integers):
For consistency, integer JSON numbers SHOULD NOT be encoded with a fractional part. (should not == not recommended)
But both the properties in json below matches to {"type": "integer"}

{ "a": 5,
  "b": 5.0
}

while the only integer property is the "a"
Note thal library works in expected way when I select draft-3 or draft-4 here: https://tryjsonschematypes.appspot.com/#validate

The $ref is not resolved when referred schema is located in non-standard keywords

Given the schema:

{ 
  "defs":{ "myType": {"type": "string"}},
  "$defs":{ "myType": {"type": "string"}},  
  "properties":{
     "propA": {"$ref": "#/defs/myType"},
     "propB": {"$ref": "#/$defs/myType"},
  }  
}

When I use this schema to validate the json:

{
    "propA": 0,
    "propB": 0
}

Then I have the only 1 error for "propB" which use $ref to the #/$defs/myType
But I expect to have the error for "propA" as well. The only defference is that $ref for propA is use json pointer to "non-standard" keyword for schema location.

Actually I cannot proove that it is definetly wrong behavior, because the official test-suite for $ref does not contain such testcase. In the suite all the refrenced schemas are contained inside "$defs", "definitions" or "properties".

Bun on another side, in the standard did not find any restriction which prohibit to use refrences outside of the standard keywords. The only requirement to $ref (in 2019+) is that refreced element must contain schema. From 2020-12: "The value of the "$ref" keyword MUST be a string which is a URI-Reference. Resolved against the current URI base, it produces the URI of the schema to apply."

Performance and functional comparison

Hi,

I've recently needed to compare the performance and functionality of this and other JVM based JSON validation libraries, and I thought you might like to see how this implementation compares. I've published to the code and the results here: https://github.com/creek-service/json-schema-validation-comparison.

While I've spent time trying to get the best out of each library under test, it's possible that the results for this implementation could be improved if someone with more in-depth knowledge were to look into it. If you feel I'm not showing in its best light, please feel free to raise PRs to fix issues and improve your score.

Please feel free to link to the code and results.

I hope this is of some use to you.

Thanks,

Andy

Support for JSON Schema simplification?

Hi,

Out of curiosity, since the documentation states that parsing a JSON Schema is supported: Does this tool include a feature that allows simplification of a given JSON Schema? With simplification, I mean merging all allOf constraints (and possibly de-referencing any schema references). I know that some other software tools exist that claim to support that kind of simplification, and that this is a non-trivial task. I am just interested to know if jsonschemafriend has something in this area.

Background: We have a schema that makes extensive use of allOf, but some (non-validator) tools which we would like to feed that schema do not support allOf.

Cheers,
Johannes

Cannot validate json string with Jackson.

from the demo code in readme file like this:

package xxxxxx;


import com.fasterxml.jackson.databind.ObjectMapper;
import net.jimblackler.jsonschemafriend.*;

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

public class Test {
    static String schemaStr = "{\n" +
            "  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n" +
            "  \"properties\": {\n" +
            "    \"name\": {\n" +
            "      \"type\": \"string\",\n" +
            "      \"minLength\": 2\n" +
            "    }\n" +
            "  }\n" +
            "}";

    static String data1 = "{\n" +
            "  \"name\": \"Bill\"\n" +
            "}\n";
    static String data2 = "{\n" +
            "  \"name\": \"\"\n" +
            "}\n";

    public static void main(String[] args) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            SchemaStore schemaStore = new SchemaStore(); // Initialize a SchemaStore.

            Map map = mapper.readValue(schemaStr, HashMap.class);
            Schema schema = schemaStore.loadSchema(map);
            Validator validator = new Validator();

            // Will not throw an exception.
            validator.validate(schema, data1);
            // Will throw a ValidationException.
            validator.validate(schema, data2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

how to work with json string.

Incorrect handling of format-assertions

Hi @jimblackler,

Thought I'd let you know that I think this library is currently mishandling schemas that have format-assertion listed in its $vocabulary.

Turns out that having "https://json-schema.org/draft/2020-12/vocab/format-assertion": false e.g.:

"$vocabulary": {
        "https://json-schema.org/draft/2020-12/vocab/core": true,
        "https://json-schema.org/draft/2020-12/vocab/format-assertion": false
    },

...doesn't turn off format assertions, as I'd first assumed. Instead the false just means parsers/validators that don't understand format-assertsions can still parse the schema, (a value of true means such implementations should error out).

SchemaFriend fails 2 of the optional/format-assertions.json tests. I'm assuming this is because it turns off format assertions when it sees the "https://json-schema.org/draft/2020-12/vocab/format-assertion": false.

Here's the slack conversation about what the false means...

Example from specification fails with NPE

I've prepared test suite based on https://json-schema.org/draft/2020-12/json-schema-core.html#recursive-example in json-schema-org/JSON-Schema-Test-Suite#521

Currently it fails with NullPointerException:

java.lang.NullPointerException
	at net.jimblackler.jsonschemafriend.Validator.validate(Validator.java:95)
	at net.jimblackler.jsonschemafriend.Validator.validate(Validator.java:179)
	at net.jimblackler.jsonschemafriend.Validator.validate(Validator.java:76)
	at net.jimblackler.jsonschemafriend.Validator.validate(Validator.java:412)
	at net.jimblackler.jsonschemafriend.Validator.validate(Validator.java:76)
	at net.jimblackler.jsonschemafriend.Validator.validate(Validator.java:505)
	at net.jimblackler.jsonschemafriend.Validator.validate(Validator.java:156)
	at net.jimblackler.jsonschemafriend.Validator.validate(Validator.java:71)
	at net.jimblackler.jsonschemafriend.SuiteTest.lambda$scan$1(SuiteTest.java:100)

Parsing composite schema object definition

Thank you very much for making this library available as open source. This is extremely useful and I am glad I chanced upon it before giving up. I am using this library to build a quality check tool that scans JSON schemas for compliance with certain design standards. There is one particular design pattern (composition) that seems to be slipping through the parser. Here is the schema snippet:
"BaseAddress": {
"type": "object",
"properties": {
"addressLineText": {
"$ref": "#/definitions/String50"
},
"addressUnitIdentifier": {
"$ref": "#/definitions/String11"
},
"cityName": {
"$ref": "#/definitions/String35"
},
"postalCode": {
"$ref": "#/definitions/PostalCodeType"
}
}
},
"ResidenceAddress": {
"allOf": [
{
"$ref": "#/definitions/BaseAddress"
},
{
"properties": {
"stateCode": {
"$ref": "#/definitions/ResidenceStateCodeType"
}
}
}
],
"required": [ "addressLineText", "cityName", "postalCode", "stateCode" ]
},
While the BaseAddress object is being correctly read, the ResidenceAddress object is not being recognized. What am I missing?

Regards

Support for custom error message in schema

Hello @jimblackler ,
You have done a nice job especially in handling all the nested exception messages from oneOf,anyOf etc., and summarising the reason of failure in single, simple message.
Can you please provide support to customise that error message from schema itself similar to this

Maven Central

Many thanks for open sourcing this great library! Would you consider uploading it to Maven Central? I can't add jitpack as a maven repository in some of the projects I'd like to use this lib, unfortunately.

Migrate AddressException from javax.mail to jakarta in FormatChecker.java

As you may know the package javax.mail has not been updated for a while (Maven Central shows last release in 2018), more and more projects are migrating over to Jakarta.
In FormatChecker an AddressException from javax.mail is being used, which is causing problems if software already has moved on to use Jakarta. The following exception is being thrown:
Exception in thread "main" java.lang.NoClassDefFoundError: javax/mail/internet/AddressException
It would be appreciated, if you could migrate onto newer library.

Issue in Android 5

Fatal Exception: java.lang.NoClassDefFoundError: Failed resolution of: Ljava/nio/file/FileSystems;
       at net.jimblackler.jsonschemafriend.CacheLoader.<clinit>(CacheLoader.java:17)
       at net.jimblackler.jsonschemafriend.SchemaStore.<init>(SchemaStore.java:71)
       at net.jimblackler.jsonschemafriend.SchemaStore.<init>(SchemaStore.java:51)

since FileSystems is added in API version 26, it will crash on android version under 26

com.ibm.icu:icu4j is too heavy

hi,

currently, me and my teams are working with json schema to build a dynamic form for our client, and we found this library and use it as a validator.

all features work as expected and no issues on the functionality, but we found that our app size is increased by approximately 10MB and after we check it, we found that com.ibm.icu gives a contribution to the app size.

Screenshot 2023-08-26 at 12 51 32

after doing some research, we found that com.ibm.icu is from this library.

can you use another library to reduce the size? that would be so much help, and I will be very appreciate that.

thank you.

Base64 encoding error

Hi.
Your schema validator is just fine, but i get an error while validating base64 encoded data.

Part of the schema is:
...
"signature": {
"type": "string",
"contentEncoding": "base64"
},
...

The JSON data is:
"signature": "cckZGzGyCvsX0RRKqc94VuFlX83/XLoZjvXMT0beE79PwVsBwjwyCYJqPEPZnz0RDvl0nnV3A5+T0GCZcJAsCuZUAWhvDz6ezHkU2eBGcdwRzoL7FdaVcGeVZSJeuzkl"

The exception is:
.../signature with "Content encoding failed on: base64. Reason: Illegal base64 character 2f"]

I have no idea why the JSON data is wrong. In my opinion it is a valid base64 string.

Do you have any idea?

Greetings from germany
Stefan

Allow alternate means of retrieving content

At the moment the SchemaStore will, if it finds a schema that hasn't yet been resolved, call the getContent method to retrieve it:
https://github.com/jimblackler/jsonschemafriend/blob/master/library/src/main/java/net/jimblackler/jsonschemafriend/SchemaStore.java#L144
That getContent method will then use the static CacheLoader.load method.

I see you can also preload the SchemaStore using the public store or register methods.

What I'm asking for though is the ability to intercept that getContent loading method (in my case I may want to store schemas in some persistence layer), via say an interface ContentLoader ...

  public SchemaStore(UrlRewriter urlRewriter, boolean cacheSchema, ContentLoader contentLoader) {
     ...
     this.contentLoader = contentLoader;
  }

  private String getContent(URI documentUri) throws IOException {
    Uri uriToLoad = urlRewriter == null : documentUri : urlRewriter.rewrite(documentUri);
    if (contentLoader != null) {
      return contentLoader.load(uriToLoad, cacheSchema);
    }
    return load(uriToLoad, cacheSchema);
  }

Maybe that would also help with developers who have issues like #3 and need to provide their own means of resolving a schema?

JavaDoc link broken

The JavaDoc link in Readme.md seems to be broken:

Javadocs can be found here.

Tag or commit '0.11.3' not found. Rechecking.

Validating a schema using strings

I can load a schema from a file just fine, either as a resource, or directly using a java.io.file.
When I try to take a string, and transform it into a ByteArrayInputStream, I get this rather cryptic error.

    net.jimblackler.jsonschemafriend.StandardGenerationException: {valid=false, errors=[{error=Unexpected type in data: ByteArrayInputStream, keywordLocation=http://json-schema.org/draft-04/schema, absoluteKeywordLocation=http://json-schema.org/draft-04/schema, instanceLocation=#}]}

I checked out the code, walked through SchemaStore, added some logging, re-compiled, and re-ran and I don't see a clear path on how to fix my issue.

My use case is pretty simple. I have a string that contains a schema, and a string that contains JSON data that I want to validate with the schema mentioned earlier. I can't figure out how to do this with this library, so I am moving on to something else.

Schema with a wrong pointers to subschema passes the validation

Given the schema:

{
	"$defs":{ "myType": {"type": "string"}},  
	"properties":{"myProperty": {"$ref": "#/$defs/MyType"}}  
}

with the wrong pointer to the type of 'myProperty' (for example, when type is misspelled). This schema succesfully pass the next json:

{ "myProperty": 0}

I expect that library should fail when I load the schema (with the GeneraionException or StandardGenerationException).
Currently the library passes such verification with a warning: WARNING: No match for #/$defs/MyType. But I cannot get 'programmatic' access to this case, so all warnings just leave in logs

Reason:
As I understand the standard, we cannot define the ref "#/$defs/myType2" in some another file and should be resolved in current context. So all local refrences must be available at schema resolution stage

Such behavior is critical in my application, where the library is used for schema linting as well. Will be good to have errors during schema load (for local refrences) of when schema is validated (for absolute refrences in external files).

Set module name

At the moment, as no module name is specified by the project, if a user is using JPMS (jigsaw), then the the automatic module names for the core and extra jars are simply core and extra. This isn't very descriptive and its very possible there's another core jar on the module path, causing a module name clash.

Ideally, we should add a module-info class to the projects that defines the module names and which packages they export.

Until this is done it would be great if we could at least set a more descriptive / unique automatic module name in the jar manifests.

See http://branchandbound.net/blog/java/2017/12/automatic-module-name/ for more info.

uuid validation doesn't work for draft/2019-09 schema in version 0.11.x

When using draft/2019-09 as the schema, having a property with type string and format uuid validates that the string value is actually a valid UUID in version 0.10.6, but not in version 0.11.0 or later.

Was this actually removed from the standard in that edition or was a bug introduced in the library?

The following test succeeds when using version 0.10.6 but fails with version 0.11.0 or later:


/test-schemas/TEST.json:

{
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "$id": "urn:test:TEST",
  "title": "TEST",
  "type": "object",
  "required": [
    "testId"
  ],
  "additionalProperties": false,
  "properties": {
    "testId": {
      "type": "string",
      "format": "uuid"
    },
    "testNumber": {
      "type": "number"
    },
    "testEnum": {
      "type": "string",
      "enum": [
        "VALID_ENUM_VALUE"
      ]
    },
    "testReference": {
      "$ref": "urn:test:TEST#/$defs/reference"
    }
  },
  "$defs": {
    "reference": {
      "type": "boolean"
    }
  }
}

JsonSchemaValidatorTest.java:

package com.princh.resource.validation;

import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import net.jimblackler.jsonschemafriend.GenerationException;
import net.jimblackler.jsonschemafriend.Schema;
import net.jimblackler.jsonschemafriend.SchemaStore;
import net.jimblackler.jsonschemafriend.ValidationException;
import net.jimblackler.jsonschemafriend.Validator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatThrownBy;

public class JsonSchemaValidatorTest {
  private JsonSchemaValidator validator;

  @BeforeEach
  public void setUp() {
    URL schemaUrl = this.getClass().getResource("/test-schemas/TEST.json");
    validator = new JsonSchemaValidator(schemaUrl);
  }

  @Test
  public void testInvalidUuid() {
    Map<String, Object> object = new HashMap<>();
    object.put("testId", "foo");

    assertThatThrownBy(() -> {
      validator.validate(object);
    }).isInstanceOf(ValidationException.class)
      .hasMessageContaining("Not compliant with format: uuid");
  }

  public static class JsonSchemaValidator {
    private final Schema schema;

    public JsonSchemaValidator(URL schemaUrl) {
      try {
        SchemaStore schemaStore = new SchemaStore();
        schema = schemaStore.loadSchema(schemaUrl);
      } catch (GenerationException e) {
        throw new RuntimeException(e);
      }
    }

    public void validate(Map<String, Object> jsonMap) throws ValidationException {
      Validator validator = new Validator();
      validator.validate(schema, jsonMap);
    }
  }
}

SchemaStore enters infinite loop when $schema returns no content

Loading a JSON schema through a SchemaStore object results in an infinite loop if a JSON schema has a $schema that has no content (such as http://json-schema.org/schema, which returns a 301) and also does not have an $id.

Here's how this happens:

  1. We enter a while (true) loop here.
  2. Then we try getting content from the $schema here and content is null.
  3. The store call here throws an exception due to the null content.
  4. We catch this exception in the catch (JsonProcessingException e) block.
  5. Then we make a Document object called doc and an Elements object called links here. However, since content is null, doc is null and links has a size of zero.
  6. As a result, we never set resolved to true here because there are no links to loop through, and we display the "Was not valid JSON" warning from this block.
  7. Then we continue here, loop again, hit the same problem, and keep looping ad infinitum.

Even though the jsonschemafriend readme lists a specific set of schemas that are supported in the $schema field, jsonschemafriend should throw an exception if the $schema has no content rather than looping infinitely.

Let me know if you'd like me to fix this myself or if someone closer to jsonschema friend would prefer to address this.

Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.