< prev index next >
src/java.base/share/classes/jdk/internal/module/ModulePath.java
Print this page
*** 1,7 ****
/*
! * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
--- 1,7 ----
/*
! * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*** 193,217 ****
try {
if (attrs.isDirectory()) {
Path mi = entry.resolve(MODULE_INFO);
if (!Files.exists(mi)) {
! // does not exist or unable to determine so 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);
} else {
! // skipped
! return Collections.emptyMap();
}
} catch (IOException ioe) {
throw new FindException(ioe);
}
}
--- 193,222 ----
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);
}
}
*** 264,307 ****
return nameToReference;
}
/**
! * Locates a packaged or exploded module, returning a {@code ModuleReference}
! * to the module. Returns {@code null} if the entry is skipped because it is
! * to a directory that does not contain a module-info.class or it's a hidden
! * file.
*
* @throws IOException if an I/O error occurs
! * @throws FindException if the file is not recognized as a module or an
! * error occurs parsing its module descriptor
*/
private ModuleReference readModule(Path entry, BasicFileAttributes attrs)
throws IOException
{
try {
if (attrs.isDirectory()) {
return readExplodedModule(entry); // may return null
! }
!
String fn = entry.getFileName().toString();
if (attrs.isRegularFile()) {
if (fn.endsWith(".jar")) {
return readJar(entry);
! } else if (fn.endsWith(".jmod")) {
! if (isLinkPhase)
return readJMod(entry);
- throw new FindException("JMOD files not supported: " + entry);
}
}
-
- // skip hidden files
- if (fn.startsWith(".") || Files.isHidden(entry)) {
return null;
- } else {
- throw new FindException("Unrecognized module: " + entry);
}
} catch (InvalidModuleDescriptorException e) {
throw new FindException("Error reading module: " + entry, e);
}
--- 269,301 ----
return nameToReference;
}
/**
! * 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 {
if (attrs.isDirectory()) {
return readExplodedModule(entry); // may return null
! } else {
String fn = entry.getFileName().toString();
if (attrs.isRegularFile()) {
if (fn.endsWith(".jar")) {
return readJar(entry);
! } else if (isLinkPhase && fn.endsWith(".jmod")) {
return readJMod(entry);
}
}
return null;
}
} catch (InvalidModuleDescriptorException e) {
throw new FindException("Error reading module: " + entry, e);
}
*** 360,370 ****
private static final String SERVICES_PREFIX = "META-INF/services/";
/**
* Returns the service type corresponding to the name of a services
! * configuration file if it is a valid Java identifier.
*
* For example, if called with "META-INF/services/p.S" then this method
* returns a container with the value "p.S".
*/
private Optional<String> toServiceName(String cf) {
--- 354,364 ----
private static final String SERVICES_PREFIX = "META-INF/services/";
/**
* Returns the service type corresponding to the name of a services
! * configuration file if it is a legal type name.
*
* For example, if called with "META-INF/services/p.S" then this method
* returns a container with the value "p.S".
*/
private Optional<String> toServiceName(String cf) {
*** 372,382 ****
int index = cf.lastIndexOf("/") + 1;
if (index < cf.length()) {
String prefix = cf.substring(0, index);
if (prefix.equals(SERVICES_PREFIX)) {
String sn = cf.substring(index);
! if (Checks.isJavaIdentifier(sn))
return Optional.of(sn);
}
}
return Optional.empty();
}
--- 366,376 ----
int index = cf.lastIndexOf("/") + 1;
if (index < cf.length()) {
String prefix = cf.substring(0, index);
if (prefix.equals(SERVICES_PREFIX)) {
String sn = cf.substring(index);
! if (Checks.isClassName(sn))
return Optional.of(sn);
}
}
return Optional.empty();
}
*** 401,415 ****
/**
* Treat the given JAR file as a module as follows:
*
* 1. The module name (and optionally the version) is derived from the file
* name of the JAR file
! * 2. All packages are exported and open
! * 3. It has no non-exported/non-open packages
! * 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
*/
private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
throws IOException
{
--- 395,408 ----
/**
* Treat the given JAR file as a module as follows:
*
* 1. The module name (and optionally the version) is derived from the file
* name of the JAR file
! * 2. All packages are derived from the .class files in the JAR file
! * 3. The contents of any META-INF/services configuration files are mapped
* to "provides" declarations
! * 4. The Main-Class attribute in the main attributes of the JAR manifest
* is mapped to the module descriptor mainClass
*/
private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
throws IOException
{
*** 441,471 ****
// finally clean up the module name
mn = cleanModuleName(mn);
// Builder throws IAE if module name is empty or invalid
! ModuleDescriptor.Builder builder
! = ModuleDescriptor.automaticModule(mn)
! .requires(Set.of(Requires.Modifier.MANDATED), "java.base");
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)
.collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX),
Collectors.toSet()));
! Set<String> resources = map.get(Boolean.FALSE);
Set<String> configFiles = map.get(Boolean.TRUE);
! // all packages are exported and open
! resources.stream()
.map(this::toPackageName)
.flatMap(Optional::stream)
.distinct()
! .forEach(pn -> builder.exports(pn).opens(pn));
// map names of service configuration files to service names
Set<String> serviceNames = configFiles.stream()
.map(this::toServiceName)
.flatMap(Optional::stream)
--- 434,467 ----
// finally clean up the module name
mn = cleanModuleName(mn);
// Builder throws IAE if module name is empty or invalid
! ModuleDescriptor.Builder builder = ModuleDescriptor.newAutomaticModule(mn);
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)
*** 479,488 ****
--- 475,489 ----
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 IOException(msg);
+ }
providerClasses.add(cn);
}
}
}
if (!providerClasses.isEmpty())
*** 492,503 ****
// Main-Class attribute if it exists
Manifest man = jf.getManifest();
if (man != null) {
Attributes attrs = man.getMainAttributes();
String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
! if (mainClass != null)
! builder.mainClass(mainClass.replace("/", "."));
}
return builder.build();
}
--- 493,511 ----
// Main-Class attribute if it exists
Manifest man = jf.getManifest();
if (man != null) {
Attributes attrs = man.getMainAttributes();
String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
! if (mainClass != null) {
! mainClass = mainClass.replace("/", ".");
! String pn = packageName(mainClass);
! if (!packages.contains(pn)) {
! String msg = "Main-Class " + mainClass + " not in module";
! throw new IOException(msg);
! }
! builder.mainClass(mainClass);
! }
}
return builder.build();
}
*** 567,580 ****
// no module-info.class so treat it as automatic module
try {
ModuleDescriptor md = deriveModuleDescriptor(jf);
attrs = new ModuleInfo.Attributes(md, null, null);
! } catch (IllegalArgumentException iae) {
throw new FindException(
"Unable to derive module descriptor for: "
! + jf.getName(), iae);
}
} else {
attrs = ModuleInfo.read(jf.getInputStream(entry),
() -> jarPackages(jf));
--- 575,588 ----
// no module-info.class so treat it as automatic module
try {
ModuleDescriptor md = deriveModuleDescriptor(jf);
attrs = new ModuleInfo.Attributes(md, null, null);
! } catch (IllegalArgumentException e) {
throw new FindException(
"Unable to derive module descriptor for: "
! + jf.getName(), e);
}
} else {
attrs = ModuleInfo.read(jf.getInputStream(entry),
() -> jarPackages(jf));
*** 619,649 ****
}
return ModuleReferences.newExplodedModule(attrs, dir);
}
/**
* Maps the name of an entry in a JAR or ZIP file to a package name.
*
* @throws IllegalArgumentException if the name is a class file in
* the top-level directory of the JAR/ZIP file (and it's
* not module-info.class)
*/
private Optional<String> toPackageName(String name) {
assert !name.endsWith("/");
-
int index = name.lastIndexOf("/");
if (index == -1) {
if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
throw new IllegalArgumentException(name
! + " found in top-level directory:"
+ " (unnamed package not allowed in module)");
}
return Optional.empty();
}
String pn = name.substring(0, index).replace('/', '.');
! if (Checks.isJavaIdentifier(pn)) {
return Optional.of(pn);
} else {
// not a valid package name
return Optional.empty();
}
--- 627,664 ----
}
return ModuleReferences.newExplodedModule(attrs, dir);
}
/**
+ * Maps a type name to its package name.
+ */
+ private static String packageName(String cn) {
+ int index = cn.lastIndexOf('.');
+ return (index == -1) ? "" : cn.substring(0, index);
+ }
+
+ /**
* Maps the name of an entry in a JAR or ZIP file to a package name.
*
* @throws IllegalArgumentException if the name is a class file in
* the top-level directory of the JAR/ZIP file (and it's
* not module-info.class)
*/
private Optional<String> toPackageName(String name) {
assert !name.endsWith("/");
int index = name.lastIndexOf("/");
if (index == -1) {
if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
throw new IllegalArgumentException(name
! + " found in top-level directory"
+ " (unnamed package not allowed in module)");
}
return Optional.empty();
}
String pn = name.substring(0, index).replace('/', '.');
! if (Checks.isPackageName(pn)) {
return Optional.of(pn);
} else {
// not a valid package name
return Optional.empty();
}
*** 662,679 ****
Path parent = file.getParent();
if (parent == null) {
String name = file.toString();
if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
throw new IllegalArgumentException(name
! + " found in in top-level directory"
+ " (unnamed package not allowed in module)");
}
return Optional.empty();
}
String pn = parent.toString().replace(File.separatorChar, '.');
! if (Checks.isJavaIdentifier(pn)) {
return Optional.of(pn);
} else {
// not a valid package name
return Optional.empty();
}
--- 677,694 ----
Path parent = file.getParent();
if (parent == null) {
String name = file.toString();
if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
throw new IllegalArgumentException(name
! + " found in top-level directory"
+ " (unnamed package not allowed in module)");
}
return Optional.empty();
}
String pn = parent.toString().replace(File.separatorChar, '.');
! if (Checks.isPackageName(pn)) {
return Optional.of(pn);
} else {
// not a valid package name
return Optional.empty();
}
< prev index next >