Browse Source

Reject sealed interfaces in AopProxyUtils.completeJdkProxyInterfaces()

See gh-28745
pull/28788/head
Sam Brannen 2 years ago
parent
commit
7bfcb4c753
  1. 38
      spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java
  2. 25
      spring-aop/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java

38
spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java

@ -29,8 +29,6 @@ import org.springframework.aop.TargetClassAware; @@ -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 { @@ -101,12 +99,10 @@ public abstract class AopProxyUtils {
* proxy generated by Spring AOP.
* <p>Specifically, {@link SpringProxy}, {@link Advised}, and {@link DecoratingProxy}
* will be appended to the set of user-specified interfaces.
* <p>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.
* <p>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.
* <p>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.
* <pre class="code">
* RuntimeHints hints = ...
* hints.proxies().registerJdkProxy(completeJdkProxyInterfaces(MyInterface.class));
@ -114,21 +110,24 @@ public abstract class AopProxyUtils { @@ -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<Class<?>> 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 { @@ -141,9 +140,10 @@ public abstract class AopProxyUtils {
* proxy generated by Spring AOP.
* <p>Specifically, {@link SpringProxy}, {@link Advised}, and {@link DecoratingProxy}
* will be appended to the set of user-specified interfaces.
* <p>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.
* <p>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.
* <pre class="code">
* RuntimeHints hints = ...
* hints.proxies().registerJdkProxy(completeJdkProxyInterfaces("com.example.MyInterface"));
@ -156,8 +156,8 @@ public abstract class AopProxyUtils { @@ -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) {

25
spring-aop/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java

@ -109,11 +109,25 @@ class AopProxyUtilsTests { @@ -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 { @@ -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 { @@ -158,7 +165,7 @@ class AopProxyUtilsTests {
sealed interface SealedInterface {
}
static final class SealedType implements SealedInterface {
static final class SealedClass implements SealedInterface {
}
}

Loading…
Cancel
Save