Validate JSON schema compliance with Jackson against an external schema file

后端 未结 3 1182
刺人心
刺人心 2021-01-11 21:43

I would like to use the Jackson library (https://github.com/FasterXML/jackson) to deal with JSON files in Java, which are described by a JSON schema file.

Now, I wo

相关标签:
3条回答
  • 2021-01-11 22:27

    As far as I know Jackson can only produce schemas for given types, but not do validation. There is json-schema-validator but it is no longer maintained.

    0 讨论(0)
  • 2021-01-11 22:40

    Just stumbled about https://github.com/leadpony/justify another implementation of a validator for json schema, also more recent draft versions. (7,6,4)

    0 讨论(0)
  • 2021-01-11 22:41

    1.) Add Dependency pom.xml :-

        <dependency>
            <groupId>com.github.fge</groupId>
            <artifactId>json-schema-validator</artifactId>
            <version>2.2.6</version>
        </dependency>
    

    2.) NoSqlEntity is a meta data for entity that can reside in no-sql database.

    Initialized NoSqlEntity with schema file.

    public static final NoSqlEntity entity = new NoSqlEntity("PAYOUT_ENTITY", "DB_","/schema/payout_entity.json");

    public class NoSqlEntity {
    private static final Map<String, NoSqlEntity> STORE = new HashMap<>();
    
    private final AtomicLong seq = new AtomicLong(System.currentTimeMillis());
    private IdentityGenerator identityGenerator;
    private String entity;
    private String collectionName;
    private String jsonSchema;
    private String idColumn = "id";
    private String database;
    
    
    public NoSqlEntity(String entity, String idColumn, String collectionPrefix,      String jsonSchema) {
        this.entity = entity;
        this.idColumn = idColumn;
    
        this.collectionName = collectionPrefix + "_" + entity;
        this.jsonSchema = jsonSchema;
        STORE.put(entity, this);
    }
    
    public NoSqlEntity(String collectionName, String jsonSchema) {
        this.collectionName = collectionName;
        this.jsonSchema = jsonSchema;
    }
    
    public static NoSqlEntity valueOf(String entityType) {
        return STORE.get(entityType);
    }
    
    public boolean isNotNullSchema() {
        return jsonSchema != null;
    }
     ...
     // Other Getter/Setter properties and methods.
    }
    

    3.) Sample format of validation schema file of payout_entity.json-

       {
        "properties":{
              "txId":{"type":"string"}
    
        }
        "required" :["txId","currency"]
      }
    

    4.) JsonSchemaManager - Validate the incoming JSON schema and cache the schema as well.

    public class JsonSchemaManager {
    private final static Logger LOGGER = LoggerFactory.getLogger(JsonSchemaManager.class);
    protected final static String LS = StandardSystemProperty.LINE_SEPARATOR.value();
    
    private final JsonValidator validator = JsonSchemaFactory.byDefault().getValidator();
    private final Map<NoSqlEntity, JsonNode> schemaMap = new HashMap<>();
    
    public JsonNode load(NoSqlEntity noSqlEntity) throws IOException {
        final JsonNode schema = JsonLoader.fromURL(this.getClass().getResource(noSqlEntity.getJsonSchema()));
        schemaMap.put(noSqlEntity, schema);
        return schema;
    }
    
    public void validateSchema(NoSqlEntity noSqlEntity, JsonNode toBeValidated, Consumer<ProcessingReport> consumer) {
        try {
            JsonNode schema = schemaMap.get(noSqlEntity);
            if (schema == null) {
                schema = load(noSqlEntity);
            }
            final ProcessingReport report = validator.validate(schema, toBeValidated);
            if (!report.isSuccess()) {
                consumer.accept(report);
            }
        } catch (IOException ex) { //NOSONAR
            throw new InvalidRequestException(ex.toString());
        } catch (ProcessingException ex) { //NOSONAR
            throw new InvalidRequestException(ex.toString());
        }
    }
    
     public synchronized boolean synchronizedCheck(NoSqlEntity noSqlEntity, JsonNode toBeValidated, Consumer<Map<String, Object>> messageConsumers) {
        boolean flags = CommonUtils.unchecked(() -> {
            validateSchema(noSqlEntity, toBeValidated, report -> {
                report.forEach(processingMessage -> messageConsumers.accept(JsonConverter.jsonAsMapObject(processingMessage.asJson())));
            });
            return true;
        }, ex -> {
            throw new RuntimeException(ex.toString()); //NOSONAR
        });
        return flags;
    }
    }
    

    5.) NoSqlRepository which persist meta data into NoSql DB.

    @Component
    public class NoSqlRepository {
    private static final Logger LOGGER = LoggerFactory.getLogger(NoSqlRepository.class);
    private final DocumentFormat documentFormat = DocumentFormat.JSON;
    private static final String SEPARATOR = ",";
    
    private static final ThreadLocal<MyLocalVariable> THREAD_LOCAL_VARIABLES = ThreadLocal.withInitial(() -> new MyLocalVariable());
    
    
    static class MyLocalVariable {
        private JsonSchemaManager schemaManager = new JsonSchemaManager();
        private BasicBSONDecoder bsonDecoder = new BasicBSONDecoder();
    
        public JsonSchemaManager getSchemaManager() {
            return schemaManager;
        }
    
        public BasicBSONDecoder getBsonDecoder() {
            return bsonDecoder;
        }
    }
    
    private void checkSchemaIfAny(NoSqlEntity noSqlEntity, JsonNode entity) {
        if (noSqlEntity.isNotNullSchema()) {
            THREAD_LOCAL_VARIABLES.get().getSchemaManager().check(noSqlEntity, entity);
        }
    }
    
    public String saveEntity(NoSqlEntity noSqlEntity, JsonNode entity){
      // Before persisting payload into noSQL, validate payload against schema.
      this.checkSchemaIfAny(noSqlEntity,entity);
    }
    // Other CURD methods here...
    }
    
    0 讨论(0)
提交回复
热议问题