You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by gn...@apache.org on 2026/03/13 07:30:39 UTC

(camel) 01/01: CAMEL-22090: Fix couchbase consumer when Jackson is on classpath

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

gnodet pushed a commit to branch camel-22090-couchbase-jackson
in repository https://gitbox.apache.org/repos/asf/camel.git

commit c45f8ab762aefc9bb7af1bd7d3a5620956f1cdce
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Fri Mar 13 08:30:23 2026 +0100

    CAMEL-22090: Fix couchbase consumer when Jackson is on classpath
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
---
 .../component/couchbase/CouchbaseConsumer.java     |  7 +++--
 .../component/couchbase/CouchbaseEndpoint.java     | 33 ++++++++++++++++------
 .../component/couchbase/CouchbaseEndpointTest.java | 26 +++++++++++++++++
 3 files changed, 55 insertions(+), 11 deletions(-)

diff --git a/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseConsumer.java b/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseConsumer.java
index 8453d71ca817..1499f16e873b 100644
--- a/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseConsumer.java
+++ b/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseConsumer.java
@@ -21,7 +21,6 @@ import java.util.Queue;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
-import com.couchbase.client.core.deps.com.fasterxml.jackson.databind.JsonNode;
 import com.couchbase.client.java.Bucket;
 import com.couchbase.client.java.Collection;
 import com.couchbase.client.java.Scope;
@@ -143,7 +142,11 @@ public class CouchbaseConsumer extends ScheduledBatchPollingConsumer implements
                     doc = row.valueAs(Object.class);
                 }
 
-                String key = row.keyAs(JsonNode.class).get().asText();
+                // Use String.class instead of the shaded JsonNode class to avoid conflicts
+                // when Jackson is on the classpath (CAMEL-22090). The Couchbase SDK's
+                // auto-detection of non-shaded Jackson would otherwise cause deserialization
+                // failures when trying to deserialize into the shaded JsonNode class.
+                String key = row.keyAs(String.class).orElse(null);
                 String designDocumentName = endpoint.getDesignDocumentName();
                 String viewName = endpoint.getViewName();
 
diff --git a/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseEndpoint.java b/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseEndpoint.java
index d38b5a3d9f5d..989a43da501d 100644
--- a/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseEndpoint.java
+++ b/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseEndpoint.java
@@ -561,15 +561,7 @@ public class CouchbaseEndpoint extends ScheduledPollEndpoint implements Endpoint
             throw new CamelException(COUCHBASE_URI_ERROR);
         }
 
-        ClusterEnvironment.Builder cfb = ClusterEnvironment.builder();
-        cfb.jsonSerializer(DefaultJsonSerializer.create());
-        if (queryTimeout != DEFAULT_QUERY_TIMEOUT) {
-            cfb.timeoutConfig()
-                    .connectTimeout(Duration.ofMillis(connectTimeout))
-                    .queryTimeout(Duration.ofMillis(queryTimeout));
-        }
-
-        ClusterEnvironment env = cfb.build();
+        ClusterEnvironment env = createClusterEnvironment();
 
         String addHosts = hosts.stream()
                 .map(URI::getHost)
@@ -588,6 +580,29 @@ public class CouchbaseEndpoint extends ScheduledPollEndpoint implements Endpoint
         return cluster.bucket(bucket);
     }
 
+    /**
+     * Creates the {@link ClusterEnvironment} for connecting to Couchbase.
+     * <p>
+     * Explicitly configures the {@link DefaultJsonSerializer} to prevent the Couchbase SDK from auto-detecting Jackson
+     * on the classpath (CAMEL-22090). Without this, when a non-shaded Jackson library is present (e.g., via
+     * camel-jackson, Spring Boot, or Quarkus), the SDK would use {@code JacksonJsonSerializer} backed by the non-shaded
+     * Jackson {@code ObjectMapper}. This causes deserialization failures because the SDK's internal types (such as view
+     * row keys) rely on the shaded Jackson classes bundled within the Couchbase SDK.
+     * <p>
+     * The {@link DefaultJsonSerializer} uses the shaded Jackson {@code ObjectMapper} bundled inside the Couchbase SDK,
+     * ensuring consistent serialization/deserialization regardless of what other Jackson versions are on the classpath.
+     */
+    ClusterEnvironment createClusterEnvironment() {
+        ClusterEnvironment.Builder cfb = ClusterEnvironment.builder();
+        cfb.jsonSerializer(DefaultJsonSerializer.create());
+        if (queryTimeout != DEFAULT_QUERY_TIMEOUT) {
+            cfb.timeoutConfig()
+                    .connectTimeout(Duration.ofMillis(connectTimeout))
+                    .queryTimeout(Duration.ofMillis(queryTimeout));
+        }
+        return cfb.build();
+    }
+
     /**
      * Compares retry strategy with query timeout and gets the higher value : for write operations with retry
      *
diff --git a/components/camel-couchbase/src/test/java/org/apache/camel/component/couchbase/CouchbaseEndpointTest.java b/components/camel-couchbase/src/test/java/org/apache/camel/component/couchbase/CouchbaseEndpointTest.java
index bf050e20bd92..c614e6c3726d 100644
--- a/components/camel-couchbase/src/test/java/org/apache/camel/component/couchbase/CouchbaseEndpointTest.java
+++ b/components/camel-couchbase/src/test/java/org/apache/camel/component/couchbase/CouchbaseEndpointTest.java
@@ -19,6 +19,9 @@ package org.apache.camel.component.couchbase;
 import java.util.HashMap;
 import java.util.Map;
 
+import com.couchbase.client.java.codec.DefaultJsonSerializer;
+import com.couchbase.client.java.codec.JsonSerializer;
+import com.couchbase.client.java.env.ClusterEnvironment;
 import org.apache.camel.Processor;
 import org.junit.jupiter.api.Test;
 
@@ -169,4 +172,27 @@ public class CouchbaseEndpointTest {
 
         endpoint.setDescending(false);
     }
+
+    /**
+     * Verifies that the ClusterEnvironment is configured with DefaultJsonSerializer to prevent the Couchbase SDK from
+     * auto-detecting non-shaded Jackson on the classpath (CAMEL-22090). When non-shaded Jackson is present (e.g., via
+     * camel-jackson, Spring Boot, or Quarkus), auto-detection would cause the SDK to use JacksonJsonSerializer, leading
+     * to deserialization failures for SDK internal types that depend on shaded Jackson classes.
+     */
+    @Test
+    public void testClusterEnvironmentUsesDefaultJsonSerializer() {
+        CouchbaseEndpoint endpoint = new CouchbaseEndpoint();
+        ClusterEnvironment env = endpoint.createClusterEnvironment();
+        try {
+            JsonSerializer serializer = env.jsonSerializer();
+            // The serializer must not be JacksonJsonSerializer since that would fail
+            // when a non-shaded Jackson is on the classpath. It should be wrapped in
+            // JsonValueSerializerWrapper which delegates to DefaultJsonSerializer.
+            assertEquals("com.couchbase.client.java.codec.JsonValueSerializerWrapper",
+                    serializer.getClass().getName(),
+                    "ClusterEnvironment should wrap DefaultJsonSerializer in JsonValueSerializerWrapper");
+        } finally {
+            env.shutdown();
+        }
+    }
 }