use of java.lang.module.FindException in project Bytecoder by mirkosertic.
the class ModulePath method scan.
/**
* Scan the given module path entry. If the entry is a directory then it is
* a directory of modules or an exploded module. If the entry is a regular
* file then it is assumed to be a packaged module.
*
* @throws FindException if an error occurs scanning the entry
*/
private Map<String, ModuleReference> scan(Path entry) {
BasicFileAttributes attrs;
try {
attrs = Files.readAttributes(entry, BasicFileAttributes.class);
} catch (NoSuchFileException e) {
return Collections.emptyMap();
} catch (IOException ioe) {
throw new FindException(ioe);
}
try {
if (attrs.isDirectory()) {
Path mi = entry.resolve(MODULE_INFO);
if (!Files.exists(mi)) {
// assume a directory of modules
return scanDirectory(entry);
}
}
// packaged or exploded module
ModuleReference mref = readModule(entry, attrs);
if (mref != null) {
String name = mref.descriptor().name();
return Collections.singletonMap(name, mref);
}
// not recognized
String msg;
if (!isLinkPhase && entry.toString().endsWith(".jmod")) {
msg = "JMOD format not supported at execution time";
} else {
msg = "Module format not recognized";
}
throw new FindException(msg + ": " + entry);
} catch (IOException ioe) {
throw new FindException(ioe);
}
}
use of java.lang.module.FindException in project Bytecoder by mirkosertic.
the class ModulePath method deriveModuleDescriptor.
/**
* Treat the given JAR file as a module as follows:
*
* 1. The value of the Automatic-Module-Name attribute is the module name
* 2. The version, and the module name when the Automatic-Module-Name
* attribute is not present, is derived from the file ame of the JAR file
* 3. All packages are derived from the .class files in the JAR file
* 4. The contents of any META-INF/services configuration files are mapped
* to "provides" declarations
* 5. The Main-Class attribute in the main attributes of the JAR manifest
* is mapped to the module descriptor mainClass if possible
*/
private ModuleDescriptor deriveModuleDescriptor(JarFile jf) throws IOException {
// Read Automatic-Module-Name attribute if present
Manifest man = jf.getManifest();
Attributes attrs = null;
String moduleName = null;
if (man != null) {
attrs = man.getMainAttributes();
if (attrs != null) {
moduleName = attrs.getValue(AUTOMATIC_MODULE_NAME);
}
}
// Derive the version, and the module name if needed, from JAR file name
String fn = jf.getName();
int i = fn.lastIndexOf(File.separator);
if (i != -1)
fn = fn.substring(i + 1);
// drop ".jar"
String name = fn.substring(0, fn.length() - 4);
String vs = null;
// find first occurrence of -${NUMBER}. or -${NUMBER}$
Matcher matcher = Patterns.DASH_VERSION.matcher(name);
if (matcher.find()) {
int start = matcher.start();
// attempt to parse the tail as a version string
try {
String tail = name.substring(start + 1);
ModuleDescriptor.Version.parse(tail);
vs = tail;
} catch (IllegalArgumentException ignore) {
}
name = name.substring(0, start);
}
// Create builder, using the name derived from file name when
// Automatic-Module-Name not present
Builder builder;
if (moduleName != null) {
try {
builder = ModuleDescriptor.newAutomaticModule(moduleName);
} catch (IllegalArgumentException e) {
throw new FindException(AUTOMATIC_MODULE_NAME + ": " + e.getMessage());
}
} else {
builder = ModuleDescriptor.newAutomaticModule(cleanModuleName(name));
}
// module version if present
if (vs != null)
builder.version(vs);
// scan the names of the entries in the JAR file
Map<Boolean, Set<String>> map = VersionedStream.stream(jf).filter(e -> !e.isDirectory()).map(JarEntry::getName).filter(e -> (e.endsWith(".class") ^ e.startsWith(SERVICES_PREFIX))).collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX), Collectors.toSet()));
Set<String> classFiles = map.get(Boolean.FALSE);
Set<String> configFiles = map.get(Boolean.TRUE);
// the packages containing class files
Set<String> packages = classFiles.stream().map(this::toPackageName).flatMap(Optional::stream).distinct().collect(Collectors.toSet());
// all packages are exported and open
builder.packages(packages);
// map names of service configuration files to service names
Set<String> serviceNames = configFiles.stream().map(this::toServiceName).flatMap(Optional::stream).collect(Collectors.toSet());
// parse each service configuration file
for (String sn : serviceNames) {
JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
List<String> providerClasses = new ArrayList<>();
try (InputStream in = jf.getInputStream(entry)) {
BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
String cn;
while ((cn = nextLine(reader)) != null) {
if (cn.length() > 0) {
String pn = packageName(cn);
if (!packages.contains(pn)) {
String msg = "Provider class " + cn + " not in module";
throw new InvalidModuleDescriptorException(msg);
}
providerClasses.add(cn);
}
}
}
if (!providerClasses.isEmpty())
builder.provides(sn, providerClasses);
}
// Main-Class attribute if it exists
if (attrs != null) {
String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
if (mainClass != null) {
mainClass = mainClass.replace("/", ".");
if (Checks.isClassName(mainClass)) {
String pn = packageName(mainClass);
if (packages.contains(pn)) {
builder.mainClass(mainClass);
}
}
}
}
return builder.build();
}
use of java.lang.module.FindException in project Bytecoder by mirkosertic.
the class ModulePath method readJar.
/**
* Returns a {@code ModuleReference} to a module in modular JAR file on
* the file system.
*
* @throws IOException
* @throws FindException
* @throws InvalidModuleDescriptorException
*/
private ModuleReference readJar(Path file) throws IOException {
try (JarFile jf = new JarFile(file.toFile(), // verify
true, ZipFile.OPEN_READ, releaseVersion)) {
ModuleInfo.Attributes attrs;
JarEntry entry = jf.getJarEntry(MODULE_INFO);
if (entry == null) {
// no module-info.class so treat it as automatic module
try {
ModuleDescriptor md = deriveModuleDescriptor(jf);
attrs = new ModuleInfo.Attributes(md, null, null, null);
} catch (RuntimeException e) {
throw new FindException("Unable to derive module descriptor for " + jf.getName(), e);
}
} else {
attrs = ModuleInfo.read(jf.getInputStream(entry), () -> jarPackages(jf));
}
return ModuleReferences.newJarModule(attrs, patcher, file);
} catch (ZipException e) {
throw new FindException("Error reading " + file, e);
}
}
use of java.lang.module.FindException 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.FindException in project Bytecoder by mirkosertic.
the class ModulePath method readModule.
/**
* Reads a packaged or exploded module, returning a {@code ModuleReference}
* to the module. Returns {@code null} if the entry is not recognized.
*
* @throws IOException if an I/O error occurs
* @throws FindException if an error occurs parsing its module descriptor
*/
private ModuleReference readModule(Path entry, BasicFileAttributes attrs) throws IOException {
try {
// exploded module
if (attrs.isDirectory()) {
// may return null
return readExplodedModule(entry);
}
// JAR or JMOD file
if (attrs.isRegularFile()) {
String fn = entry.getFileName().toString();
boolean isDefaultFileSystem = isDefaultFileSystem(entry);
// JAR file
if (fn.endsWith(".jar")) {
if (isDefaultFileSystem) {
return readJar(entry);
} else {
// the JAR file is in a custom file system so
// need to copy it to the local file system
Path tmpdir = Files.createTempDirectory("mlib");
Path target = Files.copy(entry, tmpdir.resolve(fn));
return readJar(target);
}
}
// JMOD file
if (isDefaultFileSystem && isLinkPhase && fn.endsWith(".jmod")) {
return readJMod(entry);
}
}
return null;
} catch (InvalidModuleDescriptorException e) {
throw new FindException("Error reading module: " + entry, e);
}
}
Aggregations