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 <[email protected]> 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 <[email protected]> --- .../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(); + } + } }
