2929import org .springframework .core .convert .support .DefaultConversionService ;
3030import org .springframework .core .convert .support .GenericConversionService ;
3131import org .springframework .data .convert .Jsr310Converters ;
32+ import org .springframework .data .util .Lazy ;
3233import org .springframework .data .util .NullableWrapperConverters ;
3334import org .springframework .lang .Nullable ;
3435import org .springframework .util .Assert ;
3738
3839/**
3940 * 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.
4344 *
4445 * @author Oliver Gierke
4546 * @author Christoph Strobl
@@ -59,9 +60,12 @@ class ProxyProjectionFactory implements ProjectionFactory, BeanClassLoaderAware
5960 }
6061
6162 private final List <MethodInterceptorFactory > factories ;
62- private final Map <Class <?>, ProjectionInformation > projectionInformationCache = new ConcurrentReferenceHashMap <>();
63+ private final Map <Class <?>, ProjectionMetadata > projectionInformationCache = new ConcurrentReferenceHashMap <>();
6364 private @ Nullable ClassLoader classLoader ;
6465
66+ private final Lazy <DefaultMethodInvokingMethodInterceptor > defaultMethodInvokingMethodInterceptor = Lazy
67+ .of (DefaultMethodInvokingMethodInterceptor ::new );
68+
6569 /**
6670 * Creates a new {@link ProxyProjectionFactory}.
6771 */
@@ -116,7 +120,12 @@ public <T> T createProjection(Class<T> projectionType, Object source) {
116120 factory .setOpaque (true );
117121 factory .setInterfaces (projectionType , TargetAware .class );
118122
119- factory .addAdvice (new DefaultMethodInvokingMethodInterceptor ());
123+ ProjectionMetadata projectionMetadata = getProjectionMetadata (projectionType );
124+
125+ if (projectionMetadata .hasDefaultMethods ) {
126+ factory .addAdvice (defaultMethodInvokingMethodInterceptor .get ());
127+ }
128+
120129 factory .addAdvice (new TargetAwareMethodInterceptor (source .getClass ()));
121130 factory .addAdvice (getMethodInterceptor (source , projectionType ));
122131
@@ -141,8 +150,12 @@ public <T> T createProjection(Class<T> projectionType) {
141150 */
142151 @ Override
143152 public final ProjectionInformation getProjectionInformation (Class <?> projectionType ) {
153+ return getProjectionMetadata (projectionType ).projectionInformation ;
154+ }
144155
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 )));
146159 }
147160
148161 /**
@@ -310,4 +323,27 @@ public boolean supports(Object source, Class<?> targetType) {
310323 return true ;
311324 }
312325 }
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+ }
313349}
0 commit comments