undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,179 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 4227192 4487672
* @summary This is a basic functional test of the dynamic proxy API (part 1).
* @author Peter Jones
*
* @build Basic1
* @run main Basic1
*/
import java.lang.reflect.*;
import java.security.*;
import java.util.*;
public class Basic1 {
public static void main(String[] args) {
System.err.println(
"\nBasic functional test of dynamic proxy API, part 1\n");
try {
Class<?>[] interfaces =
new Class<?>[] { Runnable.class, Observer.class };
ClassLoader loader = ClassLoader.getSystemClassLoader();
/*
* Generate a proxy class.
*/
Class<?> proxyClass = Proxy.getProxyClass(loader, interfaces);
System.err.println("+ generated proxy class: " + proxyClass);
/*
* Verify that it is public, final, and not abstract.
*/
int flags = proxyClass.getModifiers();
System.err.println(
"+ proxy class's modifiers: " + Modifier.toString(flags));
if (!Modifier.isPublic(flags)) {
throw new RuntimeException("proxy class in not public");
}
if (!Modifier.isFinal(flags)) {
throw new RuntimeException("proxy class in not final");
}
if (Modifier.isAbstract(flags)) {
throw new RuntimeException("proxy class in abstract");
}
/*
* Verify that it is assignable to the proxy interfaces.
*/
for (Class<?> intf : interfaces) {
if (!intf.isAssignableFrom(proxyClass)) {
throw new RuntimeException(
"proxy class not assignable to proxy interface " +
intf.getName());
}
}
/*
* Verify that it has the given permutation of interfaces.
*/
List<Class<?>> l1 = Arrays.asList(interfaces);
List<Class<?>> l2 = Arrays.asList(proxyClass.getInterfaces());
System.err.println("+ proxy class's interfaces: " + l2);
if (!l1.equals(l2)) {
throw new RuntimeException(
"proxy class interfaces are " + l2 +
" (expected " + l1 + ")");
}
/*
* Verify that system agress that it is a proxy class.
*/
if (Proxy.isProxyClass(Object.class)) {
throw new RuntimeException(
"Proxy.isProxyClass returned true for java.lang.Object");
}
if (!Proxy.isProxyClass(proxyClass)) {
throw new RuntimeException(
"Proxy.isProxyClass returned false for proxy class");
}
/*
* Verify that its protection domain is the bootstrap domain.
*/
ProtectionDomain pd = proxyClass.getProtectionDomain();
System.err.println("+ proxy class's protection domain: " + pd);
if (!pd.implies(new AllPermission())) {
throw new RuntimeException(
"proxy class does not have AllPermission");
}
/*
* Verify that it has a constructor that takes an
* InvocationHandler instance.
*/
Constructor<?> cons = proxyClass.getConstructor(InvocationHandler.class);
/*
* Test constructor with null InvocationHandler
*/
try {
cons.newInstance(new Object[] { null });
throw new RuntimeException("Expected NullPointerException thrown");
} catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
if (!(t instanceof NullPointerException)) {
throw t;
}
}
/*
* Construct a proxy instance.
*/
Handler handler = new Handler();
Object proxy = cons.newInstance(handler);
handler.currentProxy = proxy;
/*
* Invoke a method on a proxy instance.
*/
Method m = Runnable.class.getMethod("run");
((Runnable) proxy).run();
if (!handler.lastMethod.equals(m)) {
throw new RuntimeException(
"proxy method invocation failure (lastMethod = " +
handler.lastMethod + ")");
}
System.err.println("\nTEST PASSED");
} catch (Throwable e) {
System.err.println("\nTEST FAILED:");
e.printStackTrace();
throw new RuntimeException("TEST FAILED: " + e.toString());
}
}
public static class Handler implements InvocationHandler {
Object currentProxy;
Method lastMethod;
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
if (proxy != currentProxy) {
throw new RuntimeException(
"wrong proxy instance passed to invoke method");
}
lastMethod = method;
return null;
}
}
}

View file

@ -0,0 +1,156 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 4889342
* @summary This test verifies that when a primitive boolean value is
* passed by a dynamic proxy class to an invocation handler, it is
* boxed as one of the canonical Boolean instances (Boolean.TRUE or
* Boolean.FALSE). This test also exercises a dynamic proxy class's
* boxing of all primitive types.
* @author Peter Jones
*
* @run main Boxing
*/
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Random;
public class Boxing {
private interface Test {
void m(byte b,
char c,
double d,
float f,
int i,
long j,
short s,
boolean z);
}
private static final int REPS = 100000;
private byte b;
private char c;
private double d;
private float f;
private int i;
private long j;
private short s;
private boolean z;
public static void main(String[] args) {
(new Boxing()).run();
System.err.println("TEST PASSED");
}
private void run() {
Random random = new Random(42); // ensure consistent test domain
Test proxy = (Test) Proxy.newProxyInstance(
Test.class.getClassLoader(),
new Class<?>[] { Test.class },
new TestHandler());
for (int rep = 0; rep < REPS; rep++) {
b = (byte) random.nextInt();
c = (char) random.nextInt();
d = random.nextDouble();
f = random.nextFloat();
i = random.nextInt();
j = random.nextLong();
s = (short) random.nextInt();
z = random.nextBoolean();
proxy.m(b,c,d,f,i,j,s,z);
}
}
private class TestHandler implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
if (!method.getName().equals("m")) {
throw new AssertionError();
}
byte b2 = ((Byte) args[0]).byteValue();
if (b2 != b) {
throw new RuntimeException("TEST FAILED: " +
"wrong byte, expected " + b + " but got " + b2);
}
char c2 = ((Character) args[1]).charValue();
if (c2 != c) {
throw new RuntimeException("TEST FAILED: " +
"wrong char, expected " + c + " but got " + c2);
}
double d2 = ((Double) args[2]).doubleValue();
if (d2 != d) {
throw new RuntimeException("TEST FAILED: " +
"wrong double, expected " + d + " but got " + d2);
}
float f2 = ((Float) args[3]).floatValue();
if (f2 != f) {
throw new RuntimeException("TEST FAILED: " +
"wrong float, expected " + f + " but got " + f2);
}
int i2 = ((Integer) args[4]).intValue();
if (i2 != i) {
throw new RuntimeException("TEST FAILED: " +
"wrong int, expected " + i + " but got " + i2);
}
long j2 = ((Long) args[5]).longValue();
if (j2 != j) {
throw new RuntimeException("TEST FAILED: " +
"wrong long, expected " + j + " but got " + j2);
}
short s2 = ((Short) args[6]).shortValue();
if (s2 != s) {
throw new RuntimeException("TEST FAILED: " +
"wrong short, expected " + s + " but got " + s2);
}
Boolean Z = Boolean.valueOf(z);
Boolean Z2 = (Boolean) args[7];
if (Z2 != Z) {
throw new RuntimeException("TEST FAILED: " +
"wrong Boolean instance, expected " +
identityToString(Z) + " but got " + identityToString(Z2));
}
return null;
}
}
private static String identityToString(Object obj) {
return obj.toString() + "@" + System.identityHashCode(obj);
}
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/*
* @test
* @bug 8370839
* @summary Behavior of bridge methods in interfaces
* @run junit BridgeMethodsTest
*/
public class BridgeMethodsTest {
interface StringCallable extends Callable<String> {
@Override
String call(); // throws no exception
}
@Test
void testExceptionTypes() throws Throwable {
class MyException extends Exception {}
// This proxy has two distinct methods, even though the
// Java language would treat the first one as overridden:
// Object call() throws Exception; - from Callable
// String call(); - from StringCallable
var instance = Proxy.newProxyInstance(StringCallable.class.getClassLoader(),
new Class[] { StringCallable.class }, (_, _, _) -> { throw new MyException(); });
// The exception can't be thrown through StringCallable.call which has no throws
var undeclared = assertThrows(UndeclaredThrowableException.class, () -> ((StringCallable) instance).call());
assertInstanceOf(MyException.class, undeclared.getCause());
// But it can be thrown through Callable.call which permits Exception
assertThrows(MyException.class, () -> ((Callable<?>) instance).call());
}
interface SpecificConsumer extends Consumer<String> {
@Override
void accept(String s);
}
@Test
@SuppressWarnings("unchecked")
void testMethodObjects() throws Throwable {
List<Method> methods = new ArrayList<>();
// This proxy has two distinct methods, even though the
// Java language would treat the first one as overridden:
// void accept(Object); - from Consumer
// void accept(String); - from SpecificConsumer
var instance = Proxy.newProxyInstance(SpecificConsumer.class.getClassLoader(),
new Class[] { SpecificConsumer.class }, (_, m, _) -> methods.add(m));
((Consumer<Object>) instance).accept(null);
((SpecificConsumer) instance).accept(null);
assertEquals(2, methods.size());
// invocation handler gets different method due to covariant parameter types
assertNotEquals(methods.getFirst(), methods.getLast());
}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4346224
* @summary Test against a typo in ProxyGenerator:
* "java/lang/Character" should be used instead of
* "java/lang/Char".
*/
import java.lang.reflect.*;
public class CharType {
public static void main (String args[]) throws Exception {
Proxy.newProxyInstance(CharMethod.class.getClassLoader(), new Class[] {
CharMethod.class }, new H());
}
static interface CharMethod {
void setChar(char c);
}
static class H implements InvocationHandler {
public Object invoke(Object o, Method m, Object[] arr) {
return null;
}
}
}

View file

@ -0,0 +1,123 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 4227192 8004928 8072656 8319436
* @summary This is a test of the restrictions on the parameters that may
* be passed to the Proxy.getProxyClass method.
* @author Peter Jones
*
* @build ClassRestrictions
* @run junit ClassRestrictions
*/
import java.io.File;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.net.URLClassLoader;
import java.net.URL;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.*;
public class ClassRestrictions {
public interface Bar {
int foo();
}
public interface Baz {
long foo();
}
interface Bashful {
void foo();
}
private static final String TEST_CLASSES = System.getProperty("test.classes", ".");
private static final ClassLoader LOADER = ClassRestrictions.class.getClassLoader();
static Stream<List<Class<?>>> badProxyInterfaces() {
return Stream.of(
List.of(Object.class), // proxy interface cannot be a class
List.of(int.class), // proxy interface can't be primitive type
List.of(Bar.class, Bar.class), // cannot have repeated interfaces
// two proxy interfaces have the method of same method name but different return type
List.of(Bar.class, Baz.class)
);
}
/*
* Test cases for illegal proxy interfaces
*/
@ParameterizedTest
@MethodSource("badProxyInterfaces")
void testForName(List<Class<?>> interfaces) {
assertThrows(IllegalArgumentException.class, () -> Proxy.getProxyClass(LOADER, interfaces.toArray(Class[]::new)));
}
private static final String nonPublicIntrfaceName = "java.util.zip.ZipConstants";
/*
* All non-public interfaces must be in the same package.
*/
@Test
void testNonPublicIntfs() throws Exception {
var nonPublic1 = Bashful.class;
var nonPublic2 = Class.forName(nonPublicIntrfaceName);
assertFalse(Modifier.isPublic(nonPublic2.getModifiers()),
"Interface " + nonPublicIntrfaceName + " is public and need to be changed!");
var interfaces = new Class<?>[] { nonPublic1, nonPublic2 };
assertThrows(IllegalArgumentException.class, () -> Proxy.getProxyClass(LOADER, interfaces));
}
static Stream<ClassLoader> loaders() {
return Stream.of(null,
ClassLoader.getPlatformClassLoader(),
ClassLoader.getSystemClassLoader(),
LOADER);
}
/*
* All of the interfaces types must be visible by name though the
* specified class loader.
*/
@ParameterizedTest
@MethodSource("loaders")
void testNonVisibleInterface(ClassLoader loader) throws Exception {
String[] cpaths = TEST_CLASSES.split(File.pathSeparator);
URL[] urls = new URL[cpaths.length];
for (int i = 0; i < cpaths.length; i++) {
urls[i] = Paths.get(cpaths[i]).toUri().toURL();
}
var altLoader = new URLClassLoader(urls, null);
var altBarClass = Class.forName(Bar.class.getName(), false, altLoader);
var interfaces = new Class<?>[]{ altBarClass };
assertThrows(IllegalArgumentException.class, () -> Proxy.getProxyClass(loader, interfaces));
}
}

View file

@ -0,0 +1,371 @@
/*
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
/*
* @test
* @bug 8159746
* @run junit DefaultMethods
* @summary Basic tests for Proxy::invokeSuper default method
*/
public class DefaultMethods {
public interface I1 {
default int m() {
return 10;
}
}
public interface I2 {
default int m() {
return 20;
}
private void privateMethod() {
throw new Error("should not reach here");
}
}
// I3::m inherits from I2:m
public interface I3 extends I2 {
default int m3(String... s) {
return Arrays.stream(s).mapToInt(String::length).sum();
}
}
public interface I4 extends I1, I2 {
default int m() {
return 40;
}
default int mix(int a, String b) {
return 0;
}
}
public interface I12 extends I1, I2 {
@Override
int m();
default int sum(int a, int b) {
return a + b;
}
default Object[] concat(Object first, Object... rest) {
Object[] result = new Object[1 + rest.length];
result[0] = first;
System.arraycopy(rest, 0, result, 1, rest.length);
return result;
}
}
public interface IX {
default void doThrow(Throwable exception) throws Throwable {
throw exception;
}
}
private static Method findDefaultMethod(Class<?> refc, Method m) {
assertTrue(refc.isInterface());
Method method = assertDoesNotThrow(() -> refc.getMethod(m.getName(), m.getParameterTypes()));
assertTrue(method.isDefault());
return method;
}
@Test
public void test() {
ClassLoader loader = DefaultMethods.class.getClassLoader();
Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { I1.class, I2.class},
(o, method, params) -> {
return InvocationHandler.invokeDefault(o, findDefaultMethod(I2.class, method), params);
});
I1 i1 = (I1) proxy;
assertEquals(20, i1.m());
}
// a default method is declared in one of the proxy interfaces
private static Object[][] defaultMethods() {
return new Object[][]{
new Object[]{new Class<?>[]{I1.class, I2.class}, true, 10},
new Object[]{new Class<?>[]{I1.class, I3.class}, true, 10},
new Object[]{new Class<?>[]{I1.class, I12.class}, true, 10},
new Object[]{new Class<?>[]{I2.class, I12.class}, true, 20},
new Object[]{new Class<?>[]{I4.class}, true, 40},
new Object[]{new Class<?>[]{I4.class, I3.class}, true, 40},
new Object[]{new Class<?>[]{I12.class}, false, -1},
new Object[]{new Class<?>[]{I12.class, I1.class, I2.class}, false, -1}
};
}
@ParameterizedTest
@MethodSource("defaultMethods")
public void testDefaultMethod(Class<?>[] intfs, boolean isDefault, int expected) throws Throwable {
InvocationHandler ih = (proxy, method, params) -> {
System.out.format("invoking %s with parameters: %s%n", method, Arrays.toString(params));
switch (method.getName()) {
case "m":
assertEquals(isDefault, method.isDefault());
assertTrue(Arrays.stream(proxy.getClass().getInterfaces())
.anyMatch(intf -> method.getDeclaringClass() == intf),
Arrays.toString(proxy.getClass().getInterfaces()));
if (method.isDefault()) {
return InvocationHandler.invokeDefault(proxy, method, params);
} else {
return -1;
}
default:
throw new UnsupportedOperationException(method.toString());
}
};
Object proxy = Proxy.newProxyInstance(DefaultMethods.class.getClassLoader(), intfs, ih);
Method m = proxy.getClass().getMethod("m");
int result = (int)m.invoke(proxy);
assertEquals(expected, result);
}
// a default method may be declared in a proxy interface or
// inherited from a superinterface of a proxy interface
private static Object[][] supers() {
return new Object[][]{
// invoke "m" implemented in the first proxy interface
// same as the method passed to InvocationHandler::invoke
new Object[]{new Class<?>[]{I1.class}, I1.class, 10},
new Object[]{new Class<?>[]{I2.class}, I2.class, 20},
new Object[]{new Class<?>[]{I1.class, I2.class}, I1.class, 10},
// "m" is implemented in I2, an indirect superinterface of I3
new Object[]{new Class<?>[]{I3.class}, I3.class, 20},
// "m" is implemented in I1, I2 and overridden in I4
new Object[]{new Class<?>[]{I4.class}, I4.class, 40},
// invoke "m" implemented in the second proxy interface
// different from the method passed to InvocationHandler::invoke
new Object[]{new Class<?>[]{I1.class, I2.class}, I2.class, 20},
new Object[]{new Class<?>[]{I1.class, I3.class}, I3.class, 20},
// I2::m is implemented in more than one proxy interface directly or indirectly
// I3::m resolves to I2::m (indirect superinterface)
// I2 is the superinterface of I4 and I4 overrides m
// the proxy class can invoke I4::m and I2::m
new Object[]{new Class<?>[]{I3.class, I4.class}, I3.class, 20},
new Object[]{new Class<?>[]{I3.class, I4.class}, I4.class, 40},
new Object[]{new Class<?>[]{I4.class, I3.class}, I3.class, 20},
new Object[]{new Class<?>[]{I4.class, I3.class}, I4.class, 40}
};
}
@ParameterizedTest
@MethodSource("supers")
public void testSuper(Class<?>[] intfs, Class<?> proxyInterface, int expected) throws Throwable {
final InvocationHandler ih = (proxy, method, params) -> {
switch (method.getName()) {
case "m":
assertTrue(method.isDefault());
return InvocationHandler.invokeDefault(proxy, findDefaultMethod(proxyInterface, method), params);
default:
throw new UnsupportedOperationException(method.toString());
}
};
ClassLoader loader = proxyInterface.getClassLoader();
Object proxy = Proxy.newProxyInstance(loader, intfs, ih);
if (proxyInterface == I1.class) {
I1 i1 = (I1) proxy;
assertEquals(expected, i1.m());
} else if (proxyInterface == I2.class) {
I2 i2 = (I2) proxy;
assertEquals(expected, i2.m());
} else if (proxyInterface == I3.class) {
I3 i3 = (I3) proxy;
assertEquals(expected, i3.m());
} else if (proxyInterface == I4.class) {
I4 i4 = (I4) proxy;
assertEquals(expected, i4.m());
} else {
throw new UnsupportedOperationException(proxyInterface.toString());
}
// invoke via InvocationHandler.invokeDefaultMethod directly
assertEquals(expected, InvocationHandler.invokeDefault(proxy, proxyInterface.getMethod("m")));
}
// invoke I12 default methods with parameters and var args
@Test
public void testI12() throws Throwable {
final InvocationHandler ih = (proxy, method, params) -> {
System.out.format("invoking %s with parameters: %s%n", method, Arrays.toString(params));
switch (method.getName()) {
case "sum":
case "concat":
assertTrue(method.isDefault());
return InvocationHandler.invokeDefault(proxy, method, params);
default:
throw new UnsupportedOperationException(method.toString());
}
};
ClassLoader loader = DefaultMethods.class.getClassLoader();
I12 i12 = (I12) Proxy.newProxyInstance(loader, new Class<?>[] { I12.class }, ih);
assertEquals(3, i12.sum(1, 2));
assertArrayEquals(new Object[]{1, 2, 3, 4}, i12.concat(1, 2, 3, 4));
Method m = I12.class.getMethod("concat", Object.class, Object[].class);
assertTrue(m.isDefault());
assertArrayEquals(new Object[] {100, "foo", true, "bar"}, (Object[])
InvocationHandler.invokeDefault(i12, m, 100, new Object[] {"foo", true, "bar"}));
}
// test a no-arg default method with and without arguments passed in the invocation
@Test
public void testEmptyArgument() throws Throwable {
ClassLoader loader = DefaultMethods.class.getClassLoader();
Object proxy = Proxy.newProxyInstance(loader, new Class<?>[]{I4.class}, HANDLER);
Method m1 = I4.class.getMethod("m");
assertSame(I4.class, m1.getDeclaringClass());
assertTrue(m1.isDefault());
InvocationHandler.invokeDefault(proxy, m1);
InvocationHandler.invokeDefault(proxy, m1, new Object[0]);
Method m2 = I4.class.getMethod("mix", int.class, String.class);
assertSame(I4.class, m1.getDeclaringClass());
assertTrue(m1.isDefault());
InvocationHandler.invokeDefault(proxy, m2, Integer.valueOf(100), "foo");
}
@Test
public void testVarArgs() throws Throwable {
ClassLoader loader = DefaultMethods.class.getClassLoader();
I3 proxy = (I3)Proxy.newProxyInstance(loader, new Class<?>[]{I3.class}, HANDLER);
Method m = I3.class.getMethod("m3", String[].class);
assertTrue(m.isVarArgs() && m.isDefault());
assertEquals(5, proxy.m3("a", "b", "cde"));
assertEquals(3, InvocationHandler.invokeDefault(proxy, m, (Object)new String[] { "a", "bc" }));
}
/*
* Invoke I12::m which is an abstract method
*/
@Test
public void invokeAbstractMethod() throws Exception {
ClassLoader loader = DefaultMethods.class.getClassLoader();
I12 proxy = (I12) Proxy.newProxyInstance(loader, new Class<?>[]{I12.class}, HANDLER);
Method method = I12.class.getMethod("m");
assertSame(I12.class, method.getDeclaringClass());
assertFalse(method.isDefault());
assertThrows(IllegalArgumentException.class, () -> proxy.m());
}
/*
* Invoke a non proxy (default) method with parameters
*/
@Test
public void invokeNonProxyMethod() throws Throwable {
ClassLoader loader = DefaultMethods.class.getClassLoader();
I3 proxy = (I3) Proxy.newProxyInstance(loader, new Class<?>[]{I3.class}, HANDLER);
Method m = I4.class.getMethod("mix", int.class, String.class);
assertTrue(m.isDefault());
assertThrows(IllegalArgumentException.class, () -> InvocationHandler.invokeDefault(proxy, m));
}
// negative cases
private static Object[][] negativeCases() {
return new Object[][]{
// I4::m overrides I1::m and I2::m
new Object[] { new Class<?>[]{I4.class}, I1.class, "m" },
new Object[] { new Class<?>[]{I4.class}, I2.class, "m" },
// I12::m is not a default method
new Object[] { new Class<?>[]{I12.class}, I12.class, "m" },
// non-proxy default method
new Object[] { new Class<?>[]{I3.class}, I1.class, "m" },
// not a default method and not a proxy interface
new Object[] { new Class<?>[]{I12.class}, DefaultMethods.class, "test" },
new Object[] { new Class<?>[]{I12.class}, Runnable.class, "run" },
// I2::privateMethod is a private method
new Object[] { new Class<?>[]{I3.class}, I2.class, "privateMethod" }
};
}
@ParameterizedTest
@MethodSource("negativeCases")
public void testNegativeCase(Class<?>[] interfaces, Class<?> defc, String name)
throws Throwable {
ClassLoader loader = DefaultMethods.class.getClassLoader();
Object proxy = Proxy.newProxyInstance(loader, interfaces, HANDLER);
Method method = defc.getDeclaredMethod(name);
assertThrows(IllegalArgumentException.class, () ->
InvocationHandler.invokeDefault(proxy, method));
}
private static Object[] illegalArguments() {
return new Object[] {
new Object[] { null },
new Object[] { new Object[] { 100 }},
new Object[] { new Object[] { 100, "foo", 100 }},
new Object[] { new Object[] { 100L, "foo" }},
new Object[] { new Object[] { "foo", 100 }},
new Object[] { new Object[] { null, "foo" }}
};
}
@ParameterizedTest
@MethodSource("illegalArguments")
public void testIllegalArgument(Object[] args) throws Throwable {
ClassLoader loader = DefaultMethods.class.getClassLoader();
I4 proxy = (I4)Proxy.newProxyInstance(loader, new Class<?>[]{I4.class}, HANDLER);
Method m = I4.class.getMethod("mix", int.class, String.class);
assertTrue(m.isDefault());
assertThrows(IllegalArgumentException.class, () ->
InvocationHandler.invokeDefault(proxy, m, args));
}
private static Object[][] throwables() {
return new Object[][] {
new Object[] { new IOException() },
new Object[] { new IllegalArgumentException() },
new Object[] { new ClassCastException() },
new Object[] { new NullPointerException() },
new Object[] { new AssertionError() },
new Object[] { new Throwable() }
};
}
@ParameterizedTest
@MethodSource("throwables")
public void testInvocationException(Throwable exception) throws Throwable {
ClassLoader loader = DefaultMethods.class.getClassLoader();
IX proxy = (IX)Proxy.newProxyInstance(loader, new Class<?>[]{IX.class}, HANDLER);
Method m = IX.class.getMethod("doThrow", Throwable.class);
assertSame(exception, assertThrows(Throwable.class, () ->
InvocationHandler.invokeDefault(proxy, m, exception)));
}
private static final InvocationHandler HANDLER = (proxy, method, params) -> {
System.out.format("invoking %s with parameters: %s%n", method, Arrays.toString(params));
return InvocationHandler.invokeDefault(proxy, method, params);
};
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8250219
* @run junit HiddenProxyInterface
*/
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
public class HiddenProxyInterface {
private static final Path CLASSES_DIR = Paths.get(System.getProperty("test.classes"));
interface Intf {
void m();
}
@Test
public void testHiddenInterface() throws Exception {
Path classFile = CLASSES_DIR.resolve("HiddenProxyInterface$Intf.class");
byte[] bytes = Files.readAllBytes(classFile);
Class<?> hiddenIntf = MethodHandles.lookup().defineHiddenClass(bytes, false).lookupClass();
assertThrows(IllegalArgumentException.class, () -> Proxy.newProxyInstance(
HiddenProxyInterface.class.getClassLoader(),
new Class<?>[]{ hiddenIntf },
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}));
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.reflect.Proxy;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/*
* @test
* @bug 8285401
* @summary Avoid initialization of parameter types in proxy construction
* @run junit LazyInitializationTest
*/
public final class LazyInitializationTest {
private static volatile boolean initialized = false;
interface Intf {
void m(Parameter parameter);
}
static class Parameter {
static {
initialized = true;
}
}
@Test
public void testLazyInitialization() {
Intf value = (Intf) Proxy.newProxyInstance(LazyInitializationTest.class.getClassLoader(),
new Class<?>[]{ Intf.class },
(proxy, method, args) -> null);
assertFalse(initialized, "parameter type initialized unnecessarily");
value.m(new Parameter());
assertTrue(initialized, "parameter type initialized after instantiation");
}
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.reflect.Proxy;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/*
* @test
* @bug 8333854 8370839
* @summary Behavior of methods whose signature has package-private
* class or interfaces but the proxy interface is public
* @run junit NonPublicMethodTypeTest
*/
public class NonPublicMethodTypeTest {
// Java language and JVM allow using fields and methods with inaccessible
// classes or interfaces in its signature, as long as the field or method
// is accessible and its declaring class or interface is accessible.
// Such inaccessible classes and interfaces are treated as if an arbitrary
// subtype of their accessible types, or an arbitrary supertype of their
// accessible subtypes.
// java.lang.invoke is stricter - MethodType constant pool entry resolution
// for such signatures fail, so they can't be used for MethodHandle or indy.
enum Internal { INSTANCE }
public interface InternalParameter {
void call(Internal parameter);
}
@Test
void testNonPublicParameter() throws Throwable {
// Creation should be successful
// 8333854 - BSM usage fails for looking up such methods
InternalParameter instance = (InternalParameter) Proxy.newProxyInstance(
InternalParameter.class.getClassLoader(),
new Class[] { InternalParameter.class },
(_, _, _) -> null);
assertNotSame(Internal.class.getPackage(),
instance.getClass().getPackage(),
"Proxy class should not be able to access method parameter " +
"Internal class's package");
// Calls should be always successful
instance.call(null);
instance.call(Internal.INSTANCE);
}
public interface InternalReturn {
Internal call();
}
@Test
void testNonPublicReturn() throws Throwable {
AtomicReference<Internal> returnValue = new AtomicReference<>();
// Creation should be successful
// A lot of annotation interfaces are implemented by such proxy classes,
// due to presence of package-private annotation interface or enum-typed
// elements in public annotation interfaces.
InternalReturn instance = (InternalReturn) Proxy.newProxyInstance(
InternalReturn.class.getClassLoader(),
new Class[] { InternalReturn.class },
(_, _, _) -> returnValue.get());
assertNotSame(Internal.class.getPackage(),
instance.getClass().getPackage(),
"Proxy class should not be able to access method parameter " +
"Internal class's package");
// The generated call() implementation is as follows:
// aload0, getfield Proxy.h, aload 0, getstatic (Method), aconst_null,
// invokevirtual InvocationHandler::invoke(Object, Method, Object[])Object,
// checkcast Internal.class, areturn
// In this bytecode, checkcast Internal.class will fail with a
// IllegalAccessError as a result of resolution of Internal.class
// if and only if the incoming reference is non-null.
// checkcast does not perform access check for null
returnValue.set(null);
instance.call();
// checkcast fails - proxy class cannot access the return type
// See JDK-8349716
returnValue.set(Internal.INSTANCE);
assertThrows(IllegalAccessError.class, instance::call);
}
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 4227192
* @summary This test verifies that a proxy class can be created with
* (and defined in) the null class loader.
* @author Peter Jones
*
* @build NullClassLoader
* @run main NullClassLoader
*/
import java.lang.reflect.*;
import java.util.Observer;
public class NullClassLoader {
public static void main(String[] args) {
System.err.println(
"\nTest creating proxy class with the null class loader.\n");
try {
ClassLoader ld = null;
Class p = Proxy.getProxyClass(ld, new Class[] { Runnable.class, Observer.class });
System.err.println("proxy class: " + p);
ClassLoader loader = p.getClassLoader();
System.err.println("proxy class's class loader: " + loader);
if (loader != null) {
throw new RuntimeException(
"proxy class not defined in the null class loader");
}
System.err.println("\nTEST PASSED");
} catch (Throwable e) {
System.err.println("\nTEST FAILED:");
e.printStackTrace();
throw new RuntimeException("TEST FAILED: " + e.toString());
}
}
}

View file

@ -0,0 +1,190 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Proxy;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/*
* @test
* @bug 8370839
* @summary Behavior of protected methods in java.lang.Object
* @modules java.base/java.lang:+open
* @run junit ProtectedObjectMethodsTest
*/
public class ProtectedObjectMethodsTest {
static final MethodHandle OBJECT_CLONE;
static final MethodHandle OBJECT_FINALIZE;
static {
try {
var lookup = MethodHandles.privateLookupIn(Object.class, MethodHandles.lookup());
OBJECT_CLONE = lookup.findVirtual(Object.class, "clone", MethodType.methodType(Object.class));
OBJECT_FINALIZE = lookup.findVirtual(Object.class, "finalize", MethodType.methodType(void.class));
} catch (ReflectiveOperationException ex) {
throw new ExceptionInInitializerError(ex);
}
}
interface FakeClone {
// This method is not related to Object::clone in the JVM, but most
// implementations in the Java Language override Object::clone as
// covariant overrides
FakeClone clone();
}
interface TrueClone {
// This method is identical to Object::clone in the JVM, that calls
// to Object::clone can always call an implementation of this method
// if it exists
Object clone();
}
interface PrimitiveClone {
// This method is not related to Object::clone in the JVM, but it can't
// be implemented in the Java Language unless using a lambda expression,
// due to the Java language covariant override restrictions.
int clone();
}
// Does not duplicate with Object::clone so it is not proxied
@Test
void testDistinctClone() throws Throwable {
{
// This proxy declares FakeClone clone(); which cannot be
// invoked through Object::clone.
var fake = (FakeClone) Proxy.newProxyInstance(FakeClone.class.getClassLoader(), new Class[] { FakeClone.class }, (p, _, _) -> p);
assertSame(fake, fake.clone());
// Verify the default Object::clone behavior (this is not Cloneable)
assertThrows(CloneNotSupportedException.class, () -> {
var _ = (Object) OBJECT_CLONE.invoke((Object) fake);
});
}
{
// This proxy declares FakeClone clone(); which cannot be
// invoked through Object::clone.
var fake = (FakeClone) Proxy.newProxyInstance(FakeClone.class.getClassLoader(), new Class[] { FakeClone.class, Cloneable.class }, (p, _, _) -> p);
assertSame(fake, fake.clone());
// Verify the default Object::clone behavior (this is Cloneable)
var fakeClone = (Object) OBJECT_CLONE.invoke((Object) fake);
assertNotSame(fake, fakeClone);
assertSame(fake.getClass(), fakeClone.getClass());
assertSame(fakeClone, ((FakeClone) fakeClone).clone());
}
{
// This proxy declares int clone(); which cannot be
// invoked through Object::clone.
var instance = (PrimitiveClone) Proxy.newProxyInstance(PrimitiveClone.class.getClassLoader(), new Class[] { PrimitiveClone.class }, (_, _, _) -> 42);
assertEquals(42, instance.clone());
// Verify the default Object::clone behavior (this is not Cloneable)
assertThrows(CloneNotSupportedException.class, () -> {
var _ = (Object) OBJECT_CLONE.invoke((Object) instance);
});
}
{
// This proxy declares int clone(); which cannot be
// invoked through Object::clone
var instance = (PrimitiveClone) Proxy.newProxyInstance(PrimitiveClone.class.getClassLoader(), new Class[] { PrimitiveClone.class, Cloneable.class }, (_, _, _) -> 76);
assertEquals(76, instance.clone());
// Verify the default Object::clone behavior (this is Cloneable)
var clone = (Object) OBJECT_CLONE.invoke((Object) instance);
assertNotSame(instance, clone);
assertSame(instance.getClass(), clone.getClass());
assertEquals(76, ((PrimitiveClone) clone).clone());
}
}
// Duplicates with Object::clone so it is proxied
@Test
void testDuplicateClone() throws Throwable {
{
// This proxy declares Object clone();, which
// accidentally overrides Object::clone
var instance = (TrueClone) Proxy.newProxyInstance(TrueClone.class.getClassLoader(), new Class[] { TrueClone.class }, (p, _, _) -> p);
assertSame(instance, instance.clone());
// Verify Object::clone is overridden
assertSame(instance, (Object) OBJECT_CLONE.invoke((Object) instance));
}
{
// This proxy declares Object clone(); and FakeClone clone();.
// They are considered duplicate methods and dispatched equivalently.
// Object clone() accidentally overrides Object::clone, so now
// FakeClone clone() can be called through Object::clone
var instance = Proxy.newProxyInstance(TrueClone.class.getClassLoader(), new Class[] { TrueClone.class, FakeClone.class }, (p, _, _) -> p);
assertSame(instance, ((FakeClone) instance).clone());
assertSame(instance, ((TrueClone) instance).clone());
// Verify Object::clone is overridden
assertSame(instance, (Object) OBJECT_CLONE.invoke((Object) instance));
}
}
interface FalseFinalize {
// This method is not related to Object::finalize in the JVM, but it can't
// be implemented in the Java Language unless using a lambda expression,
// due to the Java language covariant override restrictions.
int finalize();
}
interface TrueFinalize {
// This method is identical to Object::finalize in the JVM, that calls
// to Object::finalize can always call an implementation of this method
// if it exists
void finalize();
}
@Test
void testDistinctFinalize() throws Throwable {
AtomicInteger invokeCount = new AtomicInteger();
// This proxy declares int finalize(), which cannot be
// invoked through Object::finalize.
var instance = Proxy.newProxyInstance(FalseFinalize.class.getClassLoader(), new Class[] { FalseFinalize.class }, (_, _, _) -> invokeCount.incrementAndGet());
// Verify the default Object::finalize behavior
OBJECT_FINALIZE.invoke(instance);
assertEquals(0, invokeCount.get());
assertEquals(1, ((FalseFinalize) instance).finalize());
}
@Test
void testDuplicateFinalize() throws Throwable {
AtomicInteger invokeCount = new AtomicInteger();
// This proxy declares void finalize(), which can be
// invoked through Object::finalize.
var instance = Proxy.newProxyInstance(TrueFinalize.class.getClassLoader(), new Class[] { TrueFinalize.class }, (_, _, _) -> invokeCount.incrementAndGet());
// Verify the overridden Object::finalize behavior
OBJECT_FINALIZE.invoke(instance);
assertEquals(1, invokeCount.get());
((TrueFinalize) instance).finalize();
assertEquals(2, invokeCount.get());
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 8188240
* @summary This is a test to ensure that proxies do not try to intercept interface static methods.
*
* @build ProxyClashTest
* @run main ProxyClashTest
*/
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Observer;
public class ProxyClashTest {
public interface ClashWithRunnable {
static int run() { return 123; }
static void foo() {}
}
public static void main(String[] args) {
System.err.println(
"\nDynamic proxy API static method clash test\n");
Class<?>[] interfaces =
new Class<?>[] { ClashWithRunnable.class, Runnable.class, Observer.class };
ClassLoader loader = ProxyClashTest.class.getClassLoader();
/*
* Generate a proxy class.
*/
Class<?> proxyClass = Proxy.getProxyClass(loader, interfaces);
System.err.println("+ generated proxy class: " + proxyClass);
for (Method method : proxyClass.getDeclaredMethods()) {
if (method.getName().equals("run") && method.getReturnType() == int.class) {
throw new RuntimeException("proxy intercept a static method");
}
if (method.getName().equals("foo")) {
throw new RuntimeException("proxy intercept a static method");
}
}
System.err.println("\nTEST PASSED");
}
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.lang.reflect.Proxy;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import jdk.test.lib.compiler.CompilerUtils;
import static jdk.test.lib.process.ProcessTools.executeTestJava;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
/*
* @test
* @library /test/lib
* @modules jdk.compiler
* @build ProxyClassAccessTest q.NP
* jdk.test.lib.compiler.CompilerUtils
* @run junit ProxyClassAccessTest
* @summary Driver for testing proxy class doesn't have access to
* types referenced by proxy interfaces
*/
public class ProxyClassAccessTest {
private static final String TEST_SRC = System.getProperty("test.src");
private static final String TEST_CLASSES = System.getProperty("test.classes");
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
private static final Path MODS_DIR = Paths.get("mods");
// the names of the modules in this test
private static List<String> modules = Arrays.asList("m1", "m2", "m3", "test");
/**
* Compiles all modules used by the test
*/
@BeforeAll
public static void compileAll() throws Exception {
for (String mn : modules) {
Path msrc = SRC_DIR.resolve(mn);
assertTrue(CompilerUtils.compile(msrc, MODS_DIR, "--module-source-path", SRC_DIR.toString()));
}
}
/**
* Run the modular test
*/
@Test
public void runTest() throws Exception {
int exitValue = executeTestJava("--module-path", MODS_DIR.toString(),
"-m", "test/jdk.test.ProxyClassAccess")
.outputTo(System.out)
.errorTo(System.out)
.getExitValue();
assertEquals(0, exitValue);
}
/**
* Test unnamed module has no access to other proxy interface
*/
@Test
public void testNoReadAccess() throws Throwable {
ModuleFinder finder = ModuleFinder.of(MODS_DIR);
ModuleLayer bootLayer = ModuleLayer.boot();
Configuration cf = bootLayer
.configuration()
.resolveAndBind(ModuleFinder.of(), finder, modules);
ClassLoader parentLoader = this.getClass().getClassLoader();
ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, parentLoader);
ClassLoader loader = layer.findLoader("m1");
Class<?>[] interfaces = new Class<?>[] {
Class.forName("p.one.I", false, loader),
Class.forName("q.NP", false, loader) // non-public interface in unnamed module
};
checkIAE(loader, interfaces);
}
private void checkIAE(ClassLoader loader, Class<?>[] interfaces) throws Throwable {
assertThrows(IllegalArgumentException.class, () -> Proxy.getProxyClass(loader, interfaces));
assertThrows(IllegalArgumentException.class, () -> Proxy.newProxyInstance(loader, interfaces,
(proxy, m, params) -> { throw new RuntimeException(m.toString()); }));
}
}

View file

@ -0,0 +1,568 @@
/*
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Proxy Generator Combo tests
* @library /test/langtools/tools/javac/lib .
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.code
* jdk.compiler/com.sun.tools.javac.comp
* jdk.compiler/com.sun.tools.javac.file
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.javac.tree
* jdk.compiler/com.sun.tools.javac.util
* @build combo.ComboTestHelper
* @run main/othervm ProxyGeneratorCombo
*/
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
import combo.ComboInstance;
import combo.ComboParameter;
import combo.ComboTask.Result;
import combo.ComboTestHelper;
public class ProxyGeneratorCombo extends ComboInstance<ProxyGeneratorCombo> {
// The unique number to qualify interface names, unique across multiple runs
private static int uniqueId = 0;
/**
* Class Access kinds.
*/
enum ClassAccessKind implements ComboParameter {
PUBLIC("public"),
PACKAGE(""),
;
String classAccessTemplate;
ClassAccessKind(String classAccessTemplate) {
this.classAccessTemplate = classAccessTemplate;
}
@Override
public String expand(String optParameter) {
return classAccessTemplate;
}
}
/**
* Signatures of methods to be tested.
*/
enum MethodsKind implements ComboParameter {
NONE(""),
ZERO("#{METHODACCESS} void zero() #{EXCEPTION};"),
ONE("#{METHODACCESS} void one(#{ARG[0]} a) #{EXCEPTION};"),
TWO("#{METHODACCESS} void one(#{ARG[0]} b);\n" +
"#{METHODACCESS} void two(#{ARG[0]} a, #{ARG[1]} b);"),
THREE("#{METHODACCESS} void one(#{ARG[0]} a);\n" +
"#{METHODACCESS} void two(#{ARG[0]} a, #{ARG[1]} b);\n" +
"#{METHODACCESS} void three(#{ARG[0]} a, #{ARG[1]} b, #{ARG[0]} c);");
String methodsKindTemplate;
MethodsKind(String methodsKindTemplate) {
this.methodsKindTemplate = methodsKindTemplate;
}
@Override
public String expand(String optParameter) {
return methodsKindTemplate;
}
}
/**
* Type of arguments to insert in method signatures
*/
enum ArgumentKind implements ComboParameter {
BOOLEAN("boolean"),
BYTE("byte"),
CHAR("char"),
SHORT("short"),
INT("int"),
LONG("long"),
FLOAT("float"),
DOUBLE("double"),
STRING("String");
String argumentsKindTemplate;
ArgumentKind(String argumentsKindTemplate) {
this.argumentsKindTemplate = argumentsKindTemplate;
}
@Override
public String expand(String optParameter) {
return argumentsKindTemplate;
}
}
/**
* Exceptions to be added to zero and one methods.
*/
enum ExceptionKind implements ComboParameter {
NONE(null),
EXCEPTION(java.lang.Exception.class),
RUNTIME_EXCEPTION(java.lang.RuntimeException.class),
ILLEGAL_ARGUMENT_EXCEPTION(java.lang.IllegalArgumentException.class),
IOEXCEPTION(java.io.IOException.class),
/**
* Used only for throw testing, is empty for throws clause in the source,
*/
UNDECLARED_EXCEPTION(Exception1.class),
;
Class<? extends Throwable> exceptionKindClass;
ExceptionKind(Class<? extends Throwable> exceptionKindClass) {
this.exceptionKindClass = exceptionKindClass;
}
@Override
public String expand(String optParameter) {
return exceptionKindClass == null || exceptionKindClass == Exception1.class
? "" : "throws " + exceptionKindClass.getName();
}
}
/**
* Extra interfaces to be added.
*/
enum MultiInterfacesKind implements ComboParameter {
NONE(new Class<?>[0]),
INTERFACE_WITH_EXCEPTION(new Class<?>[] {InterfaceWithException.class}),
;
Class<?>[] multiInterfaceClasses;
MultiInterfacesKind(Class<?>[] multiInterfaceClasses) {
this.multiInterfaceClasses = multiInterfaceClasses;
}
@Override
// Not used for expansion only execution
public String expand(String optParameter) {
throw new RuntimeException("NYI");
}
Class<?>[] classes() {
return multiInterfaceClasses;
}
}
@Override
public int id() {
return ++uniqueId;
}
protected void fail(String msg, Throwable thrown) {
super.fail(msg);
thrown.printStackTrace();
}
/**
* Test interface with a "one(int)" method.
*/
interface InterfaceWithException {
// The signature must match the ONE MethodsKind above
void one(int a) throws RuntimeException, IOException;
}
/**
* Main to generate combinations and run the tests.
* @param args unused
* @throws Exception In case of failure
*/
public static void main(String... args) throws Exception {
// Test variations of access declarations
new ComboTestHelper<ProxyGeneratorCombo>()
.withDimension("CLASSACCESS", ClassAccessKind.values())
.withDimension("METHODACCESS", new ClassAccessKind[]{ClassAccessKind.PUBLIC})
.withDimension("METHODS", ProxyGeneratorCombo::saveMethod,
new MethodsKind[] {MethodsKind.NONE, MethodsKind.ZERO, MethodsKind.ONE})
.withDimension("ARG[0]", new ArgumentKind[] {ArgumentKind.INT})
.withDimension("EXCEPTION", ProxyGeneratorCombo::saveException,
new ExceptionKind[]{ExceptionKind.NONE})
.run(ProxyGeneratorCombo::new);
// Test variations of argument types
new ComboTestHelper<ProxyGeneratorCombo>()
.withDimension("CLASSACCESS", new ClassAccessKind[]{ClassAccessKind.PUBLIC})
.withDimension("METHODACCESS", new ClassAccessKind[]{ClassAccessKind.PUBLIC})
.withDimension("METHODS", ProxyGeneratorCombo::saveMethod,
MethodsKind.values())
.withArrayDimension("ARG", ProxyGeneratorCombo::saveArg, 2,
ArgumentKind.values())
.withDimension("EXCEPTION", ProxyGeneratorCombo::saveException,
new ExceptionKind[]{ExceptionKind.NONE})
.withFilter(ProxyGeneratorCombo::filter)
.run(ProxyGeneratorCombo::new);
// Test for conflicts in Exceptions on methods with the same signatures
new ComboTestHelper<ProxyGeneratorCombo>()
.withDimension("CLASSACCESS", new ClassAccessKind[]{ClassAccessKind.PUBLIC})
.withDimension("METHODACCESS", new ClassAccessKind[]{ClassAccessKind.PUBLIC})
.withDimension("METHODS", ProxyGeneratorCombo::saveMethod, new MethodsKind[] {
MethodsKind.ZERO})
.withDimension("EXCEPTION", ProxyGeneratorCombo::saveException,
ExceptionKind.values())
.withDimension("MULTI_INTERFACES", ProxyGeneratorCombo::saveInterface,
new MultiInterfacesKind[] {MultiInterfacesKind.NONE})
.run(ProxyGeneratorCombo::new);
}
/**
* Basic template.
*/
String template = "#{CLASSACCESS} interface #{TESTNAME} {\n" +
"#{METHODS}" +
"}";
// Saved values of Combo values
private MultiInterfacesKind currInterface = MultiInterfacesKind.NONE;
private MethodsKind currMethod = MethodsKind.NONE;
private ExceptionKind currException = ExceptionKind.NONE;
private ArgumentKind[] currArgs = new ArgumentKind[0];
void saveInterface(ComboParameter s) {
currInterface = (MultiInterfacesKind)s;
}
void saveMethod(ComboParameter s) {
currMethod = (MethodsKind)s;
}
void saveException(ComboParameter s) {
currException = (ExceptionKind)s;
}
void saveArg(ComboParameter s, int index) {
if (index >= currArgs.length) {
currArgs = Arrays.copyOf(currArgs, index + 1);
}
currArgs[index] = (ArgumentKind)s;
}
/**
* Filter out needless tests (mostly with more variations of arguments than needed).
* @return true to run the test, false if not
*/
boolean filter() {
if ((currMethod == MethodsKind.NONE || currMethod == MethodsKind.ZERO) &&
currArgs.length >= 2) {
return currArgs[0] == ArgumentKind.INT &&
currArgs[1] == ArgumentKind.INT;
}
if (currMethod == MethodsKind.ONE &&
currArgs.length >= 2 ) {
return currArgs[0] == currArgs[1];
}
return true;
}
/**
* Generate the source file and compile.
* Generate a proxy for the interface and test the resulting Proxy
* for the methods, exceptions and handling of a thrown exception
* @throws IOException catch all IOException
*/
@Override
public void doWork() throws IOException {
String cp = System.getProperty("test.classes");
String ifaceName = "Interface_" + this.id();
newCompilationTask()
.withSourceFromTemplate(ifaceName, template.replace("#{TESTNAME}", ifaceName))
.withOption("-d")
.withOption(cp)
.generate(this::checkCompile);
try {
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class<?> tc = Class.forName(ifaceName);
InvocationHandler handler =
new ProxyHandler(currException.exceptionKindClass);
// Construct array of interfaces for the proxy
Class<?>[] interfaces = new Class<?>[currInterface.classes().length + 1];
interfaces[0] = tc;
System.arraycopy(currInterface.classes(), 0,
interfaces, 1,
currInterface.classes().length);
Object proxy = Proxy.newProxyInstance(loader, interfaces, handler);
if (!Proxy.isProxyClass(proxy.getClass())) {
fail("generated proxy is not a proxy class");
return;
}
for (Class<?> i : interfaces) {
if (!i.isAssignableFrom(proxy.getClass())) {
fail("proxy is not assignable to " + i.getName());
}
}
try {
String s = proxy.toString();
} catch (Exception ex) {
ex.printStackTrace();
fail("proxy.toString() threw an exception");
}
checkDeclaredProxyExceptions(proxy, interfaces);
if (currMethod == MethodsKind.ZERO && currException != ExceptionKind.NONE) {
checkThrowsException(proxy, interfaces);
}
} catch (Exception ex) {
throw new RuntimeException("doWork unexpected", ex);
}
}
/**
* Check that the exceptions declared on the proxy match the declarations for
* exceptions from the interfaces.
*
* @param proxy a proxy object
* @param interfaces the interfaces that defined it
*/
void checkDeclaredProxyExceptions(Object proxy, Class<?>[] interfaces) {
var allMethods = allMethods(Arrays.asList(interfaces));
Method[] methods = proxy.getClass().getDeclaredMethods();
for (Method m : methods) {
String sig = toShortSignature(m);
var imethods = allMethods.get(sig);
if (imethods != null) {
var expectedEx = Set.copyOf(Arrays.asList(m.getExceptionTypes()));
var exs = Set.copyOf(extractExceptions(imethods));
if (!expectedEx.equals(exs)) {
System.out.printf("mismatch on exceptions for method %s:%nExpected: " +
"%s%nActual: %s%n",
sig, expectedEx, exs);
fail("Exceptions declared on proxy don't match interface methods");
}
}
}
}
void checkThrowsException(Object proxy, Class<?>[] interfaces) {
ProxyHandler ph = (ProxyHandler)(Proxy.getInvocationHandler(proxy));
try {
Method m = proxy.getClass().getDeclaredMethod("zero");
m.invoke(proxy);
fail("Missing exception: " + ph.exceptionClass);
} catch (NoSuchMethodException nsme) {
System.out.printf("No method 'zero()' to test exceptions with%n");
for (var cl : interfaces) {
System.out.printf(" i/f %s: %s%n", cl, Arrays.toString(cl.getMethods()));
}
Method[] methods = proxy.getClass().getMethods();
System.out.printf(" Proxy methods: %s%n", Arrays.toString(methods));
fail("No such method test bug", nsme);
} catch (InvocationTargetException actual) {
ph.checkThrownException(actual.getTargetException());
} catch (IllegalAccessException iae) {
fail("IllegalAccessException", iae);
}
}
/**
* Exceptions known to be supported by all methods with the same signature.
* @return a list of universal exception types
*/
private static List<Class<?>> extractExceptions(List<Method> methods) {
// for all methods with the same signature
// start with the exceptions from the first method
// while there are any exceptions remaining
// look at the next method
List<Class<?>> exceptions = null;
for (Method m : methods) {
var e = m.getExceptionTypes();
if (e.length == 0)
return emptyClassList();
List<Class<?>> elist = Arrays.asList(e);
if (exceptions == null) {
exceptions = elist; // initialize to first method exceptions
} else {
// for each exception
// if it is compatible (both ways) with any of the existing exceptions continue
// else remove the current exception
var okExceptions = new HashSet<Class<?>>();
for (int j = 0; j < exceptions.size(); j++) {
var ex = exceptions.get(j);
for (int i = 0; i < elist.size();i++) {
var ci = elist.get(i);
if (ci.isAssignableFrom(ex)) {
okExceptions.add(ex);
}
if (ex.isAssignableFrom(ci)) {
okExceptions.add(ci);
}
}
}
if (exceptions.isEmpty()) {
// The empty set terminates the search for a common set of exceptions
return emptyClassList();
}
// Use the new set for the next iteration
exceptions = List.copyOf(okExceptions);
}
}
return (exceptions == null) ? emptyClassList() : exceptions;
}
/**
* An empty correctly typed list of classes.
* @return An empty typed list of classes
*/
@SuppressWarnings("unchecked")
static List<Class<?>> emptyClassList() {
return Collections.EMPTY_LIST;
}
/**
* Accumulate all of the unique methods.
*
* @param interfaces a list of interfaces
* @return a map from signature to List of methods, unique by signature
*/
private static Map<String, List<Method>> allMethods(List<Class<?>> interfaces) {
Map<String, List<Method>> methods = new HashMap<>();
for (Class<?> c : interfaces) {
for (Method m : c.getMethods()) {
if (!Modifier.isStatic(m.getModifiers())) {
String sig = toShortSignature(m);
methods.computeIfAbsent(sig, s -> new ArrayList<Method>())
.add(m);
}
}
}
return methods;
}
/**
* The signature of a method without the return type.
* @param m a Method
* @return the signature with method name and parameters
*/
static String toShortSignature(Method m) {
StringJoiner sj = new StringJoiner(",", m.getName() + "(", ")");
for (Class<?> parameterType : m.getParameterTypes()) {
sj.add(parameterType.getTypeName());
}
return sj.toString();
}
/**
* Report any compilation errors.
* @param res the result
*/
void checkCompile(Result<?> res) {
if (res.hasErrors()) {
fail("invalid diagnostics for source:\n" +
res.compilationInfo() +
"\nFound error: " + res.hasErrors());
}
}
/**
* The Handler for the proxy includes the method to invoke the proxy
* and the expected exception, if any.
*/
class ProxyHandler implements InvocationHandler {
private final Class<? extends Throwable> exceptionClass;
ProxyHandler(Class<? extends Throwable> throwable) {
this.exceptionClass = throwable;
}
/**
* Invoke a method on the proxy or return a value.
* @param proxy the proxy instance that the method was invoked on
* @param method a method
* @param args some args
* @return
* @throws Throwable a throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("toString")) {
return "Proxy" + System.identityHashCode(proxy);
}
if (method.getName().equals("zero")) {
if (exceptionClass != null) {
throw exceptionClass.getDeclaredConstructor().newInstance();
}
}
return "meth: " + method.toString();
}
/**
* Check that the expected exception was thrown.
* Special case is handled for Exception1 which does not appear in the
* throws clause of the method so UndeclaredThrowableException is expected.
*/
void checkThrownException(Throwable thrown) {
if (exceptionClass == Exception1.class &&
thrown instanceof UndeclaredThrowableException &&
((UndeclaredThrowableException)thrown).getUndeclaredThrowable() instanceof Exception1) {
// Exception1 caused UndeclaredThrowableException
return;
} else if (exceptionClass == Exception1.class) {
fail("UndeclaredThrowableException", thrown);
}
if (exceptionClass != null &&
!exceptionClass.equals(thrown.getClass())) {
throw new RuntimeException("Wrong exception thrown: expected: " + exceptionClass +
", actual: " + thrown.getClass());
}
}
}
/**
* Exception to be thrown as a test of InvocationTarget.
*/
static class Exception1 extends Exception {
private static final long serialVersionUID = 1L;
Exception1() {}
}
}

View file

@ -0,0 +1,175 @@
/*
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import jdk.test.lib.compiler.CompilerUtils;
import static jdk.test.lib.process.ProcessTools.executeTestJava;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
/*
* @test
* @library /test/lib
* @modules jdk.compiler
* @build ProxyTest jdk.test.lib.process.ProcessTools
* jdk.test.lib.compiler.CompilerUtils
* @run junit ProxyLayerTest
* @summary Test proxies to implement interfaces in a layer
*/
public class ProxyLayerTest {
private static final String TEST_SRC = System.getProperty("test.src");
private static final String TEST_CLASSES = System.getProperty("test.classes");
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
private static final Path MODS_DIR = Paths.get("mods");
private static final Path CPATH_DIR = Paths.get(TEST_CLASSES);
// the names of the modules in this test
private static String[] modules = new String[] {"m1", "m2", "m3"};
/**
* Compiles all modules used by the test
*/
@BeforeAll
public static void compileAll() throws Exception {
for (String mn : modules) {
Path msrc = SRC_DIR.resolve(mn);
assertTrue(CompilerUtils.compile(msrc, MODS_DIR, "--module-source-path", SRC_DIR.toString()));
}
}
/**
* Test proxy implementing interfaces in a layer defined in
* an unnamed module
*/
@Test
public void testProxyInUnnamed() throws Exception {
ModuleFinder finder = ModuleFinder.of(MODS_DIR);
ModuleLayer bootLayer = ModuleLayer.boot();
Configuration cf = bootLayer
.configuration()
.resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules));
ClassLoader scl = ClassLoader.getSystemClassLoader();
ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
ClassLoader loader = layer.findLoader("m1");
assertTrue(layer.findModule("m1").isPresent());
assertTrue(layer.findModule("m2").isPresent());
assertTrue(layer.findModule("m3").isPresent());
Class<?>[] interfaces = new Class<?>[] {
Class.forName("p.one.I", false, loader),
Class.forName("p.two.A", false, loader),
Class.forName("p.three.P", false, loader),
};
Object o = Proxy.newProxyInstance(loader, interfaces, handler);
Class<?> proxyClass = o.getClass();
Package pkg = proxyClass.getPackage();
assertTrue(proxyClass.getModule().isNamed());
assertTrue(pkg.isSealed());
assertTrue(proxyClass.getModule().isExported(pkg.getName()));
assertNull(proxyClass.getModule().getLayer());
}
/**
* Test proxy implementing interfaces in a Layer and defined in a
* dynamic module
*/
@Test
public void testProxyInDynamicModule() throws Exception {
ModuleFinder finder = ModuleFinder.of(MODS_DIR);
ModuleLayer bootLayer = ModuleLayer.boot();
Configuration cf = bootLayer
.configuration()
.resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules));
ClassLoader scl = ClassLoader.getSystemClassLoader();
ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
ClassLoader loader = layer.findLoader("m1");
assertTrue(layer.findModule("m1").isPresent());
assertTrue(layer.findModule("m2").isPresent());
assertTrue(layer.findModule("m3").isPresent());
Class<?>[] interfaces = new Class<?>[] {
Class.forName("p.one.internal.J", false, loader),
};
Object o = Proxy.newProxyInstance(loader, interfaces, handler);
Class<?> proxyClass = o.getClass();
Package pkg = proxyClass.getPackage();
assertTrue(proxyClass.getModule().isNamed());
assertTrue(pkg.isSealed());
assertFalse(proxyClass.getModule().isExported(pkg.getName()));
assertNull(proxyClass.getModule().getLayer());
}
/**
* Test proxy implementing interfaces that the target module has no access
*/
@Test
public void testNoReadAccess() throws Exception {
ModuleFinder finder = ModuleFinder.of(MODS_DIR);
ModuleLayer bootLayer = ModuleLayer.boot();
Configuration cf = bootLayer
.configuration()
.resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules));
ClassLoader scl = ClassLoader.getSystemClassLoader();
ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
ClassLoader loader = layer.findLoader("m1");
assertTrue(layer.findModule("m1").isPresent());
assertTrue(layer.findModule("m2").isPresent());
assertTrue(layer.findModule("m3").isPresent());
Class<?>[] interfaces = new Class<?>[] {
Class.forName("p.one.I", false, loader),
Class.forName("p.two.B", false, loader) // non-public interface but exported package
};
checkIAE(loader, interfaces);
}
private void checkIAE(ClassLoader loader, Class<?>[] interfaces) {
assertThrows(IllegalArgumentException.class, () -> Proxy.getProxyClass(loader, interfaces));
assertThrows(IllegalArgumentException.class, () -> Proxy.newProxyInstance(loader, interfaces, handler));
}
private final static InvocationHandler handler =
(proxy, m, params) -> { throw new RuntimeException(m.toString()); };
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/*
* @test
* @summary Basic test of proxy module mapping and the access to Proxy class
* @modules java.base/jdk.internal.misc
*/
public class ProxyModuleMapping {
public static void main(String... args) throws Exception {
ClassLoader ld = ProxyModuleMapping.class.getClassLoader();
Module unnamed = ld.getUnnamedModule();
new ProxyModuleMapping(Runnable.class).test();
// unnamed module gets access to jdk.internal.misc package (e.g. via --add-exports)
new ProxyModuleMapping(jdk.internal.misc.VM.BufferPool.class).test();
Class<?> modulePrivateIntf = Class.forName("sun.net.PlatformSocketImpl");
new ProxyModuleMapping(modulePrivateIntf).test();
}
final Module target;
final ClassLoader loader;
final Class<?>[] interfaces;
ProxyModuleMapping(Module m, Class<?>... interfaces) {
this.target = m;
this.loader = m.getClassLoader();
this.interfaces = interfaces;
}
ProxyModuleMapping(Class<?>... interfaces) {
this.target = null; // expected to be dynamic module
this.loader = interfaces[0].getClassLoader(); // same class loader
this.interfaces = interfaces;
}
void test() throws Exception {
verifyProxyClass();
verifyNewProxyInstance();
}
void verifyProxyClass() throws Exception {
Class<?> c = Proxy.getProxyClass(loader, interfaces);
Module m = c.getModule();
if (target != null && m != target) {
throw new RuntimeException(c.getModule() + " not expected: " + target);
}
// expect dynamic module
if (target == null && (!m.isNamed() || !m.getName().startsWith("jdk.proxy"))) {
throw new RuntimeException("Unexpected:" + m);
}
Module module = c.getModule();
try {
Constructor<?> cons = c.getConstructor(InvocationHandler.class);
cons.newInstance(ih);
// the exported package name is same as the module name
if (!c.getPackageName().equals(module.getName())) {
throw new RuntimeException("expected IAE not thrown");
}
} catch (IllegalAccessException e) {
// non-exported package from the dynamic module
if (c.getPackageName().equals(module.getName())) {
throw e;
}
}
}
void verifyNewProxyInstance() throws Exception {
Object o = Proxy.newProxyInstance(loader, interfaces, ih);
Module m = o.getClass().getModule();
if (target != null && m != target) {
throw new RuntimeException(m + " not expected: " + target);
}
if (target == null && (!m.isNamed() || !m.getName().startsWith("jdk.proxy"))) {
throw new RuntimeException(m + " not expected: dynamic module");
}
}
private final static InvocationHandler ih =
(proxy, m, params) -> { System.out.println(m); return null; };
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8371953
* @summary Basic API null checks for Proxy.
* @run junit ProxyNullCheckTest
*/
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class ProxyNullCheckTest {
@SuppressWarnings("deprecation")
@Test
void nullChecks() throws ReflectiveOperationException {
InvocationHandler h = (_, _, _) -> null;
// newProxyInstance
assertDoesNotThrow(() -> Proxy.newProxyInstance(null, new Class[0], h));
assertThrows(NullPointerException.class, () -> Proxy.newProxyInstance(null, null, h));
assertThrows(NullPointerException.class, () -> Proxy.newProxyInstance(null, new Class[] { null }, h));
assertThrows(NullPointerException.class, () -> Proxy.newProxyInstance(null, new Class[0], null));
// getProxyClass
assertDoesNotThrow(() -> Proxy.getProxyClass(null, new Class[0]));
assertThrows(NullPointerException.class, () -> Proxy.getProxyClass(null, (Class[]) null));
assertThrows(NullPointerException.class, () -> Proxy.getProxyClass(null, new Class[] { null }));
// isProxyClass
assertFalse(Proxy.isProxyClass(Object.class));
assertThrows(NullPointerException.class, () -> Proxy.isProxyClass(null));
// getInvocationHandler
assertThrows(NullPointerException.class, () -> Proxy.getInvocationHandler(null));
assertThrows(IllegalArgumentException.class, () -> Proxy.getInvocationHandler(42));
}
}

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import jdk.test.lib.compiler.CompilerUtils;
import static jdk.test.lib.process.ProcessTools.executeTestJava;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
/*
* @test
* @library /test/lib
* @modules jdk.compiler
* @build ProxyTest q.U
* jdk.test.lib.compiler.CompilerUtils
* @run junit ProxyTest
* @summary Driver for testing proxies accessing interfaces in named modules
*/
public class ProxyTest {
private static final String TEST_SRC = System.getProperty("test.src");
private static final String TEST_CLASSES = System.getProperty("test.classes");
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
private static final Path MODS_DIR = Paths.get("mods");
private static final Path CPATH_DIR = Paths.get(TEST_CLASSES);
// the names of the modules in this test
private static List<String> modules = Arrays.asList("test", "m1", "m2", "m3");
/**
* Compiles all modules used by the test
*/
@BeforeAll
public static void compileAll() throws Exception {
for (String mn : modules) {
Path msrc = SRC_DIR.resolve(mn);
assertTrue(CompilerUtils.compile(msrc, MODS_DIR, "--module-source-path", SRC_DIR.toString()));
}
}
/**
* Run the modular test
*/
@Test
public void runTest() throws Exception {
int exitValue = executeTestJava("-cp", CPATH_DIR.toString(),
"--module-path", MODS_DIR.toString(),
"-m", "test/jdk.test.Main")
.outputTo(System.out)
.errorTo(System.out)
.getExitValue();
assertEquals(0, exitValue);
}
/**
* Tests invocation of default methods in exported and non-exported types
* in a named module
*/
@Test
public void runDefaultMethodsTest() throws Exception {
int exitValue = executeTestJava("-cp", CPATH_DIR.toString(),
"--module-path", MODS_DIR.toString(),
"-m", "test/jdk.test.DefaultMethods")
.outputTo(System.out)
.errorTo(System.out)
.getExitValue();
assertEquals(0, exitValue);
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8269351
* @run junit SealedInterfaceTest
*/
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
public class SealedInterfaceTest {
sealed interface Intf permits NonSealedInterface {
void m1();
}
non-sealed interface NonSealedInterface extends Intf {
void m2();
}
@Test
public void testSealedInterface() {
assertThrows(IllegalArgumentException.class, () -> Proxy.newProxyInstance(
SealedInterfaceTest.class.getClassLoader(),
new Class<?>[]{ Intf.class },
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}));
}
@Test
public void testNonSealedInterface() {
Proxy.newProxyInstance(SealedInterfaceTest.class.getClassLoader(),
new Class<?>[]{ NonSealedInterface.class },
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});
}
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8022795
* @run junit TestVarArgs
* @summary Verify if a method defined in a proxy interface has ACC_VARARGS set
*/
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class TestVarArgs {
interface I {
Object call(Object... values);
}
interface J {
Object call(Object[] values);
}
public static Object[][] proxyInterfaces() {
return new Object[][] {
{ new Class<?>[] { I.class }, true},
{ new Class<?>[] { J.class }, false},
{ new Class<?>[] { I.class, J.class }, true},
{ new Class<?>[] { J.class, I.class }, false},
};
}
@ParameterizedTest
@MethodSource("proxyInterfaces")
public void testMethod(Class<?>[] proxyInterfaces, boolean isVarArgs) throws Throwable {
// check if the first proxy interface with the method named "call" declares var result
Method m = proxyInterfaces[0].getMethod("call", Object[].class);
assertEquals(isVarArgs, m.isVarArgs());
// the method in the generated proxy class should match the method
// declared in the proxy interface
Object proxy = Proxy.newProxyInstance(TestVarArgs.class.getClassLoader(),
proxyInterfaces, IH);
Class<?> proxyClass = proxy.getClass();
assertTrue(Proxy.isProxyClass(proxyClass));
Method method = proxyClass.getMethod("call", Object[].class);
assertEquals(isVarArgs, method.isVarArgs());
Object[] params = new Object[] { "foo", "bar", "goo" };
Object[] result;
// test reflection
result = (Object[]) method.invoke(proxy, new Object[] {params});
assertEquals(params, result);
// test method handle
MethodHandle mh = MethodHandles.lookup().findVirtual(proxyClass, "call",
MethodType.methodType(Object.class, Object[].class));
assertEquals(isVarArgs, mh.isVarargsCollector());
MethodHandle mhVarArity = mh;
MethodHandle mhFixedArity = mh;
if (isVarArgs) {
mhFixedArity = mh.asFixedArity();
} else {
mhVarArity = mh.asVarargsCollector(Object[].class);
}
result = (Object[]) mhVarArity.invoke(proxy, "foo", "bar", "goo");
assertArrayEquals(params, result);
result = (Object[]) mhFixedArity.invoke(proxy, params);
assertArrayEquals(params, result);
if (!isVarArgs) {
MethodType mt = MethodType.methodType(Object.class, Object.class, String.class, String.class, String.class);
mh = mh.asVarargsCollector(Object[].class).asType(mt);
}
result = (Object[]) mh.invoke(proxy, "foo", "bar", "goo");
assertArrayEquals(params, result);
}
private static final InvocationHandler IH = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return args[0];
}
};
}

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 4978925
* @summary This test verifies that java.lang.reflect.Proxy will work
* with a proxy interface that contains names that are not valid Java
* identifiers but that are legal at runtime as of version 49.0 of the
* class file format.
* @author Peter Jones
*
* @build Test
* @run main Test
*/
import java.lang.reflect.Proxy;
public class Test {
private static final String CLASS_NAME = "Test+Interface";
/**
* class file for empty interface named "Test+Interface"
*/
private static final byte[] CLASS_FILE = {
(byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe,
0x00, 0x00, 0x00, 0x31,
0x00, 0x07, 0x07, 0x00, 0x05, 0x07, 0x00, 0x06,
0x01, 0x00, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x46, 0x69, 0x6c, 0x65, 0x01, 0x00, 0x13,
0x54, 0x65, 0x73, 0x74, 0x2b, 0x49, 0x6e, 0x74,
0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x2e, 0x6a,
0x61, 0x76, 0x61, 0x01, 0x00, 0x0e, 0x54, 0x65,
0x73, 0x74, 0x2b, 0x49, 0x6e, 0x74, 0x65, 0x72,
0x66, 0x61, 0x63, 0x65, 0x01, 0x00, 0x10, 0x6a,
0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e, 0x67,
0x2f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x06,
0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00,
0x00, 0x00, 0x02, 0x00, 0x04
};
public static void main(String[] args) throws Exception {
ClassLoader l = new Loader();
Class i = Class.forName(CLASS_NAME, false, l);
System.out.println(i);
Class p = Proxy.getProxyClass(i.getClassLoader(), new Class[] { i });
System.out.println(p);
}
private static class Loader extends ClassLoader {
Loader() { }
protected Class findClass(String name) throws ClassNotFoundException {
if (name.equals(CLASS_NAME)) {
return defineClass(name, CLASS_FILE, 0, CLASS_FILE.length);
} else {
return super.findClass(name);
}
}
}
}

View file

@ -0,0 +1,123 @@
/*
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
/*
* @test
* @bug 8159746
* @summary Test invoking a default method in a non-public proxy interface
* @build p.Foo p.Bar p.ProxyMaker
* @run junit DefaultMethodProxy
*/
public class DefaultMethodProxy {
public interface I {
default String m() { return "I"; }
}
@Test
public void publicInterface() throws ReflectiveOperationException {
// create a proxy instance of a public proxy interface should succeed
Proxy proxy = (Proxy)Proxy.newProxyInstance(DefaultMethodProxy.class.getClassLoader(),
new Class<?>[] { I.class }, IH);
testDefaultMethod(proxy, "I");
// can get the invocation handler
assertSame(IH, Proxy.getInvocationHandler(proxy));
}
private static Object[][] nonPublicIntfs() throws ClassNotFoundException {
Class<?> fooClass = Class.forName("p.Foo");
Class<?> barClass = Class.forName("p.Bar");
return new Object[][]{
new Object[]{new Class<?>[]{ fooClass }, "foo"},
new Object[]{new Class<?>[]{ barClass, fooClass }, "bar"},
new Object[]{new Class<?>[]{ barClass }, "bar"},
};
}
@ParameterizedTest
@MethodSource("nonPublicIntfs")
public void hasPackageAccess(Class<?>[] intfs, String expected) throws ReflectiveOperationException {
Proxy proxy = (Proxy)Proxy.newProxyInstance(DefaultMethodProxy.class.getClassLoader(), intfs, IH);
testDefaultMethod(proxy, expected);
// proxy instance is created successfully even invocation handler has no access
Proxy.newProxyInstance(DefaultMethodProxy.class.getClassLoader(), intfs, IH_NO_ACCESS);
}
// IAE thrown at invocation time
@ParameterizedTest
@MethodSource("nonPublicIntfs")
public void noPackageAccess(Class<?>[] intfs, String ignored) throws Throwable {
Proxy proxy = (Proxy)Proxy.newProxyInstance(DefaultMethodProxy.class.getClassLoader(), intfs, IH_NO_ACCESS);
InvocationTargetException ite = assertThrows(InvocationTargetException.class, () -> testDefaultMethod(proxy, "dummy"));
var ute = assertInstanceOf(UndeclaredThrowableException.class, ite.getCause(), "unwrap the InvocationTargetException");
assertInstanceOf(IllegalAccessException.class, ute.getCause(), "unwrap the UndeclaredThrowableException");
}
/*
* Verify if a default method "m" can be invoked successfully
*/
static void testDefaultMethod(Proxy proxy, String expected) throws ReflectiveOperationException {
Method m = proxy.getClass().getDeclaredMethod("m");
m.setAccessible(true);
String name = (String) m.invoke(proxy);
if (!expected.equals(name)) {
throw new RuntimeException("return value: " + name + " expected: " + expected);
}
}
// invocation handler with access to the non-public interface in package p
private static final InvocationHandler IH = (proxy, method, params) -> {
System.out.format("Proxy for %s: invoking %s%n",
Arrays.stream(proxy.getClass().getInterfaces())
.map(Class::getName)
.collect(Collectors.joining(", ")), method.getName());
if (method.isDefault()) {
return p.ProxyMaker.invoke(proxy, method, params);
}
throw new UnsupportedOperationException(method.toString());
};
// invocation handler with no access to the non-public interface in package p
// expect IllegalAccessException thrown
private static final InvocationHandler IH_NO_ACCESS = (proxy, method, params) -> {
System.out.format("Proxy for %s: invoking %s%n",
Arrays.stream(proxy.getClass().getInterfaces())
.map(Class::getName)
.collect(Collectors.joining(", ")), method.getName());
if (method.isDefault()) {
InvocationHandler.invokeDefault(proxy, method, params);
}
throw new UnsupportedOperationException(method.toString());
};
}

View file

@ -0,0 +1,119 @@
/*
* Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.*;
/*
* @test
* @bug 8004260 8189291
* @summary Test proxy classes that implement non-public interface
*
* @build p.Foo
* @run main/othervm NonPublicProxyClass
*/
public class NonPublicProxyClass {
public interface PublicInterface {
void foo();
}
interface NonPublicInterface {
void bar();
}
public static void main(String[] args) throws Exception {
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class<?> zipConstantsClass = Class.forName("java.util.zip.ZipConstants", false, null);
Class<?> fooClass = Class.forName("p.Foo");
NonPublicProxyClass test1 =
new NonPublicProxyClass(loader, PublicInterface.class, NonPublicInterface.class);
NonPublicProxyClass test2 =
new NonPublicProxyClass(loader, fooClass, PublicInterface.class);
NonPublicProxyClass test3 =
new NonPublicProxyClass(null, zipConstantsClass);
test1.run();
test2.run();
test3.run();
}
private final ClassLoader loader;
private final Class<?>[] interfaces;
private final InvocationHandler handler = newInvocationHandler();
private Class<?> proxyClass;
public NonPublicProxyClass(ClassLoader loader, Class<?> ... intfs) {
this.loader = loader;
this.interfaces = intfs;
}
public void run() throws Exception {
proxyClass = Proxy.getProxyClass(loader, interfaces);
if (Modifier.isPublic(proxyClass.getModifiers())) {
throw new RuntimeException(proxyClass + " must be non-public");
}
newProxyInstance();
newInstanceFromConstructor(proxyClass);
}
private void newProxyInstance() {
// expect newProxyInstance to succeed if it's in the same runtime package
int i = proxyClass.getName().lastIndexOf('.');
String pkg = (i != -1) ? proxyClass.getName().substring(0, i) : "";
Proxy.newProxyInstance(loader, interfaces, handler);
}
private void newInstanceFromConstructor(Class<?> proxyClass)
throws Exception
{
// expect newInstance to succeed if it's in the same runtime package
boolean isSamePackage = proxyClass.getName().lastIndexOf('.') == -1;
try {
Constructor cons = proxyClass.getConstructor(InvocationHandler.class);
cons.newInstance(newInvocationHandler());
if (!isSamePackage) {
throw new RuntimeException("ERROR: Constructor.newInstance should not succeed");
}
} catch (IllegalAccessException e) {
if (isSamePackage) {
throw e;
}
}
}
private static InvocationHandler newInvocationHandler() {
return new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Class<?>[] intfs = proxy.getClass().getInterfaces();
System.out.println("Proxy for " + Arrays.toString(intfs)
+ " " + method.getName() + " is being invoked");
return null;
}
};
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.reflect.*;
import java.security.*;
import java.util.Arrays;
/*
* @test
* @bug 8004260
* @summary Test making a proxy instance that implements a non-public interface
* @build p.Foo p.Bar
* @run main/othervm SimpleProxy
*/
public class SimpleProxy {
public static void main(String[] args) throws Exception {
ClassLoader loader = SimpleProxy.class.getClassLoader();
Class<?> fooClass = Class.forName("p.Foo");
Class<?> barClass = Class.forName("p.Bar");
makeProxy(loader, fooClass);
}
private static void makeProxy(ClassLoader loader, Class<?> cls) {
Class<?>[] intfs = new Class<?>[] { cls };
Proxy.newProxyInstance(loader, intfs, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Class<?>[] intfs = proxy.getClass().getInterfaces();
System.out.println("Proxy for " + Arrays.toString(intfs)
+ " " + method.getName() + " is being invoked");
return null;
}
});
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package p;
interface Bar {
default String m() { return "bar"; }
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package p;
interface Foo {
default String m() { return "foo"; }
}

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package p;
import java.lang.reflect.*;
public class ProxyMaker {
public static Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
return InvocationHandler.invokeDefault(proxy, method, args);
}
// get the invocation handler associated with the proxy
public static InvocationHandler getInvocationHandler(Object proxy) {
return Proxy.getInvocationHandler(proxy);
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package q;
interface NP {
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package q;
public interface U {
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
public interface GetArray {
Object[] get(double[][][] x);
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
public interface GetCloneable {
Cloneable get(double[][][] x);
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
public interface GetObject {
Object get(double[][][] x);
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.Serializable;
public interface GetSerializable {
Serializable get(double[][][] x);
}

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 4838310
* @summary This test verifies that the restrictions on proxy interface
* methods with the same signature but different return types are
* correctly enforced.
* @author Peter Jones
*
* @build GetObject GetSerializable GetCloneable GetArray
* @run main Test
*/
import java.lang.reflect.Proxy;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class Test {
// additional test cases may be added to both of these lists:
private static final Class<?>[][] GOOD = {
{ Collection.class },
{ Iterable.class, Collection.class },
{ Iterable.class, Collection.class, List.class },
{ GetSerializable.class, GetCloneable.class, GetArray.class },
{ GetObject.class, GetSerializable.class, GetCloneable.class,
GetArray.class }
};
private static final Class<?>[][] BAD = {
{ Runnable.class, PrivilegedAction.class },
{ GetSerializable.class, GetCloneable.class },
{ GetObject.class, GetSerializable.class, GetCloneable.class }
};
public static void main(String[] args) throws Exception {
System.err.println("\nRegression test for bug 4838310\n");
ClassLoader loader = Test.class.getClassLoader();
System.err.println("Testing GOOD combinations:");
for (int i = 0; i < GOOD.length; i++) {
Class<?>[] interfaces = GOOD[i];
System.err.println(Arrays.asList(interfaces));
Proxy.getProxyClass(loader, interfaces);
System.err.println("--- OK.");
}
System.err.println("Testing BAD combinations:");
for (int i = 0; i < BAD.length; i++) {
Class<?>[] interfaces = BAD[i];
System.err.println(Arrays.asList(interfaces));
try {
Proxy.getProxyClass(loader, interfaces);
throw new RuntimeException(
"TEST FAILED: bad combination succeeded");
} catch (IllegalArgumentException e) {
e.printStackTrace();
System.err.println("--- OK.");
}
}
System.err.println("TEST PASSED");
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
module m1 {
exports p.one;
exports p.one.internal to test;
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package p.one;
public interface I {
void run();
default int m() { return 1; }
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package p.one.internal;
public interface J {
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
module m2 {
exports p.two;
exports p.two.internal to test;
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package p.two;
public interface A {
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package p.two;
interface B {
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package p.two;
public class Bar {
public Bar() {
}
@Override
public String toString() {
return this.getClass().getName();
}
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package p.two.internal;
public interface C {
default int m() { return 2; }
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
module m3 {
requires transitive m2;
exports p.three;
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package p.three;
import p.two.Bar;
public interface P {
public Bar bar();
public Bar[][][] barArrays();
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package p.three.internal;
public interface Q {
default int m() {
throw new UnsupportedOperationException("Q::m is in a non-exported package");
}
}

View file

@ -0,0 +1,97 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
/**
* Tests invocation of default methods in exported types and inaccessible types
* in a named module
*/
public class DefaultMethods {
private final static Module TEST_MODULE = DefaultMethods.class.getModule();
private final static InvocationHandler IH = (proxy, method, params) -> {
return InvocationHandler.invokeDefault(proxy, method, params);
};
public static void main(String... args) throws Throwable {
// exported types from m1
testDefaultMethod(new Class<?>[] { p.one.I.class, p.two.A.class}, 1);
// qualified-exported type from m2
testDefaultMethod(new Class<?>[] { p.two.internal.C.class, p.two.A.class }, 2);
// module-private type from test module
testDefaultMethod(new Class<?>[] { jdk.test.internal.R.class }, 10);
// non-public interface in the same runtime package
testDefaultMethod(new Class<?>[] { Class.forName("jdk.test.NP") }, 100);
// inaccessible type - not exported to test module
Class<?> qType = Class.forName("p.three.internal.Q");
inaccessibleDefaultMethod(qType);
// non-public interface in the same runtime package
Class<?> nonPublicType = Class.forName("jdk.test.internal.NP");
inaccessibleDefaultMethod(nonPublicType);
}
static void testDefaultMethod(Class<?>[] intfs, int expected) throws Exception {
Object proxy = Proxy.newProxyInstance(TEST_MODULE.getClassLoader(), intfs, IH);
if (!proxy.getClass().getModule().isNamed()) {
throw new RuntimeException(proxy.getClass() + " expected to be in a named module");
}
Method m = intfs[0].getMethod("m");
int result = (int)m.invoke(proxy);
if (result != expected) {
throw new RuntimeException("return value: " + result + " expected: " + expected);
}
}
static void inaccessibleDefaultMethod(Class<?> intf) throws Throwable {
Object proxy = Proxy.newProxyInstance(TEST_MODULE.getClassLoader(), new Class<?>[] { intf }, IH);
if (!proxy.getClass().getModule().isNamed()) {
throw new RuntimeException(proxy.getClass() + " expected to be in a named module");
}
Method m = intf.getMethod("m");
try {
InvocationHandler.invokeDefault(proxy, m, null);
throw new RuntimeException("IAE not thrown invoking: " + m);
} catch (IllegalAccessException e) {}
if (m.trySetAccessible()) {
try {
m.invoke(proxy);
throw new RuntimeException("IAE not thrown invoking: " + m);
} catch (InvocationTargetException e) {
// IAE wrapped by InvocationHandler::invoke with UndeclaredThrowableException
// then wrapped by Method::invoke with InvocationTargetException
assert e.getCause() instanceof UndeclaredThrowableException;
Throwable cause = e.getCause().getCause();
if (!(cause instanceof IllegalAccessException))
throw e;
}
}
}
}

View file

@ -0,0 +1,160 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test;
import java.net.URL;
import java.net.URLClassLoader;
import static jdk.test.ProxyTest.*;
public class Main {
public static void main(String... args) {
ProxyTest ptest = new jdk.test.ProxyTest();
for (Data d : proxiesForExportedTypes()) {
ptest.test(d);
}
for (Data d : proxiesForPackagePrivateTypes()) {
ptest.test(d);
}
for (Data d : proxiesForModulePrivateTypes()) {
ptest.test(d);
}
for (Data d : proxiesWithAddReads()) {
ptest.test(d);
}
for (Data d : proxiesWithAddExports()) {
ptest.test(d);
}
}
private final static Module m1 = p.one.I.class.getModule();
private final static Module m2 = p.two.A.class.getModule();
private final static Module m3 = p.three.P.class.getModule();
private final static Module test = Main.class.getModule();
private final static Class<?> unnamedModuleClass = classForName("q.U");
private final static Class<?> m3InternalType = classForName("p.three.internal.Q");
/*
* Test cases for proxy class to implement exported proxy interfaces
* will result in the unnamed module.
*
* The proxy class is accessible to unnamed module.
*/
static Data[] proxiesForExportedTypes() {
ClassLoader ld = Main.class.getClassLoader();
ClassLoader ld2 = new URLClassLoader(new URL[0], ld);
return new Data[] {
new Data(ld, Runnable.class),
new Data(ld, p.one.I.class),
new Data(ld, p.one.I.class, p.two.A.class),
new Data(ld, p.one.I.class, unnamedModuleClass),
new Data(ld2, Runnable.class),
new Data(ld2, p.one.I.class),
new Data(ld2, p.one.I.class, p.two.A.class),
new Data(ld2, p.one.I.class, unnamedModuleClass),
new Data(m1.getClassLoader(), p.one.I.class),
new Data(m2.getClassLoader(), p.two.A.class),
new Data(m3.getClassLoader(), p.three.P.class),
};
}
/*
* Test cases for proxy class to implement package-private proxy interface
* will result in same runtime package and same module as the proxy interface
*
* The proxy class is accessible to classes in the same runtime package
*/
static Data[] proxiesForPackagePrivateTypes() {
Class<?> bClass = classForName("p.two.B"); // package-private type
return new Data[] {
new Data(m2, m2.getClassLoader(), p.two.A.class, bClass),
new Data(m2, m2.getClassLoader(), p.two.A.class, bClass, p.two.internal.C.class)
};
}
/*
* Test cases for proxy class to implement one or more module-private types.
*
* This will result in a dynamic module which can read the modules of the interfaces
* and their dependences and also qualified exports to the module-private packages.
* The proxy class is not accessible to any module.
*/
static Data[] proxiesForModulePrivateTypes() {
ClassLoader ld = Main.class.getClassLoader();
ClassLoader customLoader = new URLClassLoader(new URL[0], ld);
return new Data[] {
// different loaders
new Data(m1.getClassLoader(), p.one.internal.J.class),
new Data(customLoader, p.one.internal.J.class),
new Data(m2.getClassLoader(), p.two.internal.C.class, Runnable.class),
// interfaces from m2 only
new Data(m2.getClassLoader(), p.two.internal.C.class, p.two.A.class),
// p.two.A is accessible to m3
new Data(m3.getClassLoader(), m3InternalType, p.two.A.class),
new Data(customLoader, unnamedModuleClass, jdk.test.internal.R.class, p.one.I.class),
// two module-private types in two different modules
new Data(m3.getClassLoader(), p.two.internal.C.class, m3InternalType),
new Data(m3.getClassLoader(), p.three.P.class, m3InternalType, jdk.test.internal.R.class),
};
}
/*
* Test cases for proxy class to implement accessible proxy interfaces
* after addReads. That does not change the target module.
*/
static Data[] proxiesWithAddReads() {
Module unnamed = test.getClassLoader().getUnnamedModule();
test.addReads(unnamed);
return new Data[] {
new Data(test.getClassLoader(),
unnamedModuleClass, p.one.I.class,
jdk.test.internal.R.class), // module-private interface in test
};
}
/*
* Test cases for proxy class to implement accessible proxy interfaces
* after addExports. That does not change the target module.
*/
static Data[] proxiesWithAddExports() {
return new Data[] {
new Data(test.getClassLoader(),
p.one.internal.J.class,
p.two.internal.C.class), // module-private interfaces in m2 and m3
};
}
static Class<?> classForName(String cn) {
try {
return Class.forName(cn);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test;
/*
* Non-public interface
*/
interface NP {
void test();
default int m() {
return 100;
}
}

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test;
import jdk.test.internal.*;
import jdk.test.internal.foo.*;
import p.two.Bar;
import p.three.P;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.net.URLClassLoader;
/**
* Test proxy class to have access to types referenced in the public methods.
*/
public class ProxyClassAccess {
public static void main(String... args) throws Exception {
testImplClass();
testProxyClass1();
testProxyClass2();
testNonPublicProxy();
}
/*
* Invoke methods from implementation class
*/
static void testImplClass() {
R impl = new RImpl();
impl.foo();
Bar[][] bars = new Bar[0][0];
impl.setBarArray(bars);
try {
impl.throwException();
throw new RuntimeException("FooException not thrown");
} catch (FooException e) { }
}
/*
* Invoke methods via proxy
*/
static void testProxyClass1() {
R proxy = (R) Proxy.newProxyInstance(R.class.getClassLoader(),
new Class<?>[] { R.class }, handler);
proxy.foo();
Bar[][] bars = new Bar[0][0];
proxy.setBarArray(bars);
}
/*
* Invoke methods via proxy defined with a custom class loader
*/
static void testProxyClass2() {
URLClassLoader loader = new URLClassLoader(new URL[0]);
P proxy = (P) Proxy.newProxyInstance(loader,
new Class<?>[] { R.class, P.class }, handler);
proxy.bar();
proxy.barArrays();
}
static void testNonPublicProxy() {
NP proxy = (NP) Proxy.newProxyInstance(NP.class.getClassLoader(),
new Class<?>[]{NP.class}, handler);
proxy.test();
try {
URLClassLoader loader = new URLClassLoader(new URL[0]);
proxy = (NP) Proxy.newProxyInstance(loader,
new Class<?>[]{NP.class}, handler);
throw new RuntimeException("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
}
static InvocationHandler handler = new InvocationHandler() {
final R impl = new RImpl();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == R.class) {
return method.invoke(impl, args);
} else {
return null;
}
}
};
}

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class ProxyTest {
public static class Data {
private static int count = 0;
final int testcase;
final ClassLoader loader;
final Module module;
final Class<?>[] interfaces;
// Expected the proxy class in the specified module
public Data(Module m, ClassLoader loader, Class<?>... interfaces) {
this.module = m;
this.loader = loader;
this.interfaces = interfaces;
this.testcase = ++count;
}
// Expected the proxy class in a dynamic module
public Data(ClassLoader loader, Class<?>... interfaces) {
this(null, loader, interfaces);
}
@Override
public String toString() {
String expected = module != null
? (module.isNamed() ? module.getName() : "unnamed")
: "dynamic";
return String.format("%2d: Expected: %s %s loader: %s", testcase, expected,
Arrays.toString(interfaces), loader);
}
}
public void test(Data d) {
System.out.println(d);
if (d.module != null) {
testProxyClass(d.module, d.loader, d.interfaces);
} else {
testDynamicModule(d);
}
}
private void testDynamicModule(Data d) {
Class<?> proxyClass = Proxy.getProxyClass(d.loader, d.interfaces);
assertDynamicModule(proxyClass.getModule(), d.loader, proxyClass);
Object proxy = Proxy.newProxyInstance(d.loader, d.interfaces, handler);
assertDynamicModule(proxy.getClass().getModule(), d.loader, proxy.getClass());
}
private static void testProxyClass(Module module, ClassLoader ld, Class<?>... interfaces) {
Class<?> proxyClass = Proxy.getProxyClass(ld, interfaces);
assertEquals(proxyClass.getModule(), module);
Object proxy = Proxy.newProxyInstance(ld, interfaces, handler);
assertEquals(proxy.getClass().getModule(), module);
}
public static void assertDynamicModule(Module m, ClassLoader ld, Class<?> proxyClass) {
if (!m.isNamed() || !m.getName().startsWith("jdk.proxy")) {
throw new RuntimeException(m.getName() + " not dynamic module");
}
if (ld != m.getClassLoader() || proxyClass.getClassLoader() != ld) {
throw new RuntimeException("unexpected class loader");
}
try {
Constructor<?> cons = proxyClass.getConstructor(InvocationHandler.class);
cons.newInstance(handler);
// the exported package has the same name as the dynamic module
if (!proxyClass.getPackageName().equals(m.getName())) {
throw new RuntimeException("Expected IllegalAccessException: " + proxyClass);
}
} catch (IllegalAccessException e) {
// expected
} catch (NoSuchMethodException|InstantiationException|InvocationTargetException e) {
throw new RuntimeException(e);
}
}
public static void assertEquals(Object o1, Object o2) {
if (o1 != o2) {
throw new RuntimeException(o1 + " != " + o2);
}
}
private final static InvocationHandler handler =
(proxy, m, params) -> { throw new RuntimeException(m.toString()); };
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.internal;
/*
* Non-public interface
*/
interface NP {
default int m() {
throw new UnsupportedOperationException("non-public interface: " + NP.class.getName());
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.internal;
import jdk.test.internal.foo.*;
import p.two.Bar;
public interface R {
public Foo foo();
public void throwException() throws FooException;
public void setBarArray(Bar[][] array);
default int m() { return 10; }
}

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.internal;
import jdk.test.internal.foo.*;
import p.two.Bar;
public class RImpl implements R {
public Foo foo() {
return new Foo();
}
public void throwException() throws FooException {
throw new FooException();
}
public void setBarArray(Bar[][] array) {
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.internal.foo;
public class Foo {
@Override
public String toString() {
return this.getClass().getName();
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.internal.foo;
public class FooException extends RuntimeException {
public FooException() {
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
module test {
requires m1;
requires m3; // requires transitive m2
exports jdk.test;
}