You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2024/03/01 12:25:53 UTC

(camel) branch jp-list created (now 014e83d5ada)

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a change to branch jp-list
in repository https://gitbox.apache.org/repos/asf/camel.git


      at 014e83d5ada CAMEL-20495: camel-jsonpath - If resultType is List then automatic wrap single element into a List.

This branch includes the following new commits:

     new 014e83d5ada CAMEL-20495: camel-jsonpath - If resultType is List then automatic wrap single element into a List.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(camel) 01/01: CAMEL-20495: camel-jsonpath - If resultType is List then automatic wrap single element into a List.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch jp-list
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 014e83d5adab53a53d5d9f5b6a7ac9ebfdd5763f
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Mar 1 13:25:27 2024 +0100

    CAMEL-20495: camel-jsonpath - If resultType is List then automatic wrap single element into a List.
---
 .../src/main/docs/jsonpath-language.adoc           |  9 ++-
 .../apache/camel/jsonpath/JsonPathExpression.java  | 14 ++++-
 .../jsonpath/JsonPathSplitSingleListTest.java      | 69 ++++++++++++++++++++++
 3 files changed, 88 insertions(+), 4 deletions(-)

diff --git a/components/camel-jsonpath/src/main/docs/jsonpath-language.adoc b/components/camel-jsonpath/src/main/docs/jsonpath-language.adoc
index d93c48c8603..37e45a1b942 100644
--- a/components/camel-jsonpath/src/main/docs/jsonpath-language.adoc
+++ b/components/camel-jsonpath/src/main/docs/jsonpath-language.adoc
@@ -284,10 +284,15 @@ You can use JSONPath to split a JSON document, such as:
 [source,java]
 ----
 from("direct:start")
-    .split().jsonpath("$.store.book[*]")
+    .split().jsonpath("$.store.book[*]", List.class)
     .to("log:book");
 ----
 
+IMPORTANT: Notice how we specify `List.class` as the result-type. This is because if there is only
+a single element (only 1 book), then jsonpath will return the single entity as a `Map` instead of `List<Map>`.
+Therefore, we tell Camel that the result should always be a `List`, and Camel will then automatic wrap the
+single element into a new `List` object.
+
 Then each book is logged, however the message body is a `Map` instance. Sometimes
 you may want to output this as plain String JSON value instead, which can be done
 with the `writeAsString` option as shown:
@@ -295,7 +300,7 @@ with the `writeAsString` option as shown:
 [source,java]
 ----
 from("direct:start")
-    .split().jsonpathWriteAsString("$.store.book[*]")
+    .split().jsonpathWriteAsString("$.store.book[*]", List.class)
     .to("log:book");
 ----
 
diff --git a/components/camel-jsonpath/src/main/java/org/apache/camel/jsonpath/JsonPathExpression.java b/components/camel-jsonpath/src/main/java/org/apache/camel/jsonpath/JsonPathExpression.java
index e6bbfd0a473..f4ce1e74ea8 100644
--- a/components/camel-jsonpath/src/main/java/org/apache/camel/jsonpath/JsonPathExpression.java
+++ b/components/camel-jsonpath/src/main/java/org/apache/camel/jsonpath/JsonPathExpression.java
@@ -17,6 +17,7 @@
 package org.apache.camel.jsonpath;
 
 import java.util.Collection;
+import java.util.LinkedList;
 import java.util.List;
 
 import com.jayway.jsonpath.Option;
@@ -156,13 +157,22 @@ public class JsonPathExpression extends ExpressionAdapter {
                 if (unpackArray) {
                     // in some cases we get a single element that is wrapped in a List, so unwrap that
                     // if we for example want to grab the single entity and convert that to a int/boolean/String etc
-                    boolean resultIsCollection = Collection.class.isAssignableFrom(resultType);
+                    boolean resultTypeIsCollection = Collection.class.isAssignableFrom(resultType);
                     boolean singleElement = result instanceof List && ((List<?>) result).size() == 1;
-                    if (singleElement && !resultIsCollection) {
+                    if (singleElement && !resultTypeIsCollection) {
                         result = ((List<?>) result).get(0);
                         LOG.trace("Unwrapping result: {} from single element List before converting to: {}", result,
                                 resultType);
                     }
+                } else {
+                    // special for List
+                    boolean resultTypeIsCollection = Collection.class.isAssignableFrom(resultType);
+                    boolean resultIsCollection = result instanceof List;
+                    if (resultTypeIsCollection && !resultIsCollection) {
+                        var list = new LinkedList<>();
+                        list.add(result);
+                        return list;
+                    }
                 }
                 return exchange.getContext().getTypeConverter().convertTo(resultType, exchange, result);
             } else {
diff --git a/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathSplitSingleListTest.java b/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathSplitSingleListTest.java
new file mode 100644
index 00000000000..9325c3a97cb
--- /dev/null
+++ b/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathSplitSingleListTest.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.jsonpath;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class JsonPathSplitSingleListTest extends CamelTestSupport {
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        // we select first book, but since we split after wards then ensure
+                        // it will be wrapped inside a List object.
+                        .split().jsonpath("$.store.book[0]", List.class)
+                        .to("mock:authors")
+                        .convertBodyTo(String.class);
+            }
+        };
+    }
+
+    @Test
+    public void testSplit() throws Exception {
+        getMockEndpoint("mock:authors").expectedMessageCount(1);
+
+        String out = template.requestBody("direct:start", new File("src/test/resources/books.json"), String.class);
+        assertNotNull(out);
+
+        MockEndpoint.assertIsSatisfied(context);
+
+        Map row = getMockEndpoint("mock:authors").getReceivedExchanges().get(0).getIn().getBody(Map.class);
+        assertEquals("Nigel Rees", row.get("author"));
+        assertEquals(Double.valueOf("8.95"), row.get("price"));
+
+        // should preserve quotes etc
+        assertTrue(out.contains("\"author\": \"Nigel Rees\""));
+        assertTrue(out.contains("\"price\": 8.95"));
+        assertTrue(out.contains("\"title\": \"Sword's of Honour\""));
+        assertTrue(out.contains("\"price\": 12.99,"));
+    }
+
+}