Skip to content

Commit 3d0d27c

Browse files
author
Mandy Chung
committed
8269351: Proxy::newProxyInstance and MethodHandleProxies::asInterfaceInstance should reject sealed interfaces
Reviewed-by: darcy, alanb
1 parent 824a516 commit 3d0d27c

4 files changed

Lines changed: 101 additions & 4 deletions

File tree

src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ private MethodHandleProxies() { } // do not instantiate
5959
* even though it re-declares the {@code Object.equals} method and also
6060
* declares default methods, such as {@code Comparator.reverse}.
6161
* <p>
62-
* The interface must be public. No additional access checks are performed.
62+
* The interface must be public and not {@linkplain Class#isSealed() sealed}.
63+
* No additional access checks are performed.
6364
* <p>
6465
* The resulting instance of the required type will respond to
6566
* invocation of the type's uniquely named method by calling
@@ -156,6 +157,8 @@ private MethodHandleProxies() { } // do not instantiate
156157
public static <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
157158
if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
158159
throw newIllegalArgumentException("not a public interface", intfc.getName());
160+
if (intfc.isSealed())
161+
throw newIllegalArgumentException("a sealed interface", intfc.getName());
159162
final MethodHandle mh;
160163
if (System.getSecurityManager() != null) {
161164
final Class<?> caller = Reflection.getCallerClass();

src/java.base/share/classes/java/lang/reflect/Proxy.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,10 @@ private static void validateProxyInterfaces(ClassLoader loader,
710710
throw new IllegalArgumentException(intf.getName() + " is a hidden interface");
711711
}
712712

713+
if (intf.isSealed()) {
714+
throw new IllegalArgumentException(intf.getName() + " is a sealed interface");
715+
}
716+
713717
/*
714718
* Verify that the class loader resolves the name of this
715719
* interface to the same Class object.
@@ -930,7 +934,8 @@ private static Module getDynamicModule(ClassLoader loader) {
930934
* if any of the following restrictions is violated:</a>
931935
* <ul>
932936
* <li>All of {@code Class} objects in the given {@code interfaces} array
933-
* must represent {@linkplain Class#isHidden() non-hidden} interfaces,
937+
* must represent {@linkplain Class#isHidden() non-hidden} and
938+
* {@linkplain Class#isSealed() non-sealed} interfaces,
934939
* not classes or primitive types.
935940
*
936941
* <li>No two elements in the {@code interfaces} array may

test/jdk/java/lang/invoke/MethodHandlesProxiesTest.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -22,7 +22,7 @@
2222
*/
2323

2424
/* @test
25-
* @bug 8206955
25+
* @bug 8206955 8269351
2626
* @run testng/othervm -ea -esa test.java.lang.invoke.MethodHandlesProxiesTest
2727
*/
2828

@@ -99,4 +99,24 @@ public static void testOverriddenDefaultMethods() throws Throwable {
9999
assertEquals(proxy.b(), "OB");
100100
assertEquals(proxy.c(), "OC");
101101
}
102+
103+
public sealed interface Intf permits NonSealedInterface {
104+
String m();
105+
}
106+
107+
public non-sealed interface NonSealedInterface extends Intf {
108+
}
109+
110+
@Test(expectedExceptions = { IllegalArgumentException.class })
111+
public void testSealedInterface() {
112+
MethodHandle target = MethodHandles.constant(String.class, "Sealed");
113+
MethodHandleProxies.asInterfaceInstance(Intf.class, target);
114+
}
115+
116+
@Test
117+
public void testNonSealedInterface() {
118+
MethodHandle target = MethodHandles.constant(String.class, "Non-Sealed");
119+
NonSealedInterface proxy = MethodHandleProxies.asInterfaceInstance(NonSealedInterface.class, target);
120+
assertEquals(proxy.m(), "Non-Sealed");
121+
}
102122
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8269351
27+
* @run testng SealedInterfaceTest
28+
*/
29+
30+
import java.lang.reflect.InvocationHandler;
31+
import java.lang.reflect.Method;
32+
import java.lang.reflect.Proxy;
33+
34+
import org.testng.annotations.Test;
35+
import static org.testng.Assert.*;
36+
37+
public class SealedInterfaceTest {
38+
sealed interface Intf permits NonSealedInterface {
39+
void m1();
40+
}
41+
42+
non-sealed interface NonSealedInterface extends Intf {
43+
void m2();
44+
}
45+
46+
@Test(expectedExceptions = { IllegalArgumentException.class })
47+
public void testSealedInterface() {
48+
Proxy.newProxyInstance(SealedInterfaceTest.class.getClassLoader(),
49+
new Class<?>[]{ Intf.class },
50+
new InvocationHandler() {
51+
@Override
52+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
53+
return null;
54+
}
55+
});
56+
}
57+
58+
@Test
59+
public void testNonSealedInterface() {
60+
Proxy.newProxyInstance(SealedInterfaceTest.class.getClassLoader(),
61+
new Class<?>[]{ NonSealedInterface.class },
62+
new InvocationHandler() {
63+
@Override
64+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
65+
return null;
66+
}
67+
});
68+
}
69+
}

0 commit comments

Comments
 (0)