0

我正在使用流行的 JSON 模式库 - json-schema-validator - 根据我自己的模式检查传入的有效负载。

以下是我悲痛的总结:

private final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
    private JsonSchema preparedSchema;
    public ReportByTeamCriteriaSchemaChecker(String schemaLocationPath) {
        try {
            JsonNode schemaNode = JsonLoader.fromPath(schemaLocationPath);
            this.preparedSchema = this.factory.getJsonSchema(schemaNode);
        } catch (ProcessingException | IOException e) {
            e.printStackTrace();
        }
    }

没有任何问题,到这里为止。在其指定位置找到 Schema 文件,并准备好 schemaNode。

给定一个传入的 JSONString(更明确的有效负载),这就是我确认其与之前加载的模式的正确性的方式:

private Try<ProcessingReport>  checkAgainstSchema(JsonSchema schema, String jsonifiedString) {

   Try<ProcessingReport> result =
      Try
      .of(() ->  JsonLoader.fromString(jsonifiedString))
      .mapTry( (jsonNode) -> schema.validate(jsonNode));

        return (result);
    }

这个函数,被称为:

Try<String> syntaxParsingresult =
     this.checkAgainstSchema(this.preparedSchema, jsonifiedString)
    .map(e -> extractErrorMessagesFromReport(e));

build.gradle文件的相关部分:

sourceCompatibility = '1.9'
targetCompatibility = '1.9'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'

if (!hasProperty('mainClass')) {
    //ext.mainClass = 'test.NewMain'
    mainClassName = "drivers.ReportServerEntryPoint"
}

repositories {
    mavenCentral()
    maven { url "http://maven.restlet.org" }
}
ext.restletVersion = "2.3.10"

// ........

 // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
    compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.8'
    // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
    compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.8'
    // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
    compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.9.8'
    // https://mvnrepository.com/artifact/commons-io/commons-io
    compile group: 'commons-io', name: 'commons-io', version: '2.6'
    compile(group: "com.github.java-json-tools", name: "json-schema-validator", version: "2.2.10")
    // https://mvnrepository.com/artifact/io.vavr/vavr
    compile group: 'io.vavr', name: 'vavr', version: '0.9.2'

从IntelliJ IDEA 内部运行时,这工作得非常(包括所有测试用例)。但是,当我构建 JAR 并从命令行运行时抛出的异常非常令人困惑:

在此处输入图像描述

JVM 发现令人反感的源代码行 (ReportByTeamCriteriaSchemaChecker.java:59) 对应于前面提到的函数调用:

schema.validate(jsonNode)

我正在使用 vavr - 因此,我最初怀疑 vavr 和 json-schema-validator 和 Jackson 在一起是否不舒服 - 但我已经确认即使我不使用 vavr 的 Try,异常也会在运行时引发。

我在 StackOverflow 上提到了这个对话,但对我来说用处不大。

我正在使用 JDK 1.9:

java version "9.0.1"
Java(TM) SE Runtime Environment (build 9.0.1+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.1+11, mixed mode)

熟悉 JSON 验证的任何人都可以指出正确的方向吗?


更新

作为实验,我在依赖项中添加了以下内容:

    dependencies {
      compile(group: "com.github.fge", name: "jackson-coreutils", version: "1.8");
    }

在这种情况下,当我从命令行运行 JAR 时,错误消息完全相反:

Caused by: java.lang.IncompatibleClassChangeError: Found interface com.github.fge.jsonschema.main.JsonSchema, but class was expected
    at com.oneHuddle.application.utility.schemaChecker.ReportByTeamCriteriaSchemaChecker.validateAgainstSchema(ReportByTeamCriteriaSchemaChecker.java:59)
    at com.oneHuddle.application.ReportByTeamResource.lambda$getDefaultTeamReport$0(ReportByTeamResource.java:60)
    at io.vavr.control.Either.flatMap(Either.java:331)
    at com.oneHuddle.application.ReportByTeamResource.getDefaultTeamReport(ReportByTeamResource.java:59)

如果有的话,我更困惑!:-) 为什么它应该在 IntelliJ 内部正常运行,但在从命令行运行可执行 JAR时会抛出此错误?

4

1 回答 1

1

通过诉诸以下课程,

com.github.fge.jsonschema.main.JsonValidator

我已经能够回避这个问题。

当前代码如下所示:

private final JsonValidator validator = 
    JsonSchemaFactory.byDefault().getValidator();
private  JsonNode   schemaNode;
public ReportByTeamCriteriaSchemaChecker(String schemaLocationPath) {
    try {
        this.schemaNode = JsonLoader.fromPath(schemaLocationPath);
    } catch (IOException e) {
         e.printStackTrace();
    }
}

之前使用模式的函数现在使用验证器:

private Try<ProcessingReport>  
validatePayload(
     JsonNode schemaNode, String payload) {

   Try<ProcessingReport> result =
      Try
      .of(()->  JsonLoader.fromString(payload))
      .mapTry((jsonNode)  ->  
             this.validator.validate(schemaNode,jsonNode));

   return (result);

}

控制函数的行为与之前的化身中一样:

 public Either<Tuple2<Enum<ReportByTeamExecutionStatus>,String>,String>
    validateAgainstSchema(String jsonifiedString) {

       Try<String> syntaxParsingresult =
               this.validateAgainstSchema(this.schemaNode, jsonifiedString)
               .map(e -> extractErrorMessagesFromReport(e));
// ..... rest of the logic

我尝试了 3-4 种可能性,包括:

  • 强制刷新所有依赖项
  • 创建 gradle 的扫描报告
  • 玩弄几个不同版本的 Jackson 和其他依赖库

但他们都没有工作,但这个工作。

只是为了澄清一下,我还没有发现 IntelliJ 的 runtimeclasspath 视图和 gradle 命令的视图之间的确切区别。显然,它们以微妙(或不那么微妙)不同的方式解决了依赖关系。但是,我没有时间。

我想我应该发布我的解决方案,以防万一它对某人有所帮助。

于 2018-12-21T10:57:30.007 回答