25
25
import java .util .*;
26
26
import java .util .concurrent .ConcurrentHashMap ;
27
27
import java .util .function .Function ;
28
+ import java .util .stream .Collectors ;
28
29
29
30
import org .springframework .core .GenericTypeResolver ;
30
31
import org .springframework .core .convert .converter .Converter ;
@@ -57,6 +58,10 @@ public class CustomConversions {
57
58
private static final String READ_CONVERTER_NOT_SIMPLE = "Registering converter from %s to %s as reading converter although it doesn't convert from a store-supported type! You might wanna check you annotation setup at the converter implementation." ;
58
59
private static final String WRITE_CONVERTER_NOT_SIMPLE = "Registering converter from %s to %s as writing converter although it doesn't convert to a store-supported type! You might wanna check you annotation setup at the converter implementation." ;
59
60
private static final String NOT_A_CONVERTER = "Converter %s is neither a Spring Converter, GenericConverter or ConverterFactory!" ;
61
+ private static final String CONVERTER_FILTER = "converter from %s to %s as %s converter." ;
62
+ private static final String ADD_CONVERTER = "Adding %s" + CONVERTER_FILTER ;
63
+ private static final String SKIP_CONVERTER = "Skipping " + CONVERTER_FILTER
64
+ + "%s is not a store supported simple type!" ;
60
65
private static final List <Object > DEFAULT_CONVERTERS ;
61
66
62
67
static {
@@ -89,7 +94,10 @@ public class CustomConversions {
89
94
convertiblePair .getSourceType (), null , writingPairs );
90
95
91
96
/**
92
- * Creates a new {@link CustomConversions} instance registering the given converters.
97
+ * Creates a new {@link CustomConversions} instance registering all given user defined converters and selecting
98
+ * {@link Converter converters} from {@link StoreConversions} depending on
99
+ * {@link StoreConversions#getSimpleTypeHolder() store simple types} only considering those that either convert
100
+ * to/from a store supported type.
93
101
*
94
102
* @param storeConversions must not be {@literal null}.
95
103
* @param converters must not be {@literal null}.
@@ -99,21 +107,47 @@ public CustomConversions(StoreConversions storeConversions, Collection<?> conver
99
107
Assert .notNull (storeConversions , "StoreConversions must not be null!" );
100
108
Assert .notNull (converters , "List of converters must not be null!" );
101
109
102
- List <Object > toRegister = new ArrayList <>();
110
+ List <Object > registeredConverters = collectPotentialConverterRegistrations (storeConversions , converters ).stream () //
111
+ .filter (this ::isSupportedConverter ) //
112
+ .map (ConverterRegistrationIntent ::getConverterRegistration ) //
113
+ .map (this ::register ) //
114
+ .distinct () //
115
+ .collect (Collectors .toList ());
103
116
104
- // Add user provided converters to make sure they can override the defaults
105
- toRegister .addAll (converters );
106
- toRegister .addAll (storeConversions .getStoreConverters ());
107
- toRegister .addAll (DEFAULT_CONVERTERS );
117
+ Collections .reverse (registeredConverters );
108
118
109
- toRegister . stream () //
110
- . flatMap ( it -> storeConversions .getRegistrationsFor ( it ). stream ()) //
111
- . forEach ( this :: register );
119
+ this . converters = Collections . unmodifiableList ( registeredConverters );
120
+ this . simpleTypeHolder = new SimpleTypeHolder ( customSimpleTypes , storeConversions .getStoreTypeHolder ());
121
+ }
112
122
113
- Collections .reverse (toRegister );
123
+ /**
124
+ * Validate a given {@link ConverterRegistration} in a specific setup. <br />
125
+ * Non {@link ReadingConverter reading} and user defined {@link Converter converters} are only considered supported if
126
+ * the {@link ConverterRegistrationIntent#isSimpleTargetType() target type} is considered to be a store simple type.
127
+ *
128
+ * @param registration
129
+ * @return
130
+ * @since 2.3
131
+ */
132
+ protected boolean isSupportedConverter (ConverterRegistrationIntent registration ) {
114
133
115
- this .converters = Collections .unmodifiableList (toRegister );
116
- this .simpleTypeHolder = new SimpleTypeHolder (customSimpleTypes , storeConversions .getStoreTypeHolder ());
134
+ boolean register = registration .isUserConverter () || (registration .isReading () && registration .isSimpleSourceType ())
135
+ || (registration .isWriting () && registration .isSimpleTargetType ());
136
+
137
+ if (LOG .isDebugEnabled ()) {
138
+
139
+ if (register ) {
140
+ LOG .debug (String .format (ADD_CONVERTER , registration .isUserConverter () ? "user defined " : "" ,
141
+ registration .getSourceType (), registration .getTargetType (),
142
+ registration .isReading () ? "reading" : "writing" ));
143
+ } else {
144
+ LOG .debug (String .format (SKIP_CONVERTER , registration .getSourceType (), registration .getTargetType (),
145
+ registration .isReading () ? "reading" : "writing" ,
146
+ registration .isReading () ? registration .getSourceType () : registration .getTargetType ()));
147
+ }
148
+ }
149
+
150
+ return register ;
117
151
}
118
152
119
153
/**
@@ -152,6 +186,36 @@ public void registerConvertersIn(ConverterRegistry conversionService) {
152
186
converters .forEach (it -> registerConverterIn (it , conversionService ));
153
187
}
154
188
189
+ /**
190
+ * Get all converters and add some origin information
191
+ *
192
+ * @param storeConversions
193
+ * @param converters
194
+ * @return
195
+ */
196
+ private List <ConverterRegistrationIntent > collectPotentialConverterRegistrations (StoreConversions storeConversions ,
197
+ Collection <?> converters ) {
198
+
199
+ List <ConverterRegistrationIntent > converterRegistrations = new ArrayList <>();
200
+
201
+ converterRegistrations .addAll (converters .stream () //
202
+ .flatMap (it -> storeConversions .getRegistrationsFor (it ).stream ()) //
203
+ .map (ConverterRegistrationIntent ::userConverters ) //
204
+ .collect (Collectors .toList ()));
205
+
206
+ converterRegistrations .addAll (storeConversions .getStoreConverters ().stream () //
207
+ .flatMap (it -> storeConversions .getRegistrationsFor (it ).stream ()) //
208
+ .map (ConverterRegistrationIntent ::storeConverters ) //
209
+ .collect (Collectors .toList ()));
210
+
211
+ converterRegistrations .addAll (DEFAULT_CONVERTERS .stream () //
212
+ .flatMap (it -> storeConversions .getRegistrationsFor (it ).stream ()) //
213
+ .map (ConverterRegistrationIntent ::defaultConverters ) //
214
+ .collect (Collectors .toList ()));
215
+
216
+ return converterRegistrations ;
217
+ }
218
+
155
219
/**
156
220
* Registers the given converter in the given {@link GenericConversionService}.
157
221
*
@@ -193,7 +257,7 @@ private void registerConverterIn(Object candidate, ConverterRegistry conversionS
193
257
*
194
258
* @param converterRegistration
195
259
*/
196
- private void register (ConverterRegistration converterRegistration ) {
260
+ private Object register (ConverterRegistration converterRegistration ) {
197
261
198
262
Assert .notNull (converterRegistration , "Converter registration must not be null!" );
199
263
@@ -217,6 +281,8 @@ private void register(ConverterRegistration converterRegistration) {
217
281
LOG .warn (String .format (WRITE_CONVERTER_NOT_SIMPLE , pair .getSourceType (), pair .getTargetType ()));
218
282
}
219
283
}
284
+
285
+ return converterRegistration .getConverter ();
220
286
}
221
287
222
288
/**
@@ -442,15 +508,90 @@ public Class<?> computeIfAbsent(Class<?> targetType, Function<ConvertiblePair, C
442
508
}
443
509
}
444
510
511
+ /**
512
+ * Value class tying together a {@link ConverterRegistration} and its {@link ConverterOrigin origin} to allow fine
513
+ * grained registration based on store supported types.
514
+ *
515
+ * @since 2.3
516
+ * @author Christoph Strobl
517
+ */
518
+ protected static class ConverterRegistrationIntent {
519
+
520
+ private final ConverterRegistration delegate ;
521
+ private final ConverterOrigin origin ;
522
+
523
+ ConverterRegistrationIntent (ConverterRegistration delegate , ConverterOrigin origin ) {
524
+ this .delegate = delegate ;
525
+ this .origin = origin ;
526
+ }
527
+
528
+ static ConverterRegistrationIntent userConverters (ConverterRegistration delegate ) {
529
+ return new ConverterRegistrationIntent (delegate , ConverterOrigin .USER_DEFINED );
530
+ }
531
+
532
+ static ConverterRegistrationIntent storeConverters (ConverterRegistration delegate ) {
533
+ return new ConverterRegistrationIntent (delegate , ConverterOrigin .STORE );
534
+ }
535
+
536
+ static ConverterRegistrationIntent defaultConverters (ConverterRegistration delegate ) {
537
+ return new ConverterRegistrationIntent (delegate , ConverterOrigin .DEFAULT );
538
+ }
539
+
540
+ Class <?> getSourceType () {
541
+ return delegate .getConvertiblePair ().getSourceType ();
542
+ }
543
+
544
+ Class <?> getTargetType () {
545
+ return delegate .getConvertiblePair ().getTargetType ();
546
+ }
547
+
548
+ public boolean isWriting () {
549
+ return delegate .isWriting ();
550
+ }
551
+
552
+ public boolean isReading () {
553
+ return delegate .isReading ();
554
+ }
555
+
556
+ public boolean isSimpleSourceType () {
557
+ return delegate .isSimpleSourceType ();
558
+ }
559
+
560
+ public boolean isSimpleTargetType () {
561
+ return delegate .isSimpleTargetType ();
562
+ }
563
+
564
+ public boolean isUserConverter () {
565
+ return isConverterOfSource (ConverterOrigin .USER_DEFINED );
566
+ }
567
+
568
+ public boolean isDefaultConveter () {
569
+ return isConverterOfSource (ConverterOrigin .DEFAULT );
570
+ }
571
+
572
+ public ConverterRegistration getConverterRegistration () {
573
+ return delegate ;
574
+ }
575
+
576
+ private boolean isConverterOfSource (ConverterOrigin source ) {
577
+ return origin .equals (source );
578
+ }
579
+
580
+ protected enum ConverterOrigin {
581
+ DEFAULT , USER_DEFINED , STORE
582
+ }
583
+ }
584
+
445
585
/**
446
586
* Conversion registration information.
447
587
*
448
588
* @author Oliver Gierke
449
589
* @author Mark Paluch
450
590
*/
451
591
@ RequiredArgsConstructor (access = AccessLevel .PRIVATE )
452
- static class ConverterRegistration {
592
+ private static class ConverterRegistration {
453
593
594
+ private final Object converter ;
454
595
private final @ NonNull ConvertiblePair convertiblePair ;
455
596
private final @ NonNull StoreConversions storeConversions ;
456
597
private final boolean reading ;
@@ -500,6 +641,13 @@ public boolean isSimpleSourceType() {
500
641
public boolean isSimpleTargetType () {
501
642
return storeConversions .isStoreSimpleType (convertiblePair .getTargetType ());
502
643
}
644
+
645
+ /**
646
+ * @return
647
+ */
648
+ Object getConverter () {
649
+ return converter ;
650
+ }
503
651
}
504
652
505
653
/**
@@ -575,7 +723,7 @@ public Streamable<ConverterRegistration> getRegistrationsFor(Object converter) {
575
723
576
724
return convertibleTypes == null //
577
725
? Streamable .empty () //
578
- : Streamable .of (convertibleTypes ).map (it -> register (it , isReading , isWriting ));
726
+ : Streamable .of (convertibleTypes ).map (it -> register (converter , it , isReading , isWriting ));
579
727
580
728
} else if (converter instanceof ConverterFactory ) {
581
729
@@ -600,15 +748,17 @@ private Streamable<ConverterRegistration> getRegistrationFor(Object converter, C
600
748
throw new IllegalStateException (String .format ("Couldn't resolve type arguments for %s!" , converterType ));
601
749
}
602
750
603
- return Streamable .of (register (arguments [0 ], arguments [1 ], isReading , isWriting ));
751
+ return Streamable .of (register (converter , arguments [0 ], arguments [1 ], isReading , isWriting ));
604
752
}
605
753
606
- private ConverterRegistration register (Class <?> source , Class <?> target , boolean isReading , boolean isWriting ) {
607
- return register (new ConvertiblePair (source , target ), isReading , isWriting );
754
+ private ConverterRegistration register (Object converter , Class <?> source , Class <?> target , boolean isReading ,
755
+ boolean isWriting ) {
756
+ return register (converter , new ConvertiblePair (source , target ), isReading , isWriting );
608
757
}
609
758
610
- private ConverterRegistration register (ConvertiblePair pair , boolean isReading , boolean isWriting ) {
611
- return new ConverterRegistration (pair , this , isReading , isWriting );
759
+ private ConverterRegistration register (Object converter , ConvertiblePair pair , boolean isReading ,
760
+ boolean isWriting ) {
761
+ return new ConverterRegistration (converter , pair , this , isReading , isWriting );
612
762
}
613
763
614
764
private boolean isStoreSimpleType (Class <?> type ) {
0 commit comments