boolean isAutomaticModuleNameAttributeAvailable(ModuleReference moduleReference) { try (var moduleReader = moduleReference.open()) { var manifestString = moduleReader .read("META-INF/MANIFEST.MF") .map(StandardCharsets.UTF_8::decode) .map(Object::toString) .orElse(""); if (manifestString.contains("Automatic-Module-Name")) { return true; } } catch (Exception e) { debug("reading manifest failed: {0}", e); } return false; }
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); } } }
private static Set<String> javaSE() { String root = "java.se.ee"; ModuleFinder system = ModuleFinder.ofSystem(); if (system.find(root).isPresent()) { return Stream.concat(Stream.of(root), Configuration.empty().resolve(system, ModuleFinder.of(), Set.of(root)) .findModule(root).get() .reads().stream() .map(ResolvedModule::name)) .collect(toSet()); } else { // approximation return system.findAll().stream() .map(ModuleReference::descriptor) .map(ModuleDescriptor::name) .filter(name -> name.startsWith("java.") && !name.equals("java.smartcardio")) .collect(Collectors.toSet()); } }
public Module toModule(ModuleReference mref) { try { String mn = mref.descriptor().name(); URI location = mref.location().orElseThrow(FileNotFoundException::new); ModuleDescriptor md = mref.descriptor(); Module.Builder builder = new Module.Builder(md, system.find(mn).isPresent()); final ClassFileReader reader; if (location.getScheme().equals("jrt")) { reader = system.getClassReader(mn); } else { reader = ClassFileReader.newInstance(Paths.get(location), version); } builder.classes(reader); builder.location(location); return builder.build(); } catch (IOException e) { throw new UncheckedIOException(e); } }
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 that a JAR file with a Main-Class attribute that is not in the module */ public void testMissingMainClassPackage() 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, "p.Main"); Path dir = Files.createTempDirectory(USER_DIR, "mods"); createDummyJarFile(dir.resolve("m.jar"), man); // Main-Class should be ignored because package p is not in module Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m"); assertTrue(omref.isPresent()); ModuleDescriptor descriptor = omref.get().descriptor(); assertFalse(descriptor.mainClass().isPresent()); }
/** * 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(); }
/** * Creates a {@code Loader} that loads classes/resources from a collection * of modules. * * @throws IllegalArgumentException * If two or more modules have the same package */ public Loader(Collection<ResolvedModule> modules, ClassLoader parent) { super(parent); this.pool = null; this.parent = parent; Map<String, ModuleReference> nameToModule = new HashMap<>(); Map<String, LoadedModule> localPackageToModule = new HashMap<>(); for (ResolvedModule resolvedModule : modules) { ModuleReference mref = resolvedModule.reference(); ModuleDescriptor descriptor = mref.descriptor(); nameToModule.put(descriptor.name(), mref); descriptor.packages().forEach(pn -> { LoadedModule lm = new LoadedModule(mref); if (localPackageToModule.put(pn, lm) != null) throw new IllegalArgumentException("Package " + pn + " in more than one module"); }); } this.nameToModule = nameToModule; this.localPackageToModule = localPackageToModule; this.acc = AccessController.getContext(); }
/** * Register a module this class loader. This has the effect of making the * types in the module visible. */ public void loadModule(ModuleReference mref) { String mn = mref.descriptor().name(); if (nameToModule.putIfAbsent(mn, mref) != null) { throw new InternalError(mn + " already defined to this loader"); } LoadedModule loadedModule = new LoadedModule(this, mref); for (String pn : mref.descriptor().packages()) { LoadedModule other = packageToModule.putIfAbsent(pn, loadedModule); if (other != null) { throw new InternalError(pn + " in modules " + mn + " and " + other.mref().descriptor().name()); } } // clear resources cache if VM is already initialized if (VM.isModuleSystemInited() && resourceCache != null) { resourceCache = null; } }
/** * Returns a URL to a resource of the given name in a module defined to * this class loader. */ @Override public URL findResource(String mn, String name) throws IOException { URL url = null; if (mn != null) { // find in module ModuleReference mref = nameToModule.get(mn); if (mref != null) { url = findResource(mref, name); } } else { // find on class path url = findResourceOnClassPath(name); } return checkURL(url); // check access before returning }
/** * Returns an input stream to a resource of the given name in a module * defined to this class loader. */ public InputStream findResourceAsStream(String mn, String name) throws IOException { // Need URL to resource when running with a security manager so that // the right permission check is done. if (System.getSecurityManager() != null || mn == null) { URL url = findResource(mn, name); return (url != null) ? url.openStream() : null; } // find in module defined to this loader, no security manager ModuleReference mref = nameToModule.get(mn); if (mref != null) { return moduleReaderFor(mref).open(name).orElse(null); } else { return null; } }
/** * 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; }
/** * 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; }
/** * Checks incubating status of modules in the configuration */ private static void checkIncubatingStatus(Configuration cf) { String incubating = null; for (ResolvedModule resolvedModule : cf.modules()) { ModuleReference mref = resolvedModule.reference(); // emit warning if the WARN_INCUBATING module resolution bit set if (ModuleResolution.hasIncubatingWarning(mref)) { String mn = mref.descriptor().name(); if (incubating == null) { incubating = mn; } else { incubating += ", " + mn; } } } if (incubating != null) warn("Using incubator modules: " + incubating); }
@Override public Optional<ModuleReference> find(String name) { Objects.requireNonNull(name); // try cached modules ModuleReference m = cachedModules.get(name); if (m != null) return Optional.of(m); // the module may not have been encountered yet while (hasNextEntry()) { scanNextEntry(); m = cachedModules.get(name); if (m != null) return Optional.of(m); } return Optional.empty(); }
/** * 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); } }
/** * 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()); }
/** * 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; } } } }
/** * 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 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()); }
static Configuration validate(ResourcePool pool) { checkPackages(pool); final Map<String, ModuleReference> nameToModRef = allModRefs(pool); final Set<ModuleReference> allRefs = new HashSet<>(nameToModRef.values()); final ModuleFinder finder = new ModuleFinder() { @Override public Optional<ModuleReference> find(String name) { return Optional.ofNullable(nameToModRef.get(name)); } @Override public Set<ModuleReference> findAll() { return allRefs; } }; return Configuration.empty().resolve( finder, ModuleFinder.of(), nameToModRef.keySet()); }
public static void main(String[] args) throws Exception { String mn = args[0]; ModuleReference mref = ModuleLayer.boot() .configuration() .findModule(mn) .map(ResolvedModule::reference) .orElseThrow(() -> new RuntimeException(mn + " not resolved!!")); try (ModuleReader reader = mref.open()) { reader.list().forEach(name -> { testFindUnchecked(name); // if the resource is a directory then find without trailing slash if (name.endsWith("/")) { testFindUnchecked(name.substring(0, name.length() - 1)); } }); } }
/** * Test ModuleFinder.ofSystem */ public void testOfSystem() { ModuleFinder finder = ModuleFinder.ofSystem(); assertTrue(finder.find("java.se").isPresent()); assertTrue(finder.find("java.base").isPresent()); assertFalse(finder.find("java.rhubarb").isPresent()); Set<String> names = finder.findAll().stream() .map(ModuleReference::descriptor) .map(ModuleDescriptor::name) .collect(Collectors.toSet()); assertTrue(names.contains("java.se")); assertTrue(names.contains("java.base")); assertFalse(names.contains("java.rhubarb")); }
/** * Test ModuleFinder with a JAR file containing a mix of class and * non-class resources. */ public void testOfOneJarFileWithResources() throws Exception { Path dir = Files.createTempDirectory(USER_DIR, "mods"); Path jar = createModularJar(dir.resolve("m.jar"), "m", "LICENSE", "README", "WEB-INF/tags", "p/Type.class", "p/resources/m.properties", "q-/Type.class", // not a legal package name "q-/resources/m/properties"); ModuleFinder finder = ModuleFinder.of(jar); Optional<ModuleReference> mref = finder.find("m"); assertTrue(mref.isPresent(), "m1 not found"); ModuleDescriptor descriptor = mref.get().descriptor(); assertTrue(descriptor.packages().size() == 2); assertTrue(descriptor.packages().contains("p")); assertTrue(descriptor.packages().contains("p.resources")); }
/** * Test ModuleFinder with an exploded module containing a mix of class * and non-class resources */ public void testOfOneExplodedModuleWithResources() throws Exception { Path dir = Files.createTempDirectory(USER_DIR, "mods"); Path m_dir = createExplodedModule(dir.resolve("m"), "m", "LICENSE", "README", "WEB-INF/tags", "p/Type.class", "p/resources/m.properties", "q-/Type.class", // not a legal package name "q-/resources/m/properties"); ModuleFinder finder = ModuleFinder.of(m_dir); Optional<ModuleReference> mref = finder.find("m"); assertTrue(mref.isPresent(), "m not found"); ModuleDescriptor descriptor = mref.get().descriptor(); assertTrue(descriptor.packages().size() == 2); assertTrue(descriptor.packages().contains("p")); assertTrue(descriptor.packages().contains("p.resources")); }
/** * Test non-class resources in a JAR file. */ public void testNonClassResources() throws IOException { Path dir = Files.createTempDirectory(USER_DIR, "mods"); createDummyJarFile(dir.resolve("m.jar"), "LICENSE", "README", "WEB-INF/tags", "p/Type.class", "p/resources/m.properties"); 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")); }
/** * 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()); }
private static Set<String> jdk() { return ModuleFinder.ofSystem().findAll().stream() .map(ModuleReference::descriptor) .map(ModuleDescriptor::name) .filter(name -> !JAVA_SE_SUBGRAPH.contains(name) && (name.startsWith("java.") || name.startsWith("jdk.") || name.startsWith("javafx."))) .collect(Collectors.toSet()); }
private void initProfiles() { // other system modules are not observed and not added in nameToModule map Map<String, Module> systemModules = system.moduleNames() .collect(toMap(Function.identity(), (mn) -> { Module m = nameToModule.get(mn); if (m == null) { ModuleReference mref = finder.find(mn).get(); m = toModule(mref); } return m; })); Profile.init(systemModules); }
private Map<String, ModuleReference> walk(Path root) { try (Stream<Path> stream = Files.walk(root, 1)) { return stream.filter(path -> !path.equals(root)) .map(this::toModuleReference) .collect(toMap(mref -> mref.descriptor().name(), Function.identity())); } catch (IOException e) { throw new UncheckedIOException(e); } }
static void genReport(Path outfile, Map<String, ModuleSummary> modules, Set<String> roots, String title) throws IOException { Configuration cf = resolve(roots); try (PrintStream out = new PrintStream(Files.newOutputStream(outfile))) { HtmlDocument doc = new HtmlDocument(title, modules); Set<ModuleDescriptor> descriptors = cf.modules().stream() .map(ResolvedModule::reference) .map(ModuleReference::descriptor) .collect(Collectors.toSet()); doc.writeTo(out, descriptors); } }
/** * Returns the location of the module if this named package is in * a named module; otherwise, returns null. */ URI location() { if (module.isNamed() && module.getLayer() != null) { Configuration cf = module.getLayer().configuration(); ModuleReference mref = cf.findModule(module.getName()).get().reference(); return mref.location().orElse(null); } return null; }
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); }
/** * Creates a ModuleReader for the given module. */ private ModuleReader createModuleReader(ModuleReference mref) { 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(); } }
/** * 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; if (mref.location().isPresent()) { try { url = mref.location().get().toURL(); } catch (MalformedURLException | IllegalArgumentException e) { } } this.loader = loader; this.mref = mref; this.codeSourceURL = url; }
public static void main(String... args) { Set<String> modules = ModuleFinder.ofSystem().findAll() .stream() .map(ModuleReference::descriptor) .map(ModuleDescriptor::name) .collect(Collectors.toSet()); Set<String> expected = Arrays.stream(args).collect(Collectors.toSet()); if (!modules.equals(expected)) { throw new RuntimeException(modules + " != " + expected); } }
/** * 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; } }