18
18
19
19
import static com .couchbase .client .java .ClusterOptions .clusterOptions ;
20
20
21
+ import java .lang .annotation .Annotation ;
21
22
import java .util .ArrayList ;
23
+ import java .util .HashMap ;
22
24
import java .util .HashSet ;
23
25
import java .util .List ;
26
+ import java .util .Map ;
24
27
import java .util .Set ;
25
28
29
+ import com .couchbase .client .java .encryption .annotation .Encrypted ;
30
+ import com .fasterxml .jackson .annotation .JsonValue ;
26
31
import org .springframework .beans .factory .config .BeanDefinition ;
27
32
import org .springframework .context .annotation .Bean ;
28
33
import org .springframework .context .annotation .ClassPathScanningCandidateComponentProvider ;
37
42
import org .springframework .data .couchbase .SimpleCouchbaseClientFactory ;
38
43
import org .springframework .data .couchbase .core .CouchbaseTemplate ;
39
44
import org .springframework .data .couchbase .core .ReactiveCouchbaseTemplate ;
45
+ import org .springframework .data .couchbase .core .convert .BooleanToEnumConverterFactory ;
40
46
import org .springframework .data .couchbase .core .convert .CouchbaseCustomConversions ;
41
47
import 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 ;
42
51
import 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 ;
43
54
import org .springframework .data .couchbase .core .convert .translation .JacksonTranslationService ;
44
55
import org .springframework .data .couchbase .core .convert .translation .TranslationService ;
45
56
import org .springframework .data .couchbase .core .mapping .CouchbaseMappingContext ;
60
71
import org .springframework .util .ClassUtils ;
61
72
import org .springframework .util .StringUtils ;
62
73
63
- import com .couchbase .client .core .deps .com .fasterxml .jackson .databind .DeserializationFeature ;
64
74
import com .couchbase .client .core .encryption .CryptoManager ;
65
75
import com .couchbase .client .core .env .Authenticator ;
66
76
import com .couchbase .client .core .env .PasswordAuthenticator ;
72
82
import com .couchbase .client .java .json .JacksonTransformers ;
73
83
import com .couchbase .client .java .json .JsonValueModule ;
74
84
import com .couchbase .client .java .query .QueryScanConsistency ;
85
+ import com .fasterxml .jackson .databind .DeserializationFeature ;
75
86
import com .fasterxml .jackson .databind .ObjectMapper ;
76
87
77
88
/**
87
98
@ Configuration
88
99
public abstract class AbstractCouchbaseConfiguration {
89
100
90
- ObjectMapper mapper ;
91
- CryptoManager cryptoManager = null ;
101
+ volatile ObjectMapper objectMapper ;
102
+ volatile CryptoManager cryptoManager = null ;
92
103
93
104
/**
94
105
* The connection string which allows the SDK to connect to the cluster.
@@ -157,7 +168,7 @@ public ClusterEnvironment couchbaseClusterEnvironment() {
157
168
if (!nonShadowedJacksonPresent ()) {
158
169
throw new CouchbaseException ("non-shadowed Jackson not present" );
159
170
}
160
- builder .jsonSerializer (JacksonJsonSerializer .create (getCouchbaseObjectMapper ()));
171
+ builder .jsonSerializer (JacksonJsonSerializer .create (getObjectMapper ()));
161
172
builder .cryptoManager (getCryptoManager ());
162
173
configureEnvironment (builder );
163
174
return builder .build ();
@@ -277,10 +288,12 @@ public MappingCouchbaseConverter mappingCouchbaseConverter(CouchbaseMappingConte
277
288
@ Bean
278
289
public TranslationService couchbaseTranslationService () {
279
290
final JacksonTranslationService jacksonTranslationService = new JacksonTranslationService ();
280
- jacksonTranslationService .setObjectMapper (getCouchbaseObjectMapper ());
291
+ jacksonTranslationService .setObjectMapper (getObjectMapper ());
281
292
jacksonTranslationService .afterPropertiesSet ();
282
293
// 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 );
284
297
return jacksonTranslationService ;
285
298
}
286
299
@@ -298,21 +311,26 @@ public CouchbaseMappingContext couchbaseMappingContext(CustomConversions customC
298
311
return mappingContext ;
299
312
}
300
313
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
+ }
304
321
}
305
- return mapper = couchbaseObjectMapper () ;
322
+ return objectMapper ;
306
323
}
307
324
308
325
/**
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)
310
328
*
311
329
* @return ObjectMapper
312
330
*/
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 );
316
334
om .registerModule (new JsonValueModule ());
317
335
if (getCryptoManager () != null ) {
318
336
om .registerModule (new EncryptionModule (getCryptoManager ()));
@@ -400,20 +418,35 @@ public CustomConversions customConversions(CryptoManager cryptoManager) {
400
418
List <GenericConverter > newConverters = new ArrayList ();
401
419
CustomConversions customConversions = CouchbaseCustomConversions .create (configurationAdapter -> {
402
420
SimplePropertyValueConversions valueConversions = new SimplePropertyValueConversions ();
403
- valueConversions .setConverterFactory (new CouchbasePropertyValueConverterFactory (cryptoManager ));
421
+ valueConversions .setConverterFactory (new CouchbasePropertyValueConverterFactory (cryptoManager , annotationToConverterMap () ));
404
422
valueConversions .setValueConverterRegistry (new PropertyValueConverterRegistrar ().buildRegistry ());
423
+ valueConversions .afterPropertiesSet (); // wraps the CouchbasePropertyValueConverterFactory with CachingPVCFactory
405
424
configurationAdapter .setPropertyValueConversions (valueConversions );
406
425
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 ()));
407
430
});
408
431
return customConversions ;
409
432
}
410
433
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
+ }
411
440
/**
412
441
* cryptoManager can be null, so it cannot be a bean and then used as an arg for bean methods
413
442
*/
414
443
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
+ }
417
450
}
418
451
return cryptoManager ;
419
452
}
0 commit comments