From 8a6e79dc8be012979da193642ab3a60f72753f42 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sun, 10 Jan 2021 10:10:42 +0100 Subject: [PATCH] Configure Couchbase to use the application's ObjectMapper Closes gh-24616 --- .../couchbase/CouchbaseAutoConfiguration.java | 42 ++++++++++++++++++- .../CouchbaseAutoConfigurationTests.java | 33 ++++++++++++++- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java index 52439a9974..a4c55840f6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,18 +27,24 @@ import com.couchbase.client.core.env.SecurityConfig; import com.couchbase.client.core.env.TimeoutConfig; import com.couchbase.client.java.Cluster; import com.couchbase.client.java.ClusterOptions; +import com.couchbase.client.java.codec.JacksonJsonSerializer; import com.couchbase.client.java.env.ClusterEnvironment; import com.couchbase.client.java.env.ClusterEnvironment.Builder; +import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Timeouts; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; import org.springframework.util.ResourceUtils; /** @@ -50,6 +56,7 @@ import org.springframework.util.ResourceUtils; * @since 1.4.0 */ @Configuration(proxyBeanMethods = false) +@AutoConfigureAfter(JacksonAutoConfiguration.class) @ConditionalOnClass(Cluster.class) @ConditionalOnProperty("spring.couchbase.connection-string") @EnableConfigurationProperties(CouchbaseProperties.class) @@ -111,4 +118,37 @@ public class CouchbaseAutoConfiguration { return store; } + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(ObjectMapper.class) + static class JacksonConfiguration { + + @Bean + @ConditionalOnSingleCandidate(ObjectMapper.class) + ClusterEnvironmentBuilderCustomizer cluster(ObjectMapper objectMapper) { + return new JacksonClusterEnvironmentBuilderCustomizer(objectMapper); + } + + } + + private static final class JacksonClusterEnvironmentBuilderCustomizer + implements ClusterEnvironmentBuilderCustomizer, Ordered { + + private final ObjectMapper objectMapper; + + private JacksonClusterEnvironmentBuilderCustomizer(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + @Override + public void customize(Builder builder) { + builder.jsonSerializer(JacksonJsonSerializer.create(this.objectMapper)); + } + + @Override + public int getOrder() { + return 0; + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java index 993930df0e..a7f0914f09 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,15 +23,20 @@ import com.couchbase.client.core.env.IoConfig; import com.couchbase.client.core.env.SecurityConfig; import com.couchbase.client.core.env.TimeoutConfig; import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.codec.JacksonJsonSerializer; +import com.couchbase.client.java.codec.JsonSerializer; import com.couchbase.client.java.env.ClusterEnvironment; +import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; /** * Tests for {@link CouchbaseAutoConfiguration}. @@ -60,6 +65,32 @@ class CouchbaseAutoConfigurationTests { }); } + @Test + void environmentUseObjectMapperByDefault() { + this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class) + .withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class)) + .withPropertyValues("spring.couchbase.connection-string=localhost").run((context) -> { + ClusterEnvironment env = context.getBean(ClusterEnvironment.class); + JsonSerializer serializer = env.jsonSerializer(); + assertThat(serializer).isInstanceOf(JacksonJsonSerializer.class) + .hasFieldOrPropertyWithValue("mapper", context.getBean(ObjectMapper.class)); + }); + } + + @Test + void customizeJsonSerializer() { + JsonSerializer customJsonSerializer = mock(JsonSerializer.class); + this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class) + .withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class)) + .withBean(ClusterEnvironmentBuilderCustomizer.class, + () -> (builder) -> builder.jsonSerializer(customJsonSerializer)) + .withPropertyValues("spring.couchbase.connection-string=localhost").run((context) -> { + ClusterEnvironment env = context.getBean(ClusterEnvironment.class); + JsonSerializer serializer = env.jsonSerializer(); + assertThat(serializer).isSameAs(customJsonSerializer); + }); + } + @Test void customizeEnvIo() { testClusterEnvironment((env) -> {