This is an automated email from the ASF dual-hosted git repository. JiriOndrusek pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-quarkus-examples.git
commit aedac0a947d7fa31a12b43b76f47576529317e94 Author: James Netherton <[email protected]> AuthorDate: Fri Aug 7 07:12:14 2026 +0100 Marshal the data-extract-langchain4j POJO store response with Jackson CustomPojoStore.asString() hand-built its JSON response by concatenating CustomPojo.toString() values, and that toString() was itself a String.format into a JSON-shaped template. The interpolated values are LLM output, so a single quote or backslash in a model response makes /custom-pojo-store serve malformed JSON. The store now returns the CustomPojo objects and the route marshals them with .marshal().json(JsonLibrary.Jackson). CustomPojo.toString() stays human-readable for the log line, but no longer pretends to be JSON. Co-authored-by: Claude Opus 5 (1M context) <[email protected]> --- data-extract-langchain4j/README.adoc | 8 +------- data-extract-langchain4j/pom.xml | 4 ++++ .../acme/extraction/CustomPojoExtractionService.java | 8 ++------ .../main/java/org/acme/extraction/CustomPojoStore.java | 10 +++------- .../java/org/acme/extraction/DataExtractAgent.java | 2 +- .../src/main/java/org/acme/extraction/Routes.java | 4 +++- .../src/test/java/org/acme/extraction/RouteTest.java | 18 ++++++++++++------ 7 files changed, 26 insertions(+), 28 deletions(-) diff --git a/data-extract-langchain4j/README.adoc b/data-extract-langchain4j/README.adoc index c04ca193..6f3cafe9 100644 --- a/data-extract-langchain4j/README.adoc +++ b/data-extract-langchain4j/README.adoc @@ -99,13 +99,7 @@ At the end, we are provided with a Plain Old Java Object (POJO) handling the ext [source,shell] ---- -2026-05-27 18:31:55,373 INFO [org.acme.extraction.CustomPojoStore] (Camel (camel-1) thread #1 - file://target/transcripts) An extracted POJO has been added to the store: -{ - "customerSatisfied": "true", - "customerName": "Sarah London", - "customerBirthday": "10 JULY 1986", - "summary": "The customer, Sarah London, called to declare an accident on her main vehicle. The operator confirmed that all expenses related to the accident will be reimbursed." -} +2026-05-27 18:31:55,373 INFO [org.acme.extraction.CustomPojoStore] (Camel (camel-1) thread #1 - file://target/transcripts) An extracted POJO has been added to the store: CustomPojo[customerSatisfied=true, customerName=Sarah London, customerBirthday=10 JULY 1986, summary=The customer, Sarah London, called to declare an accident on her main vehicle. The operator confirmed that all expenses related to the accident will be reimbursed.] ---- .See how the LLM shows its capacity to: diff --git a/data-extract-langchain4j/pom.xml b/data-extract-langchain4j/pom.xml index f489628e..eee99d90 100644 --- a/data-extract-langchain4j/pom.xml +++ b/data-extract-langchain4j/pom.xml @@ -88,6 +88,10 @@ <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-file</artifactId> </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-jackson</artifactId> + </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-jsonpath</artifactId> diff --git a/data-extract-langchain4j/src/main/java/org/acme/extraction/CustomPojoExtractionService.java b/data-extract-langchain4j/src/main/java/org/acme/extraction/CustomPojoExtractionService.java index c153d19b..521e2e5a 100644 --- a/data-extract-langchain4j/src/main/java/org/acme/extraction/CustomPojoExtractionService.java +++ b/data-extract-langchain4j/src/main/java/org/acme/extraction/CustomPojoExtractionService.java @@ -38,12 +38,8 @@ public interface CustomPojoExtractionService { @JsonProperty(required = true) public String summary; - private final static String FORMAT = "\n{\n" - + "\t\"customerSatisfied\": \"%s\",\n" - + "\t\"customerName\": \"%s\",\n" - + "\t\"customerBirthday\": \"%02d %s %04d\",\n" - + "\t\"summary\": \"%s\"\n" - + "}\n"; + private final static String FORMAT = "CustomPojo[customerSatisfied=%s, customerName=%s, " + + "customerBirthday=%02d %s %04d, summary=%s]"; public String toString() { return String.format(Locale.US, FORMAT, this.customerSatisfied, this.customerName, this.customerBirthday.day, diff --git a/data-extract-langchain4j/src/main/java/org/acme/extraction/CustomPojoStore.java b/data-extract-langchain4j/src/main/java/org/acme/extraction/CustomPojoStore.java index 0a7ab93e..4c827ef5 100644 --- a/data-extract-langchain4j/src/main/java/org/acme/extraction/CustomPojoStore.java +++ b/data-extract-langchain4j/src/main/java/org/acme/extraction/CustomPojoStore.java @@ -17,8 +17,8 @@ package org.acme.extraction; import java.util.List; +import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.stream.Collectors; import jakarta.enterprise.context.ApplicationScoped; import org.acme.extraction.CustomPojoExtractionService.CustomPojo; @@ -37,12 +37,8 @@ public class CustomPojoStore { } @Handler - String asString() { - StringBuilder sb = new StringBuilder("{ \"pojos\": ["); - String pojoString = pojos.stream().map(CustomPojo::toString).collect(Collectors.joining(",")); - sb.append(pojoString); - sb.append("] }"); - return sb.toString(); + Map<String, List<CustomPojo>> listPojos() { + return Map.of("pojos", List.copyOf(pojos)); } } diff --git a/data-extract-langchain4j/src/main/java/org/acme/extraction/DataExtractAgent.java b/data-extract-langchain4j/src/main/java/org/acme/extraction/DataExtractAgent.java index b4de066f..8e545dc3 100644 --- a/data-extract-langchain4j/src/main/java/org/acme/extraction/DataExtractAgent.java +++ b/data-extract-langchain4j/src/main/java/org/acme/extraction/DataExtractAgent.java @@ -38,7 +38,7 @@ public class DataExtractAgent implements Agent { } /** - * Returns a JSON representation of a {@link CustomPojo}. + * Returns a string representation of the extracted {@link CustomPojo}. */ @Override public String chat(AiAgentBody<?> aiAgentBody, ToolProvider toolProvider) { diff --git a/data-extract-langchain4j/src/main/java/org/acme/extraction/Routes.java b/data-extract-langchain4j/src/main/java/org/acme/extraction/Routes.java index 1c1f3624..dd55cdde 100644 --- a/data-extract-langchain4j/src/main/java/org/acme/extraction/Routes.java +++ b/data-extract-langchain4j/src/main/java/org/acme/extraction/Routes.java @@ -19,6 +19,7 @@ package org.acme.extraction; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; import static org.acme.extraction.DataExtractAgentConfiguration.AGENT_ID; @@ -40,6 +41,7 @@ public class Routes extends RouteBuilder { // This route make it possible to inspect the extracted POJOs, mainly used for demo and test from("platform-http:/custom-pojo-store?produces=application/json") - .bean(customPojoStore); + .bean(customPojoStore) + .marshal().json(JsonLibrary.Jackson); } } diff --git a/data-extract-langchain4j/src/test/java/org/acme/extraction/RouteTest.java b/data-extract-langchain4j/src/test/java/org/acme/extraction/RouteTest.java index 913a34fe..f9ed4ebb 100644 --- a/data-extract-langchain4j/src/test/java/org/acme/extraction/RouteTest.java +++ b/data-extract-langchain4j/src/test/java/org/acme/extraction/RouteTest.java @@ -65,19 +65,25 @@ public class RouteTest { .then() .statusCode(200) // Assert values of the first extracted POJO - .body("pojos[0].customerSatisfied", is("true")) + .body("pojos[0].customerSatisfied", is(true)) .body("pojos[0].customerName", is("Sarah London")) - .body("pojos[0].customerBirthday", is("10 JULY 1986")) + .body("pojos[0].customerBirthday.day", is(10)) + .body("pojos[0].customerBirthday.month", is(7)) + .body("pojos[0].customerBirthday.year", is(1986)) .body("pojos[0].summary", not(empty())) // Assert values of the second extracted POJO - .body("pojos[1].customerSatisfied", is("false")) + .body("pojos[1].customerSatisfied", is(false)) .body("pojos[1].customerName", is("John Doe")) - .body("pojos[1].customerBirthday", is("01 NOVEMBER 2001")) + .body("pojos[1].customerBirthday.day", is(1)) + .body("pojos[1].customerBirthday.month", is(11)) + .body("pojos[1].customerBirthday.year", is(2001)) .body("pojos[1].summary", not(empty())) // Assert values of the third extracted POJO - .body("pojos[2].customerSatisfied", is("true")) + .body("pojos[2].customerSatisfied", is(true)) .body("pojos[2].customerName", is("Kate Boss")) - .body("pojos[2].customerBirthday", is("13 AUGUST 1999")) + .body("pojos[2].customerBirthday.day", is(13)) + .body("pojos[2].customerBirthday.month", is(8)) + .body("pojos[2].customerBirthday.year", is(1999)) .body("pojos[2].summary", not(empty())); }
