Я успешно написал простой вариант использования, чтобы демаршалировать 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)
Вот что происходит:
С выше log заявление a MismatchedInputException
появляется с сообщением «Нет содержимого для сопоставления из-за конца ввода».
Без выше 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 цифра!