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 {
 	}
 
 }