29
29
import org .springframework .core .convert .support .DefaultConversionService ;
30
30
import org .springframework .core .convert .support .GenericConversionService ;
31
31
import org .springframework .data .convert .Jsr310Converters ;
32
+ import org .springframework .data .util .Lazy ;
32
33
import org .springframework .data .util .NullableWrapperConverters ;
33
34
import org .springframework .lang .Nullable ;
34
35
import org .springframework .util .Assert ;
37
38
38
39
/**
39
40
* A {@link ProjectionFactory} to create JDK proxies to back interfaces and handle method invocations on them. By
40
- * default accessor methods are supported. In case the delegating lookups result in an object of different type that the
41
- * projection interface method's return type, another projection will be created to transparently mitigate between the
42
- * types.
41
+ * default, accessor methods are supported. In case the delegating lookups result in an object of different type that
42
+ * the projection interface method's return type, another projection will be created to transparently mitigate between
43
+ * the types.
43
44
*
44
45
* @author Oliver Gierke
45
46
* @author Christoph Strobl
@@ -59,9 +60,12 @@ class ProxyProjectionFactory implements ProjectionFactory, BeanClassLoaderAware
59
60
}
60
61
61
62
private final List <MethodInterceptorFactory > factories ;
62
- private final Map <Class <?>, ProjectionInformation > projectionInformationCache = new ConcurrentReferenceHashMap <>();
63
+ private final Map <Class <?>, ProjectionMetadata > projectionInformationCache = new ConcurrentReferenceHashMap <>();
63
64
private @ Nullable ClassLoader classLoader ;
64
65
66
+ private final Lazy <DefaultMethodInvokingMethodInterceptor > defaultMethodInvokingMethodInterceptor = Lazy
67
+ .of (DefaultMethodInvokingMethodInterceptor ::new );
68
+
65
69
/**
66
70
* Creates a new {@link ProxyProjectionFactory}.
67
71
*/
@@ -116,7 +120,12 @@ public <T> T createProjection(Class<T> projectionType, Object source) {
116
120
factory .setOpaque (true );
117
121
factory .setInterfaces (projectionType , TargetAware .class );
118
122
119
- factory .addAdvice (new DefaultMethodInvokingMethodInterceptor ());
123
+ ProjectionMetadata projectionMetadata = getProjectionMetadata (projectionType );
124
+
125
+ if (projectionMetadata .hasDefaultMethods ) {
126
+ factory .addAdvice (defaultMethodInvokingMethodInterceptor .get ());
127
+ }
128
+
120
129
factory .addAdvice (new TargetAwareMethodInterceptor (source .getClass ()));
121
130
factory .addAdvice (getMethodInterceptor (source , projectionType ));
122
131
@@ -141,8 +150,12 @@ public <T> T createProjection(Class<T> projectionType) {
141
150
*/
142
151
@ Override
143
152
public final ProjectionInformation getProjectionInformation (Class <?> projectionType ) {
153
+ return getProjectionMetadata (projectionType ).projectionInformation ;
154
+ }
144
155
145
- return projectionInformationCache .computeIfAbsent (projectionType , this ::createProjectionInformation );
156
+ private ProjectionMetadata getProjectionMetadata (Class <?> projectionType ) {
157
+ return projectionInformationCache .computeIfAbsent (projectionType ,
158
+ it -> ProjectionMetadata .create (it , createProjectionInformation (it )));
146
159
}
147
160
148
161
/**
@@ -310,4 +323,27 @@ public boolean supports(Object source, Class<?> targetType) {
310
323
return true ;
311
324
}
312
325
}
326
+
327
+ /**
328
+ * Holder for {@link ProjectionInformation} and whether the target projection type uses {@code default} interface
329
+ * methods.
330
+ *
331
+ * @since 2.7.13
332
+ */
333
+ static class ProjectionMetadata {
334
+
335
+ final boolean hasDefaultMethods ;
336
+
337
+ final ProjectionInformation projectionInformation ;
338
+
339
+ ProjectionMetadata (boolean hasDefaultMethods , ProjectionInformation projectionInformation ) {
340
+ this .hasDefaultMethods = hasDefaultMethods ;
341
+ this .projectionInformation = projectionInformation ;
342
+ }
343
+
344
+ public static ProjectionMetadata create (Class <?> projectionType , ProjectionInformation projectionInformation ) {
345
+ return new ProjectionMetadata (DefaultMethodInvokingMethodInterceptor .hasDefaultMethods (projectionType ),
346
+ projectionInformation );
347
+ }
348
+ }
313
349
}
0 commit comments