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 d8971947f6..fb78503e20 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 @@ -29,8 +29,6 @@ import org.springframework.aop.TargetClassAware; import org.springframework.aop.TargetSource; import org.springframework.aop.support.AopUtils; import org.springframework.aop.target.SingletonTargetSource; -import org.springframework.aot.hint.ProxyHints; -import org.springframework.aot.hint.RuntimeHints; import org.springframework.core.DecoratingProxy; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -101,12 +99,10 @@ public abstract class AopProxyUtils { * proxy generated by Spring AOP. *
Specifically, {@link SpringProxy}, {@link Advised}, and {@link DecoratingProxy} * will be appended to the set of user-specified interfaces. - *
Any {@linkplain Class#isSealed() sealed} interface in the set of - * user-specified interfaces will be omitted from the results, since only - * non-sealed interfaces are eligible for JDK dynamic proxies. - *
This method can be useful when registering {@linkplain ProxyHints proxy - * hints} for Spring's AOT support, as demonstrated in the following example - * which uses this method via a {@code static} import. + *
This method can be useful when registering + * {@linkplain org.springframework.aot.hint.ProxyHints proxy hints} for Spring's + * AOT support, as demonstrated in the following example which uses this method + * via a {@code static} import. *
* RuntimeHints hints = ... * hints.proxies().registerJdkProxy(completeJdkProxyInterfaces(MyInterface.class)); @@ -114,21 +110,24 @@ public abstract class AopProxyUtils { * @param userInterfaces the set of user-specified interfaces implemented by * the component to be proxied * @return the complete set of interfaces that the proxy should implement + * @throws IllegalArgumentException if a supplied {@code Class} is {@code null}, + * is not an {@linkplain Class#isInterface() interface}, or is a + * {@linkplain Class#isSealed() sealed} interface * @since 6.0 * @see SpringProxy * @see Advised * @see DecoratingProxy - * @see RuntimeHints#proxies() - * @see ProxyHints#registerJdkProxy(Class...) + * @see org.springframework.aot.hint.RuntimeHints#proxies() + * @see org.springframework.aot.hint.ProxyHints#registerJdkProxy(Class...) * @see #completeJdkProxyInterfaces(String...) */ public static Class>[] completeJdkProxyInterfaces(Class>... userInterfaces) { List> completedInterfaces = new ArrayList<>(userInterfaces.length + 3); for (Class> ifc : userInterfaces) { - Assert.isTrue(ifc.isInterface(), () -> ifc.getName() + " must be an interface"); - if (!ifc.isSealed()) { - completedInterfaces.add(ifc); - } + Assert.notNull(ifc, "'userInterfaces' must not contain null values"); + Assert.isTrue(ifc.isInterface() && !ifc.isSealed(), + () -> ifc.getName() + " must be a non-sealed interface"); + completedInterfaces.add(ifc); } completedInterfaces.add(SpringProxy.class); completedInterfaces.add(Advised.class); @@ -141,9 +140,10 @@ public abstract class AopProxyUtils { * proxy generated by Spring AOP. * Specifically, {@link SpringProxy}, {@link Advised}, and {@link DecoratingProxy} * will be appended to the set of user-specified interfaces. - *
This method can be useful when registering {@linkplain ProxyHints proxy - * hints} for Spring's AOT support, as demonstrated in the following example - * which uses this method via a {@code static} import. + *
This method can be useful when registering + * {@linkplain org.springframework.aot.hint.ProxyHints proxy hints} for Spring's + * AOT support, as demonstrated in the following example which uses this method + * via a {@code static} import. *
* RuntimeHints hints = ... * hints.proxies().registerJdkProxy(completeJdkProxyInterfaces("com.example.MyInterface")); @@ -156,8 +156,8 @@ public abstract class AopProxyUtils { * @see SpringProxy * @see Advised * @see DecoratingProxy - * @see RuntimeHints#proxies() - * @see ProxyHints#registerJdkProxy(Class...) + * @see org.springframework.aot.hint.RuntimeHints#proxies() + * @see org.springframework.aot.hint.ProxyHints#registerJdkProxy(Class...) * @see #completeJdkProxyInterfaces(Class...) */ public static String[] completeJdkProxyInterfaces(String... userInterfaces) { 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 8fd095c653..adac73e879 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 @@ -109,11 +109,25 @@ class AopProxyUtilsTests { assertThatIllegalArgumentException().isThrownBy(() -> AopProxyUtils.proxiedUserInterfaces(proxy)); } + @Test + void completeJdkProxyInterfacesFromNullInterface() { + assertThatIllegalArgumentException() + .isThrownBy(() -> AopProxyUtils.completeJdkProxyInterfaces(ITestBean.class, null, Comparable.class)) + .withMessage("'userInterfaces' must not contain null values"); + } + @Test void completeJdkProxyInterfacesFromClassThatIsNotAnInterface() { assertThatIllegalArgumentException() .isThrownBy(() -> AopProxyUtils.completeJdkProxyInterfaces(TestBean.class)) - .withMessage(TestBean.class.getName() + " must be an interface"); + .withMessage(TestBean.class.getName() + " must be a non-sealed interface"); + } + + @Test + void completeJdkProxyInterfacesFromSealedInterface() { + assertThatIllegalArgumentException() + .isThrownBy(() -> AopProxyUtils.completeJdkProxyInterfaces(SealedInterface.class)) + .withMessage(SealedInterface.class.getName() + " must be a non-sealed interface"); } @Test @@ -130,13 +144,6 @@ class AopProxyUtilsTests { ITestBean.class, Comparable.class, SpringProxy.class, Advised.class, DecoratingProxy.class); } - @Test - void completeJdkProxyInterfacesIgnoresSealedInterfaces() { - Class>[] jdkProxyInterfaces = AopProxyUtils.completeJdkProxyInterfaces(SealedInterface.class, Comparable.class); - assertThat(jdkProxyInterfaces).containsExactly( - Comparable.class, SpringProxy.class, Advised.class, DecoratingProxy.class); - } - @Test void completeJdkProxyInterfacesFromSingleClassName() { String[] jdkProxyInterfaces = AopProxyUtils.completeJdkProxyInterfaces(ITestBean.class.getName()); @@ -158,7 +165,7 @@ class AopProxyUtilsTests { sealed interface SealedInterface { } - static final class SealedType implements SealedInterface { + static final class SealedClass implements SealedInterface { } }