Apache Camel 3.4 - Различные ошибки демаршалинга с использованием Джексона - PullRequest
0 голосов
/ 14 июля 2020

Я успешно написал простой вариант использования, чтобы демаршалировать JSON ответ от Quickbooks oAuth API для обновления sh токенов.

После этого мне нужно go и получить фактические данные:

https://quickbooks.api.intuit.com/v3/company/XXXXXXXXXXXXXX/query?query=SELECT * FROM Invoice WHERE Metadata.LastUpdatedTime%3E='2020-07-01T01:00:00' ORDERBY Metadata.LastUpdatedTime, Id STARTPOSITION 1 MAXRESULTS 1000 &minorversion=47

HTTP-вызов работает нормально:

    // make the HTTP REST call, without C10y* & Camel* headers:
    .toD("https://${header." + Headers.IEP_API_HOST + "}?headerFilterStrategy=C10yHeaderFilterStrategy")

Я могу проверить, что возвращенный JSON в порядке:

.log(LoggingLevel.DEBUG, API_LOG, "JSON returned: ${body}")

Но с здесь он выглядит грушевидным:

.unmarshal().json(JsonLibrary.Jackson, Payload.class)

Вот что происходит:

  1. С выше log заявление a MismatchedInputException появляется с сообщением «Нет содержимого для сопоставления из-за конца ввода».

  2. Без выше log оператор a ClassNotFoundException возникает с сообщением "Payload.class".

Re. 1.

Насколько я понимаю, ответы кэшируются по умолчанию, поэтому должна быть возможность читать входной поток несколько раз. По умолчанию для параметра конечной точки HTTP disableStreamCache установлено значение false, поэтому он включен .

Трассировка стека:

com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input
 at [Source: (org.apache.camel.converter.stream.CachedOutputStream$WrappedInputStream); line: 1, column: 0]
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4624) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4469) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3471) ~[jackson-databind-2.11.0.jar:2.11.0]
    at org.apache.camel.component.jackson.JacksonDataFormat.unmarshal(JacksonDataFormat.java:188) ~[camel-jackson-3.4.0.jar:3.4.0]
    at org.apache.camel.support.processor.UnmarshalProcessor.process(UnmarshalProcessor.java:64) ~[camel-support-3.4.0.jar:3.4.0]
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.doRun(RedeliveryErrorHandler.java:702) ~[camel-base-3.4.0.jar:3.4.0]
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.run(RedeliveryErrorHandler.java:616) ~[camel-base-3.4.0.jar:3.4.0]
    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148) ~[camel-base-3.4.0.jar:3.4.0]
    at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:60) ~[camel-base-3.4.0.jar:3.4.0]
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:147) ~[camel-base-3.4.0.jar:3.4.0]
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:286) ~[camel-base-3.4.0.jar:3.4.0]
    at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:203) ~[camel-timer-3.4.0.jar:3.4.0]
    at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:76) ~[camel-timer-3.4.0.jar:3.4.0]
    at java.base/java.util.TimerThread.mainLoop(Timer.java:556) ~[na:na]
    at java.base/java.util.TimerThread.run(Timer.java:506) ~[na:na]

Re . 2.

Трассировка стека для этого:

org.apache.camel.CamelExecutionException: Exception occurred during execution on the exchange: Exchange[ID-WIN-10-DM-1594724136485-0-1]
    at org.apache.camel.CamelExecutionException.wrapCamelExecutionException(CamelExecutionException.java:47) ~[camel-api-3.4.0.jar:3.4.0]
    at org.apache.camel.language.simple.SimpleExpressionBuilder$26.evaluate(SimpleExpressionBuilder.java:590) ~[camel-core-languages-3.4.0.jar:3.4.0]
    at org.apache.camel.support.ExpressionAdapter.evaluate(ExpressionAdapter.java:36) ~[camel-support-3.4.0.jar:3.4.0]
    at org.apache.camel.reifier.language.SimpleExpressionReifier$1.evaluate(SimpleExpressionReifier.java:42) ~[camel-core-engine-3.4.0.jar:3.4.0]
    at org.apache.camel.processor.SetHeaderProcessor.process(SetHeaderProcessor.java:48) ~[camel-base-3.4.0.jar:3.4.0]
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.doRun(RedeliveryErrorHandler.java:702) ~[camel-base-3.4.0.jar:3.4.0]
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.run(RedeliveryErrorHandler.java:616) ~[camel-base-3.4.0.jar:3.4.0]
    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148) ~[camel-base-3.4.0.jar:3.4.0]
    at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:60) ~[camel-base-3.4.0.jar:3.4.0]
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:147) ~[camel-base-3.4.0.jar:3.4.0]
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:286) ~[camel-base-3.4.0.jar:3.4.0]
    at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:203) ~[camel-timer-3.4.0.jar:3.4.0]
    at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:76) ~[camel-timer-3.4.0.jar:3.4.0]
    at java.base/java.util.TimerThread.mainLoop(Timer.java:556) ~[na:na]
    at java.base/java.util.TimerThread.run(Timer.java:506) ~[na:na]
Caused by: java.lang.ClassNotFoundException: Payload.class
    at org.apache.camel.impl.engine.DefaultClassResolver.resolveMandatoryClass(DefaultClassResolver.java:87) ~[camel-base-3.4.0.jar:3.4.0]
    at org.apache.camel.language.simple.SimpleExpressionBuilder$26.evaluate(SimpleExpressionBuilder.java:588) ~[camel-core-languages-3.4.0.jar:3.4.0]
    ... 13 common frames omitted

Все это выполняется в рамках проекта Eclipse / Maven, поэтому я очистил, обновил, скомпилировал, перестроил, et c, et c, безрезультатно.

Я написал простой jUnit, и он отлично работает, используя JSON из приведенного выше журнала, сохраненного в файл:

/**
 * POJO Jackson unmarshalling
 */
@Test
public void pojoUnmarshallTest() {
    ObjectMapper om = new ObjectMapper();
    try {
        Payload payload = om.readValue(getFile("qb.Payload.Invoice.json"), Payload.class);
        assertTrue(payload.toString().startsWith("c10y.model.qb.Payload"));

    } catch (Exception e) {
        e.printStackTrace();
        fail(e.getMessage());
    }
}

Наконец, я использую последние версии Camel & Spring Boot:

<properties>
    <!-- latest versions @ Jul 2020 -->
    <java.version>11</java.version>
    <camel.version>3.4.0</camel.version>    <!-- latest long term support version -->
    <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
    <maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
    <spring-boot.version>2.3.0.RELEASE</spring-boot.version>
    <run.profiles>dev</run.profiles>
</properties>

Как всегда, заранее спасибо за вашу помощь!

PS :

Классы POJO, которые получают неупорядоченный JSON, были созданы в http://www.jsonschema2pojo.org/. POJO для рабочего маршрута заводился вручную. Я упоминаю об этом на всякий случай, если это может иметь значение (это не должно, ИМХО).

Весь маршрут можно получить здесь: https://drive.google.com/file/d/1Qu0vwJaSlggH6BrIgUFMU_BZNpmMQYuh/view?usp=sharing.

I попробовали библиотеку Gson и получили ту же ошибку ClassNotFoundException: Payload.class. Это похоже не столько на проблему демаршалинга, сколько на проблему пути к классам.

Наличие двух операторов .log() дает следующий результат:

2020-07-15 10:06:27.108 DEBUG 6720 --- [mer://startHere] c.c.r.qb.fetch.delta                     : JSON returned: {"QueryResponse":{"Invoice":[{"AllowIPNPayment":false, ...removed... ,"Balance":0}],"startPosition":1,"maxResults":1,"totalCount":1},"time":"2020-07-15T02:06:21.869-07:00"}
2020-07-15 10:06:27.108 DEBUG 6720 --- [mer://startHere] c.c.r.qb.fetch.delta                     : JSON returned: 

Вопреки документации, это выглядит так: входной поток на самом деле не кэшируется.

PS2:

Добавление .streamCaching() к маршруту и ​​&disableStreamCache=false к URI конечной точки не привело к Никаких отличий от второго .log(); он остался пустым.

Я также пробовал следующий подход Java Config:

@Configuration
public class Config {

    @Bean
    CamelContextConfiguration contextConfiguration() {
        return new CamelContextConfiguration() {
            
            @Override
            public void beforeApplicationStart(CamelContext context) {
                System.out.println("****** beforeApplicationStart ******");
                
            }
            
            @Override
            public void afterApplicationStart(CamelContext context) {
                System.out.println("****** afterApplicationStart ******");
                context.setStreamCaching(true);
                
            }
        };
    }

}

Я вижу системный вывод в консоли, но это тоже не сработало.

Я загрузил jsonschema2pojo-1.0.2 и запустил его на гораздо большем образце JSON со следующими аргументами:

--annotation-style JACKSON2
--big-decimals 
--date-class java.util.Date
--format-dates 
--format-date-times 
--package c10y.model.qb.jxon
--remove-old-output 
--source C:\Users\...\src\test\resources\qb.Payload.Invoice.json
--source-type JSON
--target c:\temp
--target-language JAVA
--target-version 11

Это создало корневой / базовый POJO с именем QbPayloadInvoice, который выглядит так, как будто он взят имя входного файла. Я обновил свой маршрут:

.unmarshal().json(JsonLibrary.Jackson, QbPayloadInvoice.class)

Он все еще вызывает java.lang.ClassNotFoundException: Payload.class.

Нет ничего в ответе JSON или в любом другом сгенерированном POJO, называемые Payload.

В то же время мой обновленный jUnit работает нормально:

QbPayloadInvoice payload = om.readValue(getFile("qb.Payload.Invoice.json"), QbPayloadInvoice.class);
expected = "c10y.model.qb.jxon.QbPayloadInvoice";
assertEquals(expected, payload.toString().substring(0, expected.length()));

Go цифра!

1 Ответ

0 голосов
/ 15 июля 2020

Подсказка существует выше, где я написал: «Нет ничего в ответе JSON или в любом из других сгенерированных POJO, называемых Payload». Это утверждение оказалось абсолютно правильным.

Демаршаллинг работал все время:

.unmarshal().json(JsonLibrary.Jackson, QbPayloadInvoice.class)

Это была следующая строка: Это стало более очевидным, учитывая, что я изменил класс демаршаллинга с Payload на QbPayloadInvoice.

...