【问题标题】:JSON Validation fails at runtime, even though tests passJSON 验证在运行时失败,即使测试通过
【发布时间】:2021-03-01 17:20:37
【问题描述】:

我正在使用流行的 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 上提到了这个conversation,但对我来说用处不大。

我使用的是 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 时抛出此错误

【问题讨论】:

  • 根据异常,存在不兼容的二进制更改导致错误(请参阅stackoverflow.com/questions/1980452/…)。也许它在测试中起作用,因为你在那里有不同的依赖关系?
  • @Phillipp ,好点子,但我有两个观察结果:(a) 测试依赖项仅在 JUnit 和 Hamcrest 上,与 JSON 相关的东西一起使用都不会让人感到不舒服;(b)我正在从菜单选项中的 IntelliJ 内部运行应用程序(不仅仅是测试,它们仍然通过)。那么,问题是在运行时,IntelliJ 知道可执行 JAR 不知道什么?我将进一步探索。

标签: java json jsonschema json-schema-validator vavr


【解决方案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 命令的视图之间的确切区别。显然,它们以微妙(或不那么微妙)不同的方式解决了依赖关系。但是,我没有时间。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-30
    • 2017-05-09
    • 2020-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-24
    相关资源
    最近更新 更多