use of java.lang.module.ModuleReference in project Bytecoder by mirkosertic.
the class ModulePatcher method patchIfNeeded.
/**
* Returns a module reference that interposes on the given module if
* needed. If there are no patches for the given module then the module
* reference is simply returned. Otherwise the patches for the module
* are scanned (to find any new packages) and a new module reference is
* returned.
*
* @throws UncheckedIOException if an I/O error is detected
*/
public ModuleReference patchIfNeeded(ModuleReference mref) {
// if there are no patches for the module then nothing to do
ModuleDescriptor descriptor = mref.descriptor();
String mn = descriptor.name();
List<Path> paths = map.get(mn);
if (paths == null)
return mref;
// Scan the JAR file or directory tree to get the set of packages.
// For automatic modules then packages that do not contain class files
// must be ignored.
Set<String> packages = new HashSet<>();
boolean isAutomatic = descriptor.isAutomatic();
try {
for (Path file : paths) {
if (Files.isRegularFile(file)) {
// is not supported by the boot class loader
try (JarFile jf = new JarFile(file.toString())) {
jf.stream().filter(e -> !e.isDirectory() && (!isAutomatic || e.getName().endsWith(".class"))).map(e -> toPackageName(file, e)).filter(Checks::isPackageName).forEach(packages::add);
}
} else if (Files.isDirectory(file)) {
// exploded directory without following sym links
Path top = file;
Files.find(top, Integer.MAX_VALUE, ((path, attrs) -> attrs.isRegularFile())).filter(path -> (!isAutomatic || path.toString().endsWith(".class")) && !isHidden(path)).map(path -> toPackageName(top, path)).filter(Checks::isPackageName).forEach(packages::add);
}
}
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
// if there are new packages then we need a new ModuleDescriptor
packages.removeAll(descriptor.packages());
if (!packages.isEmpty()) {
Builder builder = JLMA.newModuleBuilder(descriptor.name(), /*strict*/
false, descriptor.modifiers());
if (!descriptor.isAutomatic()) {
descriptor.requires().forEach(builder::requires);
descriptor.exports().forEach(builder::exports);
descriptor.opens().forEach(builder::opens);
descriptor.uses().forEach(builder::uses);
}
descriptor.provides().forEach(builder::provides);
descriptor.version().ifPresent(builder::version);
descriptor.mainClass().ifPresent(builder::mainClass);
// original + new packages
builder.packages(descriptor.packages());
builder.packages(packages);
descriptor = builder.build();
}
// return a module reference to the patched module
URI location = mref.location().orElse(null);
ModuleTarget target = null;
ModuleHashes recordedHashes = null;
ModuleHashes.HashSupplier hasher = null;
ModuleResolution mres = null;
if (mref instanceof ModuleReferenceImpl) {
ModuleReferenceImpl impl = (ModuleReferenceImpl) mref;
target = impl.moduleTarget();
recordedHashes = impl.recordedHashes();
hasher = impl.hasher();
mres = impl.moduleResolution();
}
return new ModuleReferenceImpl(descriptor, location, () -> new PatchedModuleReader(paths, mref), this, target, recordedHashes, hasher, mres);
}
use of java.lang.module.ModuleReference in project Bytecoder by mirkosertic.
the class ModulePath method scanDirectory.
/**
* 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;
}
use of java.lang.module.ModuleReference in project Bytecoder by mirkosertic.
the class ModuleReferences method newJarModule.
/**
* 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);
}
use of java.lang.module.ModuleReference in project Bytecoder by mirkosertic.
the class SystemModuleFinders method of.
/**
* Returns a ModuleFinder that is backed by the given SystemModules object.
*
* @apiNote The returned ModuleFinder is thread safe.
*/
static ModuleFinder of(SystemModules systemModules) {
ModuleDescriptor[] descriptors = systemModules.moduleDescriptors();
ModuleTarget[] targets = systemModules.moduleTargets();
ModuleHashes[] recordedHashes = systemModules.moduleHashes();
ModuleResolution[] moduleResolutions = systemModules.moduleResolutions();
int moduleCount = descriptors.length;
ModuleReference[] mrefs = new ModuleReference[moduleCount];
@SuppressWarnings(value = { "rawtypes", "unchecked" }) Map.Entry<String, ModuleReference>[] map = (Map.Entry<String, ModuleReference>[]) new Map.Entry[moduleCount];
Map<String, byte[]> nameToHash = generateNameToHash(recordedHashes);
for (int i = 0; i < moduleCount; i++) {
String name = descriptors[i].name();
HashSupplier hashSupplier = hashSupplier(nameToHash, name);
ModuleReference mref = toModuleReference(descriptors[i], targets[i], recordedHashes[i], hashSupplier, moduleResolutions[i]);
mrefs[i] = mref;
map[i] = Map.entry(name, mref);
}
return new SystemModuleFinder(mrefs, map);
}
use of java.lang.module.ModuleReference in project Bytecoder by mirkosertic.
the class SystemModuleFinders method toModuleReference.
/**
* Creates a ModuleReference to the system module.
*/
static ModuleReference toModuleReference(ModuleDescriptor descriptor, ModuleTarget target, ModuleHashes recordedHashes, HashSupplier hasher, ModuleResolution mres) {
String mn = descriptor.name();
URI uri = JNUA.create("jrt", "/".concat(mn));
Supplier<ModuleReader> readerSupplier = new Supplier<>() {
@Override
public ModuleReader get() {
return new SystemModuleReader(mn, uri);
}
};
ModuleReference mref = new ModuleReferenceImpl(descriptor, uri, readerSupplier, null, target, recordedHashes, hasher, mres);
// may need a reference to a patched module if --patch-module specified
mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
return mref;
}
Aggregations