// special-case java.base as it is created before the boot layer if (loader == null && name.equals("java.base")) { return ModuleLayer.boot();
}
} returnnull;
}
// Returns the Module object that holds the enableNativeAccess // flag for this module. private Module moduleForNativeAccess() { return isNamed() ? this : ALL_UNNAMED_MODULE;
}
// This is invoked from Reflection.ensureNativeAccess void ensureNativeAccess(Class<?> owner, String methodName) { // The target module whose enableNativeAccess flag is ensured
Module target = moduleForNativeAccess(); // racy read of the enable native access flag boolean isNativeAccessEnabled = target.enableNativeAccess; if (!isNativeAccessEnabled) { synchronized (target) { // safe read of the enableNativeAccess of the target module
isNativeAccessEnabled = target.enableNativeAccess;
// check again with the safely read flag if (isNativeAccessEnabled) { // another thread beat us to it - nothing to do return;
} elseif (ModuleBootstrap.hasEnableNativeAccessFlag()) { thrownew IllegalCallerException("Illegal native access from: " + this);
} else { // warn and set flag, so that only one warning is reported per module
String cls = owner.getName();
String mtd = cls + "::" + methodName;
String mod = isNamed() ? "module " + getName() : "the unnamed module";
String modflag = isNamed() ? getName() : "ALL-UNNAMED";
System.err.printf("""
WARNING: A restricted method in %s has been called
WARNING: %s has been called by %s
WARNING: Use --enable-native-access=%s to avoid a warning forthis module
%n""", cls, mtd, mod, modflag);
// set the flag
target.enableNativeAccess = true;
}
}
}
}
// an unnamed module reads all modules if (!this.isNamed()) returntrue;
// all modules read themselves if (other == this) returntrue;
// check if this module reads other if (other.isNamed()) {
Set<Module> reads = this.reads; // volatile read if (reads != null && reads.contains(other)) returntrue;
}
// check if this module reads the other module reflectively if (ReflectionData.reads.containsKeyPair(this, other)) returntrue;
// if other is an unnamed module then check if this module reads // all unnamed modules if (!other.isNamed()
&& ReflectionData.reads.containsKeyPair(this, ALL_UNNAMED_MODULE)) returntrue;
// the packages are open to other modules, can be null // if the value contains EVERYONE_MODULE then the package is open to all privatevolatile Map<String, Set<Module>> openPackages;
// the packages that are exported, can be null // if the value contains EVERYONE_MODULE then the package is exported to all privatevolatile Map<String, Set<Module>> exportedPackages;
/** *Returns{@codetrue}ifthismoduleexportsoropensthegivenpackage *tothegivenmodule.Iftheothermoduleis{@codeEVERYONE_MODULE}then *thismethodtestsifthepackageisexportedoropenedunconditionally.
*/ privateboolean implIsExportedOrOpen(String pn, Module other, boolean open) { // all packages in unnamed modules are open if (!isNamed()) returntrue;
// all packages are exported/open to self if (other == this && descriptor.packages().contains(pn)) returntrue;
// all packages in open and automatic modules are open if (descriptor.isOpen() || descriptor.isAutomatic()) return descriptor.packages().contains(pn);
// exported/opened via module declaration/descriptor if (isStaticallyExportedOrOpen(pn, other, open)) returntrue;
// exported via addExports/addOpens if (isReflectivelyExportedOrOpen(pn, other, open)) returntrue;
// not exported or open to other returnfalse;
}
/** *Returns{@codetrue}ifthismoduleexportsoropensapackageto *thegivenmoduleviaitsmoduledeclarationorCLIoptions.
*/ privateboolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) { // test if package is open to everyone or <other>
Map<String, Set<Module>> openPackages = this.openPackages; if (openPackages != null && allows(openPackages.get(pn), other)) { returntrue;
}
if (!open) { // test package is exported to everyone or <other>
Map<String, Set<Module>> exportedPackages = this.exportedPackages; if (exportedPackages != null && allows(exportedPackages.get(pn), other)) { returntrue;
}
}
returnfalse;
}
/** *Returns{@codetrue}iftargetsisnon-nullandcontainsEVERYONE_MODULE *orthegivenmodule.Alsoreturnstrueifthegivenmoduleisanunnamed *moduleandtargetscontainsALL_UNNAMED_MODULE.
*/ privateboolean allows(Set<Module> targets, Module module) { if (targets != null) { if (targets.contains(EVERYONE_MODULE)) returntrue; if (module != EVERYONE_MODULE) { if (targets.contains(module)) returntrue; if (!module.isNamed() && targets.contains(ALL_UNNAMED_MODULE)) returntrue;
}
} returnfalse;
}
/** *Returns{@codetrue}ifthismodulereflectivelyexportsoropensthe *givenpackagetothegivenmodule.
*/ privateboolean isReflectivelyExportedOrOpen(String pn, Module other, boolean open) { // exported or open to all modules
Map<String, Boolean> exports = ReflectionData.exports.get(this, EVERYONE_MODULE); if (exports != null) { Boolean b = exports.get(pn); if (b != null) { boolean isOpen = b.booleanValue(); if (!open || isOpen) returntrue;
}
}
if (other != EVERYONE_MODULE) {
// exported or open to other
exports = ReflectionData.exports.get(this, other); if (exports != null) { Boolean b = exports.get(pn); if (b != null) { boolean isOpen = b.booleanValue(); if (!open || isOpen) returntrue;
}
}
// other is an unnamed module && exported or open to all unnamed if (!other.isNamed()) {
exports = ReflectionData.exports.get(this, ALL_UNNAMED_MODULE); if (exports != null) { Boolean b = exports.get(pn); if (b != null) { boolean isOpen = b.booleanValue(); if (!open || isOpen) returntrue;
}
}
}
if (isNamed()) {
Module caller = getCallerModule(Reflection.getCallerClass()); if (caller != this && (caller == null || !isOpen(pn, caller))) thrownew IllegalCallerException(pn + " is not open to " + caller);
implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true);
}
// all packages are open in unnamed, open, and automatic modules if (!isNamed() || descriptor.isOpen() || descriptor.isAutomatic()) return;
// check if the package is already exported/open to other if (implIsExportedOrOpen(pn, other, open)) return;
// can only export a package in the module if (!descriptor.packages().contains(pn)) { thrownew IllegalArgumentException("package " + pn
+ " not in contents");
}
// update VM first, just in case it fails if (syncVM) { if (other == EVERYONE_MODULE) {
addExportsToAll0(this, pn);
} elseif (other == ALL_UNNAMED_MODULE) {
addExportsToAllUnnamed0(this, pn);
} else {
addExports0(this, pn, other);
}
}
// add package name to exports if absent
Map<String, Boolean> map = ReflectionData.exports
.computeIfAbsent(this, other,
(m1, m2) -> new ConcurrentHashMap<>()); if (open) {
map.put(pn, Boolean.TRUE); // may need to promote from FALSE to TRUE
} else {
map.putIfAbsent(pn, Boolean.FALSE);
}
}
// replace this module's openPackages map with a new map that opens // the packages to all unnamed modules.
Map<String, Set<Module>> openPackages = this.openPackages; if (openPackages == null) {
openPackages = HashMap.newHashMap(concealedPkgs.size() + exportedPkgs.size());
} else {
openPackages = new HashMap<>(openPackages);
}
implAddOpensToAllUnnamed(concealedPkgs, openPackages);
implAddOpensToAllUnnamed(exportedPkgs, openPackages); this.openPackages = openPackages;
}
int numModules = cf.modules().size();
Map<String, Module> nameToModule = HashMap.newHashMap(numModules);
// to avoid repeated lookups and reduce iteration overhead, we create // arrays holding correlated information about each module.
ResolvedModule[] resolvedModules = new ResolvedModule[numModules];
Module[] modules = new Module[numModules];
ClassLoader[] classLoaders = new ClassLoader[numModules];
// record that we want to bind the layer to non-boot and non-platform // module loaders as a final step
HashSet<ClassLoader> toBindLoaders = new HashSet<>(4); boolean hasPlatformModules = false;
// map each module to a class loader
ClassLoader pcl = ClassLoaders.platformClassLoader(); boolean isModuleLoaderMapper = ModuleLoaderMap.isBuiltinMapper(clf);
for (int index = 0; index < numModules; index++) {
String name = resolvedModules[index].name();
ClassLoader loader = clf.apply(name);
if (loader == null || loader == pcl) { if (!isModuleLoaderMapper) { thrownew IllegalArgumentException("loader can't be 'null'"
+ " or the platform class loader");
}
hasPlatformModules = true;
} else {
toBindLoaders.add(loader);
}
classLoaders[index] = loader;
}
// define each module in the configuration to the VM for (int index = 0; index < numModules; index++) {
ModuleReference mref = resolvedModules[index].reference();
ModuleDescriptor descriptor = mref.descriptor();
String name = descriptor.name();
ClassLoader loader = classLoaders[index];
Module m; if (loader == null && name.equals("java.base")) { // java.base is already defined to the VM
m = Object.class.getModule();
} else {
URI uri = mref.location().orElse(null);
m = new Module(layer, loader, descriptor, uri);
}
nameToModule.put(name, m);
modules[index] = m;
}
// setup readability and exports/opens for (int index = 0; index < numModules; index++) {
ResolvedModule resolvedModule = resolvedModules[index];
ModuleReference mref = resolvedModule.reference();
ModuleDescriptor descriptor = mref.descriptor();
Module m = modules[index];
// reads
Set<Module> reads = new HashSet<>();
// name -> source Module when in parent layer
Map<String, Module> nameToSource = Map.of();
for (ResolvedModule other : resolvedModule.reads()) {
Module m2 = null; if (other.configuration() == cf) { // this configuration
m2 = nameToModule.get(other.name()); assert m2 != null;
} else { // parent layer for (ModuleLayer parent: layer.parents()) {
m2 = findModule(parent, other); if (m2 != null) break;
} assert m2 != null; if (nameToSource.isEmpty())
nameToSource = new HashMap<>();
nameToSource.put(other.name(), m2);
}
reads.add(m2);
// update VM view
addReads0(m, m2);
}
m.reads = reads;
// automatic modules read all unnamed modules if (descriptor.isAutomatic()) {
m.implAddReads(ALL_UNNAMED_MODULE, true);
}
// exports and opens, skipped for open and automatic if (!descriptor.isOpen() && !descriptor.isAutomatic()) { if (isBootLayer && descriptor.opens().isEmpty()) { // no open packages, no qualified exports to modules in parent layers
initExports(m, nameToModule);
} else {
initExportsAndOpens(m, nameToSource, nameToModule, layer.parents());
}
}
}
// if there are modules defined to the boot or platform class loaders // then register the modules in the class loader's services catalog if (hasPlatformModules) {
ServicesCatalog bootCatalog = BootLoader.getServicesCatalog();
ServicesCatalog pclCatalog = ServicesCatalog.getServicesCatalog(pcl); for (int index = 0; index < numModules; index++) {
ResolvedModule resolvedModule = resolvedModules[index];
ModuleReference mref = resolvedModule.reference();
ModuleDescriptor descriptor = mref.descriptor(); if (!descriptor.provides().isEmpty()) {
Module m = modules[index];
ClassLoader loader = classLoaders[index]; if (loader == null) {
bootCatalog.register(m);
} elseif (loader == pcl) {
pclCatalog.register(m);
}
}
}
}
// record that there is a layer with modules defined to the class loader for (ClassLoader loader : toBindLoaders) {
layer.bindToLoader(loader);
}
return nameToModule;
}
/** *FindtheruntimeModulecorrespondingtothegivenResolvedModule *inthegivenparentlayer(oritsparents).
*/ privatestatic Module findModule(ModuleLayer parent,
ResolvedModule resolvedModule) {
Configuration cf = resolvedModule.configuration();
String dn = resolvedModule.name(); return parent.layers()
.filter(l -> l.configuration() == cf)
.findAny()
.map(layer -> {
Optional<Module> om = layer.findModule(dn); assert om.isPresent() : dn + " not found in layer";
Module m = om.get(); assert m.getLayer() == layer : m + " not in expected layer"; return m;
})
.orElse(null);
}
/** *Initialize/setupamodule'sexports. * *@parammthemodule *@paramnameToModulemapofmodulenametoModule(forqualifiedexports)
*/ privatestaticvoid initExports(Module m, Map<String, Module> nameToModule) {
Map<String, Set<Module>> exportedPackages = new HashMap<>();
for (Exports exports : m.getDescriptor().exports()) {
String source = exports.source(); if (exports.isQualified()) { // qualified exports
Set<Module> targets = new HashSet<>(); for (String target : exports.targets()) {
Module m2 = nameToModule.get(target); if (m2 != null) {
addExports0(m, source, m2);
targets.add(m2);
}
} if (!targets.isEmpty()) {
exportedPackages.put(source, targets);
}
} else { // unqualified exports
addExportsToAll0(m, source);
exportedPackages.put(source, EVERYONE_SET);
}
}
if (!exportedPackages.isEmpty())
m.exportedPackages = exportedPackages;
}
// next the exports, skipping exports when the package is open for (Exports exports : descriptor.exports()) {
String source = exports.source();
// skip export if package is already open to everyone
Set<Module> openToTargets = openPackages.get(source); if (openToTargets != null && openToTargets.contains(EVERYONE_MODULE)) continue;
if (exports.isQualified()) { // qualified exports
Set<Module> targets = new HashSet<>(); for (String target : exports.targets()) {
Module m2 = findModule(target, nameToSource, nameToModule, parents); if (m2 != null) { // skip qualified export if already open to m2 if (openToTargets == null || !openToTargets.contains(m2)) {
addExports0(m, source, m2);
targets.add(m2);
}
}
} if (!targets.isEmpty()) {
exportedPackages.put(source, targets);
}
} else { // unqualified exports
addExportsToAll0(m, source);
exportedPackages.put(source, EVERYONE_SET);
}
}
if (!openPackages.isEmpty())
m.openPackages = openPackages; if (!exportedPackages.isEmpty())
m.exportedPackages = exportedPackages;
}
/** *FindtheruntimeModulewiththegivenname.Themodulenameisthe *nameofatargetmoduleinaqualifiedexportsoropensdirective. * *@paramtargetThetargetmoduletofind *@paramnameToSourceThemodulesinparentlayersthatareread *@paramnameToModuleThemodulesinthelayerunderconstruction *@paramparentsTheparentlayers
*/ privatestatic Module findModule(String target,
Map<String, Module> nameToSource,
Map<String, Module> nameToModule,
List<ModuleLayer> parents) {
Module m = nameToSource.get(target); if (m == null) {
m = nameToModule.get(target); if (m == null) { for (ModuleLayer parent : parents) {
m = parent.findModule(target).orElse(null); if (m != null) break;
}
}
} return m;
}
// -- annotations --
/** *{@inheritDoc} *Thismethodreturns{@codenull}wheninvokedonanunnamedmodule. * *<p>Notethatanyannotationreturnedbythismethodisa *declarationannotation.
*/
@Override public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { return moduleInfoClass().getDeclaredAnnotation(annotationClass);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.