mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8284942: Proxy building can just iterate superinterfaces once
Reviewed-by: mchung
This commit is contained in:
parent
2961b7eede
commit
0709a6a1fb
1 changed files with 52 additions and 55 deletions
|
@ -495,67 +495,54 @@ public class Proxy implements java.io.Serializable {
|
||||||
private static final ClassLoaderValue<Boolean> reverseProxyCache =
|
private static final ClassLoaderValue<Boolean> reverseProxyCache =
|
||||||
new ClassLoaderValue<>();
|
new ClassLoaderValue<>();
|
||||||
|
|
||||||
private static Class<?> defineProxyClass(Module m, List<Class<?>> interfaces) {
|
private record ProxyClassContext(Module module, String packageName, int accessFlags) {
|
||||||
String proxyPkg = null; // package to define proxy class in
|
private ProxyClassContext {
|
||||||
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
|
if (module.isNamed()) {
|
||||||
boolean nonExported = false;
|
if (packageName.isEmpty()) {
|
||||||
|
// Per JLS 7.4.2, unnamed package can only exist in unnamed modules.
|
||||||
|
// This means a package-private superinterface exist in the unnamed
|
||||||
|
// package of a named module.
|
||||||
|
throw new InternalError("Unnamed package cannot be added to " + module);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
if (!module.getDescriptor().packages().contains(packageName)) {
|
||||||
* Record the package of a non-public proxy interface so that the
|
throw new InternalError(packageName + " not exist in " + module.getName());
|
||||||
* proxy class will be defined in the same package. Verify that
|
}
|
||||||
* all non-public proxy interfaces are in the same package.
|
|
||||||
*/
|
if (!module.isOpen(packageName, Proxy.class.getModule())) {
|
||||||
for (Class<?> intf : interfaces) {
|
// Required for default method invocation
|
||||||
int flags = intf.getModifiers();
|
throw new InternalError(packageName + " not open to " + Proxy.class.getModule());
|
||||||
if (!Modifier.isPublic(flags)) {
|
|
||||||
accessFlags = Modifier.FINAL; // non-public, final
|
|
||||||
String pkg = intf.getPackageName();
|
|
||||||
if (proxyPkg == null) {
|
|
||||||
proxyPkg = pkg;
|
|
||||||
} else if (!pkg.equals(proxyPkg)) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"non-public interfaces from different packages");
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!intf.getModule().isExported(intf.getPackageName())) {
|
if (Modifier.isPublic(accessFlags)) {
|
||||||
// module-private types
|
// All proxy superinterfaces are public, must be in named dynamic module
|
||||||
nonExported = true;
|
throw new InternalError("public proxy in unnamed module: " + module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (proxyPkg == null) {
|
if ((accessFlags & ~Modifier.PUBLIC) != 0) {
|
||||||
// all proxy interfaces are public and exported
|
throw new InternalError("proxy access flags must be Modifier.PUBLIC or 0");
|
||||||
if (!m.isNamed())
|
|
||||||
throw new InternalError("unnamed module: " + m);
|
|
||||||
proxyPkg = nonExported ? PROXY_PACKAGE_PREFIX + "." + m.getName()
|
|
||||||
: m.getName();
|
|
||||||
} else if (proxyPkg.isEmpty() && m.isNamed()) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Unnamed package cannot be added to " + m);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m.isNamed()) {
|
|
||||||
if (!m.getDescriptor().packages().contains(proxyPkg)) {
|
|
||||||
throw new InternalError(proxyPkg + " not exist in " + m.getName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Class<?> defineProxyClass(ProxyClassContext context, List<Class<?>> interfaces) {
|
||||||
/*
|
/*
|
||||||
* Choose a name for the proxy class to generate.
|
* Choose a name for the proxy class to generate.
|
||||||
*/
|
*/
|
||||||
long num = nextUniqueNumber.getAndIncrement();
|
long num = nextUniqueNumber.getAndIncrement();
|
||||||
String proxyName = proxyPkg.isEmpty()
|
String proxyName = context.packageName().isEmpty()
|
||||||
? proxyClassNamePrefix + num
|
? proxyClassNamePrefix + num
|
||||||
: proxyPkg + "." + proxyClassNamePrefix + num;
|
: context.packageName() + "." + proxyClassNamePrefix + num;
|
||||||
|
|
||||||
ClassLoader loader = getLoader(m);
|
ClassLoader loader = getLoader(context.module());
|
||||||
trace(proxyName, m, loader, interfaces);
|
trace(proxyName, context.module(), loader, interfaces);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate the specified proxy class.
|
* Generate the specified proxy class.
|
||||||
*/
|
*/
|
||||||
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces, accessFlags);
|
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces,
|
||||||
|
context.accessFlags() | Modifier.FINAL);
|
||||||
try {
|
try {
|
||||||
Class<?> pc = JLA.defineClass(loader, proxyName, proxyClassFile,
|
Class<?> pc = JLA.defineClass(loader, proxyName, proxyClassFile,
|
||||||
null, "__dynamic_proxy__");
|
null, "__dynamic_proxy__");
|
||||||
|
@ -575,7 +562,7 @@ public class Proxy implements java.io.Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if given class is a class defined by
|
* Test if given class is a class defined by
|
||||||
* {@link #defineProxyClass(Module, List)}
|
* {@link #defineProxyClass(ProxyClassContext, List)}
|
||||||
*/
|
*/
|
||||||
static boolean isProxyClass(Class<?> c) {
|
static boolean isProxyClass(Class<?> c) {
|
||||||
return Objects.equals(reverseProxyCache.sub(c).get(c.getClassLoader()),
|
return Objects.equals(reverseProxyCache.sub(c).get(c.getClassLoader()),
|
||||||
|
@ -631,7 +618,7 @@ public class Proxy implements java.io.Serializable {
|
||||||
// ProxyBuilder instance members start here....
|
// ProxyBuilder instance members start here....
|
||||||
|
|
||||||
private final List<Class<?>> interfaces;
|
private final List<Class<?>> interfaces;
|
||||||
private final Module module;
|
private final ProxyClassContext context;
|
||||||
ProxyBuilder(ClassLoader loader, List<Class<?>> interfaces) {
|
ProxyBuilder(ClassLoader loader, List<Class<?>> interfaces) {
|
||||||
if (!VM.isModuleSystemInited()) {
|
if (!VM.isModuleSystemInited()) {
|
||||||
throw new InternalError("Proxy is not supported until "
|
throw new InternalError("Proxy is not supported until "
|
||||||
|
@ -648,8 +635,8 @@ public class Proxy implements java.io.Serializable {
|
||||||
validateProxyInterfaces(loader, interfaces, refTypes);
|
validateProxyInterfaces(loader, interfaces, refTypes);
|
||||||
|
|
||||||
this.interfaces = interfaces;
|
this.interfaces = interfaces;
|
||||||
this.module = mapToModule(loader, interfaces, refTypes);
|
this.context = proxyClassContext(loader, interfaces, refTypes);
|
||||||
assert getLoader(module) == loader;
|
assert getLoader(context.module()) == loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProxyBuilder(ClassLoader loader, Class<?> intf) {
|
ProxyBuilder(ClassLoader loader, Class<?> intf) {
|
||||||
|
@ -667,8 +654,7 @@ public class Proxy implements java.io.Serializable {
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("removal")
|
@SuppressWarnings("removal")
|
||||||
Constructor<?> build() {
|
Constructor<?> build() {
|
||||||
Class<?> proxyClass = defineProxyClass(module, interfaces);
|
Class<?> proxyClass = defineProxyClass(context, interfaces);
|
||||||
assert !module.isNamed() || module.isOpen(proxyClass.getPackageName(), Proxy.class.getModule());
|
|
||||||
|
|
||||||
final Constructor<?> cons;
|
final Constructor<?> cons;
|
||||||
try {
|
try {
|
||||||
|
@ -768,10 +754,11 @@ public class Proxy implements java.io.Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the module that the generated proxy class belongs to.
|
* Returns the context for the generated proxy class, including the
|
||||||
|
* module and the package it belongs to and whether it is package-private.
|
||||||
*
|
*
|
||||||
* If any of proxy interface is package-private, then the proxy class
|
* If any of proxy interface is package-private, then the proxy class
|
||||||
* is in the same module of the package-private interface.
|
* is in the same package and module as the package-private interface.
|
||||||
*
|
*
|
||||||
* If all proxy interfaces are public and in exported packages,
|
* If all proxy interfaces are public and in exported packages,
|
||||||
* then the proxy class is in a dynamic module in an unconditionally
|
* then the proxy class is in a dynamic module in an unconditionally
|
||||||
|
@ -785,14 +772,21 @@ public class Proxy implements java.io.Serializable {
|
||||||
*
|
*
|
||||||
* Reads edge and qualified exports are added for dynamic module to access.
|
* Reads edge and qualified exports are added for dynamic module to access.
|
||||||
*/
|
*/
|
||||||
private static Module mapToModule(ClassLoader loader,
|
private static ProxyClassContext proxyClassContext(ClassLoader loader,
|
||||||
List<Class<?>> interfaces,
|
List<Class<?>> interfaces,
|
||||||
Set<Class<?>> refTypes) {
|
Set<Class<?>> refTypes) {
|
||||||
Map<Class<?>, Module> packagePrivateTypes = new HashMap<>();
|
Map<Class<?>, Module> packagePrivateTypes = new HashMap<>();
|
||||||
|
boolean nonExported = false;
|
||||||
|
|
||||||
for (Class<?> intf : interfaces) {
|
for (Class<?> intf : interfaces) {
|
||||||
Module m = intf.getModule();
|
Module m = intf.getModule();
|
||||||
if (!Modifier.isPublic(intf.getModifiers())) {
|
if (!Modifier.isPublic(intf.getModifiers())) {
|
||||||
packagePrivateTypes.put(intf, m);
|
packagePrivateTypes.put(intf, m);
|
||||||
|
} else {
|
||||||
|
if (!intf.getModule().isExported(intf.getPackageName())) {
|
||||||
|
// module-private types
|
||||||
|
nonExported = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -838,7 +832,7 @@ public class Proxy implements java.io.Serializable {
|
||||||
Modules.addOpens(targetModule, targetPackageName, Proxy.class.getModule());
|
Modules.addOpens(targetModule, targetPackageName, Proxy.class.getModule());
|
||||||
}
|
}
|
||||||
// return the module of the package-private interface
|
// return the module of the package-private interface
|
||||||
return targetModule;
|
return new ProxyClassContext(targetModule, targetPackageName, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// All proxy interfaces are public. So maps to a dynamic proxy module
|
// All proxy interfaces are public. So maps to a dynamic proxy module
|
||||||
|
@ -852,7 +846,10 @@ public class Proxy implements java.io.Serializable {
|
||||||
for (Class<?> c : types) {
|
for (Class<?> c : types) {
|
||||||
ensureAccess(targetModule, c);
|
ensureAccess(targetModule, c);
|
||||||
}
|
}
|
||||||
return targetModule;
|
|
||||||
|
var pkgName = nonExported ? PROXY_PACKAGE_PREFIX + '.' + targetModule.getName()
|
||||||
|
: targetModule.getName();
|
||||||
|
return new ProxyClassContext(targetModule, pkgName, Modifier.PUBLIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue