Проверка JSON не выполняется во время выполнения, хотя тесты проходят

Я использую популярную библиотеку схем 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();
        }
    }

Пока здесь нет никаких проблем. Файл схемы находится в указанном месте, и узел 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 и Джексон неудобно находиться вместе, - но я подтвердил, что даже когда я не использую 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 запускается из командной строки?


person Nirmalya    schedule 21.12.2018    source источник
comment
Согласно исключению, существуют несовместимые двоичные изменения, вызывающие ошибку (см. stackoverflow.com/questions/1980452/). Может, в тестах работает, у вас там разные зависимости?   -  person Philipp Claßen    schedule 21.12.2018
comment
@Phillipp, Хорошее замечание, но я делаю два наблюдения: (а) тестовые зависимости есть только от JUnit и Hamcrest, ни одно из них не вызывает дискомфорта вместе с материалами, связанными с JSON, и (б) я запускаю приложение из IntelliJ (не только тесты, они все равно проходят) из пункта меню. Итак, во время выполнения возникает вопрос: что IntelliJ знает, чего не знает исполняемый JAR? Я буду исследовать немного дальше.   -  person Nirmalya    schedule 21.12.2018


Ответы (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
  • играть с несколькими разными версиями Джексона и других зависимых библиотек

но ни один из них не работал, а вот этот.

Чтобы прояснить, я не выяснил, в чем точная разница между представлением IntelliJ о runtimeclasspath и представлением команды gradle о том же. Очевидно, они разрешают зависимости тонко (или не очень тонко) разными способами. Но у меня не было времени.

Я подумал, что стоит опубликовать свое решение, на случай, если оно кому-то поможет.

person Nirmalya    schedule 21.12.2018