1818
1919import static com .couchbase .client .java .ClusterOptions .clusterOptions ;
2020
21+ import java .lang .annotation .Annotation ;
2122import java .util .ArrayList ;
23+ import java .util .HashMap ;
2224import java .util .HashSet ;
2325import java .util .List ;
26+ import java .util .Map ;
2427import java .util .Set ;
2528
29+ import com .couchbase .client .java .encryption .annotation .Encrypted ;
30+ import com .fasterxml .jackson .annotation .JsonValue ;
2631import org .springframework .beans .factory .config .BeanDefinition ;
2732import org .springframework .context .annotation .Bean ;
2833import org .springframework .context .annotation .ClassPathScanningCandidateComponentProvider ;
3742import org .springframework .data .couchbase .SimpleCouchbaseClientFactory ;
3843import org .springframework .data .couchbase .core .CouchbaseTemplate ;
3944import org .springframework .data .couchbase .core .ReactiveCouchbaseTemplate ;
45+ import org .springframework .data .couchbase .core .convert .BooleanToEnumConverterFactory ;
4046import org .springframework .data .couchbase .core .convert .CouchbaseCustomConversions ;
4147import org .springframework .data .couchbase .core .convert .CouchbasePropertyValueConverterFactory ;
48+ import org .springframework .data .couchbase .core .convert .CryptoConverter ;
49+ import org .springframework .data .couchbase .core .convert .IntegerToEnumConverterFactory ;
50+ import org .springframework .data .couchbase .core .convert .JsonValueConverter ;
4251import org .springframework .data .couchbase .core .convert .MappingCouchbaseConverter ;
52+ import org .springframework .data .couchbase .core .convert .OtherConverters ;
53+ import org .springframework .data .couchbase .core .convert .StringToEnumConverterFactory ;
4354import org .springframework .data .couchbase .core .convert .translation .JacksonTranslationService ;
4455import org .springframework .data .couchbase .core .convert .translation .TranslationService ;
4556import org .springframework .data .couchbase .core .mapping .CouchbaseMappingContext ;
6071import org .springframework .util .ClassUtils ;
6172import org .springframework .util .StringUtils ;
6273
63- import com .couchbase .client .core .deps .com .fasterxml .jackson .databind .DeserializationFeature ;
6474import com .couchbase .client .core .encryption .CryptoManager ;
6575import com .couchbase .client .core .env .Authenticator ;
6676import com .couchbase .client .core .env .PasswordAuthenticator ;
7282import com .couchbase .client .java .json .JacksonTransformers ;
7383import com .couchbase .client .java .json .JsonValueModule ;
7484import com .couchbase .client .java .query .QueryScanConsistency ;
85+ import com .fasterxml .jackson .databind .DeserializationFeature ;
7586import com .fasterxml .jackson .databind .ObjectMapper ;
7687
7788/**
8798@ Configuration
8899public abstract class AbstractCouchbaseConfiguration {
89100
90- ObjectMapper mapper ;
91- CryptoManager cryptoManager = null ;
101+ volatile ObjectMapper objectMapper ;
102+ volatile CryptoManager cryptoManager = null ;
92103
93104 /**
94105 * The connection string which allows the SDK to connect to the cluster.
@@ -157,7 +168,7 @@ public ClusterEnvironment couchbaseClusterEnvironment() {
157168 if (!nonShadowedJacksonPresent ()) {
158169 throw new CouchbaseException ("non-shadowed Jackson not present" );
159170 }
160- builder .jsonSerializer (JacksonJsonSerializer .create (getCouchbaseObjectMapper ()));
171+ builder .jsonSerializer (JacksonJsonSerializer .create (getObjectMapper ()));
161172 builder .cryptoManager (getCryptoManager ());
162173 configureEnvironment (builder );
163174 return builder .build ();
@@ -277,10 +288,12 @@ public MappingCouchbaseConverter mappingCouchbaseConverter(CouchbaseMappingConte
277288 @ Bean
278289 public TranslationService couchbaseTranslationService () {
279290 final JacksonTranslationService jacksonTranslationService = new JacksonTranslationService ();
280- jacksonTranslationService .setObjectMapper (getCouchbaseObjectMapper ());
291+ jacksonTranslationService .setObjectMapper (getObjectMapper ());
281292 jacksonTranslationService .afterPropertiesSet ();
282293 // for sdk3, we need to ask the mapper _it_ uses to ignore extra fields...
283- JacksonTransformers .MAPPER .configure (DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false );
294+ JacksonTransformers .MAPPER .configure (
295+ com .couchbase .client .core .deps .com .fasterxml .jackson .databind .DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES ,
296+ false );
284297 return jacksonTranslationService ;
285298 }
286299
@@ -298,21 +311,26 @@ public CouchbaseMappingContext couchbaseMappingContext(CustomConversions customC
298311 return mappingContext ;
299312 }
300313
301- private ObjectMapper getCouchbaseObjectMapper () {
302- if (mapper != null ) {
303- return mapper ;
314+ final public ObjectMapper getObjectMapper () {
315+ if (objectMapper == null ) {
316+ synchronized (this ) {
317+ if (objectMapper == null ) {
318+ objectMapper = couchbaseObjectMapper ();
319+ }
320+ }
304321 }
305- return mapper = couchbaseObjectMapper () ;
322+ return objectMapper ;
306323 }
307324
308325 /**
309- * Creates a {@link ObjectMapper} for the jsonSerializer of the ClusterEnvironment
326+ * Creates a {@link ObjectMapper} for the jsonSerializer of the ClusterEnvironment and spring-data-couchbase
327+ * jacksonTranslationService and also some converters (EnumToObject, StringToEnum, IntegerToEnum)
310328 *
311329 * @return ObjectMapper
312330 */
313- public ObjectMapper couchbaseObjectMapper () {
314- ObjectMapper om = new ObjectMapper (); // or use the one from the Java SDK (?) JacksonTransformers.MAPPER
315- om .configure (com . fasterxml . jackson . databind . DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false );
331+ protected ObjectMapper couchbaseObjectMapper () {
332+ ObjectMapper om = new ObjectMapper ();
333+ om .configure (DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false );
316334 om .registerModule (new JsonValueModule ());
317335 if (getCryptoManager () != null ) {
318336 om .registerModule (new EncryptionModule (getCryptoManager ()));
@@ -400,20 +418,35 @@ public CustomConversions customConversions(CryptoManager cryptoManager) {
400418 List <GenericConverter > newConverters = new ArrayList ();
401419 CustomConversions customConversions = CouchbaseCustomConversions .create (configurationAdapter -> {
402420 SimplePropertyValueConversions valueConversions = new SimplePropertyValueConversions ();
403- valueConversions .setConverterFactory (new CouchbasePropertyValueConverterFactory (cryptoManager ));
421+ valueConversions .setConverterFactory (new CouchbasePropertyValueConverterFactory (cryptoManager , annotationToConverterMap () ));
404422 valueConversions .setValueConverterRegistry (new PropertyValueConverterRegistrar ().buildRegistry ());
423+ valueConversions .afterPropertiesSet (); // wraps the CouchbasePropertyValueConverterFactory with CachingPVCFactory
405424 configurationAdapter .setPropertyValueConversions (valueConversions );
406425 configurationAdapter .registerConverters (newConverters );
426+ configurationAdapter .registerConverter (new OtherConverters .EnumToObject (getObjectMapper ()));
427+ configurationAdapter .registerConverterFactory (new IntegerToEnumConverterFactory (getObjectMapper ()));
428+ configurationAdapter .registerConverterFactory (new StringToEnumConverterFactory (getObjectMapper ()));
429+ configurationAdapter .registerConverterFactory (new BooleanToEnumConverterFactory (getObjectMapper ()));
407430 });
408431 return customConversions ;
409432 }
410433
434+ Map <Class <? extends Annotation >,Class <?>> annotationToConverterMap (){
435+ Map <Class <? extends Annotation >,Class <?>> map = new HashMap ();
436+ map .put (Encrypted .class , CryptoConverter .class );
437+ map .put (JsonValue .class , JsonValueConverter .class );
438+ return map ;
439+ }
411440 /**
412441 * cryptoManager can be null, so it cannot be a bean and then used as an arg for bean methods
413442 */
414443 private CryptoManager getCryptoManager () {
415- if (cryptoManager == null ) {
416- cryptoManager = cryptoManager ();
444+ if (cryptoManager == null ) {
445+ synchronized (this ) {
446+ if (cryptoManager == null ) {
447+ cryptoManager = cryptoManager ();
448+ }
449+ }
417450 }
418451 return cryptoManager ;
419452 }
0 commit comments