From 4b121c03ea9e435513c22a2e67c244c50ad77b7c Mon Sep 17 00:00:00 2001 From: mikereiche Date: Fri, 23 Apr 2021 16:38:42 -0400 Subject: [PATCH] Expose ObjectMapper used by JsonSerializer Closes #1130. --- .../AbstractCouchbaseConfiguration.java | 51 +++++++++++++++++-- ...chbaseRepositoryQueryIntegrationTests.java | 4 +- ...aseRepositoryKeyValueIntegrationTests.java | 14 ++--- 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java b/src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java index 32cf783c2..421832b10 100644 --- a/src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java +++ b/src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java @@ -16,12 +16,13 @@ package org.springframework.data.couchbase.config; -import static com.couchbase.client.java.ClusterOptions.*; +import static com.couchbase.client.java.ClusterOptions.clusterOptions; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; @@ -48,11 +49,19 @@ import org.springframework.util.StringUtils; import com.couchbase.client.core.deps.com.fasterxml.jackson.databind.DeserializationFeature; +import com.couchbase.client.core.deps.com.fasterxml.jackson.databind.Module; +import com.couchbase.client.core.encryption.CryptoManager; import com.couchbase.client.core.env.Authenticator; import com.couchbase.client.core.env.PasswordAuthenticator; +import com.couchbase.client.core.error.CouchbaseException; import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.codec.JacksonJsonSerializer; +import com.couchbase.client.java.encryption.databind.jackson.EncryptionModule; import com.couchbase.client.java.env.ClusterEnvironment; import com.couchbase.client.java.json.JacksonTransformers; +import com.couchbase.client.java.json.JsonValueModule; +import com.couchbase.client.java.json.RepackagedJsonValueModule; +import com.fasterxml.jackson.databind.ObjectMapper; /** * Base class for Spring Data Couchbase configuration using JavaConfig. @@ -65,12 +74,13 @@ @Configuration public abstract class AbstractCouchbaseConfiguration { + @Autowired ObjectMapper couchbaseObjectMapper; + /** * The connection string which allows the SDK to connect to the cluster. *

- * Note that the connection string can take many forms, in its simplest it is just a single hostname - * like "127.0.0.1". Please refer to the couchbase Java SDK documentation for all the different - * possibilities and options. + * Note that the connection string can take many forms, in its simplest it is just a single hostname like "127.0.0.1". + * Please refer to the couchbase Java SDK documentation for all the different possibilities and options. */ public abstract String getConnectionString(); @@ -130,6 +140,10 @@ public Cluster couchbaseCluster(ClusterEnvironment couchbaseClusterEnvironment) @Bean(destroyMethod = "shutdown") public ClusterEnvironment couchbaseClusterEnvironment() { ClusterEnvironment.Builder builder = ClusterEnvironment.builder(); + if (!nonShadowedJacksonPresent()) { + throw new CouchbaseException("non-shadowed Jackson not present"); + } + builder.jsonSerializer(JacksonJsonSerializer.create(couchbaseObjectMapper)); configureEnvironment(builder); return builder.build(); } @@ -273,6 +287,25 @@ public CouchbaseMappingContext couchbaseMappingContext(CustomConversions customC return mappingContext; } + /** + * Creates a {@link ObjectMapper} for the jsonSerializer of the ClusterEnvironment + * + * @throws Exception on Bean construction failure. + * @return ObjectMapper + */ + + @Bean + public ObjectMapper couchbaseObjectMapper() { + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.registerModule(new JsonValueModule()); + CryptoManager cryptoManager = null; + if (cryptoManager != null) { + mapper.registerModule(new EncryptionModule(cryptoManager)); + } + return mapper; + } + /** * Configure whether to automatically create indices for domain types by deriving the from the entity or not. */ @@ -327,4 +360,14 @@ protected FieldNamingStrategy fieldNamingStrategy() { return abbreviateFieldNames() ? new CamelCaseAbbreviatingFieldNamingStrategy() : PropertyNameFieldNamingStrategy.INSTANCE; } + + private boolean nonShadowedJacksonPresent() { + try { + JacksonJsonSerializer.preflightCheck(); + return true; + } catch (Throwable t) { + return false; + } + } + } diff --git a/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java index 4532a4e48..6de4a3831 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java +++ b/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java @@ -184,6 +184,7 @@ void findByTypeAlias() { vie = new Airport("airports::vie", "vie", "loww"); vie = airportRepository.save(vie); List airports = couchbaseTemplate.findByQuery(Airport.class) + .withConsistency(QueryScanConsistency.REQUEST_PLUS) .matching(new Query(QueryCriteria.where(N1QLExpression.x("_class")).is("airport"))).all(); assertFalse(airports.isEmpty(), "should have found aiport"); } finally { @@ -198,7 +199,7 @@ void findByEnum() { vie = new Airport("airports::vie", "vie", "loww"); vie = airportRepository.save(vie); Airport airport2 = airportRepository.findByIata(Iata.vie); - assertNotNull(airport2, "should have found "+vie); + assertNotNull(airport2, "should have found " + vie); assertEquals(airport2.getId(), vie.getId()); } finally { airportRepository.delete(vie); @@ -397,7 +398,6 @@ void findBySimplePropertyAudited() { } } - private void sleep(int millis) { try { Thread.sleep(millis); // so they are executed out-of-order diff --git a/src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryKeyValueIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryKeyValueIntegrationTests.java index 9f10bc476..6888dd581 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryKeyValueIntegrationTests.java +++ b/src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryKeyValueIntegrationTests.java @@ -16,11 +16,13 @@ package org.springframework.data.couchbase.repository; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; -import java.util.List; import java.util.Optional; import java.util.UUID; + import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -64,13 +66,13 @@ void saveAndFindById() { } @Test - void findBySimplePropertyAudited() { + void findByIdAudited() { Airport vie = null; try { vie = new Airport("airports::vie", "vie", "low2"); Airport saved = airportRepository.save(vie).block(); - List airports1 = airportRepository.findAllByIata("vie").collectList().block(); - assertEquals(saved, airports1.get(0)); + Airport airport1 = airportRepository.findById(saved.getId()).block(); + assertEquals(airport1, saved); assertEquals(saved.getCreatedBy(), "auditor"); // NaiveAuditorAware will provide this } finally { airportRepository.delete(vie).block(); @@ -79,7 +81,7 @@ void findBySimplePropertyAudited() { @Configuration @EnableReactiveCouchbaseRepositories("org.springframework.data.couchbase") - @EnableReactiveCouchbaseAuditing + @EnableReactiveCouchbaseAuditing static class Config extends AbstractCouchbaseConfiguration { @Override