This is an automated email from the ASF dual-hosted git repository.
jamesnetherton pushed a commit to branch camel-quarkus-main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus-examples.git
The following commit(s) were added to refs/heads/camel-quarkus-main by this
push:
new da6351b1 Marshal the data-extract-langchain4j POJO store response with
Jackson
da6351b1 is described below
commit da6351b11f39ba5f517fe1f388d8362bb52e367a
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()));
}