diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java b/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java index f6f7bd7acfd6..08274272386a 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java @@ -134,7 +134,7 @@ static Class[] completeProxiedInterfaces(AdvisedSupport advised, boolean deco if (targetClass.isInterface()) { advised.setInterfaces(targetClass); } - else if (Proxy.isProxyClass(targetClass) || isLambda(targetClass)) { + else if (Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) { advised.setInterfaces(targetClass.getInterfaces()); } specifiedInterfaces = advised.getProxiedInterfaces(); @@ -245,18 +245,4 @@ static Object[] adaptArgumentsIfNecessary(Method method, @Nullable Object[] argu return arguments; } - /** - * Determine if the supplied {@link Class} is a JVM-generated implementation - * class for a lambda expression or method reference. - *

This method makes a best-effort attempt at determining this, based on - * checks that work on modern, main stream JVMs. - * @param clazz the class to check - * @return {@code true} if the class is a lambda implementation class - * @since 5.3.16 - */ - static boolean isLambda(Class clazz) { - return (clazz.isSynthetic() && (clazz.getSuperclass() == Object.class) && - (clazz.getInterfaces().length > 0) && clazz.getName().contains("$$Lambda")); - } - } diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java b/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java index 5f1acad9a9a2..e63e17212322 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java @@ -21,6 +21,7 @@ import org.springframework.aop.SpringProxy; import org.springframework.core.NativeDetector; +import org.springframework.util.ClassUtils; /** * Default {@link AopProxyFactory} implementation, creating either a CGLIB proxy @@ -60,7 +61,7 @@ public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } - if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || AopProxyUtils.isLambda(targetClass)) { + if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); diff --git a/spring-aop/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java b/spring-aop/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java index 3dbf550a1211..2704cf1c7c2f 100644 --- a/spring-aop/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java @@ -19,7 +19,6 @@ import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.List; -import java.util.function.Supplier; import org.junit.jupiter.api.Test; @@ -134,61 +133,4 @@ public void testProxiedUserInterfacesWithNoInterface() { AopProxyUtils.proxiedUserInterfaces(proxy)); } - @Test - void isLambda() { - assertIsLambda(AopProxyUtilsTests.staticLambdaExpression); - assertIsLambda(AopProxyUtilsTests::staticStringFactory); - - assertIsLambda(this.instanceLambdaExpression); - assertIsLambda(this::instanceStringFactory); - } - - @Test - void isNotLambda() { - assertIsNotLambda(new EnigmaSupplier()); - - assertIsNotLambda(new Supplier() { - @Override - public String get() { - return "anonymous inner class"; - } - }); - - assertIsNotLambda(new Fake$$LambdaSupplier()); - } - - private static void assertIsLambda(Supplier supplier) { - assertThat(AopProxyUtils.isLambda(supplier.getClass())).isTrue(); - } - - private static void assertIsNotLambda(Supplier supplier) { - assertThat(AopProxyUtils.isLambda(supplier.getClass())).isFalse(); - } - - private static final Supplier staticLambdaExpression = () -> "static lambda expression"; - - private final Supplier instanceLambdaExpression = () -> "instance lambda expressions"; - - private static String staticStringFactory() { - return "static string factory"; - } - - private String instanceStringFactory() { - return "instance string factory"; - } - - private static class EnigmaSupplier implements Supplier { - @Override - public String get() { - return "enigma"; - } - } - - private static class Fake$$LambdaSupplier implements Supplier { - @Override - public String get() { - return "fake lambda"; - } - } - } diff --git a/spring-core/src/main/java/org/springframework/util/ClassUtils.java b/spring-core/src/main/java/org/springframework/util/ClassUtils.java index 0df6e0ece4c1..d5858c7399c7 100644 --- a/spring-core/src/main/java/org/springframework/util/ClassUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ClassUtils.java @@ -842,6 +842,20 @@ public static boolean isInnerClass(Class clazz) { return (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())); } + /** + * Determine if the supplied {@link Class} is a JVM-generated implementation + * class for a lambda expression or method reference. + *

This method makes a best-effort attempt at determining this, based on + * checks that work on modern, mainstream JVMs. + * @param clazz the class to check + * @return {@code true} if the class is a lambda implementation class + * @since 5.3.19 + */ + public static boolean isLambdaClass(Class clazz) { + return (clazz.isSynthetic() && (clazz.getSuperclass() == Object.class) && + (clazz.getInterfaces().length > 0) && clazz.getName().contains("$$Lambda")); + } + /** * Check whether the given object is a CGLIB proxy. * @param object the object to check diff --git a/spring-core/src/test/java/org/springframework/util/ClassUtilsTests.java b/spring-core/src/test/java/org/springframework/util/ClassUtilsTests.java index f14412ba4b18..640ec87eb5b4 100644 --- a/spring-core/src/test/java/org/springframework/util/ClassUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/util/ClassUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.function.Supplier; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; @@ -408,6 +409,29 @@ void isPrimitiveOrWrapperWithWrapper(Class type) { assertThat(ClassUtils.isPrimitiveOrWrapper(type)).isTrue(); } + @Test + void isLambda() { + assertIsLambda(ClassUtilsTests.staticLambdaExpression); + assertIsLambda(ClassUtilsTests::staticStringFactory); + + assertIsLambda(this.instanceLambdaExpression); + assertIsLambda(this::instanceStringFactory); + } + + @Test + void isNotLambda() { + assertIsNotLambda(new EnigmaSupplier()); + + assertIsNotLambda(new Supplier() { + @Override + public String get() { + return "anonymous inner class"; + } + }); + + assertIsNotLambda(new Fake$$LambdaSupplier()); + } + @Nested class GetStaticMethodTests { @@ -500,4 +524,38 @@ void print(String header, String[] messages, String footer) { } } + private static void assertIsLambda(Supplier supplier) { + assertThat(ClassUtils.isLambdaClass(supplier.getClass())).isTrue(); + } + + private static void assertIsNotLambda(Supplier supplier) { + assertThat(ClassUtils.isLambdaClass(supplier.getClass())).isFalse(); + } + + private static final Supplier staticLambdaExpression = () -> "static lambda expression"; + + private final Supplier instanceLambdaExpression = () -> "instance lambda expressions"; + + private static String staticStringFactory() { + return "static string factory"; + } + + private String instanceStringFactory() { + return "instance string factory"; + } + + private static class EnigmaSupplier implements Supplier { + @Override + public String get() { + return "enigma"; + } + } + + private static class Fake$$LambdaSupplier implements Supplier { + @Override + public String get() { + return "fake lambda"; + } + } + }