下面列出了怎么用java.lang.module.ModuleReference的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* Creates a {@code Loader} in a loader pool that loads classes/resources
* from one module.
*/
public Loader(ResolvedModule resolvedModule,
LoaderPool pool,
ClassLoader parent)
{
super("Loader-" + resolvedModule.name(), parent);
this.pool = pool;
this.parent = parent;
ModuleReference mref = resolvedModule.reference();
ModuleDescriptor descriptor = mref.descriptor();
String mn = descriptor.name();
this.nameToModule = Map.of(mn, mref);
Map<String, LoadedModule> localPackageToModule = new HashMap<>();
LoadedModule lm = new LoadedModule(mref);
descriptor.packages().forEach(pn -> localPackageToModule.put(pn, lm));
this.localPackageToModule = localPackageToModule;
this.acc = AccessController.getContext();
}
/**
* Test that a JAR file with a Main-Class attribute that is not a qualified
* type name.
*/
@Test(dataProvider = "badmainclass")
public void testBadMainClass(String mainClass, String ignore) throws IOException {
Manifest man = new Manifest();
Attributes attrs = man.getMainAttributes();
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
attrs.put(Attributes.Name.MAIN_CLASS, mainClass);
Path dir = Files.createTempDirectory(USER_DIR, "mods");
String entry = mainClass.replace('.', '/') + ".class";
createDummyJarFile(dir.resolve("m.jar"), man, entry);
// bad Main-Class value should be ignored
Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m");
assertTrue(omref.isPresent());
ModuleDescriptor descriptor = omref.get().descriptor();
assertFalse(descriptor.mainClass().isPresent());
}
/**
* Scans the next entry on the module path. A no-op if all entries have
* already been scanned.
*
* @throws FindException if an error occurs scanning the next entry
*/
private void scanNextEntry() {
if (hasNextEntry()) {
long t0 = System.nanoTime();
Path entry = entries[next];
Map<String, ModuleReference> modules = scan(entry);
next++;
// update cache, ignoring duplicates
int initialSize = cachedModules.size();
for (Map.Entry<String, ModuleReference> e : modules.entrySet()) {
cachedModules.putIfAbsent(e.getKey(), e.getValue());
}
// update counters
int added = cachedModules.size() - initialSize;
moduleCount.add(added);
scanTime.addElapsedTimeFrom(t0);
}
}
/**
* Load/register the modules to the built-in class loaders.
*/
private static void loadModules(Configuration cf,
Function<String, ClassLoader> clf) {
for (ResolvedModule resolvedModule : cf.modules()) {
ModuleReference mref = resolvedModule.reference();
String name = resolvedModule.name();
ClassLoader loader = clf.apply(name);
if (loader == null) {
// skip java.base as it is already loaded
if (!name.equals(JAVA_BASE)) {
BootLoader.loadModule(mref);
}
} else if (loader instanceof BuiltinClassLoader) {
((BuiltinClassLoader) loader).loadModule(mref);
}
}
}
/**
* Returns the URL to a resource in a module or {@code null} if not found.
*/
private URL findResource(ModuleReference mref, String name) throws IOException {
URI u;
if (System.getSecurityManager() == null) {
u = moduleReaderFor(mref).find(name).orElse(null);
} else {
try {
u = AccessController.doPrivileged(new PrivilegedExceptionAction<> () {
@Override
public URI run() throws IOException {
return moduleReaderFor(mref).find(name).orElse(null);
}
});
} catch (PrivilegedActionException pae) {
throw (IOException) pae.getCause();
}
}
if (u != null) {
try {
return u.toURL();
} catch (MalformedURLException | IllegalArgumentException e) { }
}
return null;
}
/**
* Test JAR file with META-INF/services configuration file with bad
* values or names.
*/
@Test(dataProvider = "badservices")
public void testBadServicesNames(String service, String provider)
throws IOException
{
Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");
Path services = tmpdir.resolve("META-INF").resolve("services");
Files.createDirectories(services);
Files.write(services.resolve(service), Set.of(provider));
Path dir = Files.createTempDirectory(USER_DIR, "mods");
JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir);
Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m");
assertTrue(omref.isPresent());
ModuleDescriptor descriptor = omref.get().descriptor();
assertTrue(descriptor.provides().isEmpty());
}
/**
* Returns the ModuleReader for the given module, creating it if needed.
*/
private ModuleReader moduleReaderFor(ModuleReference mref) {
ModuleReader reader = moduleToReader.get(mref);
if (reader == null) {
// avoid method reference during startup
Function<ModuleReference, ModuleReader> create = new Function<>() {
public ModuleReader apply(ModuleReference moduleReference) {
try {
return mref.open();
} catch (IOException e) {
// Return a null module reader to avoid a future class
// load attempting to open the module again.
return new NullModuleReader();
}
}
};
reader = moduleToReader.computeIfAbsent(mref, create);
}
return reader;
}
/**
* Creates a ModuleReference to a possibly-patched module
*/
private static ModuleReference newModule(ModuleInfo.Attributes attrs,
URI uri,
Supplier<ModuleReader> supplier,
ModulePatcher patcher,
HashSupplier hasher) {
ModuleReference mref = new ModuleReferenceImpl(attrs.descriptor(),
uri,
supplier,
null,
attrs.target(),
attrs.recordedHashes(),
hasher,
attrs.moduleResolution());
if (patcher != null)
mref = patcher.patchIfNeeded(mref);
return mref;
}
/**
* Creates the ModuleReader to reads resources in a patched module.
*/
PatchedModuleReader(List<Path> patches, ModuleReference mref) {
List<ResourceFinder> finders = new ArrayList<>();
boolean initialized = false;
try {
for (Path file : patches) {
if (Files.isRegularFile(file)) {
finders.add(new JarResourceFinder(file));
} else {
finders.add(new ExplodedResourceFinder(file));
}
}
initialized = true;
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
} finally {
// close all ResourceFinder in the event of an error
if (!initialized) closeAll(finders);
}
this.finders = finders;
this.mref = mref;
this.delegateCodeSourceURL = codeSourceURL(mref);
}
/**
* Prints the module location and name, checks if the module is
* shadowed by a previously seen module, and finally checks for
* package conflicts with previously seen modules.
*/
void process(ModuleReference mref) {
printModule(mref);
String name = mref.descriptor().name();
ModuleReference previous = nameToModule.putIfAbsent(name, mref);
if (previous != null) {
ostream.print(INDENT + "shadowed by ");
printModule(previous);
} else {
// check for package conflicts when not shadowed
for (String pkg : mref.descriptor().packages()) {
previous = packageToModule.putIfAbsent(pkg, mref);
if (previous != null) {
String mn = previous.descriptor().name();
ostream.println(INDENT + "contains " + pkg
+ " conflicts with module " + mn);
errorFound = true;
}
}
}
}
private static Optional<ModuleReference> validateModuleReferenceFromArtifact(Log log, ArtifactDescriptor resolvedArtifact) {
var finder = ModuleFinder.of(resolvedArtifact.getPath());
Set<ModuleReference> moduleReferences;
try {
moduleReferences = finder.findAll();
} catch (FindException e) {
log.info(null, __ -> "WARNING! finding " + resolvedArtifact + " failed: " + e);
return Optional.empty();
}
var referenceOpt = moduleReferences.stream().findFirst();
if (!referenceOpt.isPresent()) {
log.info(null, __ -> "WARNING! artifact " + resolvedArtifact + " is not a valid jar");
return Optional.empty();
}
return referenceOpt;
}
private static Optional<String> findMainModule(List<Path> modulePath, Log log) {
for(var path: modulePath) {
var finder = ModuleFinder.of(path);
var mainClasses = finder.findAll().stream()
.map(ModuleReference::descriptor)
.flatMap(desc -> desc.mainClass().map(mainClass -> desc.name() + '/' + mainClass).stream())
.collect(toUnmodifiableSet());
switch(mainClasses.size()) {
case 0:
break;
case 1:
return Optional.of(mainClasses.iterator().next());
default:
log.error(mainClasses, _mainClasses -> "several main classes found " + String.join(", ", _mainClasses));
return Optional.empty();
}
}
log.error(modulePath, _modulePath -> "no main class found in " + _modulePath.stream().map(Path::toString).collect(joining(":")));
return Optional.empty();
}
/**
* Returns the URL to a resource in a module or {@code null} if not found.
*/
private URL findResource(ModuleReference mref, String name) throws IOException {
URI u;
if (System.getSecurityManager() == null) {
u = moduleReaderFor(mref).find(name).orElse(null);
} else {
try {
u = AccessController.doPrivileged(new PrivilegedExceptionAction<> () {
@Override
public URI run() throws IOException {
return moduleReaderFor(mref).find(name).orElse(null);
}
});
} catch (PrivilegedActionException pae) {
throw (IOException) pae.getCause();
}
}
if (u != null) {
try {
return u.toURL();
} catch (MalformedURLException | IllegalArgumentException e) { }
}
return null;
}
void add(ModuleDescriptor... descriptors) {
for (ModuleDescriptor descriptor: descriptors) {
String name = descriptor.name();
if (!namesToReference.containsKey(name)) {
//modules.add(descriptor);
URI uri = URI.create("module:/" + descriptor.name());
ModuleReference mref = new ModuleReference(descriptor, uri) {
@Override
public ModuleReader open() {
throw new UnsupportedOperationException();
}
};
namesToReference.put(name, mref);
}
}
}
/**
* Scan a JAR file or exploded module.
*/
private Optional<ModuleReference> scanModule(Path entry) {
ModuleFinder finder = ModuleFinder.of(entry);
try {
return finder.findAll().stream().findFirst();
} catch (FindException e) {
ostream.println(entry);
ostream.println(INDENT + e.getMessage());
Throwable cause = e.getCause();
if (cause != null) {
ostream.println(INDENT + cause);
}
errorFound = true;
return Optional.empty();
}
}
/**
* Test all packages are exported
*/
public void testPackages() throws IOException {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
createDummyJarFile(dir.resolve("m.jar"),
"p/C1.class", "p/C2.class", "q/C1.class");
ModuleFinder finder = ModuleFinder.of(dir);
Optional<ModuleReference> mref = finder.find("m");
assertTrue(mref.isPresent(), "m not found");
ModuleDescriptor descriptor = mref.get().descriptor();
assertTrue(descriptor.isAutomatic());
assertTrue(descriptor.packages().size() == 2);
assertTrue(descriptor.packages().contains("p"));
assertTrue(descriptor.packages().contains("q"));
assertTrue(descriptor.exports().isEmpty());
assertTrue(descriptor.opens().isEmpty());
}
public static void main(String[] args) throws IOException {
if (args.length != 1) {
System.err.println("Usage AddPackagesAttribute exploded-java-home");
System.exit(-1);
}
String home = args[0];
Path dir = Paths.get(home, "modules");
ModuleFinder finder = ModuleFinder.of(dir);
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path entry : stream) {
Path mi = entry.resolve("module-info.class");
if (Files.isRegularFile(mi)) {
String mn = entry.getFileName().toString();
Optional<ModuleReference> omref = finder.find(mn);
if (omref.isPresent()) {
Set<String> packages = omref.get().descriptor().packages();
addPackagesAttribute(mi, packages);
}
}
}
}
}
/**
* Test class files in JAR file where the entry does not correspond to a
* legal package name.
*/
public void testBadPackage() throws IOException {
Path dir = Files.createTempDirectory(USER_DIR, "mods");
createDummyJarFile(dir.resolve("m.jar"), "p/C1.class", "p-/C2.class");
ModuleFinder finder = ModuleFinder.of(dir);
Optional<ModuleReference> mref = finder.find("m");
assertTrue(mref.isPresent(), "m not found");
ModuleDescriptor descriptor = mref.get().descriptor();
assertTrue(descriptor.isAutomatic());
assertTrue(descriptor.packages().size() == 1);
assertTrue(descriptor.packages().contains("p"));
assertTrue(descriptor.exports().isEmpty());
assertTrue(descriptor.opens().isEmpty());
}
private static ModuleDescriptor primitiveModuleDescriptor(Path jar, String filename) throws IOException {
String tempName = "a" + jar.getFileName();
Path temp = Paths.get(System.getProperty("user.home"), tempName + ".jar");
ModuleDescriptor mod;
try {
Files.copy(jar, temp);
mod = ModuleFinder.of(temp) //
.findAll()
.stream()
.map(ModuleReference::descriptor)
.findAny()
.orElseThrow(IllegalStateException::new);
} finally {
Files.deleteIfExists(temp);
}
if (tempName.equals(mod.name())) {
String newModuleName = StringUtils.deriveModuleName(filename);
if (!StringUtils.isModuleName(newModuleName)) {
Warning.illegalModule(jar.getFileName().toString());
throw new IllegalStateException("Automatic module name '" + newModuleName + "' for file '"
+ jar.getFileName() + "' is not valid.");
}
return ModuleDescriptor.newAutomaticModule(newModuleName).packages(mod.packages()).build();
}
return mod;
}
/**
* Returns the URL to a resource in a module. Returns {@code null} if not found
* or an I/O error occurs.
*/
private URL findResourceOrNull(ModuleReference mref, String name) {
try {
return findResource(mref, name);
} catch (IOException ignore) {
return null;
}
}
private static int patchModularJar(ToolProvider jarTool, ModuleReference ref, Path generatedModuleInfo) {
System.out.println("[modulefixer] fix " + ref.descriptor().name());
return jarTool.run(System.out, System.err,
"--update",
"--file", Path.of(ref.location().orElseThrow()).toString(),
"-C", generatedModuleInfo.getParent().toString(),
generatedModuleInfo.getFileName().toString());
}
LoadedModule(ModuleReference mref) {
URL url = null;
if (mref.location().isPresent()) {
try {
url = mref.location().get().toURL();
} catch (MalformedURLException | IllegalArgumentException e) { }
}
this.mref = mref;
this.url = url;
this.cs = new CodeSource(url, (CodeSigner[]) null);
}
private static ModuleReference moduleReference(ModuleDescriptor descriptor, URI uri, ModuleReader moduleReader) {
return new ModuleReference(descriptor, uri) {
@Override
public ModuleReader open() {
return moduleReader;
}
@Override
public String toString() {
return descriptor.name() + " at " + uri;
}
};
}
/**
* Returns true if the given module opens the given package
* unconditionally.
*
* @implNote This method currently iterates over each of the open
* packages. This will be replaced once the ModuleDescriptor.Opens
* API is updated.
*/
private boolean isOpen(ModuleReference mref, String pn) {
ModuleDescriptor descriptor = mref.descriptor();
if (descriptor.isOpen() || descriptor.isAutomatic())
return true;
for (ModuleDescriptor.Opens opens : descriptor.opens()) {
String source = opens.source();
if (!opens.isQualified() && source.equals(pn)) {
return true;
}
}
return false;
}
LoadedModule(BuiltinClassLoader loader, ModuleReference mref) {
URL url = null;
this.uri = mref.location().orElse(null);
// for non-jrt schemes we need to resolve the codeSourceURL
// eagerly during bootstrap since the handler might be
// overridden
if (uri != null && !"jrt".equals(uri.getScheme())) {
url = createURL(uri);
}
this.loader = loader;
this.mref = mref;
this.codeSourceURL = url;
}
/**
* Scans the given directory for packaged or exploded modules.
*
* @return a map of module name to ModuleReference for the modules found
* in the directory
*
* @throws IOException if an I/O error occurs
* @throws FindException if an error occurs scanning the entry or the
* directory contains two or more modules with the same name
*/
private Map<String, ModuleReference> scanDirectory(Path dir)
throws IOException
{
// The map of name -> mref of modules found in this directory.
Map<String, ModuleReference> nameToReference = new HashMap<>();
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path entry : stream) {
BasicFileAttributes attrs;
try {
attrs = Files.readAttributes(entry, BasicFileAttributes.class);
} catch (NoSuchFileException ignore) {
// file has been removed or moved, ignore for now
continue;
}
ModuleReference mref = readModule(entry, attrs);
// module found
if (mref != null) {
// can have at most one version of a module in the directory
String name = mref.descriptor().name();
ModuleReference previous = nameToReference.put(name, mref);
if (previous != null) {
String fn1 = fileName(mref);
String fn2 = fileName(previous);
throw new FindException("Two versions of module "
+ name + " found in " + dir
+ " (" + fn1 + " and " + fn2 + ")");
}
}
}
}
return nameToReference;
}
public static ModuleTarget read(ModuleReference modRef) throws IOException {
ModuleReader reader = modRef.open();
try (InputStream in = reader.open("module-info.class").get()) {
return read(in);
} finally {
reader.close();
}
}
/**
* Returns true if the given module opens the given package
* unconditionally.
*
* @implNote This method currently iterates over each of the open
* packages. This will be replaced once the ModuleDescriptor.Opens
* API is updated.
*/
private boolean isOpen(ModuleReference mref, String pn) {
ModuleDescriptor descriptor = mref.descriptor();
if (descriptor.isOpen() || descriptor.isAutomatic())
return true;
for (ModuleDescriptor.Opens opens : descriptor.opens()) {
String source = opens.source();
if (!opens.isQualified() && source.equals(pn)) {
return true;
}
}
return false;
}
/**
* Creates a ModuleReference to a possibly-patched module in a modular JAR.
*/
static ModuleReference newJarModule(ModuleInfo.Attributes attrs,
ModulePatcher patcher,
Path file) {
URI uri = file.toUri();
Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
return newModule(attrs, uri, supplier, patcher, hasher);
}
/**
* Creates a ModuleReference to a possibly-patched exploded module.
*/
static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs,
ModulePatcher patcher,
Path dir) {
Supplier<ModuleReader> supplier = () -> new ExplodedModuleReader(dir);
return newModule(attrs, dir.toUri(), supplier, patcher, null);
}