8173393: Module system implementation refresh (2/2017)
Co-authored-by: Mandy Chung <mandy.chung@oracle.com> Co-authored-by: Claes Redestad <claes.redestad@oracle.com> Co-authored-by: Alex Buckley <alex.buckley@oracle.com> Co-authored-by: Mark Reinhold <mark.reinhold@oracle.com> Co-authored-by: John Rose <john.r.rose@oracle.com> Reviewed-by: dfuchs, psandoz, mchung, alanb
This commit is contained in:
parent
b793624138
commit
a4693ee7d2
@ -153,9 +153,9 @@ public class GenGraphs {
|
||||
*/
|
||||
void genDotFile(String name, Set<String> roots) throws IOException {
|
||||
Configuration cf =
|
||||
Configuration.empty().resolveRequires(ModuleFinder.ofSystem(),
|
||||
ModuleFinder.of(),
|
||||
roots);
|
||||
Configuration.empty().resolve(ModuleFinder.ofSystem(),
|
||||
ModuleFinder.of(),
|
||||
roots);
|
||||
|
||||
Set<ModuleDescriptor> mds = cf.modules().stream()
|
||||
.map(ResolvedModule::reference)
|
||||
|
@ -291,9 +291,9 @@ public class ModuleSummary {
|
||||
|
||||
static Configuration resolve(Set<String> roots) {
|
||||
return Configuration.empty()
|
||||
.resolveRequires(ModuleFinder.ofSystem(),
|
||||
ModuleFinder.of(),
|
||||
roots);
|
||||
.resolve(ModuleFinder.ofSystem(),
|
||||
ModuleFinder.of(),
|
||||
roots);
|
||||
}
|
||||
|
||||
static class HtmlDocument {
|
||||
|
@ -425,6 +425,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* </ul>
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static Class<?> forName(Module module, String name) {
|
||||
@ -819,6 +820,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* @return the module that this class or interface is a member of
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public Module getModule() {
|
||||
return module;
|
||||
@ -924,6 +926,8 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* this method returns {@code null}.
|
||||
*
|
||||
* @return the package of this class.
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public Package getPackage() {
|
||||
if (isPrimitive() || isArray()) {
|
||||
@ -951,20 +955,30 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* declaring class} of the {@link #getEnclosingMethod enclosing method} or
|
||||
* {@link #getEnclosingConstructor enclosing constructor}.
|
||||
*
|
||||
* <p> This method returns {@code null} if this class represents an array type,
|
||||
* a primitive type or void.
|
||||
* <p> If this class represents an array type then this method returns the
|
||||
* package name of the element type. If this class represents a primitive
|
||||
* type or void then the package name "{@code java.lang}" is returned.
|
||||
*
|
||||
* @return the fully qualified package name
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
* @jls 6.7 Fully Qualified Names
|
||||
*/
|
||||
public String getPackageName() {
|
||||
String pn = this.packageName;
|
||||
if (pn == null && !isArray() && !isPrimitive()) {
|
||||
String cn = getName();
|
||||
int dot = cn.lastIndexOf('.');
|
||||
pn = (dot != -1) ? cn.substring(0, dot).intern() : "";
|
||||
if (pn == null) {
|
||||
Class<?> c = this;
|
||||
while (c.isArray()) {
|
||||
c = c.getComponentType();
|
||||
}
|
||||
if (c.isPrimitive()) {
|
||||
pn = "java.lang";
|
||||
} else {
|
||||
String cn = c.getName();
|
||||
int dot = cn.lastIndexOf('.');
|
||||
pn = (dot != -1) ? cn.substring(0, dot).intern() : "";
|
||||
}
|
||||
this.packageName = pn;
|
||||
}
|
||||
return pn;
|
||||
@ -2491,10 +2505,16 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* Finds a resource with a given name.
|
||||
*
|
||||
* <p> If this class is in a named {@link Module Module} then this method
|
||||
* will attempt to find the resource in the module by means of the absolute
|
||||
* resource name, subject to the rules for encapsulation specified in the
|
||||
* {@code Module} {@link Module#getResourceAsStream getResourceAsStream}
|
||||
* method.
|
||||
* will attempt to find the resource in the module. This is done by
|
||||
* delegating to the module's class loader {@link
|
||||
* ClassLoader#findResource(String,String) findResource(String,String)}
|
||||
* method, invoking it with the module name and the absolute name of the
|
||||
* resource. Resources in named modules are subject to the rules for
|
||||
* encapsulation specified in the {@code Module} {@link
|
||||
* Module#getResourceAsStream getResourceAsStream} method and so this
|
||||
* method returns {@code null} when the resource is a
|
||||
* non-"{@code .class}" resource in a package that is not open to the
|
||||
* caller's module.
|
||||
*
|
||||
* <p> Otherwise, if this class is not in a named module then the rules for
|
||||
* searching resources associated with a given class are implemented by the
|
||||
@ -2503,9 +2523,8 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* the bootstrap class loader, the method delegates to {@link
|
||||
* ClassLoader#getSystemResourceAsStream}.
|
||||
*
|
||||
* <p> Before finding a resource in the caller's module or delegation to a
|
||||
* class loader, an absolute resource name is constructed from the given
|
||||
* resource name using this algorithm:
|
||||
* <p> Before delegation, an absolute resource name is constructed from the
|
||||
* given resource name using this algorithm:
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
@ -2532,7 +2551,11 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* least the caller module, or access to the resource is denied
|
||||
* by the security manager.
|
||||
* @throws NullPointerException If {@code name} is {@code null}
|
||||
*
|
||||
* @see Module#getResourceAsStream(String)
|
||||
* @since 1.1
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public InputStream getResourceAsStream(String name) {
|
||||
@ -2585,10 +2608,16 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* Finds a resource with a given name.
|
||||
*
|
||||
* <p> If this class is in a named {@link Module Module} then this method
|
||||
* will attempt to find the resource in the module by means of the absolute
|
||||
* resource name, subject to the rules for encapsulation specified in the
|
||||
* {@code Module} {@link Module#getResourceAsStream getResourceAsStream}
|
||||
* method.
|
||||
* will attempt to find the resource in the module. This is done by
|
||||
* delegating to the module's class loader {@link
|
||||
* ClassLoader#findResource(String,String) findResource(String,String)}
|
||||
* method, invoking it with the module name and the absolute name of the
|
||||
* resource. Resources in named modules are subject to the rules for
|
||||
* encapsulation specified in the {@code Module} {@link
|
||||
* Module#getResourceAsStream getResourceAsStream} method and so this
|
||||
* method returns {@code null} when the resource is a
|
||||
* non-"{@code .class}" resource in a package that is not open to the
|
||||
* caller's module.
|
||||
*
|
||||
* <p> Otherwise, if this class is not in a named module then the rules for
|
||||
* searching resources associated with a given class are implemented by the
|
||||
@ -2627,6 +2656,8 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* manager.
|
||||
* @throws NullPointerException If {@code name} is {@code null}
|
||||
* @since 1.1
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public URL getResource(String name) {
|
||||
|
@ -207,6 +207,8 @@ import sun.security.util.SecurityConstants;
|
||||
* @jls 13.1 The Form of a Binary
|
||||
* @see #resolveClass(Class)
|
||||
* @since 1.0
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public abstract class ClassLoader {
|
||||
|
||||
@ -380,12 +382,12 @@ public abstract class ClassLoader {
|
||||
* method doesn't allow creation of a new class loader.
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
protected ClassLoader(String name, ClassLoader parent) {
|
||||
this(checkCreateClassLoader(name), name, parent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new class loader using the specified parent class loader for
|
||||
* delegation.
|
||||
@ -440,6 +442,7 @@ public abstract class ClassLoader {
|
||||
* this class loader is not named.
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
@ -710,6 +713,7 @@ public abstract class ClassLoader {
|
||||
* if the class could not be found.
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
protected Class<?> findClass(String moduleName, String name) {
|
||||
if (moduleName == null) {
|
||||
@ -834,6 +838,8 @@ public abstract class ClassLoader {
|
||||
* @see java.security.SecureClassLoader
|
||||
*
|
||||
* @since 1.1
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
protected final Class<?> defineClass(String name, byte[] b, int off, int len)
|
||||
throws ClassFormatError
|
||||
@ -967,6 +973,9 @@ public abstract class ClassLoader {
|
||||
* certificates than this class, or if {@code name} begins with
|
||||
* "{@code java.}" and this class loader is not the platform
|
||||
* class loader or its ancestor.
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
protected final Class<?> defineClass(String name, byte[] b, int off, int len,
|
||||
ProtectionDomain protectionDomain)
|
||||
@ -1041,6 +1050,8 @@ public abstract class ClassLoader {
|
||||
* @see #defineClass(String, byte[], int, int, ProtectionDomain)
|
||||
*
|
||||
* @since 1.5
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
protected final Class<?> defineClass(String name, java.nio.ByteBuffer b,
|
||||
ProtectionDomain protectionDomain)
|
||||
@ -1264,11 +1275,11 @@ public abstract class ClassLoader {
|
||||
* Class loader implementations that support the loading from modules
|
||||
* should override this method.
|
||||
*
|
||||
* @apiNote This method is the basis for the {@code Class} {@link
|
||||
* Class#getResource getResource} and {@link Class#getResourceAsStream
|
||||
* getResourceAsStream} methods. It is not subject to the rules for
|
||||
* encapsulation specified by {@code Module} {@link
|
||||
* Module#getResourceAsStream getResourceAsStream}.
|
||||
* @apiNote This method is the basis for the {@link
|
||||
* Class#getResource Class.getResource}, {@link Class#getResourceAsStream
|
||||
* Class.getResourceAsStream}, and {@link Module#getResourceAsStream
|
||||
* Module.getResourceAsStream} methods. It is not subject to the rules for
|
||||
* encapsulation specified by {@code Module.getResourceAsStream}.
|
||||
*
|
||||
* @implSpec The default implementation attempts to find the resource by
|
||||
* invoking {@link #findResource(String)} when the {@code moduleName} is
|
||||
@ -1292,6 +1303,7 @@ public abstract class ClassLoader {
|
||||
*
|
||||
* @see java.lang.module.ModuleReader#find(String)
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
protected URL findResource(String moduleName, String name) throws IOException {
|
||||
if (moduleName == null) {
|
||||
@ -1342,6 +1354,8 @@ public abstract class ClassLoader {
|
||||
* @throws NullPointerException If {@code name} is {@code null}
|
||||
*
|
||||
* @since 1.1
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public URL getResource(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
@ -1403,6 +1417,8 @@ public abstract class ClassLoader {
|
||||
* @see #findResources(String)
|
||||
*
|
||||
* @since 1.2
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public Enumeration<URL> getResources(String name) throws IOException {
|
||||
Objects.requireNonNull(name);
|
||||
@ -1499,6 +1515,8 @@ public abstract class ClassLoader {
|
||||
* denied by the security manager.
|
||||
*
|
||||
* @since 1.2
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
protected URL findResource(String name) {
|
||||
return null;
|
||||
@ -1531,6 +1549,8 @@ public abstract class ClassLoader {
|
||||
* If I/O errors occur
|
||||
*
|
||||
* @since 1.2
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
protected Enumeration<URL> findResources(String name) throws IOException {
|
||||
return Collections.emptyEnumeration();
|
||||
@ -1601,6 +1621,8 @@ public abstract class ClassLoader {
|
||||
* denied by the security manager.
|
||||
*
|
||||
* @since 1.1
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public static URL getSystemResource(String name) {
|
||||
return getSystemClassLoader().getResource(name);
|
||||
@ -1636,6 +1658,8 @@ public abstract class ClassLoader {
|
||||
* If I/O errors occur
|
||||
*
|
||||
* @since 1.2
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public static Enumeration<URL> getSystemResources(String name)
|
||||
throws IOException
|
||||
@ -1667,6 +1691,8 @@ public abstract class ClassLoader {
|
||||
* @throws NullPointerException If {@code name} is {@code null}
|
||||
*
|
||||
* @since 1.1
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public InputStream getResourceAsStream(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
@ -1699,6 +1725,8 @@ public abstract class ClassLoader {
|
||||
* denied by the security manager.
|
||||
*
|
||||
* @since 1.1
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public static InputStream getSystemResourceAsStream(String name) {
|
||||
URL url = getSystemResource(name);
|
||||
@ -1749,6 +1777,7 @@ public abstract class ClassLoader {
|
||||
*
|
||||
* @see Module#isNamed()
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public final Module getUnnamedModule() {
|
||||
return unnamedModule;
|
||||
@ -1772,6 +1801,7 @@ public abstract class ClassLoader {
|
||||
* {@link RuntimePermission}{@code ("getClassLoader")}
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static ClassLoader getPlatformClassLoader() {
|
||||
@ -1847,6 +1877,8 @@ public abstract class ClassLoader {
|
||||
* {@link Throwable#getCause()} method.
|
||||
*
|
||||
* @revised 1.4
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static ClassLoader getSystemClassLoader() {
|
||||
@ -2101,6 +2133,8 @@ public abstract class ClassLoader {
|
||||
* defined by this class loader
|
||||
*
|
||||
* @since 1.2
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*
|
||||
* @see <a href="../../../technotes/guides/jar/jar.html#versioning">
|
||||
* The JAR File Specification: Package Versioning</a>
|
||||
@ -2138,6 +2172,7 @@ public abstract class ClassLoader {
|
||||
* if {@code name} is {@code null}.
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public final Package getDefinedPackage(String name) {
|
||||
Objects.requireNonNull(name, "name cannot be null");
|
||||
@ -2160,6 +2195,7 @@ public abstract class ClassLoader {
|
||||
* or an zero length array if no package has been defined by this class loader.
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public final Package[] getDefinedPackages() {
|
||||
return packages().toArray(Package[]::new);
|
||||
@ -2196,6 +2232,8 @@ public abstract class ClassLoader {
|
||||
* a {@code Package} for the specified class loader.
|
||||
*
|
||||
* @since 1.2
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
protected Package getPackage(String name) {
|
||||
@ -2220,6 +2258,8 @@ public abstract class ClassLoader {
|
||||
* class loader and its ancestors
|
||||
*
|
||||
* @since 1.2
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
protected Package[] getPackages() {
|
||||
Stream<Package> pkgs = packages();
|
||||
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang;
|
||||
|
||||
/**
|
||||
* Thrown to indicate that a method has been called by an inappropriate caller.
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
* @see StackWalker#getCallerClass
|
||||
*/
|
||||
public class IllegalCallerException extends RuntimeException {
|
||||
/**
|
||||
* Constructs an IllegalCallerException with no detail message.
|
||||
*/
|
||||
public IllegalCallerException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an IllegalCallerException with the specified detail
|
||||
* message.
|
||||
*
|
||||
* @param s the String that contains a detailed message (can be null)
|
||||
*/
|
||||
public IllegalCallerException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and
|
||||
* cause.
|
||||
*
|
||||
* @param message the detail message (can be null)
|
||||
* @param cause the cause (can be null)
|
||||
*/
|
||||
public IllegalCallerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified cause and a detail
|
||||
* message of {@code (cause==null ? null : cause.toString())} (which
|
||||
* typically contains the class and detail message of {@code cause}).
|
||||
*
|
||||
* @param cause the cause (can be null)
|
||||
*/
|
||||
public IllegalCallerException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
static final long serialVersionUID = -2349421918363102232L;
|
||||
}
|
@ -111,6 +111,8 @@ import jdk.internal.reflect.Reflection;
|
||||
* @see ClassLoader#definePackage(String, String, String, String, String, String, String, URL)
|
||||
*
|
||||
* @since 1.2
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public class Package extends NamedPackage implements java.lang.reflect.AnnotatedElement {
|
||||
/**
|
||||
@ -207,6 +209,9 @@ public class Package extends NamedPackage implements java.lang.reflect.Annotated
|
||||
* is returned if it is not known.
|
||||
* @return the vendor that implemented this package, {@code null}
|
||||
* is returned if it is not known.
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public String getImplementationVendor() {
|
||||
return versionInfo.implVendor;
|
||||
@ -334,6 +339,9 @@ public class Package extends NamedPackage implements java.lang.reflect.Annotated
|
||||
* a {@code Package} for the specified class loader.
|
||||
*
|
||||
* @see ClassLoader#getDefinedPackage
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
@Deprecated(since="9")
|
||||
@ -356,6 +364,9 @@ public class Package extends NamedPackage implements java.lang.reflect.Annotated
|
||||
* class loader and its ancestors
|
||||
*
|
||||
* @see ClassLoader#getDefinedPackages
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static Package[] getPackages() {
|
||||
|
@ -1457,6 +1457,18 @@ class SecurityManager {
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by java.security.Security
|
||||
*/
|
||||
static void invalidatePackageAccessCache() {
|
||||
synchronized (packageAccessLock) {
|
||||
packageAccessValid = false;
|
||||
}
|
||||
synchronized (packageDefinitionLock) {
|
||||
packageDefinitionValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the module's loader is the boot or platform loader.
|
||||
*/
|
||||
|
@ -684,7 +684,7 @@ final class StackStreamFactory {
|
||||
frames[n++] = caller;
|
||||
}
|
||||
if (frames[1] == null) {
|
||||
throw new IllegalStateException("no caller frame");
|
||||
throw new IllegalCallerException("no caller frame");
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
@ -92,6 +92,8 @@ public final class StackTraceElement implements java.io.Serializable {
|
||||
* @throws NullPointerException if {@code declaringClass} or
|
||||
* {@code methodName} is null
|
||||
* @since 1.5
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public StackTraceElement(String declaringClass, String methodName,
|
||||
String fileName, int lineNumber) {
|
||||
@ -128,6 +130,7 @@ public final class StackTraceElement implements java.io.Serializable {
|
||||
* or {@code methodName} is {@code null}
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public StackTraceElement(String classLoaderName,
|
||||
String moduleName, String moduleVersion,
|
||||
@ -187,6 +190,7 @@ public final class StackTraceElement implements java.io.Serializable {
|
||||
* point represented by this stack trace element; {@code null}
|
||||
* if the module name is not available.
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
* @see java.lang.reflect.Module#getName()
|
||||
*/
|
||||
public String getModuleName() {
|
||||
@ -201,6 +205,7 @@ public final class StackTraceElement implements java.io.Serializable {
|
||||
* point represented by this stack trace element; {@code null}
|
||||
* if the module version is not available.
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
* @see java.lang.module.ModuleDescriptor.Version
|
||||
*/
|
||||
public String getModuleVersion() {
|
||||
@ -216,6 +221,7 @@ public final class StackTraceElement implements java.io.Serializable {
|
||||
* if the class loader is not named.
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
* @see java.lang.ClassLoader#getName()
|
||||
*/
|
||||
public String getClassLoaderName() {
|
||||
@ -329,6 +335,8 @@ public final class StackTraceElement implements java.io.Serializable {
|
||||
* {@link java.lang.StackWalker.StackFrame}, where an implementation may
|
||||
* choose to omit some element in the returned string.
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
* @see Throwable#printStackTrace()
|
||||
*/
|
||||
public String toString() {
|
||||
@ -376,6 +384,9 @@ public final class StackTraceElement implements java.io.Serializable {
|
||||
* @return true if the specified object is another
|
||||
* {@code StackTraceElement} instance representing the same
|
||||
* execution point as this instance.
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (obj==this)
|
||||
|
@ -465,8 +465,8 @@ public final class StackWalker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@code Class} object of the caller invoking the method
|
||||
* that calls this {@code getCallerClass} method.
|
||||
* Gets the {@code Class} object of the caller who invoked the method
|
||||
* that invoked {@code getCallerClass}.
|
||||
*
|
||||
* <p> Reflection frames, {@link java.lang.invoke.MethodHandle}, and
|
||||
* hidden frames are filtered regardless of the
|
||||
@ -474,19 +474,21 @@ public final class StackWalker {
|
||||
* and {@link Option#SHOW_HIDDEN_FRAMES SHOW_HIDDEN_FRAMES} options
|
||||
* this {@code StackWalker} has been configured with.
|
||||
*
|
||||
* <p> This method should be called when a caller frame is present. If
|
||||
* it is called from the bottom most frame on the stack,
|
||||
* {@code IllegalCallerException} will be thrown.
|
||||
*
|
||||
* <p> This method throws {@code UnsupportedOperationException}
|
||||
* if this {@code StackWalker} is not configured with the
|
||||
* {@link Option#RETAIN_CLASS_REFERENCE RETAIN_CLASS_REFERENCE} option.
|
||||
* This method should be called when a caller frame is present. If
|
||||
* it is called from the last frame on the stack,
|
||||
* {@code IllegalStateException} will be thrown.
|
||||
*
|
||||
* @apiNote
|
||||
* For example, {@code Util::getResourceBundle} loads a resource bundle
|
||||
* on behalf of the caller. It calls this {@code getCallerClass} method
|
||||
* to find the method calling {@code Util::getResourceBundle} and uses the caller's
|
||||
* class loader to load the resource bundle. The caller class in this example
|
||||
* is the {@code MyTool} class.
|
||||
* on behalf of the caller. It invokes {@code getCallerClass} to identify
|
||||
* the class whose method called {@code Util::getResourceBundle}.
|
||||
* Then, it obtains the class loader of that class, and uses
|
||||
* the class loader to load the resource bundle. The caller class
|
||||
* in this example is {@code MyTool}.
|
||||
*
|
||||
* <pre>{@code
|
||||
* class Util {
|
||||
@ -517,17 +519,17 @@ public final class StackWalker {
|
||||
* }</pre>
|
||||
*
|
||||
* When the {@code getCallerClass} method is called from a method that
|
||||
* is the last frame on the stack,
|
||||
* is the bottom most frame on the stack,
|
||||
* for example, {@code static public void main} method launched by the
|
||||
* {@code java} launcher, or a method invoked from a JNI attached thread,
|
||||
* {@code IllegalStateException} is thrown.
|
||||
* {@code IllegalCallerException} is thrown.
|
||||
*
|
||||
* @return {@code Class} object of the caller's caller invoking this method.
|
||||
*
|
||||
* @throws UnsupportedOperationException if this {@code StackWalker}
|
||||
* is not configured with {@link Option#RETAIN_CLASS_REFERENCE
|
||||
* Option.RETAIN_CLASS_REFERENCE}.
|
||||
* @throws IllegalStateException if there is no caller frame, i.e.
|
||||
* @throws IllegalCallerException if there is no caller frame, i.e.
|
||||
* when this {@code getCallerClass} method is called from a method
|
||||
* which is the last frame on the stack.
|
||||
*/
|
||||
|
@ -1942,10 +1942,6 @@ public final class System {
|
||||
* the application classpath or modulepath.
|
||||
*/
|
||||
private static void initPhase3() {
|
||||
// Initialize publicLookup early, to avoid bootstrapping circularities
|
||||
// with security manager using java.lang.invoke infrastructure.
|
||||
java.lang.invoke.MethodHandles.publicLookup();
|
||||
|
||||
// set security manager
|
||||
String cn = System.getProperty("java.security.manager");
|
||||
if (cn != null) {
|
||||
@ -2053,6 +2049,9 @@ public final class System {
|
||||
public String fastUUID(long lsb, long msb) {
|
||||
return Long.fastUUID(lsb, msb);
|
||||
}
|
||||
public void invalidatePackageAccessCache() {
|
||||
SecurityManager.invalidatePackageAccessCache();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,6 @@
|
||||
|
||||
package java.lang.invoke;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
@ -111,13 +109,17 @@ public class MethodHandles {
|
||||
|
||||
/**
|
||||
* Returns a {@link Lookup lookup object} which is trusted minimally.
|
||||
* It can only be used to create method handles to public members in
|
||||
* The lookup has the {@code PUBLIC} and {@code UNCONDITIONAL} modes.
|
||||
* It can only be used to create method handles to public members of
|
||||
* public classes in packages that are exported unconditionally.
|
||||
* <p>
|
||||
* For now, the {@linkplain Lookup#lookupClass lookup class} of this lookup
|
||||
* object is in an unnamed module.
|
||||
* Consequently, the lookup context of this lookup object will be the bootstrap
|
||||
* class loader, which means it cannot find user classes.
|
||||
* As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
|
||||
* of this lookup object will be {@link java.lang.Object}.
|
||||
*
|
||||
* @apiNote The use of Object is conventional, and because the lookup modes are
|
||||
* limited, there is no special access provided to the internals of Object, its package
|
||||
* or its module. Consequently, the lookup context of this lookup object will be the
|
||||
* bootstrap class loader, which means it cannot find user classes.
|
||||
*
|
||||
* <p style="font-size:smaller;">
|
||||
* <em>Discussion:</em>
|
||||
@ -129,17 +131,12 @@ public class MethodHandles {
|
||||
* Also, it cannot access
|
||||
* <a href="MethodHandles.Lookup.html#callsens">caller sensitive methods</a>.
|
||||
* @return a lookup object which is trusted minimally
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public static Lookup publicLookup() {
|
||||
// During VM startup then only classes in the java.base module can be
|
||||
// loaded and linked. This is because java.base exports aren't setup until
|
||||
// the module system is initialized, hence types in the unnamed module
|
||||
// (or any named module) can't link to java/lang/Object.
|
||||
if (!jdk.internal.misc.VM.isModuleSystemInited()) {
|
||||
return new Lookup(Object.class, Lookup.PUBLIC);
|
||||
} else {
|
||||
return LookupHelper.PUBLIC_LOOKUP;
|
||||
}
|
||||
return Lookup.PUBLIC_LOOKUP;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -172,6 +169,7 @@ public class MethodHandles {
|
||||
* @throws IllegalAccessException if the access check specified above fails
|
||||
* @throws SecurityException if denied by the security manager
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
* @see Lookup#dropLookupMode
|
||||
*/
|
||||
public static Lookup privateLookupIn(Class<?> targetClass, Lookup lookup) throws IllegalAccessException {
|
||||
@ -183,11 +181,11 @@ public class MethodHandles {
|
||||
throw new IllegalArgumentException(targetClass + " is an array class");
|
||||
Module targetModule = targetClass.getModule();
|
||||
Module callerModule = lookup.lookupClass().getModule();
|
||||
if (callerModule != targetModule && targetModule.isNamed()) {
|
||||
if (!callerModule.canRead(targetModule))
|
||||
throw new IllegalAccessException(callerModule + " does not read " + targetModule);
|
||||
if (!callerModule.canRead(targetModule))
|
||||
throw new IllegalAccessException(callerModule + " does not read " + targetModule);
|
||||
if (targetModule.isNamed()) {
|
||||
String pn = targetClass.getPackageName();
|
||||
assert pn != null && pn.length() > 0 : "unnamed package cannot be in named module";
|
||||
assert pn.length() > 0 : "unnamed package cannot be in named module";
|
||||
if (!targetModule.isOpen(pn, callerModule))
|
||||
throw new IllegalAccessException(targetModule + " does not open " + pn + " to " + callerModule);
|
||||
}
|
||||
@ -601,6 +599,8 @@ public class MethodHandles {
|
||||
* so that there can be a secure foundation for lookups.
|
||||
* Nearly all other methods in the JSR 292 API rely on lookup
|
||||
* objects to check access requests.
|
||||
*
|
||||
* @revised 9
|
||||
*/
|
||||
public static final
|
||||
class Lookup {
|
||||
@ -647,15 +647,33 @@ public class MethodHandles {
|
||||
* lookup class and public types in packages exported by other modules
|
||||
* to the module of the lookup class.
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public static final int MODULE = PACKAGE << 1;
|
||||
|
||||
private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE | MODULE);
|
||||
/** A single-bit mask representing {@code unconditional} access
|
||||
* which may contribute to the result of {@link #lookupModes lookupModes}.
|
||||
* The value is {@code 0x20}, which does not correspond meaningfully to
|
||||
* any particular {@linkplain java.lang.reflect.Modifier modifier bit}.
|
||||
* A {@code Lookup} with this lookup mode assumes {@linkplain
|
||||
* java.lang.reflect.Module#canRead(java.lang.reflect.Module) readability}.
|
||||
* In conjunction with the {@code PUBLIC} modifier bit, a {@code Lookup}
|
||||
* with this lookup mode can access all public members of public types
|
||||
* of all modules where the type is in a package that is {@link
|
||||
* java.lang.reflect.Module#isExported(String) exported unconditionally}.
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
* @see #publicLookup()
|
||||
*/
|
||||
public static final int UNCONDITIONAL = PACKAGE << 2;
|
||||
|
||||
private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE | MODULE | UNCONDITIONAL);
|
||||
private static final int FULL_POWER_MODES = (ALL_MODES & ~UNCONDITIONAL);
|
||||
private static final int TRUSTED = -1;
|
||||
|
||||
private static int fixmods(int mods) {
|
||||
mods &= (ALL_MODES - PACKAGE - MODULE);
|
||||
return (mods != 0) ? mods : (PACKAGE | MODULE);
|
||||
mods &= (ALL_MODES - PACKAGE - MODULE - UNCONDITIONAL);
|
||||
return (mods != 0) ? mods : (PACKAGE | MODULE | UNCONDITIONAL);
|
||||
}
|
||||
|
||||
/** Tells which class is performing the lookup. It is this class against
|
||||
@ -682,13 +700,14 @@ public class MethodHandles {
|
||||
* {@linkplain #PRIVATE PRIVATE (0x02)},
|
||||
* {@linkplain #PROTECTED PROTECTED (0x04)},
|
||||
* {@linkplain #PACKAGE PACKAGE (0x08)},
|
||||
* and {@linkplain #MODULE MODULE (0x10)}.
|
||||
* {@linkplain #MODULE MODULE (0x10)},
|
||||
* and {@linkplain #UNCONDITIONAL UNCONDITIONAL (0x20)}.
|
||||
* <p>
|
||||
* A freshly-created lookup object
|
||||
* on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class}
|
||||
* has all possible bits set, since the caller class can access all its own members,
|
||||
* all public types in the caller's module, and all public types in packages exported
|
||||
* by other modules to the caller's module.
|
||||
* on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class} has
|
||||
* all possible bits set, except {@code UNCONDITIONAL}. The lookup can be used to
|
||||
* access all members of the caller's class, all public types in the caller's module,
|
||||
* and all public types in packages exported by other modules to the caller's module.
|
||||
* A lookup object on a new lookup class
|
||||
* {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
|
||||
* may have some mode bits set to zero.
|
||||
@ -701,6 +720,9 @@ public class MethodHandles {
|
||||
* @return the lookup modes, which limit the kinds of access performed by this lookup object
|
||||
* @see #in
|
||||
* @see #dropLookupMode
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public int lookupModes() {
|
||||
return allowedModes & ALL_MODES;
|
||||
@ -712,9 +734,9 @@ public class MethodHandles {
|
||||
* which in turn is called by a method not in this package.
|
||||
*/
|
||||
Lookup(Class<?> lookupClass) {
|
||||
this(lookupClass, ALL_MODES);
|
||||
this(lookupClass, FULL_POWER_MODES);
|
||||
// make sure we haven't accidentally picked up a privileged class:
|
||||
checkUnprivilegedlookupClass(lookupClass, ALL_MODES);
|
||||
checkUnprivilegedlookupClass(lookupClass, FULL_POWER_MODES);
|
||||
}
|
||||
|
||||
private Lookup(Class<?> lookupClass, int allowedModes) {
|
||||
@ -730,19 +752,20 @@ public class MethodHandles {
|
||||
* However, the resulting {@code Lookup} object is guaranteed
|
||||
* to have no more access capabilities than the original.
|
||||
* In particular, access capabilities can be lost as follows:<ul>
|
||||
* <li>If the lookup class for this {@code Lookup} is not in a named module,
|
||||
* and the new lookup class is in a named module {@code M}, then no members in
|
||||
* {@code M}'s non-exported packages will be accessible.
|
||||
* <li>If the lookup for this {@code Lookup} is in a named module, and the
|
||||
* new lookup class is in a different module {@code M}, then no members, not even
|
||||
* public members in {@code M}'s exported packages, will be accessible.
|
||||
* <li>If the new lookup class differs from the old one,
|
||||
* protected members will not be accessible by virtue of inheritance.
|
||||
* (Protected members may continue to be accessible because of package sharing.)
|
||||
* <li>If the old lookup class is in a {@link Module#isNamed() named} module, and
|
||||
* the new lookup class is in a different module {@code M}, then no members, not
|
||||
* even public members in {@code M}'s exported packages, will be accessible.
|
||||
* The exception to this is when this lookup is {@link #publicLookup()
|
||||
* publicLookup}, in which case {@code PUBLIC} access is not lost.
|
||||
* <li>If the old lookup class is in an unnamed module, and the new lookup class
|
||||
* is a different module then {@link #MODULE MODULE} access is lost.
|
||||
* <li>If the new lookup class differs from the old one then {@code UNCONDITIONAL} is lost.
|
||||
* <li>If the new lookup class is in a different package
|
||||
* than the old one, protected and default (package) members will not be accessible.
|
||||
* <li>If the new lookup class is not within the same package member
|
||||
* as the old one, private members will not be accessible.
|
||||
* as the old one, private members will not be accessible, and protected members
|
||||
* will not be accessible by virtue of inheritance.
|
||||
* (Protected members may continue to be accessible because of package sharing.)
|
||||
* <li>If the new lookup class is not accessible to the old lookup class,
|
||||
* then no members, not even public members, will be accessible.
|
||||
* (In all other cases, public members will continue to be accessible.)
|
||||
@ -757,32 +780,34 @@ public class MethodHandles {
|
||||
* @return a lookup object which reports the desired lookup class, or the same object
|
||||
* if there is no change
|
||||
* @throws NullPointerException if the argument is null
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public Lookup in(Class<?> requestedLookupClass) {
|
||||
Objects.requireNonNull(requestedLookupClass);
|
||||
if (allowedModes == TRUSTED) // IMPL_LOOKUP can make any lookup at all
|
||||
return new Lookup(requestedLookupClass, ALL_MODES);
|
||||
return new Lookup(requestedLookupClass, FULL_POWER_MODES);
|
||||
if (requestedLookupClass == this.lookupClass)
|
||||
return this; // keep same capabilities
|
||||
|
||||
int newModes = (allowedModes & (ALL_MODES & ~PROTECTED));
|
||||
int newModes = (allowedModes & FULL_POWER_MODES);
|
||||
if (!VerifyAccess.isSameModule(this.lookupClass, requestedLookupClass)) {
|
||||
// Allowed to teleport from an unnamed to a named module but resulting
|
||||
// Lookup has no access to module private members
|
||||
if (this.lookupClass.getModule().isNamed()) {
|
||||
// Need to drop all access when teleporting from a named module to another
|
||||
// module. The exception is publicLookup where PUBLIC is not lost.
|
||||
if (this.lookupClass.getModule().isNamed()
|
||||
&& (this.allowedModes & UNCONDITIONAL) == 0)
|
||||
newModes = 0;
|
||||
} else {
|
||||
newModes &= ~MODULE;
|
||||
}
|
||||
else
|
||||
newModes &= ~(MODULE|PACKAGE|PRIVATE|PROTECTED);
|
||||
}
|
||||
if ((newModes & PACKAGE) != 0
|
||||
&& !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) {
|
||||
newModes &= ~(PACKAGE|PRIVATE);
|
||||
newModes &= ~(PACKAGE|PRIVATE|PROTECTED);
|
||||
}
|
||||
// Allow nestmate lookups to be created without special privilege:
|
||||
if ((newModes & PRIVATE) != 0
|
||||
&& !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) {
|
||||
newModes &= ~PRIVATE;
|
||||
newModes &= ~(PRIVATE|PROTECTED);
|
||||
}
|
||||
if ((newModes & PUBLIC) != 0
|
||||
&& !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass, allowedModes)) {
|
||||
@ -801,28 +826,29 @@ public class MethodHandles {
|
||||
* finds members, but with a lookup mode that has lost the given lookup mode.
|
||||
* The lookup mode to drop is one of {@link #PUBLIC PUBLIC}, {@link #MODULE
|
||||
* MODULE}, {@link #PACKAGE PACKAGE}, {@link #PROTECTED PROTECTED} or {@link #PRIVATE PRIVATE}.
|
||||
* {@link #PROTECTED PROTECTED} is always dropped and so the resulting lookup
|
||||
* mode will never have this access capability. When dropping {@code PACKAGE}
|
||||
* then the resulting lookup will not have {@code PACKAGE} or {@code PRIVATE}
|
||||
* access. When dropping {@code MODULE} then the resulting lookup will not
|
||||
* have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code
|
||||
* PUBLIC} is dropped then the resulting lookup has no access.
|
||||
* {@link #PROTECTED PROTECTED} and {@link #UNCONDITIONAL UNCONDITIONAL} are always
|
||||
* dropped and so the resulting lookup mode will never have these access capabilities.
|
||||
* When dropping {@code PACKAGE} then the resulting lookup will not have {@code PACKAGE}
|
||||
* or {@code PRIVATE} access. When dropping {@code MODULE} then the resulting lookup will
|
||||
* not have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code PUBLIC}
|
||||
* is dropped then the resulting lookup has no access.
|
||||
* @param modeToDrop the lookup mode to drop
|
||||
* @return a lookup object which lacks the indicated mode, or the same object if there is no change
|
||||
* @throws IllegalArgumentException if {@code modeToDrop} is not one of {@code PUBLIC},
|
||||
* {@code MODULE}, {@code PACKAGE}, {@code PROTECTED} or {@code PRIVATE}
|
||||
* @since 9
|
||||
* {@code MODULE}, {@code PACKAGE}, {@code PROTECTED}, {@code PRIVATE} or {@code UNCONDITIONAL}
|
||||
* @see MethodHandles#privateLookupIn
|
||||
* @since 9
|
||||
*/
|
||||
public Lookup dropLookupMode(int modeToDrop) {
|
||||
int oldModes = lookupModes();
|
||||
int newModes = oldModes & ~(modeToDrop | PROTECTED);
|
||||
int newModes = oldModes & ~(modeToDrop | PROTECTED | UNCONDITIONAL);
|
||||
switch (modeToDrop) {
|
||||
case PUBLIC: newModes &= ~(ALL_MODES); break;
|
||||
case MODULE: newModes &= ~(PACKAGE | PRIVATE); break;
|
||||
case PACKAGE: newModes &= ~(PRIVATE); break;
|
||||
case PROTECTED:
|
||||
case PRIVATE: break;
|
||||
case PRIVATE:
|
||||
case UNCONDITIONAL: break;
|
||||
default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop");
|
||||
}
|
||||
if (newModes == oldModes) return this; // return self if no change
|
||||
@ -835,6 +861,12 @@ public class MethodHandles {
|
||||
/** Package-private version of lookup which is trusted. */
|
||||
static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED);
|
||||
|
||||
/** Version of lookup which is trusted minimally.
|
||||
* It can only be used to create method handles to publicly accessible
|
||||
* members in packages that are exported unconditionally.
|
||||
*/
|
||||
static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, (PUBLIC|UNCONDITIONAL));
|
||||
|
||||
private static void checkUnprivilegedlookupClass(Class<?> lookupClass, int allowedModes) {
|
||||
String name = lookupClass.getName();
|
||||
if (name.startsWith("java.lang.invoke."))
|
||||
@ -845,7 +877,7 @@ public class MethodHandles {
|
||||
// TODO replace with a more formal and less fragile mechanism
|
||||
// that does not bluntly restrict classes under packages within
|
||||
// java.base from looking up MethodHandles or VarHandles.
|
||||
if (allowedModes == ALL_MODES && lookupClass.getClassLoader() == null) {
|
||||
if (allowedModes == FULL_POWER_MODES && lookupClass.getClassLoader() == null) {
|
||||
if ((name.startsWith("java.") &&
|
||||
!name.equals("java.lang.Thread") &&
|
||||
!name.startsWith("java.util.concurrent.")) ||
|
||||
@ -866,6 +898,7 @@ public class MethodHandles {
|
||||
* <ul>
|
||||
* <li>If no access is allowed, the suffix is "/noaccess".
|
||||
* <li>If only public access to types in exported packages is allowed, the suffix is "/public".
|
||||
* <li>If only public access and unconditional access are allowed, the suffix is "/publicLookup".
|
||||
* <li>If only public and module access are allowed, the suffix is "/module".
|
||||
* <li>If only public, module and package access are allowed, the suffix is "/package".
|
||||
* <li>If only public, module, package, and private access are allowed, the suffix is "/private".
|
||||
@ -884,6 +917,9 @@ public class MethodHandles {
|
||||
* because it requires a direct subclass relationship between
|
||||
* caller and callee.)
|
||||
* @see #in
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
@ -893,13 +929,15 @@ public class MethodHandles {
|
||||
return cname + "/noaccess";
|
||||
case PUBLIC:
|
||||
return cname + "/public";
|
||||
case PUBLIC|UNCONDITIONAL:
|
||||
return cname + "/publicLookup";
|
||||
case PUBLIC|MODULE:
|
||||
return cname + "/module";
|
||||
case PUBLIC|MODULE|PACKAGE:
|
||||
return cname + "/package";
|
||||
case ALL_MODES & ~PROTECTED:
|
||||
case FULL_POWER_MODES & ~PROTECTED:
|
||||
return cname + "/private";
|
||||
case ALL_MODES:
|
||||
case FULL_POWER_MODES:
|
||||
return cname;
|
||||
case TRUSTED:
|
||||
return "/trusted"; // internal only; not exported
|
||||
@ -1580,6 +1618,7 @@ return mh1;
|
||||
if (refKind == REF_invokeSpecial)
|
||||
refKind = REF_invokeVirtual;
|
||||
assert(method.isMethod());
|
||||
@SuppressWarnings("deprecation")
|
||||
Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
|
||||
return lookup.getDirectMethodNoSecurityManager(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
|
||||
}
|
||||
@ -1662,6 +1701,7 @@ return mh1;
|
||||
public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException {
|
||||
MemberName ctor = new MemberName(c);
|
||||
assert(ctor.isConstructor());
|
||||
@SuppressWarnings("deprecation")
|
||||
Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
|
||||
return lookup.getDirectConstructorNoSecurityManager(ctor.getDeclaringClass(), ctor);
|
||||
}
|
||||
@ -1692,6 +1732,7 @@ return mh1;
|
||||
assert(isSetter
|
||||
? MethodHandleNatives.refKindIsSetter(field.getReferenceKind())
|
||||
: MethodHandleNatives.refKindIsGetter(field.getReferenceKind()));
|
||||
@SuppressWarnings("deprecation")
|
||||
Lookup lookup = f.isAccessible() ? IMPL_LOOKUP : this;
|
||||
return lookup.getDirectFieldNoSecurityManager(field.getReferenceKind(), f.getDeclaringClass(), field);
|
||||
}
|
||||
@ -2033,9 +2074,9 @@ return mh1;
|
||||
(defc == refc ||
|
||||
Modifier.isPublic(refc.getModifiers())));
|
||||
if (!classOK && (allowedModes & PACKAGE) != 0) {
|
||||
classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), ALL_MODES) &&
|
||||
classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), FULL_POWER_MODES) &&
|
||||
(defc == refc ||
|
||||
VerifyAccess.isClassAccessible(refc, lookupClass(), ALL_MODES)));
|
||||
VerifyAccess.isClassAccessible(refc, lookupClass(), FULL_POWER_MODES)));
|
||||
}
|
||||
if (!classOK)
|
||||
return "class is not public";
|
||||
@ -2347,53 +2388,6 @@ return mh1;
|
||||
static ConcurrentHashMap<MemberName, DirectMethodHandle> LOOKASIDE_TABLE = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class used to lazily create PUBLIC_LOOKUP with a lookup class
|
||||
* in an <em>unnamed module</em>.
|
||||
*
|
||||
* @see Lookup#publicLookup
|
||||
*/
|
||||
private static class LookupHelper {
|
||||
private static final String UNNAMED = "Unnamed";
|
||||
private static final String OBJECT = "java/lang/Object";
|
||||
|
||||
private static Class<?> createClass() {
|
||||
try {
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
cw.visit(Opcodes.V1_8,
|
||||
Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
|
||||
UNNAMED,
|
||||
null,
|
||||
OBJECT,
|
||||
null);
|
||||
cw.visitSource(UNNAMED, null);
|
||||
cw.visitEnd();
|
||||
byte[] bytes = cw.toByteArray();
|
||||
ClassLoader loader = new ClassLoader(null) {
|
||||
@Override
|
||||
protected Class<?> findClass(String cn) throws ClassNotFoundException {
|
||||
if (cn.equals(UNNAMED))
|
||||
return super.defineClass(UNNAMED, bytes, 0, bytes.length);
|
||||
throw new ClassNotFoundException(cn);
|
||||
}
|
||||
};
|
||||
return loader.loadClass(UNNAMED);
|
||||
} catch (Exception e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Class<?> PUBLIC_LOOKUP_CLASS = createClass();
|
||||
|
||||
/**
|
||||
* Lookup that is trusted minimally. It can only be used to create
|
||||
* method handles to publicly accessible members in exported packages.
|
||||
*
|
||||
* @see MethodHandles#publicLookup
|
||||
*/
|
||||
static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_LOOKUP_CLASS, Lookup.PUBLIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a method handle constructing arrays of a desired type.
|
||||
* The return type of the method handle will be the array type.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -42,126 +42,48 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The configuration that is the result of resolution or resolution with
|
||||
* service binding.
|
||||
* A configuration that is the result of <a href="package-summary.html#resolution">
|
||||
* resolution</a> or resolution with <a href="package-summary.html#servicebinding">
|
||||
* service binding</a>.
|
||||
*
|
||||
* <h2><a name="resolution">Resolution</a></h2>
|
||||
* <p> A configuration encapsulates the <em>readability graph</em> that is the
|
||||
* output of resolution. A readability graph is a directed graph where the nodes
|
||||
* are of type {@link ResolvedModule} and the edges represent the readability
|
||||
* amongst the modules. {@code Configuration} defines the {@link #modules()
|
||||
* modules()} method to get the set of resolved modules in the graph. {@code
|
||||
* ResolvedModule} defines the {@link ResolvedModule#reads() reads()} method to
|
||||
* get the set of modules that a resolved module reads. The modules that are
|
||||
* read may be in the same configuration or may be in {@link #parents() parent}
|
||||
* configurations. </p>
|
||||
*
|
||||
* <p> Resolution is the process of computing the transitive closure of a set
|
||||
* of root modules over a set of observable modules by resolving the
|
||||
* dependences expressed by {@code requires} clauses.
|
||||
* <p> Configuration defines the {@link #resolve(ModuleFinder,List,ModuleFinder,Collection)
|
||||
* resolve} method to resolve a collection of root modules, and the {@link
|
||||
* #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection) resolveAndBind}
|
||||
* method to do resolution with service binding. There are instance and
|
||||
* static variants of both methods. The instance methods create a configuration
|
||||
* with the receiver as the parent configuration. The static methods are for
|
||||
* more advanced cases where there can be more than one parent configuration. </p>
|
||||
*
|
||||
* The <em>dependence graph</em> is augmented with edges that take account of
|
||||
* implicitly declared dependences ({@code requires transitive}) to create a
|
||||
* <em>readability graph</em>. A {@code Configuration} encapsulates the
|
||||
* resulting graph of {@link ResolvedModule resolved modules}.
|
||||
*
|
||||
* <p> Suppose we have the following observable modules: </p>
|
||||
* <pre> {@code
|
||||
* module m1 { requires m2; }
|
||||
* module m2 { requires transitive m3; }
|
||||
* module m3 { }
|
||||
* module m4 { }
|
||||
* } </pre>
|
||||
*
|
||||
* <p> If the module {@code m1} is resolved then the resulting configuration
|
||||
* contains three modules ({@code m1}, {@code m2}, {@code m3}). The edges in
|
||||
* its readability graph are: </p>
|
||||
* <pre> {@code
|
||||
* m1 --> m2 (meaning m1 reads m2)
|
||||
* m1 --> m3
|
||||
* m2 --> m3
|
||||
* } </pre>
|
||||
*
|
||||
* <p> Resolution is an additive process. When computing the transitive closure
|
||||
* then the dependence relation may include dependences on modules in parent
|
||||
* configurations. The result is a <em>relative configuration</em> that is
|
||||
* relative to one or more parent configurations and where the readability graph
|
||||
* may have edges from modules in the configuration to modules in parent
|
||||
* configurations.
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* <p> Suppose we have the following observable modules: </p>
|
||||
* <pre> {@code
|
||||
* module m1 { requires m2; requires java.xml; }
|
||||
* module m2 { }
|
||||
* } </pre>
|
||||
*
|
||||
* <p> If module {@code m1} is resolved with the configuration for the {@link
|
||||
* java.lang.reflect.Layer#boot() boot} layer as the parent then the resulting
|
||||
* configuration contains two modules ({@code m1}, {@code m2}). The edges in
|
||||
* its readability graph are:
|
||||
* <pre> {@code
|
||||
* m1 --> m2
|
||||
* m1 --> java.xml
|
||||
* } </pre>
|
||||
* where module {@code java.xml} is in the parent configuration. For
|
||||
* simplicity, this example omits the implicitly declared dependence on the
|
||||
* {@code java.base} module.
|
||||
*
|
||||
* <a name="automaticmoduleresolution"></a>
|
||||
* <p> {@link ModuleDescriptor#isAutomatic() Automatic} modules receive special
|
||||
* treatment during resolution. Each automatic module is resolved so that it
|
||||
* reads all other modules in the configuration and all parent configurations.
|
||||
* Each automatic module is also resolved as if it {@code requires transitive}
|
||||
* all other automatic modules in the configuration (and all automatic modules
|
||||
* in parent configurations). </p>
|
||||
|
||||
* <h2><a name="servicebinding">Service binding</a></h2>
|
||||
*
|
||||
* <p> Service binding is the process of augmenting a graph of resolved modules
|
||||
* from the set of observable modules induced by the service-use dependence
|
||||
* ({@code uses} and {@code provides} clauses). Any module that was not
|
||||
* previously in the graph requires resolution to compute its transitive
|
||||
* closure. Service binding is an iterative process in that adding a module
|
||||
* that satisfies some service-use dependence may introduce new service-use
|
||||
* dependences. </p>
|
||||
*
|
||||
* <p> Suppose we have the following observable modules: </p>
|
||||
* <pre> {@code
|
||||
* module m1 { exports p; uses p.S; }
|
||||
* module m2 { requires m1; provides p.S with p2.S2; }
|
||||
* module m3 { requires m1; requires m4; provides p.S with p3.S3; }
|
||||
* module m4 { }
|
||||
* } </pre>
|
||||
*
|
||||
* <p> If the module {@code m1} is resolved then the resulting graph of modules
|
||||
* has one module ({@code m1}). If the graph is augmented with modules induced
|
||||
* by the service-use dependence relation then the configuration will contain
|
||||
* four modules ({@code m1}, {@code m2}, {@code m3}, {@code m4}). The edges in
|
||||
* its readability graph are: </p>
|
||||
* <pre> {@code
|
||||
* m2 --> m1
|
||||
* m3 --> m1
|
||||
* m3 --> m4
|
||||
* } </pre>
|
||||
* <p> The edges in the conceptual service-use graph are: </p>
|
||||
* <pre> {@code
|
||||
* m1 --> m2 (meaning m1 uses a service that is provided by m2)
|
||||
* m1 --> m3
|
||||
* } </pre>
|
||||
*
|
||||
* <p> If this configuration is instantiated as a {@code Layer}, and if code in
|
||||
* module {@code m1} uses {@link java.util.ServiceLoader ServiceLoader} to
|
||||
* iterate over implementations of {@code p.S.class}, then it will iterate over
|
||||
* an instance of {@code p2.S2} and {@code p3.S3}. </p>
|
||||
* <p> Each {@link java.lang.reflect.Layer layer} of modules in the Java virtual
|
||||
* machine is created from a configuration. The configuration for the {@link
|
||||
* java.lang.reflect.Layer#boot() boot} layer is obtained by invoking {@code
|
||||
* Layer.boot().configuration()}. The configuration for the boot layer will
|
||||
* often be the parent when creating new configurations. </p>
|
||||
*
|
||||
* <h3> Example </h3>
|
||||
*
|
||||
* <p> The following example uses the {@code resolveRequires} method to resolve
|
||||
* a module named <em>myapp</em> with the configuration for the boot layer as
|
||||
* the parent configuration. It prints the name of each resolved module and
|
||||
* the names of the modules that each module reads. </p>
|
||||
* <p> The following example uses the {@link
|
||||
* #resolve(ModuleFinder,ModuleFinder,Collection) resolve} method to resolve a
|
||||
* module named <em>myapp</em> with the configuration for the boot layer as the
|
||||
* parent configuration. It prints the name of each resolved module and the
|
||||
* names of the modules that each module reads. </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
|
||||
*
|
||||
* Configuration parent = Layer.boot().configuration();
|
||||
*
|
||||
* Configuration cf = parent.resolveRequires(finder,
|
||||
* ModuleFinder.of(),
|
||||
* Set.of("myapp"));
|
||||
* Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("myapp"));
|
||||
* cf.modules().forEach(m -> {
|
||||
* System.out.format("%s -> %s%n",
|
||||
* m.name(),
|
||||
@ -172,6 +94,7 @@ import java.util.stream.Stream;
|
||||
* }</pre>
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
* @see java.lang.reflect.Layer
|
||||
*/
|
||||
public final class Configuration {
|
||||
@ -186,11 +109,23 @@ public final class Configuration {
|
||||
private final Set<ResolvedModule> modules;
|
||||
private final Map<String, ResolvedModule> nameToModule;
|
||||
|
||||
// module constraints on target
|
||||
private final String osName;
|
||||
private final String osArch;
|
||||
private final String osVersion;
|
||||
|
||||
String osName() { return osName; }
|
||||
String osArch() { return osArch; }
|
||||
String osVersion() { return osVersion; }
|
||||
|
||||
private Configuration() {
|
||||
this.parents = Collections.emptyList();
|
||||
this.graph = Collections.emptyMap();
|
||||
this.modules = Collections.emptySet();
|
||||
this.nameToModule = Collections.emptyMap();
|
||||
this.osName = null;
|
||||
this.osArch = null;
|
||||
this.osVersion = null;
|
||||
}
|
||||
|
||||
private Configuration(List<Configuration> parents,
|
||||
@ -214,27 +149,30 @@ public final class Configuration {
|
||||
this.graph = g;
|
||||
this.modules = Set.of(moduleArray);
|
||||
this.nameToModule = Map.ofEntries(nameEntries);
|
||||
}
|
||||
|
||||
this.osName = resolver.osName();
|
||||
this.osArch = resolver.osArch();
|
||||
this.osVersion = resolver.osVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a collection of root modules, with this configuration as its
|
||||
* parent, to create a new configuration. This method works exactly as
|
||||
* specified by the static {@link
|
||||
* #resolveRequires(ModuleFinder,List,ModuleFinder,Collection) resolveRequires}
|
||||
* #resolve(ModuleFinder,List,ModuleFinder,Collection) resolve}
|
||||
* method when invoked with this configuration as the parent. In other words,
|
||||
* if this configuration is {@code cf} then this method is equivalent to
|
||||
* invoking:
|
||||
* <pre> {@code
|
||||
* Configuration.resolveRequires(before, List.of(cf), after, roots);
|
||||
* Configuration.resolve(before, List.of(cf), after, roots);
|
||||
* }</pre>
|
||||
*
|
||||
* @param before
|
||||
* The <em>before</em> module finder to find modules
|
||||
* @param after
|
||||
* The <em>after</em> module finder to locate modules when a
|
||||
* module cannot be located by the {@code before} module finder
|
||||
* and the module is not in this configuration
|
||||
* The <em>after</em> module finder to locate modules when not
|
||||
* located by the {@code before} module finder or in parent
|
||||
* configurations
|
||||
* @param roots
|
||||
* The possibly-empty collection of module names of the modules
|
||||
* to resolve
|
||||
@ -242,16 +180,20 @@ public final class Configuration {
|
||||
* @return The configuration that is the result of resolving the given
|
||||
* root modules
|
||||
*
|
||||
* @throws FindException
|
||||
* If resolution fails for any of the observability-related reasons
|
||||
* specified by the static {@code resolve} method
|
||||
* @throws ResolutionException
|
||||
* If resolution or the post-resolution checks fail
|
||||
* If any of the post-resolution consistency checks specified by
|
||||
* the static {@code resolve} method fail
|
||||
* @throws SecurityException
|
||||
* If locating a module is denied by the security manager
|
||||
*/
|
||||
public Configuration resolveRequires(ModuleFinder before,
|
||||
ModuleFinder after,
|
||||
Collection<String> roots)
|
||||
public Configuration resolve(ModuleFinder before,
|
||||
ModuleFinder after,
|
||||
Collection<String> roots)
|
||||
{
|
||||
return resolveRequires(before, List.of(this), after, roots);
|
||||
return resolve(before, List.of(this), after, roots);
|
||||
}
|
||||
|
||||
|
||||
@ -259,12 +201,12 @@ public final class Configuration {
|
||||
* Resolves a collection of root modules, with service binding, and with
|
||||
* this configuration as its parent, to create a new configuration.
|
||||
* This method works exactly as specified by the static {@link
|
||||
* #resolveRequiresAndUses(ModuleFinder,List,ModuleFinder,Collection)
|
||||
* resolveRequiresAndUses} method when invoked with this configuration
|
||||
* #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection)
|
||||
* resolveAndBind} method when invoked with this configuration
|
||||
* as the parent. In other words, if this configuration is {@code cf} then
|
||||
* this method is equivalent to invoking:
|
||||
* <pre> {@code
|
||||
* Configuration.resolveRequiresAndUses(before, List.of(cf), after, roots);
|
||||
* Configuration.resolveAndBind(before, List.of(cf), after, roots);
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
@ -272,25 +214,29 @@ public final class Configuration {
|
||||
* The <em>before</em> module finder to find modules
|
||||
* @param after
|
||||
* The <em>after</em> module finder to locate modules when not
|
||||
* located by the {@code before} module finder and this
|
||||
* configuration
|
||||
* located by the {@code before} module finder or in parent
|
||||
* configurations
|
||||
* @param roots
|
||||
* The possibly-empty collection of module names of the modules
|
||||
* to resolve
|
||||
*
|
||||
* @return The configuration that is the result of resolving the given
|
||||
* root modules
|
||||
* @return The configuration that is the result of resolving, with service
|
||||
* binding, the given root modules
|
||||
*
|
||||
* @throws FindException
|
||||
* If resolution fails for any of the observability-related reasons
|
||||
* specified by the static {@code resolve} method
|
||||
* @throws ResolutionException
|
||||
* If resolution or the post-resolution checks fail
|
||||
* If any of the post-resolution consistency checks specified by
|
||||
* the static {@code resolve} method fail
|
||||
* @throws SecurityException
|
||||
* If locating a module is denied by the security manager
|
||||
*/
|
||||
public Configuration resolveRequiresAndUses(ModuleFinder before,
|
||||
ModuleFinder after,
|
||||
Collection<String> roots)
|
||||
public Configuration resolveAndBind(ModuleFinder before,
|
||||
ModuleFinder after,
|
||||
Collection<String> roots)
|
||||
{
|
||||
return resolveRequiresAndUses(before, List.of(this), after, roots);
|
||||
return resolveAndBind(before, List.of(this), after, roots);
|
||||
}
|
||||
|
||||
|
||||
@ -301,14 +247,14 @@ public final class Configuration {
|
||||
*
|
||||
* This method is used to create the configuration for the boot layer.
|
||||
*/
|
||||
static Configuration resolveRequiresAndUses(ModuleFinder finder,
|
||||
Collection<String> roots,
|
||||
boolean check,
|
||||
PrintStream traceOutput)
|
||||
static Configuration resolveAndBind(ModuleFinder finder,
|
||||
Collection<String> roots,
|
||||
boolean check,
|
||||
PrintStream traceOutput)
|
||||
{
|
||||
List<Configuration> parents = List.of(empty());
|
||||
Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput);
|
||||
resolver.resolveRequires(roots).resolveUses();
|
||||
resolver.resolve(roots).bind();
|
||||
|
||||
return new Configuration(parents, resolver, check);
|
||||
}
|
||||
@ -328,11 +274,11 @@ public final class Configuration {
|
||||
*
|
||||
* <p> When all modules have been resolved then the resulting dependency
|
||||
* graph is checked to ensure that it does not contain cycles. A
|
||||
* readability graph is constructed and in conjunction with the module
|
||||
* readability graph is constructed, and in conjunction with the module
|
||||
* exports and service use, checked for consistency. </p>
|
||||
*
|
||||
* <p> Resolution and the (post-resolution) consistency checks may fail for
|
||||
* following reasons: </p>
|
||||
* <p> Resolution may fail with {@code FindException} for the following
|
||||
* <em>observability-related</em> reasons: </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li><p> A root module, or a direct or transitive dependency, is not
|
||||
@ -343,6 +289,20 @@ public final class Configuration {
|
||||
* descriptor ({@code module-info.class}) or two versions of the same
|
||||
* module are found in the same directory. </p></li>
|
||||
*
|
||||
* <li><p> A module with the required name is found but the module
|
||||
* requires a different {@link ModuleDescriptor#osName() operating
|
||||
* system}, {@link ModuleDescriptor#osArch() architecture}, or {@link
|
||||
* ModuleDescriptor#osVersion() version} to other modules that have
|
||||
* been resolved for the new configuration or modules in the parent
|
||||
* configurations. </p></li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p> Post-resolution consistency checks may fail with {@code
|
||||
* ResolutionException} for the following reasons: </p>
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li><p> A cycle is detected, say where module {@code m1} requires
|
||||
* module {@code m2} and {@code m2} requires {@code m1}. </p></li>
|
||||
*
|
||||
@ -356,21 +316,12 @@ public final class Configuration {
|
||||
* module {@code M} nor exported to {@code M} by any module that
|
||||
* {@code M} reads. </p></li>
|
||||
*
|
||||
* <li><p> A module {@code M} declares that it
|
||||
* "{@code provides ... with q.T}" but package {@code q} is not in
|
||||
* module {@code M}. </p></li>
|
||||
*
|
||||
* <li><p> Two or more modules in the configuration are specific to
|
||||
* different {@link ModuleDescriptor#osName() operating systems},
|
||||
* {@link ModuleDescriptor#osArch() architectures}, or {@link
|
||||
* ModuleDescriptor#osVersion() versions}. </p></li>
|
||||
*
|
||||
* <li><p> Other implementation specific checks, for example referential
|
||||
* integrity checks to ensure that different versions of tighly coupled
|
||||
* modules cannot be combined in the same configuration. </p></li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* @implNote In the implementation then observability of modules may depend
|
||||
* on referential integrity checks that ensure different builds of tightly
|
||||
* coupled modules are not combined in the same configuration.
|
||||
*
|
||||
* @param before
|
||||
* The <em>before</em> module finder to find modules
|
||||
* @param parents
|
||||
@ -386,17 +337,22 @@ public final class Configuration {
|
||||
* @return The configuration that is the result of resolving the given
|
||||
* root modules
|
||||
*
|
||||
* @throws FindException
|
||||
* If resolution fails for an observability-related reason
|
||||
* @throws ResolutionException
|
||||
* If resolution or the post-resolution checks fail
|
||||
* If a post-resolution consistency checks fails
|
||||
* @throws IllegalArgumentException
|
||||
* If the list of parents is empty
|
||||
* If the list of parents is empty, or the list has two or more
|
||||
* parents with modules for different target operating systems,
|
||||
* architectures, or versions
|
||||
*
|
||||
* @throws SecurityException
|
||||
* If locating a module is denied by the security manager
|
||||
*/
|
||||
public static Configuration resolveRequires(ModuleFinder before,
|
||||
List<Configuration> parents,
|
||||
ModuleFinder after,
|
||||
Collection<String> roots)
|
||||
public static Configuration resolve(ModuleFinder before,
|
||||
List<Configuration> parents,
|
||||
ModuleFinder after,
|
||||
Collection<String> roots)
|
||||
{
|
||||
Objects.requireNonNull(before);
|
||||
Objects.requireNonNull(after);
|
||||
@ -407,7 +363,7 @@ public final class Configuration {
|
||||
throw new IllegalArgumentException("'parents' is empty");
|
||||
|
||||
Resolver resolver = new Resolver(before, parentList, after, null);
|
||||
resolver.resolveRequires(roots);
|
||||
resolver.resolve(roots);
|
||||
|
||||
return new Configuration(parentList, resolver, true);
|
||||
}
|
||||
@ -417,24 +373,24 @@ public final class Configuration {
|
||||
* configuration.
|
||||
*
|
||||
* <p> This method works exactly as specified by {@link
|
||||
* #resolveRequires(ModuleFinder,List,ModuleFinder,Collection)
|
||||
* resolveRequires} except that the graph of resolved modules is augmented
|
||||
* #resolve(ModuleFinder,List,ModuleFinder,Collection)
|
||||
* resolve} except that the graph of resolved modules is augmented
|
||||
* with modules induced by the service-use dependence relation. </p>
|
||||
*
|
||||
* <p> More specifically, the root modules are resolved as if by calling
|
||||
* {@code resolveRequires}. The resolved modules, and all modules in the
|
||||
* {@code resolve}. The resolved modules, and all modules in the
|
||||
* parent configurations, with {@link ModuleDescriptor#uses() service
|
||||
* dependences} are then examined. All modules found by the given module
|
||||
* finders that {@link ModuleDescriptor#provides() provide} an
|
||||
* implementation of one or more of the service types are added to the
|
||||
* module graph and then resolved as if by calling the {@code
|
||||
* resolveRequires} method. Adding modules to the module graph may
|
||||
* introduce new service-use dependences and so the process works
|
||||
* iteratively until no more modules are added. </p>
|
||||
* resolve} method. Adding modules to the module graph may introduce new
|
||||
* service-use dependences and so the process works iteratively until no
|
||||
* more modules are added. </p>
|
||||
*
|
||||
* <p> As service binding involves resolution then it may fail with {@link
|
||||
* ResolutionException} for exactly the same reasons specified in
|
||||
* {@code resolveRequires}. </p>
|
||||
* <p> As service binding involves resolution then it may fail with {@code
|
||||
* FindException} or {@code ResolutionException} for exactly the same
|
||||
* reasons specified in {@code resolve}. </p>
|
||||
*
|
||||
* @param before
|
||||
* The <em>before</em> module finder to find modules
|
||||
@ -448,20 +404,26 @@ public final class Configuration {
|
||||
* The possibly-empty collection of module names of the modules
|
||||
* to resolve
|
||||
*
|
||||
* @return The configuration that is the result of resolving the given
|
||||
* root modules
|
||||
* @return The configuration that is the result of resolving, with service
|
||||
* binding, the given root modules
|
||||
*
|
||||
* @throws FindException
|
||||
* If resolution fails for any of the observability-related reasons
|
||||
* specified by the static {@code resolve} method
|
||||
* @throws ResolutionException
|
||||
* If resolution or the post-resolution checks fail
|
||||
* If any of the post-resolution consistency checks specified by
|
||||
* the static {@code resolve} method fail
|
||||
* @throws IllegalArgumentException
|
||||
* If the list of parents is empty
|
||||
* If the list of parents is empty, or the list has two or more
|
||||
* parents with modules for different target operating systems,
|
||||
* architectures, or versions
|
||||
* @throws SecurityException
|
||||
* If locating a module is denied by the security manager
|
||||
*/
|
||||
public static Configuration resolveRequiresAndUses(ModuleFinder before,
|
||||
List<Configuration> parents,
|
||||
ModuleFinder after,
|
||||
Collection<String> roots)
|
||||
public static Configuration resolveAndBind(ModuleFinder before,
|
||||
List<Configuration> parents,
|
||||
ModuleFinder after,
|
||||
Collection<String> roots)
|
||||
{
|
||||
Objects.requireNonNull(before);
|
||||
Objects.requireNonNull(after);
|
||||
@ -472,7 +434,7 @@ public final class Configuration {
|
||||
throw new IllegalArgumentException("'parents' is empty");
|
||||
|
||||
Resolver resolver = new Resolver(before, parentList, after, null);
|
||||
resolver.resolveRequires(roots).resolveUses();
|
||||
resolver.resolve(roots).bind();
|
||||
|
||||
return new Configuration(parentList, resolver, true);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
@ -26,10 +26,14 @@
|
||||
package java.lang.module;
|
||||
|
||||
/**
|
||||
* Thrown by module finders when finding a module fails.
|
||||
* Thrown by a {@link ModuleFinder ModuleFinder} when an error occurs finding
|
||||
* a module. Also thrown by {@link
|
||||
* Configuration#resolve(ModuleFinder,java.util.List,ModuleFinder,java.util.Collection)
|
||||
* Configuration.resolve} when resolution fails for observability-related
|
||||
* reasons.
|
||||
*
|
||||
* @see ModuleFinder
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
|
||||
public class FindException extends RuntimeException {
|
||||
|
@ -31,6 +31,7 @@ package java.lang.module;
|
||||
*
|
||||
* @see ModuleDescriptor#read
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public class InvalidModuleDescriptorException extends RuntimeException {
|
||||
private static final long serialVersionUID = 4863390386809347380L;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -42,14 +42,15 @@ import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.module.ModuleBootstrap;
|
||||
import jdk.internal.module.ModulePath;
|
||||
import jdk.internal.module.SystemModuleFinder;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* A finder of modules. A {@code ModuleFinder} is used to find modules during
|
||||
* <a href="Configuration.html#resolution">resolution</a> or
|
||||
* <a href="Configuration.html#servicebinding">service binding</a>.
|
||||
* <a href="package-summary.html#resolution">resolution</a> or
|
||||
* <a href="package-summary.html#servicebinding">service binding</a>.
|
||||
*
|
||||
* <p> A {@code ModuleFinder} can only find one module with a given name. A
|
||||
* {@code ModuleFinder} that finds modules in a sequence of directories, for
|
||||
@ -85,6 +86,7 @@ import sun.security.action.GetPropertyAction;
|
||||
* <p> A {@code ModuleFinder} is not required to be thread safe. </p>
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
|
||||
public interface ModuleFinder {
|
||||
@ -124,8 +126,8 @@ public interface ModuleFinder {
|
||||
* to find that module. </p>
|
||||
*
|
||||
* @apiNote This is important to have for methods such as {@link
|
||||
* Configuration#resolveRequiresAndUses resolveRequiresAndUses} that need
|
||||
* to scan the module path to find modules that provide a specific service.
|
||||
* Configuration#resolveAndBind resolveAndBind} that need to scan the
|
||||
* module path to find modules that provide a specific service.
|
||||
*
|
||||
* @return The set of all module references that this finder locates
|
||||
*
|
||||
@ -172,7 +174,8 @@ public interface ModuleFinder {
|
||||
} else {
|
||||
Path mlib = Paths.get(home, "modules");
|
||||
if (Files.isDirectory(mlib)) {
|
||||
return of(mlib);
|
||||
// exploded build may be patched
|
||||
return ModulePath.of(ModuleBootstrap.patcher(), mlib);
|
||||
} else {
|
||||
throw new InternalError("Unable to detect the run-time image");
|
||||
}
|
||||
@ -198,13 +201,9 @@ public interface ModuleFinder {
|
||||
*
|
||||
* <p> If an element is a path to a directory of modules then each entry in
|
||||
* the directory is a packaged module or the top-level directory of an
|
||||
* exploded module. The module finder's {@link #find(String) find} or
|
||||
* {@link #findAll() findAll} methods throw {@link FindException} if a
|
||||
* directory containing more than one module with the same name is
|
||||
* encountered. </p>
|
||||
*
|
||||
* <p> If an element in the array is a path to a directory, and that
|
||||
* directory contains a file named {@code module-info.class}, then the
|
||||
* exploded module. It it an error if a directory contains more than one
|
||||
* module with the same name. If an element is a path to a directory, and
|
||||
* that directory contains a file named {@code module-info.class}, then the
|
||||
* directory is treated as an exploded module rather than a directory of
|
||||
* modules. </p>
|
||||
*
|
||||
@ -214,9 +213,8 @@ public interface ModuleFinder {
|
||||
* entry in a {@link java.util.jar.JarFile#isMultiRelease() multi-release}
|
||||
* JAR file) is a modular JAR and is an <em>explicit module</em>.
|
||||
* A JAR file that does not have a {@code module-info.class} in the
|
||||
* top-level directory is an {@link ModuleDescriptor#isAutomatic automatic}
|
||||
* module. The {@link ModuleDescriptor} for an automatic module is created as
|
||||
* follows:
|
||||
* top-level directory is created as an automatic module. The components
|
||||
* for the automatic module are derived as follows:
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
@ -248,46 +246,48 @@ public interface ModuleFinder {
|
||||
*
|
||||
* </ul></li>
|
||||
*
|
||||
* <li><p> It {@link ModuleDescriptor#requires() requires} {@code
|
||||
* java.base}. </p></li>
|
||||
*
|
||||
* <li><p> The set of packages in the module is derived from the names
|
||||
* of non-directory entries in the JAR file. A candidate package name
|
||||
* is derived from an entry using the characters up to, but not
|
||||
* including, the last forward slash. All remaining forward slashes are
|
||||
* replaced with dot ({@code "."}). If the resulting string is a valid
|
||||
* Java identifier then it is assumed to be a package name. For example,
|
||||
* if the JAR file contains an entry "{@code p/q/Foo.class}" then the
|
||||
* package name derived is "{@code p.q}". All packages are {@link
|
||||
* ModuleDescriptor#exports() exported}. </p></li>
|
||||
* <li><p> The set of packages in the module is derived from the
|
||||
* non-directory entries in the JAR file that have names ending in
|
||||
* "{@code .class}". A candidate package name is derived from the name
|
||||
* using the characters up to, but not including, the last forward slash.
|
||||
* All remaining forward slashes are replaced with dot ({@code "."}). If
|
||||
* the resulting string is a legal package name then it is assumed to be
|
||||
* a package name. For example, if the JAR file contains the entry
|
||||
* "{@code p/q/Foo.class}" then the package name derived is
|
||||
* "{@code p.q}".</p></li>
|
||||
*
|
||||
* <li><p> The contents of entries starting with {@code
|
||||
* META-INF/services/} are assumed to be service configuration files
|
||||
* (see {@link java.util.ServiceLoader}). If the name of a file
|
||||
* (that follows {@code META-INF/services/}) is a legal Java identifier
|
||||
* then it is assumed to be the fully-qualified binary name of a
|
||||
* service type. The entries in the file are assumed to be the
|
||||
* fully-qualified binary names of provider classes. </p></li>
|
||||
* (that follows {@code META-INF/services/}) is a legal class name
|
||||
* then it is assumed to be the fully-qualified class name of a service
|
||||
* type. The entries in the file are assumed to be the fully-qualified
|
||||
* class names of provider classes. </p></li>
|
||||
*
|
||||
* <li><p> If the JAR file has a {@code Main-Class} attribute in its
|
||||
* main manifest then its value is the {@link
|
||||
* main manifest then its value is the module {@link
|
||||
* ModuleDescriptor#mainClass() main class}. </p></li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p> If a {@code ModuleDescriptor} cannot be created (by means of the
|
||||
* {@link ModuleDescriptor.Builder ModuleDescriptor.Builder} API) for an
|
||||
* automatic module then {@code FindException} is thrown. This can arise,
|
||||
* for example, when a legal Java identifier name cannot be derived from
|
||||
* the file name of the JAR file or where the JAR file contains a {@code
|
||||
* .class} in the top-level directory of the JAR file. </p>
|
||||
* automatic module then {@code FindException} is thrown. This can arise
|
||||
* when a legal module name cannot be derived from the file name of the JAR
|
||||
* file, where the JAR file contains a {@code .class} in the top-level
|
||||
* directory of the JAR file, where an entry in a service configuration
|
||||
* file is not a legal class name or its package name is not in the set of
|
||||
* packages derived for the module, or where the module main class is not
|
||||
* a legal class name or its package is not in the module. </p>
|
||||
*
|
||||
* <p> In addition to JAR files, an implementation may also support modules
|
||||
* that are packaged in other implementation specific module formats. When
|
||||
* a file is encountered that is not recognized as a packaged module then
|
||||
* {@code FindException} is thrown. An implementation may choose to ignore
|
||||
* some files, {@link java.nio.file.Files#isHidden hidden} files for
|
||||
* example. Paths to files that do not exist are always ignored. </p>
|
||||
* that are packaged in other implementation specific module formats. If
|
||||
* an element in the array specified to this method is a path to a directory
|
||||
* of modules then entries in the directory that not recognized as modules
|
||||
* are ignored. If an element in the array is a path to a packaged module
|
||||
* that is not recognized then a {@code FindException} is thrown when the
|
||||
* file is encountered. Paths to files that do not exist are always ignored.
|
||||
* </p>
|
||||
*
|
||||
* <p> As with automatic modules, the contents of a packaged or exploded
|
||||
* module may need to be <em>scanned</em> in order to determine the packages
|
||||
@ -325,7 +325,7 @@ public interface ModuleFinder {
|
||||
};
|
||||
}
|
||||
|
||||
return new ModulePath(entries);
|
||||
return ModulePath.of(entries);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,7 +45,7 @@ import java.util.stream.Stream;
|
||||
* module. A module reader is also intended to be used by {@code ClassLoader}
|
||||
* implementations that load classes and resources from modules. </p>
|
||||
*
|
||||
* <p> A resource in a module is identified by a name that is a
|
||||
* <p> A resource in a module is identified by an abstract name that is a
|
||||
* '{@code /}'-separated path string. For example, module {@code java.base} may
|
||||
* have a resource "{@code java/lang/Object.class}" that, by convention, is the
|
||||
* class file for {@code java.lang.Object}. </p>
|
||||
@ -61,8 +61,18 @@ import java.util.stream.Stream;
|
||||
* open}, {@link #read read}, and {@link #list list} methods may throw {@code
|
||||
* SecurityException} if access is denied by the security manager. </p>
|
||||
*
|
||||
* @implSpec Implementations of {@code ModuleReader} should take great care
|
||||
* when translating an abstract resource name to the location of a resource in
|
||||
* a packaged module or on the file system. Implementations are advised to
|
||||
* treat resource names with elements such as '{@code .}, '{@code ..}',
|
||||
* elements containing file separators, or empty elements as "not found". More
|
||||
* generally, if the resource name is not in the stream of elements that the
|
||||
* {@code list} method returns then the resource should be treated as "not
|
||||
* found" to avoid inconsistencies.
|
||||
*
|
||||
* @see ModuleReference
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
|
||||
public interface ModuleReader extends Closeable {
|
||||
@ -148,6 +158,9 @@ public interface ModuleReader extends Closeable {
|
||||
* If an I/O error occurs or the module reader is closed
|
||||
* @throws SecurityException
|
||||
* If denied by the security manager
|
||||
* @throws OutOfMemoryError
|
||||
* If the resource is larger than {@code Integer.MAX_VALUE},
|
||||
* the maximum capacity of a byte buffer
|
||||
*
|
||||
* @see ClassLoader#defineClass(String, ByteBuffer, java.security.ProtectionDomain)
|
||||
*/
|
||||
|
@ -44,6 +44,7 @@ import java.util.Optional;
|
||||
* @see ModuleFinder
|
||||
* @see ModuleReader
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
|
||||
public abstract class ModuleReference {
|
||||
@ -76,7 +77,7 @@ public abstract class ModuleReference {
|
||||
/**
|
||||
* Returns the location of this module's content, if known.
|
||||
*
|
||||
* <p> This URI, when present, is used as the {@linkplain
|
||||
* <p> This URI, when present, can be used as the {@linkplain
|
||||
* java.security.CodeSource#getLocation location} value of a {@link
|
||||
* java.security.CodeSource CodeSource} so that a module's classes can be
|
||||
* granted specific permissions when loaded by a {@link
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -26,10 +26,12 @@
|
||||
package java.lang.module;
|
||||
|
||||
/**
|
||||
* Thrown when resolving a set of modules or binding fails.
|
||||
* Thrown when resolving a set of modules, or resolving a set of modules with
|
||||
* service binding, fails.
|
||||
*
|
||||
* @see Configuration
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public class ResolutionException extends RuntimeException {
|
||||
private static final long serialVersionUID = -1031186845316729450L;
|
||||
|
@ -37,6 +37,7 @@ import java.util.Set;
|
||||
* module's content.
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
* @see Configuration#modules()
|
||||
*/
|
||||
public final class ResolvedModule {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 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
|
||||
@ -49,8 +49,8 @@ import jdk.internal.module.ModuleHashes;
|
||||
import jdk.internal.module.ModuleReferenceImpl;
|
||||
|
||||
/**
|
||||
* The resolver used by {@link Configuration#resolveRequires} and
|
||||
* {@link Configuration#resolveRequiresAndUses}.
|
||||
* The resolver used by {@link Configuration#resolve} and {@link
|
||||
* Configuration#resolveAndBind}.
|
||||
*
|
||||
* @implNote The resolver is used at VM startup and so deliberately avoids
|
||||
* using lambda and stream usages in code paths used during startup.
|
||||
@ -66,7 +66,19 @@ final class Resolver {
|
||||
// maps module name to module reference
|
||||
private final Map<String, ModuleReference> nameToReference = new HashMap<>();
|
||||
|
||||
// module constraints on target platform
|
||||
private String osName;
|
||||
private String osArch;
|
||||
private String osVersion;
|
||||
|
||||
String osName() { return osName; }
|
||||
String osArch() { return osArch; }
|
||||
String osVersion() { return osVersion; }
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if there are more than one parent and
|
||||
* the constraints on the target platform conflict
|
||||
*/
|
||||
Resolver(ModuleFinder beforeFinder,
|
||||
List<Configuration> parents,
|
||||
ModuleFinder afterFinder,
|
||||
@ -75,15 +87,54 @@ final class Resolver {
|
||||
this.parents = parents;
|
||||
this.afterFinder = afterFinder;
|
||||
this.traceOutput = traceOutput;
|
||||
|
||||
// record constraints on target platform, checking that they don't conflict
|
||||
for (Configuration parent : parents) {
|
||||
String value = parent.osName();
|
||||
if (value != null) {
|
||||
if (osName == null) {
|
||||
osName = value;
|
||||
} else {
|
||||
if (!value.equals(osName)) {
|
||||
failParentConflict("Operating System", osName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
value = parent.osArch();
|
||||
if (value != null) {
|
||||
if (osArch == null) {
|
||||
osArch = value;
|
||||
} else {
|
||||
if (!value.equals(osArch)) {
|
||||
failParentConflict("OS architecture", osArch, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
value = parent.osVersion();
|
||||
if (value != null) {
|
||||
if (osVersion == null) {
|
||||
osVersion = value;
|
||||
} else {
|
||||
if (!value.equals(osVersion)) {
|
||||
failParentConflict("OS version", osVersion, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void failParentConflict(String constraint, String s1, String s2) {
|
||||
String msg = "Parents have conflicting constraints on target "
|
||||
+ constraint + ": " + s1 + ", " + s2;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the given named modules.
|
||||
*
|
||||
* @throws ResolutionException
|
||||
*/
|
||||
Resolver resolveRequires(Collection<String> roots) {
|
||||
Resolver resolve(Collection<String> roots) {
|
||||
|
||||
// create the visit stack to get us started
|
||||
Deque<ModuleDescriptor> q = new ArrayDeque<>();
|
||||
@ -100,7 +151,7 @@ final class Resolver {
|
||||
|
||||
mref = findWithAfterFinder(root);
|
||||
if (mref == null) {
|
||||
fail("Module %s not found", root);
|
||||
findFail("Module %s not found", root);
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,8 +160,7 @@ final class Resolver {
|
||||
mref.location().ifPresent(uri -> trace(" (%s)", uri));
|
||||
}
|
||||
|
||||
assert mref.descriptor().name().equals(root);
|
||||
nameToReference.put(root, mref);
|
||||
addFoundModule(mref);
|
||||
q.push(mref.descriptor());
|
||||
}
|
||||
|
||||
@ -152,19 +202,19 @@ final class Resolver {
|
||||
|
||||
mref = findWithAfterFinder(dn);
|
||||
if (mref == null) {
|
||||
fail("Module %s not found, required by %s",
|
||||
dn, descriptor.name());
|
||||
findFail("Module %s not found, required by %s",
|
||||
dn, descriptor.name());
|
||||
}
|
||||
}
|
||||
|
||||
if (!nameToReference.containsKey(dn)) {
|
||||
nameToReference.put(dn, mref);
|
||||
addFoundModule(mref);
|
||||
q.offer(mref.descriptor());
|
||||
resolved.add(mref.descriptor());
|
||||
|
||||
if (isTracing()) {
|
||||
trace("Module %s located, required by %s",
|
||||
dn, descriptor.name());
|
||||
dn, descriptor.name());
|
||||
mref.location().ifPresent(uri -> trace(" (%s)", uri));
|
||||
}
|
||||
}
|
||||
@ -181,7 +231,7 @@ final class Resolver {
|
||||
* Augments the set of resolved modules with modules induced by the
|
||||
* service-use relation.
|
||||
*/
|
||||
Resolver resolveUses() {
|
||||
Resolver bind() {
|
||||
|
||||
// Scan the finders for all available service provider modules. As
|
||||
// java.base uses services then then module finders will be scanned
|
||||
@ -246,7 +296,7 @@ final class Resolver {
|
||||
mref.location()
|
||||
.ifPresent(uri -> trace(" (%s)", uri));
|
||||
}
|
||||
nameToReference.put(pn, mref);
|
||||
addFoundModule(mref);
|
||||
q.push(provider);
|
||||
}
|
||||
}
|
||||
@ -263,6 +313,81 @@ final class Resolver {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the module to the nameToReference map. Also check any constraints on
|
||||
* the target platform with the constraints of other modules.
|
||||
*/
|
||||
private void addFoundModule(ModuleReference mref) {
|
||||
ModuleDescriptor descriptor = mref.descriptor();
|
||||
nameToReference.put(descriptor.name(), mref);
|
||||
|
||||
if (descriptor.osName().isPresent()
|
||||
|| descriptor.osArch().isPresent()
|
||||
|| descriptor.osVersion().isPresent())
|
||||
checkTargetConstraints(descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the module's constraints on the target platform do not
|
||||
* conflict with the constraints of other modules resolved so far or
|
||||
* modules in parent configurations.
|
||||
*/
|
||||
private void checkTargetConstraints(ModuleDescriptor descriptor) {
|
||||
String value = descriptor.osName().orElse(null);
|
||||
if (value != null) {
|
||||
if (osName == null) {
|
||||
osName = value;
|
||||
} else {
|
||||
if (!value.equals(osName)) {
|
||||
failTargetConstraint(descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
value = descriptor.osArch().orElse(null);
|
||||
if (value != null) {
|
||||
if (osArch == null) {
|
||||
osArch = value;
|
||||
} else {
|
||||
if (!value.equals(osArch)) {
|
||||
failTargetConstraint(descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
value = descriptor.osVersion().orElse(null);
|
||||
if (value != null) {
|
||||
if (osVersion == null) {
|
||||
osVersion = value;
|
||||
} else {
|
||||
if (!value.equals(osVersion)) {
|
||||
failTargetConstraint(descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void failTargetConstraint(ModuleDescriptor md) {
|
||||
String s1 = targetAsString(osName, osArch, osVersion);
|
||||
String s2 = targetAsString(md);
|
||||
findFail("Module %s has constraints on target platform that conflict" +
|
||||
" with other modules: %s, %s", md.name(), s1, s2);
|
||||
}
|
||||
|
||||
private String targetAsString(ModuleDescriptor descriptor) {
|
||||
String osName = descriptor.osName().orElse(null);
|
||||
String osArch = descriptor.osArch().orElse(null);
|
||||
String osVersion = descriptor.osVersion().orElse(null);
|
||||
return targetAsString(osName, osArch, osVersion);
|
||||
}
|
||||
|
||||
private String targetAsString(String osName, String osArch, String osVersion) {
|
||||
return new StringJoiner("-")
|
||||
.add(Objects.toString(osName, "*"))
|
||||
.add(Objects.toString(osArch, "*"))
|
||||
.add(Objects.toString(osVersion, "*"))
|
||||
.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute post-resolution checks and returns the module graph of resolved
|
||||
* modules as {@code Map}. The resolved modules will be in the given
|
||||
@ -281,7 +406,6 @@ final class Resolver {
|
||||
|
||||
if (check) {
|
||||
detectCycles();
|
||||
checkPlatformConstraints();
|
||||
checkHashes();
|
||||
}
|
||||
|
||||
@ -319,8 +443,7 @@ final class Resolver {
|
||||
if (!visited.contains(descriptor)) {
|
||||
boolean added = visitPath.add(descriptor);
|
||||
if (!added) {
|
||||
throw new ResolutionException("Cycle detected: " +
|
||||
cycleAsString(descriptor));
|
||||
resolveFail("Cycle detected: %s", cycleAsString(descriptor));
|
||||
}
|
||||
for (ModuleDescriptor.Requires requires : descriptor.requires()) {
|
||||
String dn = requires.name();
|
||||
@ -353,86 +476,6 @@ final class Resolver {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If there are platform specific modules then check that the OS name,
|
||||
* architecture and version match.
|
||||
*
|
||||
* @apiNote This method does not currently check if the OS matches
|
||||
* platform specific modules in parent configurations.
|
||||
*/
|
||||
private void checkPlatformConstraints() {
|
||||
|
||||
// first module encountered that is platform specific
|
||||
String savedModuleName = null;
|
||||
String savedOsName = null;
|
||||
String savedOsArch = null;
|
||||
String savedOsVersion = null;
|
||||
|
||||
for (ModuleReference mref : nameToReference.values()) {
|
||||
ModuleDescriptor descriptor = mref.descriptor();
|
||||
|
||||
String osName = descriptor.osName().orElse(null);
|
||||
String osArch = descriptor.osArch().orElse(null);
|
||||
String osVersion = descriptor.osVersion().orElse(null);
|
||||
|
||||
if (osName != null || osArch != null || osVersion != null) {
|
||||
|
||||
if (savedModuleName == null) {
|
||||
|
||||
savedModuleName = descriptor.name();
|
||||
savedOsName = osName;
|
||||
savedOsArch = osArch;
|
||||
savedOsVersion = osVersion;
|
||||
|
||||
} else {
|
||||
|
||||
boolean matches = platformMatches(osName, savedOsName)
|
||||
&& platformMatches(osArch, savedOsArch)
|
||||
&& platformMatches(osVersion, savedOsVersion);
|
||||
|
||||
if (!matches) {
|
||||
String s1 = platformAsString(savedOsName,
|
||||
savedOsArch,
|
||||
savedOsVersion);
|
||||
|
||||
String s2 = platformAsString(osName, osArch, osVersion);
|
||||
fail("Mismatching constraints on target platform: "
|
||||
+ savedModuleName + ": " + s1
|
||||
+ ", " + descriptor.name() + ": " + s2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the s1 and s2 are equal or one of them is null.
|
||||
*/
|
||||
private boolean platformMatches(String s1, String s2) {
|
||||
if (s1 == null || s2 == null)
|
||||
return true;
|
||||
else
|
||||
return Objects.equals(s1, s2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string that encodes the OS name/arch/version.
|
||||
*/
|
||||
private String platformAsString(String osName,
|
||||
String osArch,
|
||||
String osVersion) {
|
||||
|
||||
return new StringJoiner("-")
|
||||
.add(Objects.toString(osName, "*"))
|
||||
.add(Objects.toString(osArch, "*"))
|
||||
.add(Objects.toString(osVersion, "*"))
|
||||
.toString();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the hashes in the module descriptor to ensure that they match
|
||||
* any recorded hashes.
|
||||
@ -460,7 +503,7 @@ final class Resolver {
|
||||
continue;
|
||||
|
||||
if (!(mref2 instanceof ModuleReferenceImpl)) {
|
||||
fail("Unable to compute the hash of module %s", dn);
|
||||
findFail("Unable to compute the hash of module %s", dn);
|
||||
}
|
||||
|
||||
// skip checking the hash if the module has been patched
|
||||
@ -469,11 +512,11 @@ final class Resolver {
|
||||
byte[] recordedHash = hashes.hashFor(dn);
|
||||
byte[] actualHash = other.computeHash(algorithm);
|
||||
if (actualHash == null)
|
||||
fail("Unable to compute the hash of module %s", dn);
|
||||
findFail("Unable to compute the hash of module %s", dn);
|
||||
if (!Arrays.equals(recordedHash, actualHash)) {
|
||||
fail("Hash of %s (%s) differs to expected hash (%s)" +
|
||||
" recorded in %s", dn, toHexString(actualHash),
|
||||
toHexString(recordedHash), descriptor.name());
|
||||
findFail("Hash of %s (%s) differs to expected hash (%s)" +
|
||||
" recorded in %s", dn, toHexString(actualHash),
|
||||
toHexString(recordedHash), descriptor.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -694,37 +737,38 @@ final class Resolver {
|
||||
for (ResolvedModule endpoint : reads) {
|
||||
ModuleDescriptor descriptor2 = endpoint.descriptor();
|
||||
|
||||
for (ModuleDescriptor.Exports export : descriptor2.exports()) {
|
||||
if (descriptor2.isAutomatic()) {
|
||||
// automatic modules read self and export all packages
|
||||
if (descriptor2 != descriptor1){
|
||||
for (String source : descriptor2.packages()) {
|
||||
ModuleDescriptor supplier
|
||||
= packageToExporter.putIfAbsent(source, descriptor2);
|
||||
|
||||
if (export.isQualified()) {
|
||||
if (!export.targets().contains(descriptor1.name()))
|
||||
continue;
|
||||
}
|
||||
|
||||
// source is exported to descriptor2
|
||||
String source = export.source();
|
||||
ModuleDescriptor other
|
||||
= packageToExporter.putIfAbsent(source, descriptor2);
|
||||
|
||||
if (other != null && other != descriptor2) {
|
||||
// package might be local to descriptor1
|
||||
if (other == descriptor1) {
|
||||
fail("Module %s contains package %s"
|
||||
+ ", module %s exports package %s to %s",
|
||||
descriptor1.name(),
|
||||
source,
|
||||
descriptor2.name(),
|
||||
source,
|
||||
descriptor1.name());
|
||||
} else {
|
||||
fail("Modules %s and %s export package %s to module %s",
|
||||
descriptor2.name(),
|
||||
other.name(),
|
||||
source,
|
||||
descriptor1.name());
|
||||
// descriptor2 and 'supplier' export source to descriptor1
|
||||
if (supplier != null) {
|
||||
failTwoSuppliers(descriptor1, source, descriptor2, supplier);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
for (ModuleDescriptor.Exports export : descriptor2.exports()) {
|
||||
if (export.isQualified()) {
|
||||
if (!export.targets().contains(descriptor1.name()))
|
||||
continue;
|
||||
}
|
||||
|
||||
// source is exported by descriptor2
|
||||
String source = export.source();
|
||||
ModuleDescriptor supplier
|
||||
= packageToExporter.putIfAbsent(source, descriptor2);
|
||||
|
||||
// descriptor2 and 'supplier' export source to descriptor1
|
||||
if (supplier != null) {
|
||||
failTwoSuppliers(descriptor1, source, descriptor2, supplier);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -735,8 +779,8 @@ final class Resolver {
|
||||
for (String service : descriptor1.uses()) {
|
||||
String pn = packageName(service);
|
||||
if (!packageToExporter.containsKey(pn)) {
|
||||
fail("Module %s does not read a module that exports %s",
|
||||
descriptor1.name(), pn);
|
||||
resolveFail("Module %s does not read a module that exports %s",
|
||||
descriptor1.name(), pn);
|
||||
}
|
||||
}
|
||||
|
||||
@ -744,15 +788,8 @@ final class Resolver {
|
||||
for (ModuleDescriptor.Provides provides : descriptor1.provides()) {
|
||||
String pn = packageName(provides.service());
|
||||
if (!packageToExporter.containsKey(pn)) {
|
||||
fail("Module %s does not read a module that exports %s",
|
||||
descriptor1.name(), pn);
|
||||
}
|
||||
|
||||
for (String provider : provides.providers()) {
|
||||
if (!packages.contains(packageName(provider))) {
|
||||
fail("Provider %s not in module %s",
|
||||
provider, descriptor1.name());
|
||||
}
|
||||
resolveFail("Module %s does not read a module that exports %s",
|
||||
descriptor1.name(), pn);
|
||||
}
|
||||
}
|
||||
|
||||
@ -762,6 +799,42 @@ final class Resolver {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Fail because a module in the configuration exports the same package to
|
||||
* a module that reads both. This includes the case where a module M
|
||||
* containing a package p reads another module that exports p to at least
|
||||
* module M.
|
||||
*/
|
||||
private void failTwoSuppliers(ModuleDescriptor descriptor,
|
||||
String source,
|
||||
ModuleDescriptor supplier1,
|
||||
ModuleDescriptor supplier2) {
|
||||
|
||||
if (supplier2 == descriptor) {
|
||||
ModuleDescriptor tmp = supplier1;
|
||||
supplier1 = supplier2;
|
||||
supplier2 = tmp;
|
||||
}
|
||||
|
||||
if (supplier1 == descriptor) {
|
||||
resolveFail("Module %s contains package %s"
|
||||
+ ", module %s exports package %s to %s",
|
||||
descriptor.name(),
|
||||
source,
|
||||
supplier2.name(),
|
||||
source,
|
||||
descriptor.name());
|
||||
} else {
|
||||
resolveFail("Modules %s and %s export package %s to module %s",
|
||||
supplier1.name(),
|
||||
supplier2.name(),
|
||||
source,
|
||||
descriptor.name());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a module of the given name in the parent configurations
|
||||
*/
|
||||
@ -779,24 +852,16 @@ final class Resolver {
|
||||
* Invokes the beforeFinder to find method to find the given module.
|
||||
*/
|
||||
private ModuleReference findWithBeforeFinder(String mn) {
|
||||
try {
|
||||
return beforeFinder.find(mn).orElse(null);
|
||||
} catch (FindException e) {
|
||||
// unwrap
|
||||
throw new ResolutionException(e.getMessage(), e.getCause());
|
||||
}
|
||||
|
||||
return beforeFinder.find(mn).orElse(null);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the afterFinder to find method to find the given module.
|
||||
*/
|
||||
private ModuleReference findWithAfterFinder(String mn) {
|
||||
try {
|
||||
return afterFinder.find(mn).orElse(null);
|
||||
} catch (FindException e) {
|
||||
// unwrap
|
||||
throw new ResolutionException(e.getMessage(), e.getCause());
|
||||
}
|
||||
return afterFinder.find(mn).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -804,34 +869,27 @@ final class Resolver {
|
||||
* and after ModuleFinders.
|
||||
*/
|
||||
private Set<ModuleReference> findAll() {
|
||||
try {
|
||||
Set<ModuleReference> beforeModules = beforeFinder.findAll();
|
||||
Set<ModuleReference> afterModules = afterFinder.findAll();
|
||||
|
||||
Set<ModuleReference> beforeModules = beforeFinder.findAll();
|
||||
Set<ModuleReference> afterModules = afterFinder.findAll();
|
||||
if (afterModules.isEmpty())
|
||||
return beforeModules;
|
||||
|
||||
if (afterModules.isEmpty())
|
||||
return beforeModules;
|
||||
if (beforeModules.isEmpty()
|
||||
&& parents.size() == 1
|
||||
&& parents.get(0) == Configuration.empty())
|
||||
return afterModules;
|
||||
|
||||
if (beforeModules.isEmpty()
|
||||
&& parents.size() == 1
|
||||
&& parents.get(0) == Configuration.empty())
|
||||
return afterModules;
|
||||
|
||||
Set<ModuleReference> result = new HashSet<>(beforeModules);
|
||||
for (ModuleReference mref : afterModules) {
|
||||
String name = mref.descriptor().name();
|
||||
if (!beforeFinder.find(name).isPresent()
|
||||
&& findInParent(name) == null) {
|
||||
result.add(mref);
|
||||
}
|
||||
Set<ModuleReference> result = new HashSet<>(beforeModules);
|
||||
for (ModuleReference mref : afterModules) {
|
||||
String name = mref.descriptor().name();
|
||||
if (!beforeFinder.find(name).isPresent()
|
||||
&& findInParent(name) == null) {
|
||||
result.add(mref);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} catch (FindException e) {
|
||||
// unwrap
|
||||
throw new ResolutionException(e.getMessage(), e.getCause());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -842,10 +900,18 @@ final class Resolver {
|
||||
return (index == -1) ? "" : cn.substring(0, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw FindException with the given format string and arguments
|
||||
*/
|
||||
private static void findFail(String fmt, Object ... args) {
|
||||
String msg = String.format(fmt, args);
|
||||
throw new FindException(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw ResolutionException with the given format string and arguments
|
||||
*/
|
||||
private static void fail(String fmt, Object ... args) {
|
||||
private static void resolveFail(String fmt, Object ... args) {
|
||||
String msg = String.format(fmt, args);
|
||||
throw new ResolutionException(msg);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 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
|
||||
@ -27,6 +27,112 @@
|
||||
* Classes to support module descriptors and creating configurations of modules
|
||||
* by means of resolution and service binding.
|
||||
*
|
||||
* <h2><a name="resolution">Resolution</a></h2>
|
||||
*
|
||||
* <p> Resolution is the process of computing the transitive closure of a set
|
||||
* of root modules over a set of observable modules by resolving the
|
||||
* dependences expressed by {@link
|
||||
* java.lang.module.ModuleDescriptor.Requires requires} clauses.
|
||||
* The <em>dependence graph</em> is augmented with edges that take account of
|
||||
* implicitly declared dependences ({@code requires transitive}) to create a
|
||||
* <em>readability graph</em>. The result of resolution is a {@link
|
||||
* java.lang.module.Configuration Configuration} that encapsulates the
|
||||
* readability graph. </p>
|
||||
*
|
||||
* <p> As an example, suppose we have the following observable modules: </p>
|
||||
* <pre> {@code
|
||||
* module m1 { requires m2; }
|
||||
* module m2 { requires transitive m3; }
|
||||
* module m3 { }
|
||||
* module m4 { }
|
||||
* } </pre>
|
||||
*
|
||||
* <p> If the module {@code m1} is resolved then the resulting configuration
|
||||
* contains three modules ({@code m1}, {@code m2}, {@code m3}). The edges in
|
||||
* its readability graph are: </p>
|
||||
* <pre> {@code
|
||||
* m1 --> m2 (meaning m1 reads m2)
|
||||
* m1 --> m3
|
||||
* m2 --> m3
|
||||
* } </pre>
|
||||
*
|
||||
* <p> Resolution is an additive process. When computing the transitive closure
|
||||
* then the dependence relation may include dependences on modules in {@link
|
||||
* java.lang.module.Configuration#parents() parent} configurations. The result
|
||||
* is a <em>relative configuration</em> that is relative to one or more parent
|
||||
* configurations and where the readability graph may have edges from modules
|
||||
* in the configuration to modules in parent configurations. </p>
|
||||
*
|
||||
* <p> As an example, suppose we have the following observable modules: </p>
|
||||
* <pre> {@code
|
||||
* module m1 { requires m2; requires java.xml; }
|
||||
* module m2 { }
|
||||
* } </pre>
|
||||
*
|
||||
* <p> If module {@code m1} is resolved with the configuration for the {@link
|
||||
* java.lang.reflect.Layer#boot() boot} layer as the parent then the resulting
|
||||
* configuration contains two modules ({@code m1}, {@code m2}). The edges in
|
||||
* its readability graph are:
|
||||
* <pre> {@code
|
||||
* m1 --> m2
|
||||
* m1 --> java.xml
|
||||
* } </pre>
|
||||
* where module {@code java.xml} is in the parent configuration. For
|
||||
* simplicity, this example omits the implicitly declared dependence on the
|
||||
* {@code java.base} module.
|
||||
*
|
||||
* <p> Requires clauses that are "{@code requires static}" express an optional
|
||||
* dependence (except at compile-time). If a module declares that it
|
||||
* "{@code requires static M}" then resolution does not search the observable
|
||||
* modules for "{@code M}". However, if "{@code M}" is resolved (because resolution
|
||||
* resolves a module that requires "{@code M}" without the {@link
|
||||
* java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC static} modifier)
|
||||
* then the readability graph will contain read edges for each module that
|
||||
* "{@code requires static M}". </p>
|
||||
*
|
||||
* <p> {@link java.lang.module.ModuleDescriptor#isAutomatic() Automatic} modules
|
||||
* receive special treatment during resolution. Each automatic module is resolved
|
||||
* so that it reads all other modules in the configuration and all parent
|
||||
* configurations. Each automatic module is also resolved as if it
|
||||
* "{@code requires transitive}" all other automatic modules in the configuration
|
||||
* (and all automatic modules in parent configurations). </p>
|
||||
*
|
||||
* <h2><a name="servicebinding">Service binding</a></h2>
|
||||
*
|
||||
* <p> Service binding is the process of augmenting a graph of resolved modules
|
||||
* from the set of observable modules induced by the service-use dependence
|
||||
* ({@code uses} and {@code provides} clauses). Any module that was not
|
||||
* previously in the graph requires resolution to compute its transitive
|
||||
* closure. Service binding is an iterative process in that adding a module
|
||||
* that satisfies some service-use dependence may introduce new service-use
|
||||
* dependences. </p>
|
||||
*
|
||||
* <p> Suppose we have the following observable modules: </p>
|
||||
* <pre> {@code
|
||||
* module m1 { exports p; uses p.S; }
|
||||
* module m2 { requires m1; provides p.S with p2.S2; }
|
||||
* module m3 { requires m1; requires m4; provides p.S with p3.S3; }
|
||||
* module m4 { }
|
||||
* } </pre>
|
||||
*
|
||||
* <p> If the module {@code m1} is resolved then the resulting graph of modules
|
||||
* has one module ({@code m1}). If the graph is augmented with modules induced
|
||||
* by the service-use dependence relation then the configuration will contain
|
||||
* four modules ({@code m1}, {@code m2}, {@code m3}, {@code m4}). The edges in
|
||||
* its readability graph are: </p>
|
||||
* <pre> {@code
|
||||
* m2 --> m1
|
||||
* m3 --> m1
|
||||
* m3 --> m4
|
||||
* } </pre>
|
||||
* <p> The edges in the conceptual service-use graph are: </p>
|
||||
* <pre> {@code
|
||||
* m1 --> m2 (meaning m1 uses a service that is provided by m2)
|
||||
* m1 --> m3
|
||||
* } </pre>
|
||||
*
|
||||
* <h2>General Exceptions</h2>
|
||||
*
|
||||
* <p> Unless otherwise noted, passing a {@code null} argument to a constructor
|
||||
* or method of any class or interface in this package will cause a {@link
|
||||
* java.lang.NullPointerException NullPointerException} to be thrown. Additionally,
|
||||
@ -34,6 +140,7 @@
|
||||
* will cause a {@code NullPointerException}, unless otherwise specified. </p>
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
|
||||
package java.lang.module;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -28,38 +28,44 @@ package java.lang.reflect;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.security.AccessController;
|
||||
|
||||
import jdk.internal.misc.VM;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
import jdk.internal.reflect.ReflectionFactory;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* The AccessibleObject class is the base class for Field, Method and
|
||||
* Constructor objects. It provides the ability to flag a reflected
|
||||
* object as suppressing default Java language access control checks
|
||||
* when it is used. The access checks -- <em>module boundaries</em>,
|
||||
* public, default (package) access, protected, and private members --
|
||||
* are performed when Fields, Methods or Constructors are used to set
|
||||
* or get fields, to invoke methods or to create and initialize new
|
||||
* instances of classes, respectively. Unlike access control specified
|
||||
* in the <cite>The Java™ Language Specification</cite> and
|
||||
* <cite>The Java Virtual Machine Specification</cite>, access checks
|
||||
* with reflected objects assume {@link Module#canRead readability}.
|
||||
* The {@code AccessibleObject} class is the base class for {@code Field},
|
||||
* {@code Method}, and {@code Constructor} objects (known as <em>reflected
|
||||
* objects</em>). It provides the ability to flag a reflected object as
|
||||
* suppressing checks for Java language access control when it is used. This
|
||||
* permits sophisticated applications with sufficient privilege, such as Java
|
||||
* Object Serialization or other persistence mechanisms, to manipulate objects
|
||||
* in a manner that would normally be prohibited.
|
||||
*
|
||||
* <p>Setting the {@code accessible} flag in a reflected object
|
||||
* permits sophisticated applications with sufficient privilege, such
|
||||
* as Java Object Serialization or other persistence mechanisms, to
|
||||
* manipulate objects in a manner that would normally be prohibited.
|
||||
* <p> Java language access control prevents use of private members outside
|
||||
* their class; package access members outside their package; protected members
|
||||
* outside their package or subclasses; and public members outside their
|
||||
* module unless they are declared in an {@link Module#isExported(String,Module)
|
||||
* exported} package and the user {@link Module#canRead reads} their module. By
|
||||
* default, Java language access control is enforced (with one variation) when
|
||||
* {@code Field}s, {@code Method}s, or {@code Constructor}s are used to get or
|
||||
* set fields, to invoke methods, or to create and initialize new instances of
|
||||
* classes, respectively. Every reflected object checks that the code using it
|
||||
* is in an appropriate class, package, or module. </p>
|
||||
*
|
||||
* <p>By default, a reflected object is <em>not</em> accessible.
|
||||
* <p> The one variation from Java language access control is that the checks
|
||||
* by reflected objects assume readability. That is, the module containing
|
||||
* the use of a reflected object is assumed to read the module in which
|
||||
* the underlying field, method, or constructor is declared. </p>
|
||||
*
|
||||
* @see Field
|
||||
* @see Method
|
||||
* @see Constructor
|
||||
* @see ReflectPermission
|
||||
* <p> Whether the checks for Java language access control can be suppressed
|
||||
* (and thus, whether access can be enabled) depends on whether the reflected
|
||||
* object corresponds to a member in an exported or open package
|
||||
* (see {@link #setAccessible(boolean)}). </p>
|
||||
*
|
||||
* @jls 6.6 Access Control
|
||||
* @since 1.2
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public class AccessibleObject implements AnnotatedElement {
|
||||
|
||||
@ -78,15 +84,11 @@ public class AccessibleObject implements AnnotatedElement {
|
||||
|
||||
/**
|
||||
* Convenience method to set the {@code accessible} flag for an
|
||||
* array of objects with a single security check (for efficiency).
|
||||
* array of reflected objects with a single security check (for efficiency).
|
||||
*
|
||||
* <p>This method cannot be used to enable access to an object that is a
|
||||
* {@link Member member} of a class in a different module to the caller and
|
||||
* where the class is in a package that is not exported to the caller's
|
||||
* module. Additionally, if the member is non-public or its declaring
|
||||
* class is non-public, then this method can only be used to enable access
|
||||
* if the package is {@link Module#isOpen(String,Module) open} to at least
|
||||
* the caller's module.
|
||||
* <p> This method may be used to enable access to all reflected objects in
|
||||
* the array when access to each reflected object can be enabled as
|
||||
* specified by {@link #setAccessible(boolean) setAccessible(boolean)}. </p>
|
||||
*
|
||||
* <p>If there is a security manager, its
|
||||
* {@code checkPermission} method is first called with a
|
||||
@ -99,10 +101,15 @@ public class AccessibleObject implements AnnotatedElement {
|
||||
* @param array the array of AccessibleObjects
|
||||
* @param flag the new value for the {@code accessible} flag
|
||||
* in each object
|
||||
* @throws InaccessibleObjectException if access cannot be enabled
|
||||
* @throws SecurityException if the request is denied.
|
||||
* @throws InaccessibleObjectException if access cannot be enabled for all
|
||||
* objects in the array
|
||||
* @throws SecurityException if the request is denied by the security manager
|
||||
* or an element in the array is a constructor for {@code
|
||||
* java.lang.Class}
|
||||
* @see SecurityManager#checkPermission
|
||||
* @see ReflectPermission
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static void setAccessible(AccessibleObject[] array, boolean flag) {
|
||||
@ -120,41 +127,143 @@ public class AccessibleObject implements AnnotatedElement {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@code accessible} flag for this object to
|
||||
* Set the {@code accessible} flag for this reflected object to
|
||||
* the indicated boolean value. A value of {@code true} indicates that
|
||||
* the reflected object should suppress Java language access
|
||||
* checking when it is used. A value of {@code false} indicates
|
||||
* that the reflected object should enforce Java language access checks
|
||||
* while assuming readability (as noted in the class description).
|
||||
* the reflected object should suppress checks for Java language access
|
||||
* control when it is used. A value of {@code false} indicates that
|
||||
* the reflected object should enforce checks for Java language access
|
||||
* control when it is used, with the variation noted in the class description.
|
||||
*
|
||||
* <p>This method cannot be used to enable access to an object that is a
|
||||
* {@link Member member} of a class in a different module to the caller and
|
||||
* where the class is in a package that is not exported to the caller's
|
||||
* module. Additionally, if the member is non-public or its declaring
|
||||
* class is non-public, then this method can only be used to enable access
|
||||
* if the package is {@link Module#isOpen(String,Module) open} to at least
|
||||
* the caller's module.
|
||||
* <p> This method may be used by a caller in class {@code C} to enable
|
||||
* access to a {@link Member member} of {@link Member#getDeclaringClass()
|
||||
* declaring class} {@code D} if any of the following hold: </p>
|
||||
*
|
||||
* <p>If there is a security manager, its
|
||||
* <ul>
|
||||
* <li> {@code C} and {@code D} are in the same module. </li>
|
||||
*
|
||||
* <li> The member is {@code public} and {@code D} is {@code public} in
|
||||
* a package that the module containing {@code D} {@link
|
||||
* Module#isExported(String,Module) exports} to at least the module
|
||||
* containing {@code C}. </li>
|
||||
*
|
||||
* <li> The member is {@code protected} {@code static}, {@code D} is
|
||||
* {@code public} in a package that the module containing {@code D}
|
||||
* exports to at least the module containing {@code C}, and {@code C}
|
||||
* is a subclass of {@code D}. </li>
|
||||
*
|
||||
* <li> {@code D} is in a package that the module containing {@code D}
|
||||
* {@link Module#isOpen(String,Module) opens} to at least the module
|
||||
* containing {@code C}.
|
||||
* All packages in unnamed and open modules are open to all modules and
|
||||
* so this method always succeeds when {@code D} is in an unnamed or
|
||||
* open module. </li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> This method cannot be used to enable access to private members,
|
||||
* members with default (package) access, protected instance members, or
|
||||
* protected constructors when the declaring class is in a different module
|
||||
* to the caller and the package containing the declaring class is not open
|
||||
* to the caller's module. </p>
|
||||
*
|
||||
* <p> If there is a security manager, its
|
||||
* {@code checkPermission} method is first called with a
|
||||
* {@code ReflectPermission("suppressAccessChecks")} permission.
|
||||
*
|
||||
* @param flag the new value for the {@code accessible} flag
|
||||
* @throws InaccessibleObjectException if access cannot be enabled
|
||||
* @throws SecurityException if the request is denied
|
||||
* @see SecurityManager#checkPermission
|
||||
* @see ReflectPermission
|
||||
* @throws SecurityException if the request is denied by the security manager
|
||||
* @see #trySetAccessible
|
||||
* @see java.lang.invoke.MethodHandles#privateLookupIn
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public void setAccessible(boolean flag) {
|
||||
AccessibleObject.checkPermission();
|
||||
setAccessible0(flag);
|
||||
}
|
||||
|
||||
void setAccessible0(boolean flag) {
|
||||
/**
|
||||
* Sets the accessible flag and returns the new value
|
||||
*/
|
||||
boolean setAccessible0(boolean flag) {
|
||||
this.override = flag;
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@code accessible} flag for this reflected object to {@code true}
|
||||
* if possible. This method sets the {@code accessible} flag, as if by
|
||||
* invoking {@link #setAccessible(boolean) setAccessible(true)}, and returns
|
||||
* the possibly-updated value for the {@code accessible} flag. If access
|
||||
* cannot be enabled, i.e. the checks or Java language access control cannot
|
||||
* be suppressed, this method returns {@code false} (as opposed to {@code
|
||||
* setAccessible(true)} throwing {@code InaccessibleObjectException} when
|
||||
* it fails).
|
||||
*
|
||||
* <p> This method is a no-op if the {@code accessible} flag for
|
||||
* this reflected object is {@code true}.
|
||||
*
|
||||
* <p> For example, a caller can invoke {@code trySetAccessible}
|
||||
* on a {@code Method} object for a private instance method
|
||||
* {@code p.T::privateMethod} to suppress the checks for Java language access
|
||||
* control when the {@code Method} is invoked.
|
||||
* If {@code p.T} class is in a different module to the caller and
|
||||
* package {@code p} is open to at least the caller's module,
|
||||
* the code below successfully sets the {@code accessible} flag
|
||||
* to {@code true}.
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* p.T obj = ....; // instance of p.T
|
||||
* :
|
||||
* Method m = p.T.class.getDeclaredMethod("privateMethod");
|
||||
* if (m.trySetAccessible()) {
|
||||
* m.invoke(obj);
|
||||
* } else {
|
||||
* // package p is not opened to the caller to access private member of T
|
||||
* ...
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p> If there is a security manager, its {@code checkPermission} method
|
||||
* is first called with a {@code ReflectPermission("suppressAccessChecks")}
|
||||
* permission. </p>
|
||||
*
|
||||
* @return {@code true} if the {@code accessible} flag is set to {@code true};
|
||||
* {@code false} if access cannot be enabled.
|
||||
* @throws SecurityException if the request is denied by the security manager
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
* @see java.lang.invoke.MethodHandles#privateLookupIn
|
||||
*/
|
||||
@CallerSensitive
|
||||
public final boolean trySetAccessible() {
|
||||
AccessibleObject.checkPermission();
|
||||
|
||||
if (override == true) return true;
|
||||
|
||||
// if it's not a Constructor, Method, Field then no access check
|
||||
if (!Member.class.isInstance(this)) {
|
||||
return setAccessible0(true);
|
||||
}
|
||||
|
||||
// does not allow to suppress access check for Class's constructor
|
||||
Class<?> declaringClass = ((Member) this).getDeclaringClass();
|
||||
if (declaringClass == Class.class && this instanceof Constructor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checkCanSetAccessible(Reflection.getCallerClass(),
|
||||
declaringClass,
|
||||
false)) {
|
||||
return setAccessible0(true);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the given AccessibleObject is a {@code Constructor}, {@code Method}
|
||||
* or {@code Field} then checks that its declaring class is in a package
|
||||
@ -164,22 +273,29 @@ public class AccessibleObject implements AnnotatedElement {
|
||||
// do nothing, needs to be overridden by Constructor, Method, Field
|
||||
}
|
||||
|
||||
|
||||
void checkCanSetAccessible(Class<?> caller, Class<?> declaringClass) {
|
||||
checkCanSetAccessible(caller, declaringClass, true);
|
||||
}
|
||||
|
||||
private boolean checkCanSetAccessible(Class<?> caller,
|
||||
Class<?> declaringClass,
|
||||
boolean throwExceptionIfDenied) {
|
||||
Module callerModule = caller.getModule();
|
||||
Module declaringModule = declaringClass.getModule();
|
||||
|
||||
if (callerModule == declaringModule) return;
|
||||
if (callerModule == Object.class.getModule()) return;
|
||||
if (!declaringModule.isNamed()) return;
|
||||
if (callerModule == declaringModule) return true;
|
||||
if (callerModule == Object.class.getModule()) return true;
|
||||
if (!declaringModule.isNamed()) return true;
|
||||
|
||||
// package is open to caller
|
||||
String pn = packageName(declaringClass);
|
||||
if (declaringModule.isOpen(pn, callerModule)) {
|
||||
printStackTraceIfOpenedReflectively(declaringModule, pn, callerModule);
|
||||
return;
|
||||
dumpStackIfOpenedReflectively(declaringModule, pn, callerModule);
|
||||
return true;
|
||||
}
|
||||
|
||||
// package is exported to caller and class/member is public
|
||||
// package is exported to caller
|
||||
boolean isExported = declaringModule.isExported(pn, callerModule);
|
||||
boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers());
|
||||
int modifiers;
|
||||
@ -188,48 +304,72 @@ public class AccessibleObject implements AnnotatedElement {
|
||||
} else {
|
||||
modifiers = ((Field) this).getModifiers();
|
||||
}
|
||||
boolean isMemberPublic = Modifier.isPublic(modifiers);
|
||||
if (isExported && isClassPublic && isMemberPublic) {
|
||||
printStackTraceIfExportedReflectively(declaringModule, pn, callerModule);
|
||||
return;
|
||||
if (isExported && isClassPublic) {
|
||||
|
||||
// member is public
|
||||
if (Modifier.isPublic(modifiers)) {
|
||||
dumpStackIfExportedReflectively(declaringModule, pn, callerModule);
|
||||
return true;
|
||||
}
|
||||
|
||||
// member is protected-static
|
||||
if (Modifier.isProtected(modifiers)
|
||||
&& Modifier.isStatic(modifiers)
|
||||
&& isSubclassOf(caller, declaringClass)) {
|
||||
dumpStackIfExportedReflectively(declaringModule, pn, callerModule);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// not accessible
|
||||
String msg = "Unable to make ";
|
||||
if (this instanceof Field)
|
||||
msg += "field ";
|
||||
msg += this + " accessible: " + declaringModule + " does not \"";
|
||||
if (isClassPublic && isMemberPublic)
|
||||
msg += "exports";
|
||||
else
|
||||
msg += "opens";
|
||||
msg += " " + pn + "\" to " + callerModule;
|
||||
InaccessibleObjectException e = new InaccessibleObjectException(msg);
|
||||
if (Reflection.printStackTraceWhenAccessFails()) {
|
||||
e.printStackTrace(System.err);
|
||||
if (throwExceptionIfDenied) {
|
||||
// not accessible
|
||||
String msg = "Unable to make ";
|
||||
if (this instanceof Field)
|
||||
msg += "field ";
|
||||
msg += this + " accessible: " + declaringModule + " does not \"";
|
||||
if (isClassPublic && Modifier.isPublic(modifiers))
|
||||
msg += "exports";
|
||||
else
|
||||
msg += "opens";
|
||||
msg += " " + pn + "\" to " + callerModule;
|
||||
InaccessibleObjectException e = new InaccessibleObjectException(msg);
|
||||
if (Reflection.printStackTraceWhenAccessFails()) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
throw e;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void printStackTraceIfOpenedReflectively(Module module,
|
||||
String pn,
|
||||
Module other) {
|
||||
printStackTraceIfExposedReflectively(module, pn, other, true);
|
||||
private boolean isSubclassOf(Class<?> queryClass, Class<?> ofClass) {
|
||||
while (queryClass != null) {
|
||||
if (queryClass == ofClass) {
|
||||
return true;
|
||||
}
|
||||
queryClass = queryClass.getSuperclass();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void printStackTraceIfExportedReflectively(Module module,
|
||||
String pn,
|
||||
Module other) {
|
||||
printStackTraceIfExposedReflectively(module, pn, other, false);
|
||||
private void dumpStackIfOpenedReflectively(Module module,
|
||||
String pn,
|
||||
Module other) {
|
||||
dumpStackIfExposedReflectively(module, pn, other, true);
|
||||
}
|
||||
|
||||
private void printStackTraceIfExposedReflectively(Module module,
|
||||
String pn,
|
||||
Module other,
|
||||
boolean open)
|
||||
private void dumpStackIfExportedReflectively(Module module,
|
||||
String pn,
|
||||
Module other) {
|
||||
dumpStackIfExposedReflectively(module, pn, other, false);
|
||||
}
|
||||
|
||||
private void dumpStackIfExposedReflectively(Module module,
|
||||
String pn,
|
||||
Module other,
|
||||
boolean open)
|
||||
{
|
||||
if (Reflection.printStackTraceWhenAccessSucceeds()
|
||||
&& !module.isStaticallyExportedOrOpen(pn, other, open))
|
||||
&& !module.isStaticallyExportedOrOpen(pn, other, open))
|
||||
{
|
||||
String msg = other + " allowed to invoke setAccessible on ";
|
||||
if (this instanceof Field)
|
||||
@ -256,14 +396,99 @@ public class AccessibleObject implements AnnotatedElement {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the {@code accessible} flag for this object.
|
||||
* Get the value of the {@code accessible} flag for this reflected object.
|
||||
*
|
||||
* @return the value of the object's {@code accessible} flag
|
||||
*
|
||||
* @deprecated
|
||||
* This method is deprecated because its name hints that it checks
|
||||
* if the reflected object is accessible when it actually indicates
|
||||
* if the checks for Java language access control are suppressed.
|
||||
* This method may return {@code false} on a reflected object that is
|
||||
* accessible to the caller. To test if this reflected object is accessible,
|
||||
* it should use {@link #canAccess(Object)}.
|
||||
*
|
||||
* @revised 9
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
public boolean isAccessible() {
|
||||
return override;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the caller can access this reflected object. If this reflected
|
||||
* object corresponds to an instance method or field then this method tests
|
||||
* if the caller can access the given {@code obj} with the reflected object.
|
||||
* For instance methods or fields then the {@code obj} argument must be an
|
||||
* instance of the {@link Member#getDeclaringClass() declaring class}. For
|
||||
* static members and constructors then {@code obj} must be {@code null}.
|
||||
*
|
||||
* <p> This method returns {@code true} if the {@code accessible} flag
|
||||
* is set to {@code true}, i.e. the checks for Java language access control
|
||||
* are suppressed, or if the caller can access the member as
|
||||
* specified in <cite>The Java™ Language Specification</cite>,
|
||||
* with the variation noted in the class description. </p>
|
||||
*
|
||||
* @param obj an instance object of the declaring class of this reflected
|
||||
* object if it is an instance method or field
|
||||
*
|
||||
* @return {@code true} if the caller can access this reflected object.
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* <ul>
|
||||
* <li> if this reflected object is a static member or constructor and
|
||||
* the given {@code obj} is non-{@code null}, or </li>
|
||||
* <li> if this reflected object is an instance method or field
|
||||
* and the given {@code obj} is {@code null} or of type
|
||||
* that is not a subclass of the {@link Member#getDeclaringClass()
|
||||
* declaring class} of the member.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
* @jls 6.6 Access Control
|
||||
* @see #trySetAccessible
|
||||
* @see #setAccessible(boolean)
|
||||
*/
|
||||
@CallerSensitive
|
||||
public final boolean canAccess(Object obj) {
|
||||
if (!Member.class.isInstance(this)) {
|
||||
return override;
|
||||
}
|
||||
|
||||
Class<?> declaringClass = ((Member) this).getDeclaringClass();
|
||||
int modifiers = ((Member) this).getModifiers();
|
||||
if (!Modifier.isStatic(modifiers) &&
|
||||
(this instanceof Method || this instanceof Field)) {
|
||||
if (obj == null) {
|
||||
throw new IllegalArgumentException("null object for " + this);
|
||||
}
|
||||
// if this object is an instance member, the given object
|
||||
// must be a subclass of the declaring class of this reflected object
|
||||
if (!declaringClass.isAssignableFrom(obj.getClass())) {
|
||||
throw new IllegalArgumentException("object is not an instance of "
|
||||
+ declaringClass.getName());
|
||||
}
|
||||
} else if (obj != null) {
|
||||
throw new IllegalArgumentException("non-null object for " + this);
|
||||
}
|
||||
|
||||
// access check is suppressed
|
||||
if (override) return true;
|
||||
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
Class<?> targetClass;
|
||||
if (this instanceof Constructor) {
|
||||
targetClass = declaringClass;
|
||||
} else {
|
||||
targetClass = Modifier.isStatic(modifiers) ? null : obj.getClass();
|
||||
}
|
||||
return Reflection.verifyMemberAccess(caller,
|
||||
declaringClass,
|
||||
targetClass,
|
||||
modifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor: only used by the Java Virtual Machine.
|
||||
*/
|
||||
|
@ -168,6 +168,13 @@ public final class Constructor<T> extends Executable {
|
||||
* is true. </p>
|
||||
*
|
||||
* @param flag {@inheritDoc}
|
||||
*
|
||||
* @throws InaccessibleObjectException {@inheritDoc}
|
||||
* @throws SecurityException if the request is denied by the security manager
|
||||
* or this is a constructor for {@code java.lang.Class}
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@Override
|
||||
@CallerSensitive
|
||||
|
@ -158,6 +158,10 @@ class Field extends AccessibleObject implements Member {
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InaccessibleObjectException {@inheritDoc}
|
||||
* @throws SecurityException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@CallerSensitive
|
||||
public void setAccessible(boolean flag) {
|
||||
|
@ -30,6 +30,7 @@ package java.lang.reflect;
|
||||
*
|
||||
* @see AccessibleObject#setAccessible(boolean)
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
|
||||
public class InaccessibleObjectException extends RuntimeException {
|
||||
|
@ -56,20 +56,19 @@ import sun.security.util.SecurityConstants;
|
||||
/**
|
||||
* A layer of modules in the Java virtual machine.
|
||||
*
|
||||
* <p> A layer is created from a graph of modules that is the {@link
|
||||
* Configuration} and a function that maps each module to a {@link ClassLoader}.
|
||||
* <p> A layer is created from a graph of modules in a {@link Configuration}
|
||||
* and a function that maps each module to a {@link ClassLoader}.
|
||||
* Creating a layer informs the Java virtual machine about the classes that
|
||||
* may be loaded from modules so that the Java virtual machine knows which
|
||||
* module that each class is a member of. Each layer, except the {@link
|
||||
* #empty() empty} layer, has at least one {@link #parents() parent}. </p>
|
||||
* may be loaded from the modules so that the Java virtual machine knows which
|
||||
* module that each class is a member of. </p>
|
||||
*
|
||||
* <p> Creating a layer creates a {@link Module} object for each {@link
|
||||
* ResolvedModule} in the configuration. For each resolved module that is
|
||||
* {@link ResolvedModule#reads() read}, the {@code Module} {@link
|
||||
* Module#canRead reads} the corresponding run-time {@code Module}, which may
|
||||
* be in the same layer or a parent layer. The {@code Module} {@link
|
||||
* Module#isExported(String) exports} the packages described by its {@link
|
||||
* ModuleDescriptor}. </p>
|
||||
* be in the same layer or a {@link #parents() parent} layer. The {@code Module}
|
||||
* {@link Module#isExported(String) exports} and {@link Module#isOpen(String)
|
||||
* opens} the packages described by its {@link ModuleDescriptor}. </p>
|
||||
*
|
||||
* <p> The {@link #defineModulesWithOneLoader defineModulesWithOneLoader} and
|
||||
* {@link #defineModulesWithManyLoaders defineModulesWithManyLoaders} methods
|
||||
@ -80,7 +79,7 @@ import sun.security.util.SecurityConstants;
|
||||
* a function specified to the method. Each of these methods has an instance
|
||||
* and static variant. The instance methods create a layer with the receiver
|
||||
* as the parent layer. The static methods are for more advanced cases where
|
||||
* there can be more than one parent layer or a {@link Layer.Controller
|
||||
* there can be more than one parent layer or where a {@link Layer.Controller
|
||||
* Controller} is needed to control modules in the layer. </p>
|
||||
*
|
||||
* <p> A Java virtual machine has at least one non-empty layer, the {@link
|
||||
@ -93,9 +92,8 @@ import sun.security.util.SecurityConstants;
|
||||
* the {@link #parents() parent} when creating additional layers. </p>
|
||||
*
|
||||
* <p> As when creating a {@code Configuration},
|
||||
* {@link ModuleDescriptor#isAutomatic() automatic} modules receive
|
||||
* <a href="../module/Configuration.html#automaticmoduleresolution">special
|
||||
* treatment</a> when creating a layer. An automatic module is created in the
|
||||
* {@link ModuleDescriptor#isAutomatic() automatic} modules receive special
|
||||
* treatment when creating a layer. An automatic module is created in the
|
||||
* Java virtual machine as a {@code Module} that reads every unnamed {@code
|
||||
* Module} in the Java virtual machine. </p>
|
||||
*
|
||||
@ -115,8 +113,7 @@ import sun.security.util.SecurityConstants;
|
||||
*
|
||||
* Layer parent = Layer.boot();
|
||||
*
|
||||
* Configuration cf = parent.configuration()
|
||||
* .resolveRequires(finder, ModuleFinder.of(), Set.of("myapp"));
|
||||
* Configuration cf = parent.configuration().resolve(finder, ModuleFinder.of(), Set.of("myapp"));
|
||||
*
|
||||
* ClassLoader scl = ClassLoader.getSystemClassLoader();
|
||||
*
|
||||
@ -126,6 +123,7 @@ import sun.security.util.SecurityConstants;
|
||||
* }</pre>
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
* @see Module#getLayer()
|
||||
*/
|
||||
|
||||
@ -168,10 +166,15 @@ public final class Layer {
|
||||
* module layers return a {@code Controller} that can be used to control
|
||||
* modules in the layer.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument to a
|
||||
* method in this class causes a {@link NullPointerException
|
||||
* NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* @apiNote Care should be taken with {@code Controller} objects, they
|
||||
* should never be shared with untrusted code.
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public static final class Controller {
|
||||
private final Layer layer;
|
||||
@ -281,10 +284,8 @@ public final class Layer {
|
||||
* If the parent of the given configuration is not the configuration
|
||||
* for this layer
|
||||
* @throws LayerInstantiationException
|
||||
* If all modules cannot be defined to the same class loader for any
|
||||
* of the reasons listed above or the layer cannot be created because
|
||||
* the configuration contains a module named "{@code java.base}" or
|
||||
* a module with a package name starting with "{@code java.}"
|
||||
* If the layer cannot be created for any of the reasons specified
|
||||
* by the static {@code defineModulesWithOneLoader} method
|
||||
* @throws SecurityException
|
||||
* If {@code RuntimePermission("createClassLoader")} or
|
||||
* {@code RuntimePermission("getClassLoader")} is denied by
|
||||
@ -325,9 +326,8 @@ public final class Layer {
|
||||
* If the parent of the given configuration is not the configuration
|
||||
* for this layer
|
||||
* @throws LayerInstantiationException
|
||||
* If the layer cannot be created because the configuration contains
|
||||
* a module named "{@code java.base}" or a module with a package
|
||||
* name starting with "{@code java.}"
|
||||
* If the layer cannot be created for any of the reasons specified
|
||||
* by the static {@code defineModulesWithManyLoaders} method
|
||||
* @throws SecurityException
|
||||
* If {@code RuntimePermission("createClassLoader")} or
|
||||
* {@code RuntimePermission("getClassLoader")} is denied by
|
||||
@ -365,14 +365,8 @@ public final class Layer {
|
||||
* If the parent of the given configuration is not the configuration
|
||||
* for this layer
|
||||
* @throws LayerInstantiationException
|
||||
* If creating the {@code Layer} fails for any of the reasons
|
||||
* listed above, the layer cannot be created because the
|
||||
* configuration contains a module named "{@code java.base}",
|
||||
* a module with a package name starting with "{@code java.}" is
|
||||
* mapped to a class loader other than the {@link
|
||||
* ClassLoader#getPlatformClassLoader() platform class loader},
|
||||
* or the function to map a module name to a class loader returns
|
||||
* {@code null}
|
||||
* If the layer cannot be created for any of the reasons specified
|
||||
* by the static {@code defineModules} method
|
||||
* @throws SecurityException
|
||||
* If {@code RuntimePermission("getClassLoader")} is denied by
|
||||
* the security manager
|
||||
@ -396,7 +390,6 @@ public final class Layer {
|
||||
* exported to one or more of the modules in this layer. The class
|
||||
* loader delegates to the class loader of the module, throwing {@code
|
||||
* ClassNotFoundException} if not found by that class loader.
|
||||
*
|
||||
* When {@code loadClass} is invoked to load classes that do not map to a
|
||||
* module then it delegates to the parent class loader. </p>
|
||||
*
|
||||
@ -414,6 +407,10 @@ public final class Layer {
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p> In addition, a layer cannot be created if the configuration contains
|
||||
* a module named "{@code java.base}" or a module with a package name
|
||||
* starting with "{@code java.}". </p>
|
||||
*
|
||||
* <p> If there is a security manager then the class loader created by
|
||||
* this method will load classes and resources with privileges that are
|
||||
* restricted by the calling context of this method. </p>
|
||||
@ -433,9 +430,7 @@ public final class Layer {
|
||||
* the parent layers, including order
|
||||
* @throws LayerInstantiationException
|
||||
* If all modules cannot be defined to the same class loader for any
|
||||
* of the reasons listed above or the layer cannot be created because
|
||||
* the configuration contains a module named "{@code java.base}" or
|
||||
* a module with a package name starting with "{@code java.}"
|
||||
* of the reasons listed above
|
||||
* @throws SecurityException
|
||||
* If {@code RuntimePermission("createClassLoader")} or
|
||||
* {@code RuntimePermission("getClassLoader")} is denied by
|
||||
@ -480,7 +475,6 @@ public final class Layer {
|
||||
* module in a parent layer. The class loader delegates to the class loader
|
||||
* of the module, throwing {@code ClassNotFoundException} if not found by
|
||||
* that class loader.
|
||||
*
|
||||
* When {@code loadClass} is invoked to load classes that do not map to a
|
||||
* module then it delegates to the parent class loader. </p>
|
||||
*
|
||||
@ -533,15 +527,19 @@ public final class Layer {
|
||||
|
||||
/**
|
||||
* Creates a new layer by defining the modules in the given {@code
|
||||
* Configuration} to the Java virtual machine.
|
||||
* Each module is mapped, by name, to its class loader by means of the
|
||||
* given function. The class loader delegation implemented by these class
|
||||
* loaders must respect module readability. The class loaders should be
|
||||
* Configuration} to the Java virtual machine. The given function maps each
|
||||
* module in the configuration, by name, to a class loader. Creating the
|
||||
* layer informs the Java virtual machine about the classes that may be
|
||||
* loaded so that the Java virtual machine knows which module that each
|
||||
* class is a member of.
|
||||
*
|
||||
* <p> The class loader delegation implemented by the class loaders must
|
||||
* respect module readability. The class loaders should be
|
||||
* {@link ClassLoader#registerAsParallelCapable parallel-capable} so as to
|
||||
* avoid deadlocks during class loading. In addition, the entity creating
|
||||
* a new layer with this method should arrange that the class loaders are
|
||||
* a new layer with this method should arrange that the class loaders be
|
||||
* ready to load from these modules before there are any attempts to load
|
||||
* classes or resources.
|
||||
* classes or resources. </p>
|
||||
*
|
||||
* <p> Creating a {@code Layer} can fail for the following reasons: </p>
|
||||
*
|
||||
@ -558,6 +556,13 @@ public final class Layer {
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p> In addition, a layer cannot be created if the configuration contains
|
||||
* a module named "{@code java.base}", a configuration contains a module
|
||||
* with a package name starting with "{@code java.}" is mapped to a class
|
||||
* loader other than the {@link ClassLoader#getPlatformClassLoader()
|
||||
* platform class loader}, or the function to map a module name to a class
|
||||
* loader returns {@code null}. </p>
|
||||
*
|
||||
* <p> If the function to map a module name to class loader throws an error
|
||||
* or runtime exception then it is propagated to the caller of this method.
|
||||
* </p>
|
||||
@ -565,7 +570,7 @@ public final class Layer {
|
||||
* @apiNote It is implementation specific as to whether creating a Layer
|
||||
* with this method is an atomic operation or not. Consequentially it is
|
||||
* possible for this method to fail with some modules, but not all, defined
|
||||
* to Java virtual machine.
|
||||
* to the Java virtual machine.
|
||||
*
|
||||
* @param cf
|
||||
* The configuration for the layer
|
||||
@ -580,14 +585,7 @@ public final class Layer {
|
||||
* If the parent configurations do not match the configuration of
|
||||
* the parent layers, including order
|
||||
* @throws LayerInstantiationException
|
||||
* If creating the {@code Layer} fails for any of the reasons
|
||||
* listed above, the layer cannot be created because the
|
||||
* configuration contains a module named "{@code java.base}",
|
||||
* a module with a package name starting with "{@code java.}" is
|
||||
* mapped to a class loader other than the {@link
|
||||
* ClassLoader#getPlatformClassLoader() platform class loader},
|
||||
* or the function to map a module name to a class loader returns
|
||||
* {@code null}
|
||||
* If creating the layer fails for any of the reasons listed above
|
||||
* @throws SecurityException
|
||||
* If {@code RuntimePermission("getClassLoader")} is denied by
|
||||
* the security manager
|
||||
@ -763,7 +761,7 @@ public final class Layer {
|
||||
|
||||
/**
|
||||
* Returns the module with the given name in this layer, or if not in this
|
||||
* layer, the {@linkplain #parents parents} layers. Finding a module in
|
||||
* layer, the {@linkplain #parents parent} layers. Finding a module in
|
||||
* parent layers is equivalent to invoking {@code findModule} on each
|
||||
* parent, in search order, until the module is found or all parents have
|
||||
* been searched. In a <em>tree of layers</em> then this is equivalent to
|
||||
|
@ -31,6 +31,7 @@ package java.lang.reflect;
|
||||
* @see Layer
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public class LayerInstantiationException extends RuntimeException {
|
||||
private static final long serialVersionUID = -906239691613568347L;
|
||||
|
@ -179,6 +179,10 @@ public final class Method extends Executable {
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InaccessibleObjectException {@inheritDoc}
|
||||
* @throws SecurityException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@CallerSensitive
|
||||
public void setAccessible(boolean flag) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -39,7 +39,6 @@ import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
@ -74,16 +73,15 @@ import sun.security.util.SecurityConstants;
|
||||
* Java Virtual Machine when a graph of modules is defined to the Java virtual
|
||||
* machine to create a module {@link Layer Layer}. </p>
|
||||
*
|
||||
* <p> An unnamed module does not have a name. There is an unnamed module
|
||||
* per {@link ClassLoader ClassLoader} that is obtained by invoking the class
|
||||
* loader's {@link ClassLoader#getUnnamedModule() getUnnamedModule} method. The
|
||||
* {@link Class#getModule() getModule} method of all types defined by a class
|
||||
* loader that are not in a named module return the class loader's unnamed
|
||||
* <p> An unnamed module does not have a name. There is an unnamed module for
|
||||
* each {@link ClassLoader ClassLoader}, obtained by invoking its {@link
|
||||
* ClassLoader#getUnnamedModule() getUnnamedModule} method. All types that are
|
||||
* not in a named module are members of their defining class loader's unnamed
|
||||
* module. </p>
|
||||
*
|
||||
* <p> The package names that are parameters or returned by methods defined in
|
||||
* this class are the fully-qualified names of the packages as defined in
|
||||
* section 6.5.3 of <cite>The Java™ Language Specification </cite>, for
|
||||
* section 6.5.3 of <cite>The Java™ Language Specification</cite>, for
|
||||
* example, {@code "java.lang"}. </p>
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument to a method
|
||||
@ -91,6 +89,7 @@ import sun.security.util.SecurityConstants;
|
||||
* be thrown. </p>
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
* @see java.lang.Class#getModule
|
||||
*/
|
||||
|
||||
@ -327,8 +326,9 @@ public final class Module implements AnnotatedElement {
|
||||
*
|
||||
* @return this module
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* If this is a named module and the caller is not this module
|
||||
* @throws IllegalCallerException
|
||||
* If this is a named module and the caller's module is not this
|
||||
* module
|
||||
*
|
||||
* @see #canRead
|
||||
*/
|
||||
@ -338,7 +338,7 @@ public final class Module implements AnnotatedElement {
|
||||
if (this.isNamed()) {
|
||||
Module caller = Reflection.getCallerClass().getModule();
|
||||
if (caller != this) {
|
||||
throw new IllegalStateException(caller + " != " + this);
|
||||
throw new IllegalCallerException(caller + " != " + this);
|
||||
}
|
||||
implAddReads(other, true);
|
||||
}
|
||||
@ -533,8 +533,8 @@ public final class Module implements AnnotatedElement {
|
||||
if (other == this && containsPackage(pn))
|
||||
return true;
|
||||
|
||||
// all packages in open modules are open
|
||||
if (descriptor.isOpen())
|
||||
// all packages in open and automatic modules are open
|
||||
if (descriptor.isOpen() || descriptor.isAutomatic())
|
||||
return containsPackage(pn);
|
||||
|
||||
// exported/opened via module declaration/descriptor
|
||||
@ -634,8 +634,7 @@ public final class Module implements AnnotatedElement {
|
||||
* the given package to the given module.
|
||||
*
|
||||
* <p> This method has no effect if the package is already exported (or
|
||||
* <em>open</em>) to the given module. It also has no effect if
|
||||
* invoked on an {@link ModuleDescriptor#isOpen open} module. </p>
|
||||
* <em>open</em>) to the given module. </p>
|
||||
*
|
||||
* @apiNote As specified in section 5.4.3 of the <cite>The Java™
|
||||
* Virtual Machine Specification </cite>, if an attempt to resolve a
|
||||
@ -653,8 +652,9 @@ public final class Module implements AnnotatedElement {
|
||||
* @throws IllegalArgumentException
|
||||
* If {@code pn} is {@code null}, or this is a named module and the
|
||||
* package {@code pn} is not a package in this module
|
||||
* @throws IllegalStateException
|
||||
* If this is a named module and the caller is not this module
|
||||
* @throws IllegalCallerException
|
||||
* If this is a named module and the caller's module is not this
|
||||
* module
|
||||
*
|
||||
* @jvms 5.4.3 Resolution
|
||||
* @see #isExported(String,Module)
|
||||
@ -665,10 +665,10 @@ public final class Module implements AnnotatedElement {
|
||||
throw new IllegalArgumentException("package is null");
|
||||
Objects.requireNonNull(other);
|
||||
|
||||
if (isNamed() && !descriptor.isOpen()) {
|
||||
if (isNamed()) {
|
||||
Module caller = Reflection.getCallerClass().getModule();
|
||||
if (caller != this) {
|
||||
throw new IllegalStateException(caller + " != " + this);
|
||||
throw new IllegalCallerException(caller + " != " + this);
|
||||
}
|
||||
implAddExportsOrOpens(pn, other, /*open*/false, /*syncVM*/true);
|
||||
}
|
||||
@ -686,8 +686,7 @@ public final class Module implements AnnotatedElement {
|
||||
* access control checks.
|
||||
*
|
||||
* <p> This method has no effect if the package is already <em>open</em>
|
||||
* to the given module. It also has no effect if invoked on an {@link
|
||||
* ModuleDescriptor#isOpen open} module. </p>
|
||||
* to the given module. </p>
|
||||
*
|
||||
* @param pn
|
||||
* The package name
|
||||
@ -699,9 +698,9 @@ public final class Module implements AnnotatedElement {
|
||||
* @throws IllegalArgumentException
|
||||
* If {@code pn} is {@code null}, or this is a named module and the
|
||||
* package {@code pn} is not a package in this module
|
||||
* @throws IllegalStateException
|
||||
* @throws IllegalCallerException
|
||||
* If this is a named module and this module has not opened the
|
||||
* package to at least the caller
|
||||
* package to at least the caller's module
|
||||
*
|
||||
* @see #isOpen(String,Module)
|
||||
* @see AccessibleObject#setAccessible(boolean)
|
||||
@ -713,10 +712,10 @@ public final class Module implements AnnotatedElement {
|
||||
throw new IllegalArgumentException("package is null");
|
||||
Objects.requireNonNull(other);
|
||||
|
||||
if (isNamed() && !descriptor.isOpen()) {
|
||||
if (isNamed()) {
|
||||
Module caller = Reflection.getCallerClass().getModule();
|
||||
if (caller != this && !isOpen(pn, caller))
|
||||
throw new IllegalStateException(pn + " is not open to " + caller);
|
||||
throw new IllegalCallerException(pn + " is not open to " + caller);
|
||||
implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true);
|
||||
}
|
||||
|
||||
@ -767,8 +766,8 @@ public final class Module implements AnnotatedElement {
|
||||
Objects.requireNonNull(other);
|
||||
Objects.requireNonNull(pn);
|
||||
|
||||
// all packages are open in unnamed and open modules
|
||||
if (!isNamed() || descriptor.isOpen())
|
||||
// all packages are open in unnamed, open, and automatic modules
|
||||
if (!isNamed() || descriptor.isOpen() || descriptor.isAutomatic())
|
||||
return;
|
||||
|
||||
// nothing to do if already exported/open to other
|
||||
@ -819,17 +818,17 @@ public final class Module implements AnnotatedElement {
|
||||
* passed a reference to the service type by other code. This method is
|
||||
* a no-op when invoked on an unnamed module or an automatic module.
|
||||
*
|
||||
* <p> This method does not cause {@link
|
||||
* Configuration#resolveRequiresAndUses resolveRequiresAndUses} to be
|
||||
* re-run. </p>
|
||||
* <p> This method does not cause {@link Configuration#resolveAndBind
|
||||
* resolveAndBind} to be re-run. </p>
|
||||
*
|
||||
* @param service
|
||||
* The service type
|
||||
*
|
||||
* @return this module
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* If this is a named module and the caller is not this module
|
||||
* @throws IllegalCallerException
|
||||
* If this is a named module and the caller's module is not this
|
||||
* module
|
||||
*
|
||||
* @see #canUse(Class)
|
||||
* @see ModuleDescriptor#uses()
|
||||
@ -841,7 +840,7 @@ public final class Module implements AnnotatedElement {
|
||||
if (isNamed() && !descriptor.isAutomatic()) {
|
||||
Module caller = Reflection.getCallerClass().getModule();
|
||||
if (caller != this) {
|
||||
throw new IllegalStateException(caller + " != " + this);
|
||||
throw new IllegalCallerException(caller + " != " + this);
|
||||
}
|
||||
implAddUses(service);
|
||||
}
|
||||
@ -894,14 +893,13 @@ public final class Module implements AnnotatedElement {
|
||||
// -- packages --
|
||||
|
||||
// Additional packages that are added to the module at run-time.
|
||||
// The field is volatile as it may be replaced at run-time
|
||||
private volatile Set<String> extraPackages;
|
||||
private volatile Map<String, Boolean> extraPackages;
|
||||
|
||||
private boolean containsPackage(String pn) {
|
||||
if (descriptor.packages().contains(pn))
|
||||
return true;
|
||||
Set<String> extraPackages = this.extraPackages;
|
||||
if (extraPackages != null && extraPackages.contains(pn))
|
||||
Map<String, Boolean> extraPackages = this.extraPackages;
|
||||
if (extraPackages != null && extraPackages.containsKey(pn))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@ -915,7 +913,7 @@ public final class Module implements AnnotatedElement {
|
||||
* added to the module, <a href="Proxy.html#dynamicmodule">dynamic modules</a>
|
||||
* for example, after it was loaded.
|
||||
*
|
||||
* <p> For unnamed modules, this method is the equivalent of invoking the
|
||||
* <p> For unnamed modules, this method is the equivalent to invoking the
|
||||
* {@link ClassLoader#getDefinedPackages() getDefinedPackages} method of
|
||||
* this module's class loader and returning the array of package names. </p>
|
||||
*
|
||||
@ -930,12 +928,12 @@ public final class Module implements AnnotatedElement {
|
||||
if (isNamed()) {
|
||||
|
||||
Set<String> packages = descriptor.packages();
|
||||
Set<String> extraPackages = this.extraPackages;
|
||||
Map<String, Boolean> extraPackages = this.extraPackages;
|
||||
if (extraPackages == null) {
|
||||
return packages.toArray(new String[0]);
|
||||
} else {
|
||||
return Stream.concat(packages.stream(),
|
||||
extraPackages.stream())
|
||||
extraPackages.keySet().stream())
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
@ -955,10 +953,6 @@ public final class Module implements AnnotatedElement {
|
||||
* Add a package to this module.
|
||||
*
|
||||
* @apiNote This method is for Proxy use.
|
||||
*
|
||||
* @apiNote This is an expensive operation, not expected to be used often.
|
||||
* At this time then it does not validate that the package name is a
|
||||
* valid java identifier.
|
||||
*/
|
||||
void addPackage(String pn) {
|
||||
implAddPackage(pn, true);
|
||||
@ -976,49 +970,52 @@ public final class Module implements AnnotatedElement {
|
||||
/**
|
||||
* Add a package to this module.
|
||||
*
|
||||
* If {@code syncVM} is {@code true} then the VM is notified.
|
||||
* If {@code syncVM} is {@code true} then the VM is notified. This method is
|
||||
* a no-op if this is an unnamed module or the module already contains the
|
||||
* package.
|
||||
*
|
||||
* @throws IllegalArgumentException if the package name is not legal
|
||||
* @throws IllegalStateException if the package is defined to another module
|
||||
*/
|
||||
private void implAddPackage(String pn, boolean syncVM) {
|
||||
// no-op if unnamed module
|
||||
if (!isNamed())
|
||||
throw new InternalError("adding package to unnamed module?");
|
||||
if (descriptor.isOpen())
|
||||
throw new InternalError("adding package to open module?");
|
||||
return;
|
||||
|
||||
// no-op if module contains the package
|
||||
if (containsPackage(pn))
|
||||
return;
|
||||
|
||||
// check package name is legal for named modules
|
||||
if (pn.isEmpty())
|
||||
throw new InternalError("adding <unnamed> package to module?");
|
||||
|
||||
if (descriptor.packages().contains(pn)) {
|
||||
// already in module
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> extraPackages = this.extraPackages;
|
||||
if (extraPackages != null && extraPackages.contains(pn)) {
|
||||
// already added
|
||||
return;
|
||||
}
|
||||
synchronized (this) {
|
||||
// recheck under lock
|
||||
extraPackages = this.extraPackages;
|
||||
if (extraPackages != null) {
|
||||
if (extraPackages.contains(pn)) {
|
||||
// already added
|
||||
return;
|
||||
}
|
||||
|
||||
// copy the set
|
||||
extraPackages = new HashSet<>(extraPackages);
|
||||
extraPackages.add(pn);
|
||||
} else {
|
||||
extraPackages = Collections.singleton(pn);
|
||||
throw new IllegalArgumentException("Cannot add <unnamed> package");
|
||||
for (int i=0; i<pn.length(); i++) {
|
||||
char c = pn.charAt(i);
|
||||
if (c == '/' || c == ';' || c == '[') {
|
||||
throw new IllegalArgumentException("Illegal character: " + c);
|
||||
}
|
||||
|
||||
// update VM first, just in case it fails
|
||||
if (syncVM)
|
||||
addPackage0(this, pn);
|
||||
|
||||
// replace with new set
|
||||
this.extraPackages = extraPackages; // volatile write
|
||||
}
|
||||
|
||||
// create extraPackages if needed
|
||||
Map<String, Boolean> extraPackages = this.extraPackages;
|
||||
if (extraPackages == null) {
|
||||
synchronized (this) {
|
||||
extraPackages = this.extraPackages;
|
||||
if (extraPackages == null)
|
||||
this.extraPackages = extraPackages = new ConcurrentHashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
// update VM first in case it fails. This is a no-op if another thread
|
||||
// beats us to add the package first
|
||||
if (syncVM) {
|
||||
// throws IllegalStateException if defined to another module
|
||||
addPackage0(this, pn);
|
||||
if (descriptor.isOpen() || descriptor.isAutomatic()) {
|
||||
addExportsToAll0(this, pn);
|
||||
}
|
||||
}
|
||||
extraPackages.putIfAbsent(pn, Boolean.TRUE);
|
||||
}
|
||||
|
||||
|
||||
@ -1169,8 +1166,9 @@ public final class Module implements AnnotatedElement {
|
||||
Map<String, Module> nameToModule,
|
||||
Module m)
|
||||
{
|
||||
// The VM doesn't know about open modules so need to export all packages
|
||||
if (descriptor.isOpen()) {
|
||||
// The VM doesn't special case open or automatic modules so need to
|
||||
// export all packages
|
||||
if (descriptor.isOpen() || descriptor.isAutomatic()) {
|
||||
assert descriptor.opens().isEmpty();
|
||||
for (String source : descriptor.packages()) {
|
||||
addExportsToAll0(m, source);
|
||||
@ -1375,35 +1373,44 @@ public final class Module implements AnnotatedElement {
|
||||
|
||||
|
||||
/**
|
||||
* Returns an input stream for reading a resource in this module. The
|
||||
* {@code name} parameter is a {@code '/'}-separated path name that
|
||||
* identifies the resource.
|
||||
* Returns an input stream for reading a resource in this module.
|
||||
* The {@code name} parameter is a {@code '/'}-separated path name that
|
||||
* identifies the resource. As with {@link Class#getResourceAsStream
|
||||
* Class.getResourceAsStream}, this method delegates to the module's class
|
||||
* loader {@link ClassLoader#findResource(String,String)
|
||||
* findResource(String,String)} method, invoking it with the module name
|
||||
* (or {@code null} when the module is unnamed) and the name of the
|
||||
* resource. If the resource name has a leading slash then it is dropped
|
||||
* before delegation.
|
||||
*
|
||||
* <p> A resource in a named modules may be <em>encapsulated</em> so that
|
||||
* <p> A resource in a named module may be <em>encapsulated</em> so that
|
||||
* it cannot be located by code in other modules. Whether a resource can be
|
||||
* located or not is determined as follows:
|
||||
* located or not is determined as follows: </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li> The <em>package name</em> of the resource is derived from the
|
||||
* subsequence of characters that precedes the last {@code '/'} and then
|
||||
* replacing each {@code '/'} character in the subsequence with
|
||||
* {@code '.'}. For example, the package name derived for a resource
|
||||
* named "{@code a/b/c/foo.properties}" is "{@code a.b.c}". </li>
|
||||
* <li> If the resource name ends with "{@code .class}" then it is not
|
||||
* encapsulated. </li>
|
||||
*
|
||||
* <li> If the package name is a package in the module then the package
|
||||
* must be {@link #isOpen open} the module of the caller of this method.
|
||||
* If the package is not in the module then the resource is not
|
||||
* encapsulated. Resources in the unnamed package or "{@code META-INF}",
|
||||
* for example, are never encapsulated because they can never be
|
||||
* packages in a named module. </li>
|
||||
*
|
||||
* <li> As a special case, resources ending with "{@code .class}" are
|
||||
* never encapsulated. </li>
|
||||
* <li> A <em>package name</em> is derived from the resource name. If
|
||||
* the package name is a {@link #getPackages() package} in the module
|
||||
* then the resource can only be located by the caller of this method
|
||||
* when the package is {@link #isOpen(String,Module) open} to at least
|
||||
* the caller's module. If the resource is not in a package in the module
|
||||
* then the resource is not encapsulated. </li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> In the above, the <em>package name</em> for a resource is derived
|
||||
* from the subsequence of characters that precedes the last {@code '/'} in
|
||||
* the name and then replacing each {@code '/'} character in the subsequence
|
||||
* with {@code '.'}. A leading slash is ignored when deriving the package
|
||||
* name. As an example, the package name derived for a resource named
|
||||
* "{@code a/b/c/foo.properties}" is "{@code a.b.c}". A resource name
|
||||
* with the name "{@code META-INF/MANIFEST.MF}" is never encapsulated
|
||||
* because "{@code META-INF}" is not a legal package name. </p>
|
||||
*
|
||||
* <p> This method returns {@code null} if the resource is not in this
|
||||
* module, the resource is encapsulated and cannot be located by the caller,
|
||||
* or access to the resource is denied by the security manager.
|
||||
* or access to the resource is denied by the security manager. </p>
|
||||
*
|
||||
* @param name
|
||||
* The resource name
|
||||
@ -1413,11 +1420,13 @@ public final class Module implements AnnotatedElement {
|
||||
* @throws IOException
|
||||
* If an I/O error occurs
|
||||
*
|
||||
* @see java.lang.module.ModuleReader#open(String)
|
||||
* @see Class#getResourceAsStream(String)
|
||||
*/
|
||||
@CallerSensitive
|
||||
public InputStream getResourceAsStream(String name) throws IOException {
|
||||
Objects.requireNonNull(name);
|
||||
if (name.startsWith("/")) {
|
||||
name = name.substring(1);
|
||||
}
|
||||
|
||||
if (isNamed() && !ResourceHelper.isSimpleResource(name)) {
|
||||
Module caller = Reflection.getCallerClass().getModule();
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package java.lang.reflect;
|
||||
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Arrays;
|
||||
@ -52,6 +53,9 @@ import sun.reflect.misc.ReflectUtil;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import sun.security.util.SecurityConstants;
|
||||
|
||||
import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* {@code Proxy} provides static methods for creating objects that act like instances
|
||||
@ -164,7 +168,8 @@ import sun.security.util.SecurityConstants;
|
||||
* methods is specified as follows:
|
||||
*
|
||||
* <ol>
|
||||
* <li>If all the proxy interfaces are in <em>exported</em> packages:
|
||||
* <li>If all the proxy interfaces are in <em>exported</em> or <em>open</em>
|
||||
* packages:
|
||||
* <ol type="a">
|
||||
* <li>if all the proxy interfaces are <em>public</em>, then the proxy class is
|
||||
* <em>public</em> in a package exported by the
|
||||
@ -178,10 +183,11 @@ import sun.security.util.SecurityConstants;
|
||||
* <a href="#restrictions">not possible</a>.</li>
|
||||
* </ol>
|
||||
* </li>
|
||||
* <li>If at least one proxy interface is a <em>non-exported</em> package:
|
||||
* <li>If at least one proxy interface is in a package that is
|
||||
* <em>non-exported</em> and <em>non-open</em>:
|
||||
* <ol type="a">
|
||||
* <li>if all the proxy interfaces are <em>public</em>, then the proxy class is
|
||||
* <em>public</em> in a <em>non-exported</em> package of
|
||||
* <em>public</em> in a <em>non-exported</em>, <em>non-open</em> package of
|
||||
* <a href="#dynamicmodule"><em>dynamic module</em>.</a>
|
||||
* The names of the package and the module are unspecified.</li>
|
||||
*
|
||||
@ -195,21 +201,22 @@ import sun.security.util.SecurityConstants;
|
||||
* </ol>
|
||||
*
|
||||
* <p>
|
||||
* Note that if proxy interfaces with a mix of accessibilities --
|
||||
* exported public, exported non-public, non-exported public, non-exported non-public --
|
||||
* are proxied by the same instance, then the proxy class's accessibility is
|
||||
* Note that if proxy interfaces with a mix of accessibilities -- for example,
|
||||
* an exported public interface and a non-exported non-public interface -- are
|
||||
* proxied by the same instance, then the proxy class's accessibility is
|
||||
* governed by the least accessible proxy interface.
|
||||
* <p>
|
||||
* Note that it is possible for arbitrary code to obtain access to a proxy class
|
||||
* in an exported package with {@link AccessibleObject#setAccessible setAccessible},
|
||||
* whereas a proxy class in a non-exported package is never accessible to
|
||||
* in an open package with {@link AccessibleObject#setAccessible setAccessible},
|
||||
* whereas a proxy class in a non-open package is never accessible to
|
||||
* code outside the module of the proxy class.
|
||||
*
|
||||
* <p>
|
||||
* Throughout this specification, a "non-exported package" refers to a package that
|
||||
* is not exported to all modules. Specifically, it refers to a package that
|
||||
* either is not exported at all by its containing module or is exported in a
|
||||
* qualified fashion by its containing module.
|
||||
* Throughout this specification, a "non-exported package" refers to a package
|
||||
* that is not exported to all modules, and a "non-open package" refers to
|
||||
* a package that is not open to all modules. Specifically, these terms refer to
|
||||
* a package that either is not exported/open by its containing module or is
|
||||
* exported/open in a qualified fashion by its containing module.
|
||||
*
|
||||
* <h3><a name="dynamicmodule">Dynamic Modules</a></h3>
|
||||
* <p>
|
||||
@ -272,6 +279,8 @@ import sun.security.util.SecurityConstants;
|
||||
* @author Peter Jones
|
||||
* @see InvocationHandler
|
||||
* @since 1.3
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public class Proxy implements java.io.Serializable {
|
||||
private static final long serialVersionUID = -2222568056686623797L;
|
||||
@ -358,6 +367,8 @@ public class Proxy implements java.io.Serializable {
|
||||
* to create a proxy instance instead.
|
||||
*
|
||||
* @see <a href="#membership">Package and Module Membership of Proxy Class</a>
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@Deprecated
|
||||
@CallerSensitive
|
||||
@ -855,7 +866,11 @@ public class Proxy implements java.io.Serializable {
|
||||
// create a dynamic module and setup module access
|
||||
String mn = "jdk.proxy" + counter.incrementAndGet();
|
||||
String pn = PROXY_PACKAGE_PREFIX + "." + mn;
|
||||
Module m = Modules.defineModule(ld, mn, Collections.singleton(pn));
|
||||
ModuleDescriptor descriptor =
|
||||
ModuleDescriptor.newModule(mn, Set.of(SYNTHETIC))
|
||||
.packages(Set.of(pn))
|
||||
.build();
|
||||
Module m = Modules.defineModule(ld, descriptor, null);
|
||||
Modules.addReads(m, Proxy.class.getModule());
|
||||
// java.base to create proxy instance
|
||||
Modules.addExports(m, pn, Object.class.getModule());
|
||||
@ -955,6 +970,8 @@ public class Proxy implements java.io.Serializable {
|
||||
* {@code null}
|
||||
*
|
||||
* @see <a href="#membership">Package and Module Membership of Proxy Class</a>
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static Object newProxyInstance(ClassLoader loader,
|
||||
@ -1039,6 +1056,9 @@ public class Proxy implements java.io.Serializable {
|
||||
* @return {@code true} if the class is a proxy class and
|
||||
* {@code false} otherwise
|
||||
* @throws NullPointerException if {@code cl} is {@code null}
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public static boolean isProxyClass(Class<?> cl) {
|
||||
return Proxy.class.isAssignableFrom(cl) && ProxyBuilder.isProxyClass(cl);
|
||||
|
@ -45,5 +45,7 @@
|
||||
* members declared by a given class.
|
||||
*
|
||||
* @since 1.1
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
package java.lang.reflect;
|
||||
|
@ -228,6 +228,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
||||
* allow creation of a class loader.
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public URLClassLoader(String name,
|
||||
URL[] urls,
|
||||
@ -262,6 +263,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
||||
* creation of a class loader.
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public URLClassLoader(String name, URL[] urls, ClassLoader parent,
|
||||
URLStreamHandlerFactory factory) {
|
||||
@ -558,6 +560,9 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
||||
* @throws IllegalArgumentException if the package name is
|
||||
* already defined by this class loader
|
||||
* @return the newly defined {@code Package} object
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
protected Package definePackage(String name, Manifest man, URL url) {
|
||||
String path = name.replace('.', '/').concat("/");
|
||||
|
@ -125,6 +125,7 @@ public class SecureClassLoader extends ClassLoader {
|
||||
* doesn't allow creation of a class loader.
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
protected SecureClassLoader(String name, ClassLoader parent) {
|
||||
super(name, parent);
|
||||
|
@ -25,11 +25,12 @@
|
||||
|
||||
package java.security;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.util.PropertyExpander;
|
||||
|
||||
@ -800,9 +801,6 @@ public final class Security {
|
||||
* "package.definition", we need to signal to the SecurityManager
|
||||
* class that the value has just changed, and that it should
|
||||
* invalidate it's local cache values.
|
||||
*
|
||||
* Rather than create a new API entry for this function,
|
||||
* we use reflection to set a private variable.
|
||||
*/
|
||||
private static void invalidateSMCache(String key) {
|
||||
|
||||
@ -810,42 +808,8 @@ public final class Security {
|
||||
final boolean pd = key.equals("package.definition");
|
||||
|
||||
if (pa || pd) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<>() {
|
||||
public Void run() {
|
||||
try {
|
||||
/* Get the class via the bootstrap class loader. */
|
||||
Class<?> cl = Class.forName(
|
||||
"java.lang.SecurityManager", false, null);
|
||||
Field f = null;
|
||||
boolean accessible = false;
|
||||
|
||||
if (pa) {
|
||||
f = cl.getDeclaredField("packageAccessValid");
|
||||
accessible = f.isAccessible();
|
||||
f.setAccessible(true);
|
||||
} else {
|
||||
f = cl.getDeclaredField("packageDefinitionValid");
|
||||
accessible = f.isAccessible();
|
||||
f.setAccessible(true);
|
||||
}
|
||||
f.setBoolean(f, false);
|
||||
f.setAccessible(accessible);
|
||||
}
|
||||
catch (Exception e1) {
|
||||
/* If we couldn't get the class, it hasn't
|
||||
* been loaded yet. If there is no such
|
||||
* field, we shouldn't try to set it. There
|
||||
* shouldn't be a security execption, as we
|
||||
* are loaded by boot class loader, and we
|
||||
* are inside a doPrivileged() here.
|
||||
*
|
||||
* NOOP: don't do anything...
|
||||
*/
|
||||
}
|
||||
return null;
|
||||
} /* run */
|
||||
}); /* PrivilegedAction */
|
||||
} /* if */
|
||||
SharedSecrets.getJavaLangAccess().invalidatePackageAccessCache();
|
||||
}
|
||||
}
|
||||
|
||||
private static void check(String directive) {
|
||||
|
@ -350,6 +350,8 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
|
||||
* @see MissingResourceException
|
||||
* @see ResourceBundleProvider
|
||||
* @since 1.1
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public abstract class ResourceBundle {
|
||||
|
||||
@ -870,6 +872,8 @@ public abstract class ResourceBundle {
|
||||
* @throws UnsupportedOperationException
|
||||
* if this method is called in a named module
|
||||
* @since 1.6
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static final ResourceBundle getBundle(String baseName,
|
||||
@ -938,6 +942,7 @@ public abstract class ResourceBundle {
|
||||
* specified module
|
||||
* @return a resource bundle for the given base name and the default locale
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
* @see ResourceBundleProvider
|
||||
*/
|
||||
@CallerSensitive
|
||||
@ -991,6 +996,7 @@ public abstract class ResourceBundle {
|
||||
* be found in the specified {@code module}
|
||||
* @return a resource bundle for the given base name and locale in the module
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static ResourceBundle getBundle(String baseName, Locale targetLocale, Module module) {
|
||||
@ -1036,6 +1042,8 @@ public abstract class ResourceBundle {
|
||||
* @throws UnsupportedOperationException
|
||||
* if this method is called in a named module
|
||||
* @since 1.6
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
|
||||
@ -1243,6 +1251,8 @@ public abstract class ResourceBundle {
|
||||
* @exception MissingResourceException
|
||||
* if no resource bundle for the specified base name can be found
|
||||
* @since 1.2
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static ResourceBundle getBundle(String baseName, Locale locale,
|
||||
@ -1465,6 +1475,8 @@ public abstract class ResourceBundle {
|
||||
* @throws UnsupportedOperationException
|
||||
* if this method is called in a named module
|
||||
* @since 1.6
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static ResourceBundle getBundle(String baseName, Locale targetLocale,
|
||||
@ -2194,6 +2206,8 @@ public abstract class ResourceBundle {
|
||||
* by the caller's module.
|
||||
*
|
||||
* @since 1.6
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
* @see ResourceBundle.Control#getTimeToLive(String,Locale)
|
||||
*/
|
||||
@CallerSensitive
|
||||
@ -2475,6 +2489,8 @@ public abstract class ResourceBundle {
|
||||
* of {@link ResourceBundleControlProvider} are ignored in named modules.
|
||||
*
|
||||
* @since 1.6
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
* @see java.util.spi.ResourceBundleProvider
|
||||
*/
|
||||
public static class Control {
|
||||
@ -3103,6 +3119,8 @@ public abstract class ResourceBundle {
|
||||
* if an error occurred when reading resources using
|
||||
* any I/O operations
|
||||
* @see java.util.spi.ResourceBundleProvider#getBundle(String, Locale)
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public ResourceBundle newBundle(String baseName, Locale locale, String format,
|
||||
ClassLoader loader, boolean reload)
|
||||
|
@ -119,7 +119,7 @@ import jdk.internal.reflect.Reflection;
|
||||
* and deployed as an explicit module must have an appropriate <i>uses</i>
|
||||
* clause in its <i>module descriptor</i> to declare that the module uses
|
||||
* implementations of the service. A corresponding requirement is that a
|
||||
* provider deployed as a named module must have an appropriate
|
||||
* provider deployed as an explicit module must have an appropriate
|
||||
* <i>provides</i> clause in its module descriptor to declare that the module
|
||||
* provides an implementation of the service. The <i>uses</i> and
|
||||
* <i>provides</i> allow consumers of a service to be <i>linked</i> to modules
|
||||
@ -203,8 +203,11 @@ import jdk.internal.reflect.Reflection;
|
||||
* ordering of modules in a layer, is not defined. </li>
|
||||
*
|
||||
* <li> If a named module declares more than one provider then the providers
|
||||
* are located in the order that they appear in the {@code provides} table of
|
||||
* the {@code Module} class file attribute ({@code module-info.class}). </li>
|
||||
* are located in the iteration order of the {@link
|
||||
* java.lang.module.ModuleDescriptor.Provides#providers() providers} list.
|
||||
* Providers added dynamically by instrumentation agents ({@link
|
||||
* java.lang.instrument.Instrumentation#redefineModule redefineModule})
|
||||
* are always located after providers declared by the module. </li>
|
||||
*
|
||||
* <li> When locating providers in unnamed modules then the ordering is
|
||||
* based on the order that the class loader's {@link
|
||||
@ -335,6 +338,8 @@ import jdk.internal.reflect.Reflection;
|
||||
*
|
||||
* @author Mark Reinhold
|
||||
* @since 1.6
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
|
||||
public final class ServiceLoader<S>
|
||||
@ -386,6 +391,7 @@ public final class ServiceLoader<S>
|
||||
*
|
||||
* @param <S> The service type
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public static interface Provider<S> extends Supplier<S> {
|
||||
/**
|
||||
@ -927,26 +933,28 @@ public final class ServiceLoader<S>
|
||||
} else {
|
||||
catalog = ServicesCatalog.getServicesCatalogOrNull(loader);
|
||||
}
|
||||
Stream<ServiceProvider> stream1;
|
||||
List<ServiceProvider> providers;
|
||||
if (catalog == null) {
|
||||
stream1 = Stream.empty();
|
||||
providers = List.of();
|
||||
} else {
|
||||
stream1 = catalog.findServices(serviceName).stream();
|
||||
providers = catalog.findServices(serviceName);
|
||||
}
|
||||
|
||||
// modules in custom layers that define modules to the class loader
|
||||
Stream<ServiceProvider> stream2;
|
||||
if (loader == null) {
|
||||
stream2 = Stream.empty();
|
||||
return providers.iterator();
|
||||
} else {
|
||||
List<ServiceProvider> allProviders = new ArrayList<>(providers);
|
||||
Layer bootLayer = Layer.boot();
|
||||
stream2 = JLRM_ACCESS.layers(loader)
|
||||
.filter(l -> (l != bootLayer))
|
||||
.map(l -> providers(l))
|
||||
.flatMap(List::stream);
|
||||
Iterator<Layer> iterator = JLRM_ACCESS.layers(loader).iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Layer layer = iterator.next();
|
||||
if (layer != bootLayer) {
|
||||
allProviders.addAll(providers(layer));
|
||||
}
|
||||
}
|
||||
return allProviders.iterator();
|
||||
}
|
||||
|
||||
return Stream.concat(stream1, stream2).iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1214,6 +1222,9 @@ public final class ServiceLoader<S>
|
||||
*
|
||||
* @return An iterator that lazily loads providers for this loader's
|
||||
* service
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public Iterator<S> iterator() {
|
||||
|
||||
@ -1279,8 +1290,10 @@ public final class ServiceLoader<S>
|
||||
* provider to be loaded. </p>
|
||||
*
|
||||
* <p> If this loader's provider caches are cleared by invoking the {@link
|
||||
* #reload() reload} method then existing streams for this service
|
||||
* loader should be discarded. </p>
|
||||
* #reload() reload} method then existing streams for this service loader
|
||||
* should be discarded. The returned stream's source {@code Spliterator} is
|
||||
* <em>fail-fast</em> and will throw {@link ConcurrentModificationException}
|
||||
* if the provider cache has been cleared. </p>
|
||||
*
|
||||
* <p> The following examples demonstrate usage. The first example
|
||||
* creates a stream of providers, the second example is the same except
|
||||
@ -1300,6 +1313,7 @@ public final class ServiceLoader<S>
|
||||
* @return A stream that lazily loads providers for this loader's service
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public Stream<Provider<S>> stream() {
|
||||
// use cached providers as the source when all providers loaded
|
||||
@ -1414,6 +1428,9 @@ public final class ServiceLoader<S>
|
||||
* if the service type is not accessible to the caller or the
|
||||
* caller is in an explicit module and its module descriptor does
|
||||
* not declare that it uses {@code service}
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static <S> ServiceLoader<S> load(Class<S> service,
|
||||
@ -1457,6 +1474,9 @@ public final class ServiceLoader<S>
|
||||
* if the service type is not accessible to the caller or the
|
||||
* caller is in an explicit module and its module descriptor does
|
||||
* not declare that it uses {@code service}
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static <S> ServiceLoader<S> load(Class<S> service) {
|
||||
@ -1490,6 +1510,9 @@ public final class ServiceLoader<S>
|
||||
* if the service type is not accessible to the caller or the
|
||||
* caller is in an explicit module and its module descriptor does
|
||||
* not declare that it uses {@code service}
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
|
||||
@ -1522,6 +1545,7 @@ public final class ServiceLoader<S>
|
||||
* not declare that it uses {@code service}
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static <S> ServiceLoader<S> load(Layer layer, Class<S> service) {
|
||||
@ -1551,6 +1575,7 @@ public final class ServiceLoader<S>
|
||||
* or error is thrown when locating or instantiating the provider.
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public Optional<S> findFirst() {
|
||||
Iterator<S> iterator = iterator();
|
||||
|
@ -81,6 +81,7 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
|
||||
* ResourceBundleProvider Service Providers</a>
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public abstract class AbstractResourceBundleProvider implements ResourceBundleProvider {
|
||||
private static final JavaUtilResourceBundleAccess RB_ACCESS =
|
||||
|
@ -44,6 +44,8 @@ import java.util.ResourceBundle;
|
||||
*
|
||||
* @author Masayoshi Okutsu
|
||||
* @since 1.8
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
* @see ResourceBundle#getBundle(String, java.util.Locale, ClassLoader, ResourceBundle.Control)
|
||||
* ResourceBundle.getBundle
|
||||
* @see java.util.ServiceLoader#load(Class)
|
||||
|
@ -57,6 +57,7 @@ import java.util.ResourceBundle;
|
||||
* @see <a href="../ResourceBundle.html#RBP_support">
|
||||
* ResourceBundleProvider Service Providers</a>
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public interface ResourceBundleProvider {
|
||||
/**
|
||||
|
@ -186,7 +186,7 @@ public class JmodFile implements AutoCloseable {
|
||||
public Entry getEntry(Section section, String name) {
|
||||
String entry = section.jmodDir() + "/" + name;
|
||||
ZipEntry ze = zipfile.getEntry(entry);
|
||||
return (ze != null) ? new Entry(ze) : null;
|
||||
return (ze == null || ze.isDirectory()) ? null : new Entry(ze);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -201,7 +201,7 @@ public class JmodFile implements AutoCloseable {
|
||||
{
|
||||
String entry = section.jmodDir() + "/" + name;
|
||||
ZipEntry e = zipfile.getEntry(entry);
|
||||
if (e == null) {
|
||||
if (e == null || e.isDirectory()) {
|
||||
throw new IOException(name + " not found: " + file);
|
||||
}
|
||||
return zipfile.getInputStream(e);
|
||||
|
@ -57,8 +57,9 @@ import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.module.ModulePatcher.PatchedModuleReader;
|
||||
import jdk.internal.misc.VM;
|
||||
import jdk.internal.module.ModulePatcher.PatchedModuleReader;
|
||||
import jdk.internal.module.SystemModules;
|
||||
|
||||
|
||||
/**
|
||||
@ -135,7 +136,7 @@ public class BuiltinClassLoader
|
||||
|
||||
// maps package name to loaded module for modules in the boot layer
|
||||
private static final Map<String, LoadedModule> packageToModule
|
||||
= new ConcurrentHashMap<>(1024);
|
||||
= new ConcurrentHashMap<>(SystemModules.PACKAGES_IN_BOOT_LAYER);
|
||||
|
||||
// maps a module name to a module reference
|
||||
private final Map<String, ModuleReference> nameToModule;
|
||||
@ -922,13 +923,13 @@ public class BuiltinClassLoader
|
||||
* Returns the ModuleReader for the given module.
|
||||
*/
|
||||
private ModuleReader moduleReaderFor(ModuleReference mref) {
|
||||
return moduleToReader.computeIfAbsent(mref, m -> createModuleReader(mref));
|
||||
return moduleToReader.computeIfAbsent(mref, BuiltinClassLoader::createModuleReader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ModuleReader for the given module.
|
||||
*/
|
||||
private ModuleReader createModuleReader(ModuleReference mref) {
|
||||
private static ModuleReader createModuleReader(ModuleReference mref) {
|
||||
try {
|
||||
return mref.open();
|
||||
} catch (IOException e) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 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
|
||||
@ -24,6 +24,10 @@
|
||||
*/
|
||||
package jdk.internal.loader;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import jdk.internal.module.Checks;
|
||||
|
||||
/**
|
||||
@ -34,7 +38,8 @@ public final class ResourceHelper {
|
||||
private ResourceHelper() { }
|
||||
|
||||
/**
|
||||
* Returns the <em>package name</em> for a resource.
|
||||
* Returns the <em>package name</em> for a resource or the empty package if
|
||||
* the resource name does not contain a slash.
|
||||
*/
|
||||
public static String getPackageName(String name) {
|
||||
int index = name.lastIndexOf('/');
|
||||
@ -46,19 +51,75 @@ public final class ResourceHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the resource is a <em>simple resource</em> that can
|
||||
* never be encapsulated. Resources ending in "{@code .class}" or where
|
||||
* the package name is not a Java identifier are resources that can
|
||||
* never be encapsulated.
|
||||
* Returns true if the resource is a <em>simple resource</em>. Simple
|
||||
* resources can never be encapsulated. Resources ending in "{@code .class}"
|
||||
* or where the package name is not a legal package name can not be
|
||||
* encapsulated.
|
||||
*/
|
||||
public static boolean isSimpleResource(String name) {
|
||||
int len = name.length();
|
||||
if (len > 6 && name.endsWith(".class")) {
|
||||
return true;
|
||||
}
|
||||
if (!Checks.isJavaIdentifier(getPackageName(name))) {
|
||||
if (!Checks.isPackageName(getPackageName(name))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a resource name to a file path. Returns {@code null} if the
|
||||
* resource name cannot be converted into a file path. Resource names
|
||||
* with empty elements, or elements that are "." or ".." are rejected,
|
||||
* as is a resource name that translates to a file path with a root
|
||||
* component.
|
||||
*/
|
||||
public static Path toFilePath(String name) {
|
||||
// scan the resource name to eagerly reject obviously invalid names
|
||||
int next;
|
||||
int off = 0;
|
||||
while ((next = name.indexOf('/', off)) != -1) {
|
||||
int len = next - off;
|
||||
if (!mayTranslate(name, off, len)) {
|
||||
return null;
|
||||
}
|
||||
off = next + 1;
|
||||
}
|
||||
int rem = name.length() - off;
|
||||
if (!mayTranslate(name, off, rem)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// convert to file path
|
||||
Path path;
|
||||
if (File.separatorChar == '/') {
|
||||
path = Paths.get(name);
|
||||
} else {
|
||||
// not allowed to embed file separators
|
||||
if (name.contains(File.separator))
|
||||
return null;
|
||||
path = Paths.get(name.replace('/', File.separatorChar));
|
||||
}
|
||||
|
||||
// file path not allowed to have root component
|
||||
return (path.getRoot() == null) ? path : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the element in a resource name is a candidate
|
||||
* to translate to the element of a file path.
|
||||
*/
|
||||
private static boolean mayTranslate(String name, int off, int len) {
|
||||
if (len <= 2) {
|
||||
if (len == 0)
|
||||
return false;
|
||||
boolean starsWithDot = (name.charAt(off) == '.');
|
||||
if (len == 1 && starsWithDot)
|
||||
return false;
|
||||
if (len == 2 && starsWithDot && (name.charAt(off+1) == '.'))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -174,4 +174,9 @@ public interface JavaLangAccess {
|
||||
* Invokes Long.fastUUID
|
||||
*/
|
||||
String fastUUID(long lsb, long msb);
|
||||
|
||||
/**
|
||||
* Invalidate package access cache
|
||||
*/
|
||||
void invalidatePackageAccessCache();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
@ -59,20 +59,21 @@ public interface JavaLangModuleAccess {
|
||||
*/
|
||||
ModuleDescriptor.Builder newModuleBuilder(String mn,
|
||||
boolean strict,
|
||||
boolean open,
|
||||
boolean synthetic);
|
||||
Set<ModuleDescriptor.Modifier> ms);
|
||||
|
||||
/**
|
||||
* Returns the set of packages that are exported (unconditionally or
|
||||
* unconditionally).
|
||||
* Returns a snapshot of the packages in the module.
|
||||
*/
|
||||
Set<String> exportedPackages(ModuleDescriptor.Builder builder);
|
||||
Set<String> packages(ModuleDescriptor.Builder builder);
|
||||
|
||||
/**
|
||||
* Returns the set of packages that are opened (unconditionally or
|
||||
* unconditionally).
|
||||
* Adds a dependence on a module with the given (possibly un-parsable)
|
||||
* version string.
|
||||
*/
|
||||
Set<String> openPackages(ModuleDescriptor.Builder builder);
|
||||
void requires(ModuleDescriptor.Builder builder,
|
||||
Set<Requires.Modifier> ms,
|
||||
String mn,
|
||||
String compiledVersion);
|
||||
|
||||
/**
|
||||
* Returns a {@code ModuleDescriptor.Requires} of the given modifiers
|
||||
@ -113,24 +114,12 @@ public interface JavaLangModuleAccess {
|
||||
*/
|
||||
Provides newProvides(String service, List<String> providers);
|
||||
|
||||
/**
|
||||
* Returns a {@code ModuleDescriptor.Version} of the given version.
|
||||
*/
|
||||
Version newVersion(String v);
|
||||
|
||||
/**
|
||||
* Clones the given module descriptor with an augmented set of packages
|
||||
*/
|
||||
ModuleDescriptor newModuleDescriptor(ModuleDescriptor md, Set<String> pkgs);
|
||||
|
||||
/**
|
||||
* Returns a new {@code ModuleDescriptor} instance.
|
||||
*/
|
||||
ModuleDescriptor newModuleDescriptor(String name,
|
||||
Version version,
|
||||
boolean open,
|
||||
boolean automatic,
|
||||
boolean synthetic,
|
||||
Set<ModuleDescriptor.Modifier> ms,
|
||||
Set<Requires> requires,
|
||||
Set<Exports> exports,
|
||||
Set<Opens> opens,
|
||||
@ -148,9 +137,9 @@ public interface JavaLangModuleAccess {
|
||||
* and the empty configuration as the parent. The post resolution
|
||||
* checks are optionally run.
|
||||
*/
|
||||
Configuration resolveRequiresAndUses(ModuleFinder finder,
|
||||
Collection<String> roots,
|
||||
boolean check,
|
||||
PrintStream traceOutput);
|
||||
Configuration resolveAndBind(ModuleFinder finder,
|
||||
Collection<String> roots,
|
||||
boolean check,
|
||||
PrintStream traceOutput);
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
@ -38,7 +38,7 @@ import jdk.internal.misc.JavaLangModuleAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
|
||||
/**
|
||||
* This builder is optimized for reconstituting ModuleDescriptor
|
||||
* This builder is optimized for reconstituting the {@code ModuleDescriptor}s
|
||||
* for system modules. The validation should be done at jlink time.
|
||||
*
|
||||
* 1. skip name validation
|
||||
@ -136,9 +136,7 @@ final class Builder {
|
||||
}
|
||||
|
||||
final String name;
|
||||
boolean open;
|
||||
boolean automatic;
|
||||
boolean synthetic;
|
||||
boolean open, synthetic, mandated;
|
||||
Set<Requires> requires;
|
||||
Set<Exports> exports;
|
||||
Set<Opens> opens;
|
||||
@ -165,13 +163,13 @@ final class Builder {
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder automatic(boolean value) {
|
||||
this.automatic = value;
|
||||
Builder synthetic(boolean value) {
|
||||
this.synthetic = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder synthetic(boolean value) {
|
||||
this.synthetic = value;
|
||||
Builder mandated(boolean value) {
|
||||
this.mandated = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -228,13 +226,10 @@ final class Builder {
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code v} is null or cannot be
|
||||
* parsed as a version string
|
||||
* @throws IllegalStateException if the module version is already set
|
||||
*
|
||||
* @see Version#parse(String)
|
||||
*/
|
||||
public Builder version(String v) {
|
||||
if (version != null)
|
||||
throw new IllegalStateException("module version already set");
|
||||
Version ver = cachedVersion;
|
||||
if (ver != null && v.equals(ver.toString())) {
|
||||
version = ver;
|
||||
@ -246,63 +241,63 @@ final class Builder {
|
||||
|
||||
/**
|
||||
* Sets the module main class.
|
||||
*
|
||||
* @throws IllegalStateException if already set
|
||||
*/
|
||||
public Builder mainClass(String mc) {
|
||||
if (mainClass != null)
|
||||
throw new IllegalStateException("main class already set");
|
||||
mainClass = mc;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the OS name.
|
||||
*
|
||||
* @throws IllegalStateException if already set
|
||||
*/
|
||||
public Builder osName(String name) {
|
||||
if (osName != null)
|
||||
throw new IllegalStateException("OS name already set");
|
||||
this.osName = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the OS arch.
|
||||
*
|
||||
* @throws IllegalStateException if already set
|
||||
*/
|
||||
public Builder osArch(String arch) {
|
||||
if (osArch != null)
|
||||
throw new IllegalStateException("OS arch already set");
|
||||
this.osArch = arch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the OS version.
|
||||
*
|
||||
* @throws IllegalStateException if already set
|
||||
*/
|
||||
public Builder osVersion(String version) {
|
||||
if (osVersion != null)
|
||||
throw new IllegalStateException("OS version already set");
|
||||
this.osVersion = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set of the module modifiers derived from the flags.
|
||||
*/
|
||||
private Set<ModuleDescriptor.Modifier> modifiers() {
|
||||
int n = 0;
|
||||
if (open) n++;
|
||||
if (synthetic) n++;
|
||||
if (mandated) n++;
|
||||
if (n == 0) {
|
||||
return Collections.emptySet();
|
||||
} else {
|
||||
ModuleDescriptor.Modifier[] mods = new ModuleDescriptor.Modifier[n];
|
||||
if (open) mods[--n] = ModuleDescriptor.Modifier.OPEN;
|
||||
if (synthetic) mods[--n] = ModuleDescriptor.Modifier.SYNTHETIC;
|
||||
if (mandated) mods[--n] = ModuleDescriptor.Modifier.MANDATED;
|
||||
return Set.of(mods);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@code ModuleDescriptor} from the components.
|
||||
*/
|
||||
public ModuleDescriptor build(int hashCode) {
|
||||
assert name != null;
|
||||
|
||||
return JLMA.newModuleDescriptor(name,
|
||||
version,
|
||||
open,
|
||||
automatic,
|
||||
synthetic,
|
||||
modifiers(),
|
||||
requires,
|
||||
exports,
|
||||
opens,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 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
|
||||
@ -26,7 +26,7 @@
|
||||
package jdk.internal.module;
|
||||
|
||||
/**
|
||||
* Utility class for checking module name and binary names.
|
||||
* Utility class for checking module, package, and class names.
|
||||
*/
|
||||
|
||||
public final class Checks {
|
||||
@ -58,8 +58,6 @@ public final class Checks {
|
||||
throw new IllegalArgumentException(name + ": Invalid module name"
|
||||
+ ": '" + id + "' is not a Java identifier");
|
||||
}
|
||||
//if (!Character.isJavaIdentifierStart(last))
|
||||
// throw new IllegalArgumentException(name + ": Module name ends in digit");
|
||||
return name;
|
||||
}
|
||||
|
||||
@ -77,8 +75,6 @@ public final class Checks {
|
||||
int last = isJavaIdentifier(name, off, name.length() - off);
|
||||
if (last == -1)
|
||||
return false;
|
||||
//if (!Character.isJavaIdentifierStart(last))
|
||||
// return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -89,40 +85,62 @@ public final class Checks {
|
||||
* package name
|
||||
*/
|
||||
public static String requirePackageName(String name) {
|
||||
return requireBinaryName("package name", name);
|
||||
return requireTypeName("package name", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a name to ensure that it's a legal type name.
|
||||
* Returns {@code true} if the given name is a legal package name.
|
||||
*/
|
||||
public static boolean isPackageName(String name) {
|
||||
return isTypeName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a name to ensure that it's a legal qualified class name
|
||||
*
|
||||
* @throws IllegalArgumentException if name is null or not a legal
|
||||
* type name
|
||||
* qualified class name
|
||||
*/
|
||||
public static String requireServiceTypeName(String name) {
|
||||
return requireBinaryName("service type name", name);
|
||||
return requireQualifiedClassName("service type name", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a name to ensure that it's a legal type name.
|
||||
* Checks a name to ensure that it's a legal qualified class name.
|
||||
*
|
||||
* @throws IllegalArgumentException if name is null or not a legal
|
||||
* type name
|
||||
* qualified class name
|
||||
*/
|
||||
public static String requireServiceProviderName(String name) {
|
||||
return requireBinaryName("service provider name", name);
|
||||
return requireQualifiedClassName("service provider name", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given name is a legal binary name.
|
||||
* Checks a name to ensure that it's a legal qualified class name in
|
||||
* a named package.
|
||||
*
|
||||
* @throws IllegalArgumentException if name is null or not a legal
|
||||
* qualified class name in a named package
|
||||
*/
|
||||
public static boolean isJavaIdentifier(String name) {
|
||||
return isBinaryName(name);
|
||||
public static String requireQualifiedClassName(String what, String name) {
|
||||
requireTypeName(what, name);
|
||||
if (name.indexOf('.') == -1)
|
||||
throw new IllegalArgumentException(name + ": is not a qualified name of"
|
||||
+ " a Java class in a named package");
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given name is a legal binary name.
|
||||
* Returns {@code true} if the given name is a legal class name.
|
||||
*/
|
||||
public static boolean isBinaryName(String name) {
|
||||
public static boolean isClassName(String name) {
|
||||
return isTypeName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given name is a legal type name.
|
||||
*/
|
||||
private static boolean isTypeName(String name) {
|
||||
int next;
|
||||
int off = 0;
|
||||
while ((next = name.indexOf('.', off)) != -1) {
|
||||
@ -135,12 +153,12 @@ public final class Checks {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given name is a legal binary name.
|
||||
* Checks if the given name is a legal type name.
|
||||
*
|
||||
* @throws IllegalArgumentException if name is null or not a legal
|
||||
* binary name
|
||||
* type name
|
||||
*/
|
||||
public static String requireBinaryName(String what, String name) {
|
||||
private static String requireTypeName(String what, String name) {
|
||||
if (name == null)
|
||||
throw new IllegalArgumentException("Null " + what);
|
||||
int next;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
@ -26,6 +26,7 @@
|
||||
package jdk.internal.module;
|
||||
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleDescriptor.Builder;
|
||||
import java.lang.module.ModuleDescriptor.Requires;
|
||||
import java.lang.module.ModuleDescriptor.Exports;
|
||||
import java.lang.module.ModuleDescriptor.Opens;
|
||||
@ -98,14 +99,17 @@ public final class ClassFileAttributes {
|
||||
|
||||
// module_flags
|
||||
int module_flags = cr.readUnsignedShort(off);
|
||||
boolean open = ((module_flags & ACC_OPEN) != 0);
|
||||
boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
|
||||
off += 2;
|
||||
|
||||
ModuleDescriptor.Builder builder = JLMA.newModuleBuilder(mn,
|
||||
false,
|
||||
open,
|
||||
synthetic);
|
||||
Set<ModuleDescriptor.Modifier> modifiers = new HashSet<>();
|
||||
if ((module_flags & ACC_OPEN) != 0)
|
||||
modifiers.add(ModuleDescriptor.Modifier.OPEN);
|
||||
if ((module_flags & ACC_SYNTHETIC) != 0)
|
||||
modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC);
|
||||
if ((module_flags & ACC_MANDATED) != 0)
|
||||
modifiers.add(ModuleDescriptor.Modifier.MANDATED);
|
||||
|
||||
Builder builder = JLMA.newModuleBuilder(mn, false, modifiers);
|
||||
|
||||
// module_version
|
||||
String module_version = cr.readUTF8(off, buf);
|
||||
@ -142,19 +146,13 @@ public final class ClassFileAttributes {
|
||||
mods.add(Requires.Modifier.MANDATED);
|
||||
}
|
||||
|
||||
|
||||
// requires_version
|
||||
Version compiledVersion = null;
|
||||
String requires_version = cr.readUTF8(off, buf);
|
||||
off += 2;
|
||||
if (requires_version != null) {
|
||||
compiledVersion = Version.parse(requires_version);
|
||||
}
|
||||
|
||||
if (compiledVersion == null) {
|
||||
if (requires_version == null) {
|
||||
builder.requires(mods, dn);
|
||||
} else {
|
||||
builder.requires(mods, dn, compiledVersion);
|
||||
JLMA.requires(builder, mods, dn, requires_version);
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,11 +281,14 @@ public final class ClassFileAttributes {
|
||||
attr.putShort(module_name_index);
|
||||
|
||||
// module_flags
|
||||
Set<ModuleDescriptor.Modifier> modifiers = descriptor.modifiers();
|
||||
int module_flags = 0;
|
||||
if (descriptor.isOpen())
|
||||
if (modifiers.contains(ModuleDescriptor.Modifier.OPEN))
|
||||
module_flags |= ACC_OPEN;
|
||||
if (descriptor.isSynthetic())
|
||||
if (modifiers.contains(ModuleDescriptor.Modifier.SYNTHETIC))
|
||||
module_flags |= ACC_SYNTHETIC;
|
||||
if (modifiers.contains(ModuleDescriptor.Modifier.MANDATED))
|
||||
module_flags |= ACC_MANDATED;
|
||||
attr.putShort(module_flags);
|
||||
|
||||
// module_version
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
@ -46,8 +46,8 @@ public class ClassFileConstants {
|
||||
// access, requires, exports, and opens flags
|
||||
public static final int ACC_MODULE = 0x8000;
|
||||
public static final int ACC_OPEN = 0x0020;
|
||||
public static final int ACC_TRANSITIVE = 0x0010;
|
||||
public static final int ACC_STATIC_PHASE = 0x0020;
|
||||
public static final int ACC_TRANSITIVE = 0x0020;
|
||||
public static final int ACC_STATIC_PHASE = 0x0040;
|
||||
public static final int ACC_SYNTHETIC = 0x1000;
|
||||
public static final int ACC_MANDATED = 0x8000;
|
||||
|
||||
|
@ -26,7 +26,9 @@
|
||||
package jdk.internal.module;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleFinder;
|
||||
@ -35,6 +37,7 @@ import java.lang.module.ResolvedModule;
|
||||
import java.lang.reflect.Layer;
|
||||
import java.lang.reflect.Module;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
@ -46,6 +49,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.loader.BootLoader;
|
||||
import jdk.internal.loader.BuiltinClassLoader;
|
||||
@ -114,7 +118,12 @@ public final class ModuleBootstrap {
|
||||
long t0 = System.nanoTime();
|
||||
|
||||
// system modules (may be patched)
|
||||
ModuleFinder systemModules = ModuleFinder.ofSystem();
|
||||
ModuleFinder systemModules;
|
||||
if (SystemModules.MODULE_NAMES.length > 0) {
|
||||
systemModules = SystemModuleFinder.getInstance();
|
||||
} else {
|
||||
systemModules = ModuleFinder.ofSystem();
|
||||
}
|
||||
|
||||
PerfCounters.systemModulesTime.addElapsedTimeFrom(t0);
|
||||
|
||||
@ -275,10 +284,10 @@ public final class ModuleBootstrap {
|
||||
|
||||
// run the resolver to create the configuration
|
||||
Configuration cf = SharedSecrets.getJavaLangModuleAccess()
|
||||
.resolveRequiresAndUses(finder,
|
||||
roots,
|
||||
needPostResolutionChecks,
|
||||
traceOutput);
|
||||
.resolveAndBind(finder,
|
||||
roots,
|
||||
needPostResolutionChecks,
|
||||
traceOutput);
|
||||
|
||||
// time to create configuration
|
||||
PerfCounters.resolveTime.addElapsedTimeFrom(t3);
|
||||
@ -318,20 +327,20 @@ public final class ModuleBootstrap {
|
||||
// if needed check that there are no split packages in the set of
|
||||
// resolved modules for the boot layer
|
||||
if (SystemModules.hasSplitPackages() || needPostResolutionChecks) {
|
||||
Map<String, String> packageToModule = new HashMap<>();
|
||||
for (ResolvedModule resolvedModule : cf.modules()) {
|
||||
ModuleDescriptor descriptor =
|
||||
resolvedModule.reference().descriptor();
|
||||
String name = descriptor.name();
|
||||
for (String p : descriptor.packages()) {
|
||||
String other = packageToModule.putIfAbsent(p, name);
|
||||
if (other != null) {
|
||||
fail("Package " + p + " in both module "
|
||||
+ name + " and module " + other);
|
||||
}
|
||||
Map<String, String> packageToModule = new HashMap<>();
|
||||
for (ResolvedModule resolvedModule : cf.modules()) {
|
||||
ModuleDescriptor descriptor =
|
||||
resolvedModule.reference().descriptor();
|
||||
String name = descriptor.name();
|
||||
for (String p : descriptor.packages()) {
|
||||
String other = packageToModule.putIfAbsent(p, name);
|
||||
if (other != null) {
|
||||
fail("Package " + p + " in both module "
|
||||
+ name + " and module " + other);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long t4 = System.nanoTime();
|
||||
|
||||
@ -380,10 +389,9 @@ public final class ModuleBootstrap {
|
||||
Set<String> otherMods)
|
||||
{
|
||||
// resolve all root modules
|
||||
Configuration cf = Configuration.empty()
|
||||
.resolveRequires(finder,
|
||||
ModuleFinder.of(),
|
||||
roots);
|
||||
Configuration cf = Configuration.empty().resolve(finder,
|
||||
ModuleFinder.of(),
|
||||
roots);
|
||||
|
||||
// module name -> reference
|
||||
Map<String, ModuleReference> map = new HashMap<>();
|
||||
@ -416,7 +424,7 @@ public final class ModuleBootstrap {
|
||||
|
||||
/**
|
||||
* Creates a finder from the module path that is the value of the given
|
||||
* system property.
|
||||
* system property and optionally patched by --patch-module
|
||||
*/
|
||||
private static ModuleFinder createModulePathFinder(String prop) {
|
||||
String s = System.getProperty(prop);
|
||||
@ -429,7 +437,7 @@ public final class ModuleBootstrap {
|
||||
for (String dir: dirs) {
|
||||
paths[i++] = Paths.get(dir);
|
||||
}
|
||||
return ModuleFinder.of(paths);
|
||||
return ModulePath.of(patcher, paths);
|
||||
}
|
||||
}
|
||||
|
||||
@ -528,8 +536,48 @@ public final class ModuleBootstrap {
|
||||
if (!extraOpens.isEmpty()) {
|
||||
addExtraExportsOrOpens(bootLayer, extraOpens, true);
|
||||
}
|
||||
|
||||
// DEBUG_ADD_OPENS is for debugging purposes only
|
||||
String home = System.getProperty("java.home");
|
||||
Path file = Paths.get(home, "conf", "DEBUG_ADD_OPENS");
|
||||
if (Files.exists(file)) {
|
||||
warn(file + " detected; may break encapsulation");
|
||||
try (Stream<String> lines = Files.lines(file)) {
|
||||
lines.map(line -> line.trim())
|
||||
.filter(line -> (!line.isEmpty() && !line.startsWith("#")))
|
||||
.forEach(line -> {
|
||||
String[] s = line.split("/");
|
||||
if (s.length != 2) {
|
||||
fail("Unable to parse as <module>/<package>: " + line);
|
||||
} else {
|
||||
String mn = s[0];
|
||||
String pkg = s[1];
|
||||
openPackage(bootLayer, mn, pkg);
|
||||
}
|
||||
});
|
||||
} catch (IOException ioe) {
|
||||
throw new UncheckedIOException(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void openPackage(Layer bootLayer, String mn, String pkg) {
|
||||
if (mn.equals("ALL-RESOLVED") && pkg.equals("ALL-PACKAGES")) {
|
||||
bootLayer.modules().stream().forEach(m ->
|
||||
m.getDescriptor().packages().forEach(pn -> openPackage(m, pn)));
|
||||
} else {
|
||||
bootLayer.findModule(mn)
|
||||
.filter(m -> m.getDescriptor().packages().contains(pkg))
|
||||
.ifPresent(m -> openPackage(m, pkg));
|
||||
}
|
||||
}
|
||||
|
||||
private static void openPackage(Module m, String pn) {
|
||||
Modules.addOpensToAllUnnamed(m, pn);
|
||||
warn("Opened for deep reflection: " + m.getName() + "/" + pn);
|
||||
}
|
||||
|
||||
|
||||
private static void addExtraExportsOrOpens(Layer bootLayer,
|
||||
Map<String, List<String>> map,
|
||||
boolean opens)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -37,7 +37,6 @@ import java.lang.module.ModuleDescriptor.Builder;
|
||||
import java.lang.module.ModuleDescriptor.Requires;
|
||||
import java.lang.module.ModuleDescriptor.Exports;
|
||||
import java.lang.module.ModuleDescriptor.Opens;
|
||||
import java.lang.module.ModuleDescriptor.Version;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.util.ArrayList;
|
||||
@ -51,7 +50,6 @@ import java.util.function.Supplier;
|
||||
|
||||
import jdk.internal.misc.JavaLangModuleAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.module.ModuleResolution;
|
||||
|
||||
import static jdk.internal.module.ClassFileConstants.*;
|
||||
|
||||
@ -221,7 +219,7 @@ public final class ModuleInfo {
|
||||
Set<String> attributes = new HashSet<>();
|
||||
|
||||
Builder builder = null;
|
||||
Set<String> packages = null;
|
||||
Set<String> allPackages = null;
|
||||
String mainClass = null;
|
||||
String[] osValues = null;
|
||||
ModuleHashes hashes = null;
|
||||
@ -245,7 +243,7 @@ public final class ModuleInfo {
|
||||
break;
|
||||
|
||||
case MODULE_PACKAGES :
|
||||
packages = readModulePackagesAttribute(in, cpool);
|
||||
allPackages = readModulePackagesAttribute(in, cpool);
|
||||
break;
|
||||
|
||||
case MODULE_MAIN_CLASS :
|
||||
@ -284,51 +282,44 @@ public final class ModuleInfo {
|
||||
throw invalidModuleDescriptor(MODULE + " attribute not found");
|
||||
}
|
||||
|
||||
// ModuleMainClass and ModuleTarget attributes
|
||||
if (mainClass != null) {
|
||||
builder.mainClass(mainClass);
|
||||
}
|
||||
if (osValues != null) {
|
||||
if (osValues[0] != null) builder.osName(osValues[0]);
|
||||
if (osValues[1] != null) builder.osArch(osValues[1]);
|
||||
if (osValues[2] != null) builder.osVersion(osValues[2]);
|
||||
}
|
||||
|
||||
// If the ModulePackages attribute is not present then the packageFinder
|
||||
// is used to find the set of packages
|
||||
boolean usedPackageFinder = false;
|
||||
if (packages == null && packageFinder != null) {
|
||||
if (allPackages == null && packageFinder != null) {
|
||||
try {
|
||||
packages = new HashSet<>(packageFinder.get());
|
||||
allPackages = packageFinder.get();
|
||||
} catch (UncheckedIOException x) {
|
||||
throw x.getCause();
|
||||
}
|
||||
usedPackageFinder = true;
|
||||
}
|
||||
if (packages != null) {
|
||||
Set<String> exportedPackages = JLMA.exportedPackages(builder);
|
||||
Set<String> openPackages = JLMA.openPackages(builder);
|
||||
if (packages.containsAll(exportedPackages)
|
||||
&& packages.containsAll(openPackages)) {
|
||||
packages.removeAll(exportedPackages);
|
||||
packages.removeAll(openPackages);
|
||||
} else {
|
||||
// the set of packages is not complete
|
||||
Set<String> exportedAndOpenPackages = new HashSet<>();
|
||||
exportedAndOpenPackages.addAll(exportedPackages);
|
||||
exportedAndOpenPackages.addAll(openPackages);
|
||||
for (String pn : exportedAndOpenPackages) {
|
||||
if (!packages.contains(pn)) {
|
||||
String tail;
|
||||
if (usedPackageFinder) {
|
||||
tail = " not found by package finder";
|
||||
} else {
|
||||
tail = " missing from ModulePackages attribute";
|
||||
}
|
||||
throw invalidModuleDescriptor("Package " + pn + tail);
|
||||
}
|
||||
if (allPackages != null) {
|
||||
Set<String> knownPackages = JLMA.packages(builder);
|
||||
if (!allPackages.containsAll(knownPackages)) {
|
||||
Set<String> missingPackages = new HashSet<>(knownPackages);
|
||||
missingPackages.removeAll(allPackages);
|
||||
assert !missingPackages.isEmpty();
|
||||
String missingPackage = missingPackages.iterator().next();
|
||||
String tail;
|
||||
if (usedPackageFinder) {
|
||||
tail = " not found in module";
|
||||
} else {
|
||||
tail = " missing from ModulePackages class file attribute";
|
||||
}
|
||||
assert false; // should not get here
|
||||
}
|
||||
builder.contains(packages);
|
||||
}
|
||||
throw invalidModuleDescriptor("Package " + missingPackage + tail);
|
||||
|
||||
if (mainClass != null)
|
||||
builder.mainClass(mainClass);
|
||||
if (osValues != null) {
|
||||
if (osValues[0] != null) builder.osName(osValues[0]);
|
||||
if (osValues[1] != null) builder.osArch(osValues[1]);
|
||||
if (osValues[2] != null) builder.osVersion(osValues[2]);
|
||||
}
|
||||
builder.packages(allPackages);
|
||||
}
|
||||
|
||||
ModuleDescriptor descriptor = builder.build();
|
||||
@ -347,10 +338,17 @@ public final class ModuleInfo {
|
||||
String mn = cpool.getModuleName(module_name_index);
|
||||
|
||||
int module_flags = in.readUnsignedShort();
|
||||
boolean open = ((module_flags & ACC_OPEN) != 0);
|
||||
boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
|
||||
|
||||
Builder builder = JLMA.newModuleBuilder(mn, false, open, synthetic);
|
||||
Set<ModuleDescriptor.Modifier> modifiers = new HashSet<>();
|
||||
boolean open = ((module_flags & ACC_OPEN) != 0);
|
||||
if (open)
|
||||
modifiers.add(ModuleDescriptor.Modifier.OPEN);
|
||||
if ((module_flags & ACC_SYNTHETIC) != 0)
|
||||
modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC);
|
||||
if ((module_flags & ACC_MANDATED) != 0)
|
||||
modifiers.add(ModuleDescriptor.Modifier.MANDATED);
|
||||
|
||||
Builder builder = JLMA.newModuleBuilder(mn, false, modifiers);
|
||||
|
||||
int module_version_index = in.readUnsignedShort();
|
||||
if (module_version_index != 0) {
|
||||
@ -381,16 +379,11 @@ public final class ModuleInfo {
|
||||
}
|
||||
|
||||
int requires_version_index = in.readUnsignedShort();
|
||||
Version compiledVersion = null;
|
||||
if (requires_version_index != 0) {
|
||||
String vs = cpool.getUtf8(requires_version_index);
|
||||
compiledVersion = Version.parse(vs);
|
||||
}
|
||||
|
||||
if (compiledVersion == null) {
|
||||
if (requires_version_index == 0) {
|
||||
builder.requires(mods, dn);
|
||||
} else {
|
||||
builder.requires(mods, dn, compiledVersion);
|
||||
String vs = cpool.getUtf8(requires_version_index);
|
||||
JLMA.requires(builder, mods, dn, vs);
|
||||
}
|
||||
|
||||
if (dn.equals("java.base"))
|
||||
@ -629,10 +622,7 @@ public final class ModuleInfo {
|
||||
|
||||
/**
|
||||
* Return true if the given attribute name is the name of a pre-defined
|
||||
* attribute that is not allowed in the class file.
|
||||
*
|
||||
* Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and
|
||||
* Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
|
||||
* attribute in JVMS 4.7 that is not allowed in a module-info class.
|
||||
*/
|
||||
private static boolean isAttributeDisallowed(String name) {
|
||||
Set<String> notAllowed = predefinedNotAllowed;
|
||||
@ -640,6 +630,7 @@ public final class ModuleInfo {
|
||||
notAllowed = Set.of(
|
||||
"ConstantValue",
|
||||
"Code",
|
||||
"Deprecated",
|
||||
"StackMapTable",
|
||||
"Exceptions",
|
||||
"EnclosingMethod",
|
||||
|
@ -56,7 +56,7 @@ public final class ModuleInfoExtender {
|
||||
// the packages in the ModulePackages attribute
|
||||
private Set<String> packages;
|
||||
|
||||
// the value of the module_version in Module attribute
|
||||
// the value for the module version in the Module attribute
|
||||
private Version version;
|
||||
|
||||
// the value of the ModuleMainClass attribute
|
||||
@ -78,7 +78,11 @@ public final class ModuleInfoExtender {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the set of packages for the ModulePackages attribute
|
||||
* Sets the packages for the ModulePackages attribute
|
||||
*
|
||||
* @apiNote This method does not check that the package names are legal
|
||||
* package names or that the set of packages is a super set of the
|
||||
* packages in the module.
|
||||
*/
|
||||
public ModuleInfoExtender packages(Set<String> packages) {
|
||||
this.packages = Collections.unmodifiableSet(packages);
|
||||
@ -86,7 +90,7 @@ public final class ModuleInfoExtender {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the module_version in Module attribute.
|
||||
* Sets the value for the module version in the Module attribute
|
||||
*/
|
||||
public ModuleInfoExtender version(Version version) {
|
||||
this.version = version;
|
||||
@ -95,6 +99,9 @@ public final class ModuleInfoExtender {
|
||||
|
||||
/**
|
||||
* Sets the value of the ModuleMainClass attribute.
|
||||
*
|
||||
* @apiNote This method does not check that the main class is a legal
|
||||
* class name in a named package.
|
||||
*/
|
||||
public ModuleInfoExtender mainClass(String mainClass) {
|
||||
this.mainClass = mainClass;
|
||||
@ -133,7 +140,7 @@ public final class ModuleInfoExtender {
|
||||
|
||||
/**
|
||||
* A ClassVisitor that supports adding class file attributes. If an
|
||||
* attribute already exists then the first occurence of the attribute
|
||||
* attribute already exists then the first occurrence of the attribute
|
||||
* is replaced.
|
||||
*/
|
||||
private static class AttributeAddingClassVisitor extends ClassVisitor {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
@ -41,13 +41,6 @@ import jdk.internal.loader.ClassLoaders;
|
||||
* are generated at build time.
|
||||
*/
|
||||
final class ModuleLoaderMap {
|
||||
/*
|
||||
* The list of boot modules and platform modules are generated at build time.
|
||||
*/
|
||||
private static final String[] BOOT_MODULES
|
||||
= new String[] { "@@BOOT_MODULE_NAMES@@" };
|
||||
private static final String[] PLATFORM_MODULES
|
||||
= new String[] { "@@PLATFORM_MODULE_NAMES@@" };
|
||||
|
||||
/**
|
||||
* Returns the function to map modules in the given configuration to the
|
||||
@ -55,6 +48,10 @@ final class ModuleLoaderMap {
|
||||
*/
|
||||
static Function<String, ClassLoader> mappingFunction(Configuration cf) {
|
||||
|
||||
// The list of boot modules and platform modules are generated at build time.
|
||||
final String[] BOOT_MODULES = new String[] { "@@BOOT_MODULE_NAMES@@" };
|
||||
final String[] PLATFORM_MODULES = new String[] { "@@PLATFORM_MODULE_NAMES@@" };
|
||||
|
||||
Set<String> bootModules = new HashSet<>(BOOT_MODULES.length);
|
||||
for (String mn : BOOT_MODULES) {
|
||||
bootModules.add(mn);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
@ -31,6 +31,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleDescriptor.Builder;
|
||||
import java.lang.module.ModuleReader;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.net.MalformedURLException;
|
||||
@ -54,6 +55,7 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.loader.Resource;
|
||||
import jdk.internal.loader.ResourceHelper;
|
||||
import jdk.internal.misc.JavaLangModuleAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import sun.net.www.ParseUtil;
|
||||
@ -108,8 +110,11 @@ public final class ModulePatcher {
|
||||
if (paths == null)
|
||||
return mref;
|
||||
|
||||
// scan the JAR file or directory tree to get the set of packages
|
||||
// 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)) {
|
||||
@ -118,8 +123,10 @@ public final class ModulePatcher {
|
||||
// is not supported by the boot class loader
|
||||
try (JarFile jf = new JarFile(file.toFile())) {
|
||||
jf.stream()
|
||||
.filter(e -> !e.isDirectory()
|
||||
&& (!isAutomatic || e.getName().endsWith(".class")))
|
||||
.map(e -> toPackageName(file, e))
|
||||
.filter(Checks::isJavaIdentifier)
|
||||
.filter(Checks::isPackageName)
|
||||
.forEach(packages::add);
|
||||
}
|
||||
|
||||
@ -129,8 +136,10 @@ public final class ModulePatcher {
|
||||
Path top = file;
|
||||
Files.find(top, Integer.MAX_VALUE,
|
||||
((path, attrs) -> attrs.isRegularFile()))
|
||||
.filter(path -> !isAutomatic
|
||||
|| path.toString().endsWith(".class"))
|
||||
.map(path -> toPackageName(top, path))
|
||||
.filter(Checks::isJavaIdentifier)
|
||||
.filter(Checks::isPackageName)
|
||||
.forEach(packages::add);
|
||||
|
||||
}
|
||||
@ -141,10 +150,30 @@ public final class ModulePatcher {
|
||||
}
|
||||
|
||||
// if there are new packages then we need a new ModuleDescriptor
|
||||
Set<String> original = descriptor.packages();
|
||||
packages.addAll(original);
|
||||
if (packages.size() > original.size()) {
|
||||
descriptor = JLMA.newModuleDescriptor(descriptor, packages);
|
||||
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);
|
||||
descriptor.osName().ifPresent(builder::osName);
|
||||
descriptor.osArch().ifPresent(builder::osArch);
|
||||
descriptor.osVersion().ifPresent(builder::osVersion);
|
||||
|
||||
// original + new packages
|
||||
builder.packages(descriptor.packages());
|
||||
builder.packages(packages);
|
||||
|
||||
descriptor = builder.build();
|
||||
}
|
||||
|
||||
// return a module reference to the patched module
|
||||
@ -471,23 +500,14 @@ public final class ModulePatcher {
|
||||
|
||||
@Override
|
||||
public Resource find(String name) throws IOException {
|
||||
Path file = Paths.get(name.replace('/', File.separatorChar));
|
||||
if (file.getRoot() == null) {
|
||||
file = dir.resolve(file);
|
||||
} else {
|
||||
// drop the root component so that the resource is
|
||||
// located relative to the module directory
|
||||
int n = file.getNameCount();
|
||||
if (n == 0)
|
||||
return null;
|
||||
file = dir.resolve(file.subpath(0, n));
|
||||
}
|
||||
|
||||
if (Files.isRegularFile(file)) {
|
||||
return newResource(name, dir, file);
|
||||
} else {
|
||||
return null;
|
||||
Path path = ResourceHelper.toFilePath(name);
|
||||
if (path != null) {
|
||||
Path file = dir.resolve(path);
|
||||
if (Files.isRegularFile(file)) {
|
||||
return newResource(name, dir, file);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Resource newResource(String name, Path top, Path file) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -35,7 +35,6 @@ import java.io.UncheckedIOException;
|
||||
import java.lang.module.FindException;
|
||||
import java.lang.module.InvalidModuleDescriptorException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleDescriptor.Requires;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.net.URI;
|
||||
@ -70,12 +69,11 @@ import jdk.internal.util.jar.VersionedStream;
|
||||
|
||||
/**
|
||||
* A {@code ModuleFinder} that locates modules on the file system by searching
|
||||
* a sequence of directories or packaged modules.
|
||||
*
|
||||
* The {@code ModuleFinder} can be created to work in either the run-time
|
||||
* or link-time phases. In both cases it locates modular JAR and exploded
|
||||
* modules. When created for link-time then it additionally locates
|
||||
* modules in JMOD files.
|
||||
* a sequence of directories or packaged modules. The ModuleFinder can be
|
||||
* created to work in either the run-time or link-time phases. In both cases it
|
||||
* locates modular JAR and exploded modules. When created for link-time then it
|
||||
* additionally locates modules in JMOD files. The ModuleFinder can also
|
||||
* optionally patch any modules that it locates with a ModulePatcher.
|
||||
*/
|
||||
|
||||
public class ModulePath implements ModuleFinder {
|
||||
@ -87,6 +85,9 @@ public class ModulePath implements ModuleFinder {
|
||||
// true for the link phase (supports modules packaged in JMOD format)
|
||||
private final boolean isLinkPhase;
|
||||
|
||||
// for patching modules, can be null
|
||||
private final ModulePatcher patcher;
|
||||
|
||||
// the entries on this module path
|
||||
private final Path[] entries;
|
||||
private int next;
|
||||
@ -94,19 +95,51 @@ public class ModulePath implements ModuleFinder {
|
||||
// map of module name to module reference map for modules already located
|
||||
private final Map<String, ModuleReference> cachedModules = new HashMap<>();
|
||||
|
||||
public ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) {
|
||||
|
||||
private ModulePath(Runtime.Version version,
|
||||
boolean isLinkPhase,
|
||||
ModulePatcher patcher,
|
||||
Path... entries) {
|
||||
this.releaseVersion = version;
|
||||
this.isLinkPhase = isLinkPhase;
|
||||
this.patcher = patcher;
|
||||
this.entries = entries.clone();
|
||||
for (Path entry : this.entries) {
|
||||
Objects.requireNonNull(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public ModulePath(Path... entries) {
|
||||
this(JarFile.runtimeVersion(), false, entries);
|
||||
/**
|
||||
* Returns a ModuleFinder that that locates modules on the file system by
|
||||
* searching a sequence of directories and/or packaged modules. The modules
|
||||
* may be patched by the given ModulePatcher.
|
||||
*/
|
||||
public static ModuleFinder of(ModulePatcher patcher, Path... entries) {
|
||||
return new ModulePath(JarFile.runtimeVersion(), false, patcher, entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ModuleFinder that that locates modules on the file system by
|
||||
* searching a sequence of directories and/or packaged modules.
|
||||
*/
|
||||
public static ModuleFinder of(Path... entries) {
|
||||
return of((ModulePatcher)null, entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ModuleFinder that that locates modules on the file system by
|
||||
* searching a sequence of directories and/or packaged modules.
|
||||
*
|
||||
* @param version The release version to use for multi-release JAR files
|
||||
* @param isLinkPhase {@code true} if the link phase to locate JMOD files
|
||||
*/
|
||||
public static ModuleFinder of(Runtime.Version version,
|
||||
boolean isLinkPhase,
|
||||
Path... entries) {
|
||||
return new ModulePath(version, isLinkPhase, null, entries);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Optional<ModuleReference> find(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
@ -195,8 +228,7 @@ public class ModulePath implements ModuleFinder {
|
||||
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
|
||||
// assume a directory of modules
|
||||
return scanDirectory(entry);
|
||||
}
|
||||
}
|
||||
@ -206,11 +238,17 @@ public class ModulePath implements ModuleFinder {
|
||||
if (mref != null) {
|
||||
String name = mref.descriptor().name();
|
||||
return Collections.singletonMap(name, mref);
|
||||
} else {
|
||||
// skipped
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
@ -266,14 +304,11 @@ public class ModulePath implements ModuleFinder {
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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 the file is not recognized as a module or an
|
||||
* error occurs parsing its module descriptor
|
||||
* @throws FindException if an error occurs parsing its module descriptor
|
||||
*/
|
||||
private ModuleReference readModule(Path entry, BasicFileAttributes attrs)
|
||||
throws IOException
|
||||
@ -282,24 +317,16 @@ public class ModulePath implements ModuleFinder {
|
||||
|
||||
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);
|
||||
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) {
|
||||
@ -327,7 +354,7 @@ public class ModulePath implements ModuleFinder {
|
||||
}
|
||||
}
|
||||
|
||||
// -- jmod files --
|
||||
// -- JMOD files --
|
||||
|
||||
private Set<String> jmodPackages(JmodFile jf) {
|
||||
return jf.stream()
|
||||
@ -339,7 +366,7 @@ public class ModulePath implements ModuleFinder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code ModuleReference} to a module in jmod file on the
|
||||
* Returns a {@code ModuleReference} to a module in JMOD file on the
|
||||
* file system.
|
||||
*
|
||||
* @throws IOException
|
||||
@ -362,7 +389,7 @@ public class ModulePath implements ModuleFinder {
|
||||
|
||||
/**
|
||||
* Returns the service type corresponding to the name of a services
|
||||
* configuration file if it is a valid Java identifier.
|
||||
* 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".
|
||||
@ -374,7 +401,7 @@ public class ModulePath implements ModuleFinder {
|
||||
String prefix = cf.substring(0, index);
|
||||
if (prefix.equals(SERVICES_PREFIX)) {
|
||||
String sn = cf.substring(index);
|
||||
if (Checks.isJavaIdentifier(sn))
|
||||
if (Checks.isClassName(sn))
|
||||
return Optional.of(sn);
|
||||
}
|
||||
}
|
||||
@ -403,11 +430,10 @@ public class ModulePath implements ModuleFinder {
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* 5. The Main-Class attribute in the main attributes of the JAR manifest
|
||||
* 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)
|
||||
@ -443,9 +469,7 @@ public class ModulePath implements ModuleFinder {
|
||||
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");
|
||||
ModuleDescriptor.Builder builder = ModuleDescriptor.newAutomaticModule(mn);
|
||||
if (vs != null)
|
||||
builder.version(vs);
|
||||
|
||||
@ -453,17 +477,22 @@ public class ModulePath implements ModuleFinder {
|
||||
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> resources = map.get(Boolean.FALSE);
|
||||
Set<String> classFiles = map.get(Boolean.FALSE);
|
||||
Set<String> configFiles = map.get(Boolean.TRUE);
|
||||
// all packages are exported and open
|
||||
resources.stream()
|
||||
|
||||
// the packages containing class files
|
||||
Set<String> packages = classFiles.stream()
|
||||
.map(this::toPackageName)
|
||||
.flatMap(Optional::stream)
|
||||
.distinct()
|
||||
.forEach(pn -> builder.exports(pn).opens(pn));
|
||||
.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()
|
||||
@ -481,6 +510,11 @@ public class ModulePath implements ModuleFinder {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -494,8 +528,15 @@ public class ModulePath implements ModuleFinder {
|
||||
if (man != null) {
|
||||
Attributes attrs = man.getMainAttributes();
|
||||
String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
|
||||
if (mainClass != null)
|
||||
builder.mainClass(mainClass.replace("/", "."));
|
||||
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();
|
||||
@ -569,10 +610,10 @@ public class ModulePath implements ModuleFinder {
|
||||
try {
|
||||
ModuleDescriptor md = deriveModuleDescriptor(jf);
|
||||
attrs = new ModuleInfo.Attributes(md, null, null);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new FindException(
|
||||
"Unable to derive module descriptor for: "
|
||||
+ jf.getName(), iae);
|
||||
+ jf.getName(), e);
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -580,7 +621,7 @@ public class ModulePath implements ModuleFinder {
|
||||
() -> jarPackages(jf));
|
||||
}
|
||||
|
||||
return ModuleReferences.newJarModule(attrs, file);
|
||||
return ModuleReferences.newJarModule(attrs, patcher, file);
|
||||
}
|
||||
}
|
||||
|
||||
@ -617,7 +658,15 @@ public class ModulePath implements ModuleFinder {
|
||||
// for now
|
||||
return null;
|
||||
}
|
||||
return ModuleReferences.newExplodedModule(attrs, dir);
|
||||
return ModuleReferences.newExplodedModule(attrs, patcher, 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -629,19 +678,18 @@ public class ModulePath implements ModuleFinder {
|
||||
*/
|
||||
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:"
|
||||
+ " 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)) {
|
||||
if (Checks.isPackageName(pn)) {
|
||||
return Optional.of(pn);
|
||||
} else {
|
||||
// not a valid package name
|
||||
@ -654,7 +702,7 @@ public class ModulePath implements ModuleFinder {
|
||||
* name.
|
||||
*
|
||||
* @throws IllegalArgumentException if the name is a class file in
|
||||
* the top-level directory (and it's not module-info.class)
|
||||
* the top-level directory (and it's not module-info.class)
|
||||
*/
|
||||
private Optional<String> toPackageName(Path file) {
|
||||
assert file.getRoot() == null;
|
||||
@ -664,14 +712,14 @@ public class ModulePath implements ModuleFinder {
|
||||
String name = file.toString();
|
||||
if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
|
||||
throw new IllegalArgumentException(name
|
||||
+ " found in in top-level directory"
|
||||
+ " found in top-level directory"
|
||||
+ " (unnamed package not allowed in module)");
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String pn = parent.toString().replace(File.separatorChar, '.');
|
||||
if (Checks.isJavaIdentifier(pn)) {
|
||||
if (Checks.isPackageName(pn)) {
|
||||
return Optional.of(pn);
|
||||
} else {
|
||||
// not a valid package name
|
||||
|
@ -163,7 +163,14 @@ public class ModuleReferenceImpl extends ModuleReference {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[module ");
|
||||
sb.append(descriptor().name());
|
||||
sb.append(", location=");
|
||||
sb.append(location().orElseThrow(() -> new InternalError()));
|
||||
if (isPatched()) sb.append(" (patched)");
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@ -51,7 +50,7 @@ import java.util.stream.Stream;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import jdk.internal.jmod.JmodFile;
|
||||
import jdk.internal.misc.JavaLangAccess;
|
||||
import jdk.internal.loader.ResourceHelper;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.module.ModuleHashes.HashSupplier;
|
||||
import jdk.internal.util.jar.VersionedStream;
|
||||
@ -65,20 +64,16 @@ import sun.net.www.ParseUtil;
|
||||
*/
|
||||
|
||||
class ModuleReferences {
|
||||
|
||||
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
|
||||
|
||||
private ModuleReferences() { }
|
||||
|
||||
/**
|
||||
* Creates a ModuleReference to a module or to patched module when
|
||||
* creating modules for the boot Layer and --patch-module is specified.
|
||||
* 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,
|
||||
@ -86,38 +81,42 @@ class ModuleReferences {
|
||||
attrs.recordedHashes(),
|
||||
hasher,
|
||||
attrs.moduleResolution());
|
||||
if (JLA.getBootLayer() == null)
|
||||
mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
|
||||
if (patcher != null)
|
||||
mref = patcher.patchIfNeeded(mref);
|
||||
|
||||
return mref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ModuleReference to a module packaged as a modular JAR.
|
||||
* Creates a ModuleReference to a possibly-patched module in a modular JAR.
|
||||
*/
|
||||
static ModuleReference newJarModule(ModuleInfo.Attributes attrs, Path file) {
|
||||
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, hasher);
|
||||
return newModule(attrs, uri, supplier, patcher, hasher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ModuleReference to a module packaged as a JMOD.
|
||||
* Creates a ModuleReference to a module in a JMOD file.
|
||||
*/
|
||||
static ModuleReference newJModModule(ModuleInfo.Attributes attrs, Path file) {
|
||||
URI uri = file.toUri();
|
||||
Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
|
||||
HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
|
||||
return newModule(attrs, uri, supplier, hasher);
|
||||
return newModule(attrs, uri, supplier, null, hasher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ModuleReference to an exploded module.
|
||||
* Creates a ModuleReference to a possibly-patched exploded module.
|
||||
*/
|
||||
static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs, Path dir) {
|
||||
static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs,
|
||||
ModulePatcher patcher,
|
||||
Path dir) {
|
||||
Supplier<ModuleReader> supplier = () -> new ExplodedModuleReader(dir);
|
||||
return newModule(attrs, dir.toUri(), supplier, null);
|
||||
return newModule(attrs, dir.toUri(), supplier, patcher, null);
|
||||
}
|
||||
|
||||
|
||||
@ -243,7 +242,8 @@ class ModuleReferences {
|
||||
}
|
||||
|
||||
private JarEntry getEntry(String name) {
|
||||
return jf.getJarEntry(Objects.requireNonNull(name));
|
||||
JarEntry entry = jf.getJarEntry(Objects.requireNonNull(name));
|
||||
return (entry == null || entry.isDirectory()) ? null : entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -369,21 +369,6 @@ class ModuleReferences {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Path to access to the given resource.
|
||||
*/
|
||||
private Path toPath(String name) {
|
||||
Path path = Paths.get(name.replace('/', File.separatorChar));
|
||||
if (path.getRoot() == null) {
|
||||
return dir.resolve(path);
|
||||
} else {
|
||||
// drop the root component so that the resource is
|
||||
// located relative to the module directory
|
||||
int n = path.getNameCount();
|
||||
return (n > 0) ? dir.resolve(path.subpath(0, n)) : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws IOException if the module reader is closed;
|
||||
*/
|
||||
@ -391,11 +376,27 @@ class ModuleReferences {
|
||||
if (closed) throw new IOException("ModuleReader is closed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Path to access the given resource. Returns null if the
|
||||
* resource name does not convert to a file path that locates a regular
|
||||
* file in the module.
|
||||
*/
|
||||
private Path toFilePath(String name) {
|
||||
Path path = ResourceHelper.toFilePath(name);
|
||||
if (path != null) {
|
||||
Path file = dir.resolve(path);
|
||||
if (Files.isRegularFile(file)) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<URI> find(String name) throws IOException {
|
||||
ensureOpen();
|
||||
Path path = toPath(name);
|
||||
if (path != null && Files.isRegularFile(path)) {
|
||||
Path path = toFilePath(name);
|
||||
if (path != null) {
|
||||
try {
|
||||
return Optional.of(path.toUri());
|
||||
} catch (IOError e) {
|
||||
@ -409,8 +410,8 @@ class ModuleReferences {
|
||||
@Override
|
||||
public Optional<InputStream> open(String name) throws IOException {
|
||||
ensureOpen();
|
||||
Path path = toPath(name);
|
||||
if (path != null && Files.isRegularFile(path)) {
|
||||
Path path = toFilePath(name);
|
||||
if (path != null) {
|
||||
return Optional.of(Files.newInputStream(path));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
@ -420,8 +421,8 @@ class ModuleReferences {
|
||||
@Override
|
||||
public Optional<ByteBuffer> read(String name) throws IOException {
|
||||
ensureOpen();
|
||||
Path path = toPath(name);
|
||||
if (path != null && Files.isRegularFile(path)) {
|
||||
Path path = toFilePath(name);
|
||||
if (path != null) {
|
||||
return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
|
@ -82,8 +82,8 @@ public class Modules {
|
||||
String name,
|
||||
Set<String> packages)
|
||||
{
|
||||
ModuleDescriptor descriptor = ModuleDescriptor.module(name)
|
||||
.contains(packages)
|
||||
ModuleDescriptor descriptor = ModuleDescriptor.newModule(name)
|
||||
.packages(packages)
|
||||
.build();
|
||||
|
||||
return JLRMA.defineModule(loader, descriptor, null);
|
||||
@ -185,7 +185,8 @@ public class Modules {
|
||||
/**
|
||||
* Adds a package to a module's content.
|
||||
*
|
||||
* This method is a no-op if the module already contains the package.
|
||||
* This method is a no-op if the module already contains the package or the
|
||||
* module is an unnamed module.
|
||||
*/
|
||||
public static void addPackage(Module m, String pn) {
|
||||
JLRMA.addPackage(m, pn);
|
||||
|
@ -80,8 +80,6 @@ public class SystemModuleFinder implements ModuleFinder {
|
||||
= PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages");
|
||||
private static final PerfCounter exportsCount
|
||||
= PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
|
||||
// ImageReader used to access all modules in the image
|
||||
private static final ImageReader imageReader;
|
||||
|
||||
// singleton finder to find modules in the run-time images
|
||||
private static final SystemModuleFinder INSTANCE;
|
||||
@ -96,13 +94,28 @@ public class SystemModuleFinder implements ModuleFinder {
|
||||
*/
|
||||
static {
|
||||
long t0 = System.nanoTime();
|
||||
imageReader = ImageReaderFactory.getImageReader();
|
||||
|
||||
INSTANCE = new SystemModuleFinder();
|
||||
|
||||
initTime.addElapsedTimeFrom(t0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holder class for the ImageReader
|
||||
*/
|
||||
private static class SystemImage {
|
||||
static final ImageReader READER;
|
||||
static {
|
||||
long t0 = System.nanoTime();
|
||||
READER = ImageReaderFactory.getImageReader();
|
||||
initTime.addElapsedTimeFrom(t0);
|
||||
}
|
||||
|
||||
static ImageReader reader() {
|
||||
return READER;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isFastPathSupported() {
|
||||
return SystemModules.MODULE_NAMES.length > 0;
|
||||
}
|
||||
@ -114,7 +127,7 @@ public class SystemModuleFinder implements ModuleFinder {
|
||||
|
||||
// this happens when java.base is patched with java.base
|
||||
// from an exploded image
|
||||
return imageReader.getModuleNames();
|
||||
return SystemImage.reader().getModuleNames();
|
||||
}
|
||||
|
||||
// the set of modules in the run-time image
|
||||
@ -151,6 +164,7 @@ public class SystemModuleFinder implements ModuleFinder {
|
||||
descriptors = new ModuleDescriptor[n];
|
||||
recordedHashes = new ModuleHashes[n];
|
||||
moduleResolutions = new ModuleResolution[n];
|
||||
ImageReader imageReader = SystemImage.reader();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
String mn = names[i];
|
||||
ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
|
||||
@ -291,6 +305,7 @@ public class SystemModuleFinder implements ModuleFinder {
|
||||
Objects.requireNonNull(name);
|
||||
if (closed)
|
||||
throw new IOException("ModuleReader is closed");
|
||||
ImageReader imageReader = SystemImage.reader();
|
||||
if (imageReader != null) {
|
||||
return imageReader.findLocation(module, name);
|
||||
} else {
|
||||
@ -330,7 +345,7 @@ public class SystemModuleFinder implements ModuleFinder {
|
||||
public Optional<ByteBuffer> read(String name) throws IOException {
|
||||
ImageLocation location = findImageLocation(name);
|
||||
if (location != null) {
|
||||
return Optional.of(imageReader.getResourceBuffer(location));
|
||||
return Optional.of(SystemImage.reader().getResourceBuffer(location));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
@ -372,7 +387,7 @@ public class SystemModuleFinder implements ModuleFinder {
|
||||
stack = new ArrayDeque<>();
|
||||
|
||||
// push the root node to the stack to get started
|
||||
ImageReader.Node dir = imageReader.findNode(moduleRoot);
|
||||
ImageReader.Node dir = SystemImage.reader().findNode(moduleRoot);
|
||||
if (dir == null || !dir.isDirectory())
|
||||
throw new IOException(moduleRoot + " not a directory");
|
||||
stack.push(dir);
|
||||
@ -390,7 +405,7 @@ public class SystemModuleFinder implements ModuleFinder {
|
||||
String name = node.getName();
|
||||
if (node.isDirectory()) {
|
||||
// build node
|
||||
ImageReader.Node dir = imageReader.findNode(name);
|
||||
ImageReader.Node dir = SystemImage.reader().findNode(name);
|
||||
assert dir.isDirectory();
|
||||
stack.push(dir);
|
||||
} else {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 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
|
||||
@ -211,15 +211,7 @@ public class Reflection {
|
||||
if (currentModule == memberModule)
|
||||
return true; // same module (named or unnamed)
|
||||
|
||||
// memberClass may be primitive or array class
|
||||
Class<?> c = memberClass;
|
||||
while (c.isArray()) {
|
||||
c = c.getComponentType();
|
||||
}
|
||||
if (c.isPrimitive())
|
||||
return true;
|
||||
|
||||
String pkg = c.getPackageName();
|
||||
String pkg = memberClass.getPackageName();
|
||||
boolean allowed = memberModule.isExported(pkg, currentModule);
|
||||
if (allowed && memberModule.isNamed() && printStackTraceWhenAccessSucceeds()) {
|
||||
if (!SharedSecrets.getJavaLangReflectModuleAccess()
|
||||
@ -237,10 +229,6 @@ public class Reflection {
|
||||
private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) {
|
||||
if (c1.getClassLoader() != c2.getClassLoader())
|
||||
return false;
|
||||
while (c1.isArray())
|
||||
c1 = c1.getComponentType();
|
||||
while (c2.isArray())
|
||||
c2 = c2.getComponentType();
|
||||
return Objects.equals(c1.getPackageName(), c2.getPackageName());
|
||||
}
|
||||
|
||||
@ -378,12 +366,6 @@ public class Reflection {
|
||||
}
|
||||
}
|
||||
|
||||
public static void enableStackTraces() {
|
||||
printStackWhenAccessFails = true;
|
||||
printStackWhenAccessSucceeds = true;
|
||||
printStackPropertiesSet = true;
|
||||
}
|
||||
|
||||
public static boolean printStackTraceWhenAccessFails() {
|
||||
ensurePrintStackPropertiesSet();
|
||||
return printStackWhenAccessFails;
|
||||
@ -413,11 +395,7 @@ public class Reflection {
|
||||
if (m2.isNamed())
|
||||
memberSuffix = " (in " + m2 + ")";
|
||||
|
||||
Class<?> c = memberClass;
|
||||
while (c.isArray()) {
|
||||
c = c.getComponentType();
|
||||
}
|
||||
String memberPackageName = c.getPackageName();
|
||||
String memberPackageName = memberClass.getPackageName();
|
||||
|
||||
String msg = currentClass + currentSuffix + " cannot access ";
|
||||
if (m2.isExported(memberPackageName, m1)) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 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
|
||||
@ -39,6 +39,7 @@ public class VerifyAccess {
|
||||
|
||||
private VerifyAccess() { } // cannot instantiate
|
||||
|
||||
private static final int UNCONDITIONAL_ALLOWED = java.lang.invoke.MethodHandles.Lookup.UNCONDITIONAL;
|
||||
private static final int MODULE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.MODULE;
|
||||
private static final int PACKAGE_ONLY = 0;
|
||||
private static final int PACKAGE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.PACKAGE;
|
||||
@ -92,7 +93,7 @@ public class VerifyAccess {
|
||||
int allowedModes) {
|
||||
if (allowedModes == 0) return false;
|
||||
assert((allowedModes & PUBLIC) != 0 &&
|
||||
(allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED)) == 0);
|
||||
(allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0);
|
||||
// The symbolic reference class (refc) must always be fully verified.
|
||||
if (!isClassAccessible(refc, lookupClass, allowedModes)) {
|
||||
return false;
|
||||
@ -173,7 +174,7 @@ public class VerifyAccess {
|
||||
int allowedModes) {
|
||||
if (allowedModes == 0) return false;
|
||||
assert((allowedModes & PUBLIC) != 0 &&
|
||||
(allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED)) == 0);
|
||||
(allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0);
|
||||
int mods = getClassModifiers(refc);
|
||||
if (isPublic(mods)) {
|
||||
|
||||
@ -191,22 +192,17 @@ public class VerifyAccess {
|
||||
(lookupModule == refModule))
|
||||
return true;
|
||||
|
||||
// check readability
|
||||
if (lookupModule.canRead(refModule)) {
|
||||
// check readability when UNCONDITIONAL not allowed
|
||||
if (((allowedModes & UNCONDITIONAL_ALLOWED) != 0)
|
||||
|| lookupModule.canRead(refModule)) {
|
||||
|
||||
// check that refc is in an exported package
|
||||
Class<?> c = refc;
|
||||
while (c.isArray()) {
|
||||
c = c.getComponentType();
|
||||
}
|
||||
if (c.isPrimitive())
|
||||
return true;
|
||||
if ((allowedModes & MODULE_ALLOWED) != 0) {
|
||||
if (refModule.isExported(c.getPackageName(), lookupModule))
|
||||
if (refModule.isExported(refc.getPackageName(), lookupModule))
|
||||
return true;
|
||||
} else {
|
||||
// exported unconditionally
|
||||
if (refModule.isExported(c.getPackageName()))
|
||||
if (refModule.isExported(refc.getPackageName()))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -966,6 +966,10 @@ public final class LauncherHelper {
|
||||
ostream.print("open ");
|
||||
if (md.isAutomatic())
|
||||
ostream.print("automatic ");
|
||||
if (md.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC))
|
||||
ostream.print("synthetic ");
|
||||
if (md.modifiers().contains(ModuleDescriptor.Modifier.MANDATED))
|
||||
ostream.print("mandated ");
|
||||
ostream.println("module " + midAndLocation(md, mref.location()));
|
||||
|
||||
// unqualified exports (sorted by package)
|
||||
|
@ -32,7 +32,9 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.Permission;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import jdk.internal.jimage.ImageLocation;
|
||||
import jdk.internal.jimage.ImageReader;
|
||||
@ -51,7 +53,11 @@ import sun.security.action.GetPropertyAction;
|
||||
public class JavaRuntimeURLConnection extends URLConnection {
|
||||
|
||||
// ImageReader to access resources in jimage
|
||||
private static final ImageReader reader = ImageReaderFactory.getImageReader();
|
||||
private static final ImageReader reader;
|
||||
static {
|
||||
PrivilegedAction<ImageReader> pa = ImageReaderFactory::getImageReader;
|
||||
reader = AccessController.doPrivileged(pa);
|
||||
}
|
||||
|
||||
// the module and resource name in the URL
|
||||
private final String module;
|
||||
|
@ -229,6 +229,7 @@ public interface ClassFileTransformer {
|
||||
* or {@code null} if no transform is performed
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
default byte[]
|
||||
transform( Module module,
|
||||
|
@ -714,6 +714,7 @@ public interface Instrumentation {
|
||||
* @throws NullPointerException if any of the arguments are {@code null} or
|
||||
* any of the Sets or Maps contains a {@code null} key or value
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
void redefineModule(Module module,
|
||||
Set<Module> extraReads,
|
||||
|
@ -38,6 +38,7 @@ import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.io.Serializable;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
@ -107,6 +108,8 @@ import sun.rmi.server.UnicastRef2;
|
||||
import sun.rmi.transport.LiveRef;
|
||||
import java.io.NotSerializableException;
|
||||
|
||||
import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC;
|
||||
|
||||
/**
|
||||
* <p>A connection to a remote RMI connector. Usually, such
|
||||
* connections are made using {@link
|
||||
@ -2020,8 +2023,14 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
Module rmiModule = RemoteRef.class.getModule();
|
||||
|
||||
String pkg = packageOf(pRefClassName);
|
||||
assert pkg != null && pkg.length() > 0 && !pkg.equals(packageOf(proxyRefCName));
|
||||
Module m = Modules.defineModule(cl, "jdk.remoteref", Collections.singleton(pkg));
|
||||
assert pkg != null && pkg.length() > 0 &&
|
||||
!pkg.equals(packageOf(proxyRefCName));
|
||||
|
||||
ModuleDescriptor descriptor =
|
||||
ModuleDescriptor.newModule("jdk.remoteref", Set.of(SYNTHETIC))
|
||||
.packages(Set.of(pkg))
|
||||
.build();
|
||||
Module m = Modules.defineModule(cl, descriptor, null);
|
||||
|
||||
// jdk.remoteref needs to read to java.base and jmxModule
|
||||
Modules.addReads(m, Object.class.getModule());
|
||||
|
@ -157,8 +157,7 @@ class GNUStyleOptions {
|
||||
for (String dir : dirs) {
|
||||
paths[i++] = Paths.get(dir);
|
||||
}
|
||||
jartool.moduleFinder =
|
||||
new ModulePath(Runtime.version(), true, paths);
|
||||
jartool.moduleFinder = ModulePath.of(Runtime.version(), true, paths);
|
||||
}
|
||||
},
|
||||
new Option(false, OptionType.CREATE_UPDATE, "--do-not-resolve-by-default") {
|
||||
|
@ -699,7 +699,7 @@ public class Main {
|
||||
}
|
||||
String pn = toPackageName(name);
|
||||
// add if this is a class or resource in a package
|
||||
if (Checks.isJavaIdentifier(pn)) {
|
||||
if (Checks.isPackageName(pn)) {
|
||||
packages.add(pn);
|
||||
}
|
||||
}
|
||||
@ -1995,7 +1995,7 @@ public class Main {
|
||||
}
|
||||
// get a resolved module graph
|
||||
Configuration config =
|
||||
Configuration.empty().resolveRequires(system, finder, roots);
|
||||
Configuration.empty().resolve(system, finder, roots);
|
||||
|
||||
// filter modules resolved from the system module finder
|
||||
this.modules = config.modules().stream()
|
||||
|
@ -29,6 +29,7 @@ import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.FindException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReference;
|
||||
@ -232,7 +233,7 @@ public class JlinkTask {
|
||||
|
||||
return EXIT_OK;
|
||||
} catch (PluginException | IllegalArgumentException |
|
||||
UncheckedIOException |IOException | ResolutionException e) {
|
||||
UncheckedIOException |IOException | FindException | ResolutionException e) {
|
||||
log.println(taskHelper.getMessage("error.prefix") + " " + e.getMessage());
|
||||
if (DEBUG) {
|
||||
e.printStackTrace(log);
|
||||
@ -370,7 +371,7 @@ public class JlinkTask {
|
||||
*/
|
||||
private ModuleFinder modulePathFinder() {
|
||||
Path[] entries = options.modulePath.toArray(new Path[0]);
|
||||
ModuleFinder finder = new ModulePath(Runtime.version(), true, entries);
|
||||
ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
|
||||
if (!options.limitMods.isEmpty()) {
|
||||
finder = limitFinder(finder, options.limitMods, Collections.emptySet());
|
||||
}
|
||||
@ -388,7 +389,7 @@ public class JlinkTask {
|
||||
Set<String> roots)
|
||||
{
|
||||
Path[] entries = paths.toArray(new Path[0]);
|
||||
ModuleFinder finder = new ModulePath(Runtime.version(), true, entries);
|
||||
ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
|
||||
|
||||
// if limitmods is specified then limit the universe
|
||||
if (!limitMods.isEmpty()) {
|
||||
@ -418,9 +419,9 @@ public class JlinkTask {
|
||||
}
|
||||
|
||||
Configuration cf = Configuration.empty()
|
||||
.resolveRequires(finder,
|
||||
ModuleFinder.of(),
|
||||
roots);
|
||||
.resolve(finder,
|
||||
ModuleFinder.of(),
|
||||
roots);
|
||||
|
||||
// emit warning for modules that end with a digit
|
||||
cf.modules().stream()
|
||||
@ -458,9 +459,9 @@ public class JlinkTask {
|
||||
|
||||
// resolve all root modules
|
||||
Configuration cf = Configuration.empty()
|
||||
.resolveRequires(finder,
|
||||
ModuleFinder.of(),
|
||||
roots);
|
||||
.resolve(finder,
|
||||
ModuleFinder.of(),
|
||||
roots);
|
||||
|
||||
// module name -> reference
|
||||
Map<String, ModuleReference> map = new HashMap<>();
|
||||
|
@ -51,7 +51,7 @@ final class ResourcePoolConfiguration {
|
||||
ModuleDescriptor md = mod.descriptor();
|
||||
|
||||
// drop hashes
|
||||
ModuleDescriptor.Builder builder = ModuleDescriptor.module(md.name());
|
||||
ModuleDescriptor.Builder builder = ModuleDescriptor.newModule(md.name());
|
||||
md.requires().stream()
|
||||
.forEach(builder::requires);
|
||||
md.exports().stream()
|
||||
@ -62,12 +62,7 @@ final class ResourcePoolConfiguration {
|
||||
.forEach(builder::uses);
|
||||
md.provides().stream()
|
||||
.forEach(builder::provides);
|
||||
|
||||
// build the proper concealed packages
|
||||
Set<String> concealed = new HashSet<>(mod.packages());
|
||||
md.exports().stream().map(ModuleDescriptor.Exports::source).forEach(concealed::remove);
|
||||
md.opens().stream().map(ModuleDescriptor.Opens::source).forEach(concealed::remove);
|
||||
concealed.stream().forEach(builder::contains);
|
||||
builder.packages(md.packages());
|
||||
|
||||
md.version().ifPresent(builder::version);
|
||||
md.mainClass().ifPresent(builder::mainClass);
|
||||
@ -124,7 +119,7 @@ final class ResourcePoolConfiguration {
|
||||
}
|
||||
};
|
||||
|
||||
return Configuration.empty().resolveRequires(
|
||||
return Configuration.empty().resolve(
|
||||
finder, ModuleFinder.of(), nameToModRef.keySet());
|
||||
}
|
||||
}
|
||||
|
@ -718,13 +718,13 @@ public final class TaskHelper {
|
||||
static Layer createPluginsLayer(List<Path> paths) {
|
||||
|
||||
Path[] dirs = paths.toArray(new Path[0]);
|
||||
ModuleFinder finder = new ModulePath(Runtime.version(), true, dirs);
|
||||
ModuleFinder finder = ModulePath.of(Runtime.version(), true, dirs);
|
||||
Configuration bootConfiguration = Layer.boot().configuration();
|
||||
try {
|
||||
Configuration cf = bootConfiguration
|
||||
.resolveRequiresAndUses(ModuleFinder.of(),
|
||||
finder,
|
||||
Collections.emptySet());
|
||||
.resolveAndBind(ModuleFinder.of(),
|
||||
finder,
|
||||
Collections.emptySet());
|
||||
ClassLoader scl = ClassLoader.getSystemClassLoader();
|
||||
return Layer.boot().defineModulesWithOneLoader(cf, scl);
|
||||
} catch (Exception ex) {
|
||||
|
@ -771,9 +771,12 @@ public final class SystemModulesPlugin implements Plugin {
|
||||
if (md.isOpen()) {
|
||||
setModuleBit("open", true);
|
||||
}
|
||||
if (md.isSynthetic()) {
|
||||
if (md.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC)) {
|
||||
setModuleBit("synthetic", true);
|
||||
}
|
||||
if (md.modifiers().contains(ModuleDescriptor.Modifier.MANDATED)) {
|
||||
setModuleBit("mandated", true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -34,6 +34,7 @@ import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.FindException;
|
||||
import java.lang.module.ModuleReader;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.lang.module.ModuleFinder;
|
||||
@ -851,8 +852,8 @@ public class JmodTask {
|
||||
// get a resolved module graph
|
||||
Configuration config = null;
|
||||
try {
|
||||
config = Configuration.empty().resolveRequires(system, finder, roots);
|
||||
} catch (ResolutionException e) {
|
||||
config = Configuration.empty().resolve(system, finder, roots);
|
||||
} catch (FindException | ResolutionException e) {
|
||||
throw new CommandException("err.module.resolution.fail", e.getMessage());
|
||||
}
|
||||
|
||||
@ -1392,7 +1393,7 @@ public class JmodTask {
|
||||
options.legalNotices = getLastElement(opts.valuesOf(legalNotices));
|
||||
if (opts.has(modulePath)) {
|
||||
Path[] dirs = getLastElement(opts.valuesOf(modulePath)).toArray(new Path[0]);
|
||||
options.moduleFinder = new ModulePath(Runtime.version(), true, dirs);
|
||||
options.moduleFinder = ModulePath.of(Runtime.version(), true, dirs);
|
||||
}
|
||||
if (opts.has(moduleVersion))
|
||||
options.moduleVersion = getLastElement(opts.valuesOf(moduleVersion));
|
||||
|
@ -296,6 +296,8 @@ java/util/BitSet/BitSetStreamTest.java 8079538 generic-
|
||||
|
||||
sun/tools/jcmd/TestJcmdSanity.java 8031482 windows-all
|
||||
|
||||
sun/tools/jstat/jstatClassloadOutput1.sh 8173942 generic-all
|
||||
|
||||
sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java 8057732 generic-all
|
||||
|
||||
demo/jvmti/compiledMethodLoad/CompiledMethodLoadTest.java 8151899 generic-all
|
||||
|
@ -57,7 +57,7 @@ public class ReadFileOnPath {
|
||||
"module-info.class", "base", "p/App.class", "p/child");
|
||||
|
||||
// exploded module
|
||||
test("--module-path", "modules", "-m", "m/p.App", "SS+++++");
|
||||
test("--module-path", "modules", "-m", "m/p.App", "SS++++0");
|
||||
|
||||
// module in jar
|
||||
test("--module-path", "new.jar", "-m", "m/p.App", "SSSS++0");
|
||||
|
@ -46,9 +46,9 @@ public class TestLayer {
|
||||
ModuleFinder finder = ModuleFinder.of(MODS_DIR);
|
||||
|
||||
Configuration parent = Layer.boot().configuration();
|
||||
Configuration cf = parent.resolveRequiresAndUses(ModuleFinder.of(),
|
||||
finder,
|
||||
modules);
|
||||
Configuration cf = parent.resolveAndBind(ModuleFinder.of(),
|
||||
finder,
|
||||
modules);
|
||||
|
||||
ClassLoader scl = ClassLoader.getSystemClassLoader();
|
||||
Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl);
|
||||
|
@ -50,9 +50,9 @@ public class NoAccess {
|
||||
Layer bootLayer = Layer.boot();
|
||||
Configuration parent = bootLayer.configuration();
|
||||
|
||||
Configuration cf = parent.resolveRequiresAndUses(finder,
|
||||
ModuleFinder.of(),
|
||||
Set.of("m1", "m2"));
|
||||
Configuration cf = parent.resolveAndBind(finder,
|
||||
ModuleFinder.of(),
|
||||
Set.of("m1", "m2"));
|
||||
|
||||
ClassLoader scl = ClassLoader.getSystemClassLoader();
|
||||
Layer layer = bootLayer.defineModulesWithManyLoaders(cf, scl);
|
||||
|
@ -154,8 +154,8 @@ public class Basic {
|
||||
return new Object[][] {
|
||||
|
||||
{ Basic.class, TEST_PACKAGE },
|
||||
{ Basic[].class, null },
|
||||
{ Basic[][].class, null },
|
||||
{ Basic[].class, TEST_PACKAGE },
|
||||
{ Basic[][].class, TEST_PACKAGE },
|
||||
|
||||
{ getNestedClass1(), TEST_PACKAGE },
|
||||
{ getNestedClass2(), TEST_PACKAGE },
|
||||
@ -174,14 +174,14 @@ public class Basic {
|
||||
{ getAnonymousClass6(), TEST_PACKAGE },
|
||||
|
||||
{ Object.class, "java.lang" },
|
||||
{ Object[].class, null },
|
||||
{ Object[][].class, null },
|
||||
{ Object[].class, "java.lang" },
|
||||
{ Object[][].class, "java.lang" },
|
||||
|
||||
{ int.class, null },
|
||||
{ int[].class, null },
|
||||
{ int[][].class, null },
|
||||
{ int.class, "java.lang" },
|
||||
{ int[].class, "java.lang" },
|
||||
{ int[][].class, "java.lang" },
|
||||
|
||||
{ void.class, null },
|
||||
{ void.class, "java.lang" },
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public class CallerFromMain {
|
||||
try {
|
||||
Class<?> c = sw.getCallerClass();
|
||||
throw new RuntimeException("UOE not thrown. Caller: " + c);
|
||||
} catch (IllegalStateException e) {}
|
||||
} catch (IllegalCallerException e) {}
|
||||
|
||||
// StackWalker::getCallerClass
|
||||
// Runnable::run
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 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
|
||||
@ -118,6 +118,8 @@ public class AccessControlTest {
|
||||
suffix = "/noaccess";
|
||||
else if (lookupModes == PUBLIC)
|
||||
suffix = "/public";
|
||||
else if (lookupModes == (PUBLIC|UNCONDITIONAL))
|
||||
suffix = "/publicLookup";
|
||||
else if (lookupModes == (PUBLIC|MODULE))
|
||||
suffix = "/module";
|
||||
else if (lookupModes == (PUBLIC|MODULE|PACKAGE))
|
||||
@ -140,23 +142,24 @@ public class AccessControlTest {
|
||||
* [A2] However, the resulting {@code Lookup} object is guaranteed
|
||||
* to have no more access capabilities than the original.
|
||||
* In particular, access capabilities can be lost as follows:<ul>
|
||||
* <li>[A3] If the new lookup class differs from the old one,
|
||||
* protected members will not be accessible by virtue of inheritance.
|
||||
* <li> [A3] If the old lookup class is in a named module, and the new
|
||||
* lookup class is in a different module {@code M}, then no members, not
|
||||
* even public members in {@code M}'s exported packages, will be accessible.
|
||||
* The exception to this is when this lookup is publicLookup, in which case
|
||||
* public access is not lost.
|
||||
* <li> [A4] If the old lookup class is in an unnamed module, and the new
|
||||
* lookup class is a different module then module access is lost.
|
||||
* <li> [A5] If the new lookup class differs from the old one then UNCONDITIONAL
|
||||
* is lost. If the new lookup class is not within the same package member as the
|
||||
* old one, protected members will not be accessible by virtue of inheritance.
|
||||
* (Protected members may continue to be accessible because of package sharing.)
|
||||
* <li>[A4] If the new lookup class is in a different package
|
||||
* than the old one, protected and default (package) members will not be accessible.
|
||||
* <li>[A5] If the new lookup class is not within the same package member
|
||||
* <li> [A6] If the new lookup class is in a different package than the old one,
|
||||
* protected and default (package) members will not be accessible.
|
||||
* <li> [A7] If the new lookup class is not within the same package member
|
||||
* as the old one, private members will not be accessible.
|
||||
* <li>[A6] If the new lookup class is not accessible to the old lookup class,
|
||||
* using the original access modes,
|
||||
* <li> [A8] If the new lookup class is not accessible to the old lookup class,
|
||||
* then no members, not even public members, will be accessible.
|
||||
* <li>[A7] If the new lookup class for this {@code Lookup} is in the unnamed module,
|
||||
* and the new lookup class is in a named module {@code M}, then no members in
|
||||
* {@code M}'s non-exported packages will be accessible.
|
||||
* <li>[A8] If the lookup for this {@code Lookup} is in a named module, and the
|
||||
* new lookup class is in a different module, then no members, not even
|
||||
* public members in {@code M}'s exported packages, will be accessible.
|
||||
* [A8] (In all other cases, public members will continue to be accessible.)
|
||||
* <li> [A9] (In all other cases, public members will continue to be accessible.)
|
||||
* </ul>
|
||||
* Other than the above cases, the new lookup will have the same
|
||||
* access capabilities as the original. [A10]
|
||||
@ -171,36 +174,35 @@ public class AccessControlTest {
|
||||
boolean sameModule = (c1.getModule() == c2.getModule()) ||
|
||||
(!c1.getModule().isNamed() && !c2.getModule().isNamed());
|
||||
boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() &&
|
||||
packagePrefix(c1).equals(packagePrefix(c2)));
|
||||
c1.getPackageName().equals(c2.getPackageName()));
|
||||
boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2));
|
||||
boolean sameClass = (c1 == c2);
|
||||
assert(samePackage || !sameTopLevel);
|
||||
assert(sameTopLevel || !sameClass);
|
||||
boolean accessible = sameClass; // [A6]
|
||||
boolean accessible = sameClass;
|
||||
if ((m1 & PACKAGE) != 0) accessible |= samePackage;
|
||||
if ((m1 & PUBLIC ) != 0) accessible |= (c2.getModifiers() & PUBLIC) != 0;
|
||||
if (!sameModule) {
|
||||
if (c1.getModule().isNamed()) {
|
||||
accessible = false; // [A8]
|
||||
if (c1.getModule().isNamed() && (m1 & UNCONDITIONAL) == 0) {
|
||||
accessible = false; // [A3]
|
||||
} else {
|
||||
// Different module; loose MODULE and lower access.
|
||||
changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED); // [A7]
|
||||
changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED); // [A3] [A4]
|
||||
}
|
||||
}
|
||||
if (!accessible) {
|
||||
// Different package and no access to c2; lose all access.
|
||||
changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED); // [A6]
|
||||
changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED); // [A8]
|
||||
}
|
||||
if (!samePackage) {
|
||||
// Different package; loose PACKAGE and lower access.
|
||||
changed |= (PACKAGE|PRIVATE|PROTECTED); // [A4]
|
||||
changed |= (PACKAGE|PRIVATE|PROTECTED); // [A6]
|
||||
}
|
||||
if (!sameTopLevel) {
|
||||
// Different top-level class. Lose PRIVATE and lower access.
|
||||
changed |= (PRIVATE|PROTECTED); // [A5]
|
||||
// Different top-level class. Lose PRIVATE and PROTECTED access.
|
||||
changed |= (PRIVATE|PROTECTED); // [A5] [A7]
|
||||
}
|
||||
if (!sameClass) {
|
||||
changed |= (PROTECTED); // [A3]
|
||||
changed |= (UNCONDITIONAL); // [A5]
|
||||
} else {
|
||||
assert(changed == 0); // [A10] (no deprivation if same class)
|
||||
}
|
||||
@ -228,11 +230,10 @@ public class AccessControlTest {
|
||||
Class<?> c1 = lookupClass();
|
||||
Class<?> c2 = m.getDeclaringClass();
|
||||
|
||||
// if the lookup class is in a loose module with PUBLIC access then
|
||||
// public members of public types in all unnamed modules can be accessed
|
||||
if (isLooseModule(c1.getModule())
|
||||
// publicLookup has access to all public types/members of types in unnamed modules
|
||||
if ((lookupModes & UNCONDITIONAL) != 0
|
||||
&& (lookupModes & PUBLIC) != 0
|
||||
&& (!c2.getModule().isNamed())
|
||||
&& !c2.getModule().isNamed()
|
||||
&& Modifier.isPublic(c2.getModifiers())
|
||||
&& Modifier.isPublic(m.getModifiers()))
|
||||
return true;
|
||||
@ -261,17 +262,12 @@ public class AccessControlTest {
|
||||
if (load && c2.getClassLoader() != null) {
|
||||
if (c1.getClassLoader() == null) {
|
||||
// not visible
|
||||
return false;
|
||||
}
|
||||
if (c1 == publicLookup().lookupClass()) {
|
||||
// not visible as lookup class is defined by child of the boot loader
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// if the lookup class is in a loose module with PUBLIC access then
|
||||
// public types in all unnamed modules can be accessed
|
||||
if (isLooseModule(c1.getModule())
|
||||
// publicLookup has access to all public types/members of types in unnamed modules
|
||||
if ((lookupModes & UNCONDITIONAL) != 0
|
||||
&& (lookupModes & PUBLIC) != 0
|
||||
&& (!c2.getModule().isNamed())
|
||||
&& Modifier.isPublic(c2.getModifiers()))
|
||||
@ -295,11 +291,6 @@ public class AccessControlTest {
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
private boolean isLooseModule(Module m) {
|
||||
ClassLoader cl = new ClassLoader() { };
|
||||
return m.canRead(cl.getUnnamedModule());
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> topLevelClass(Class<?> cls) {
|
||||
@ -311,14 +302,6 @@ public class AccessControlTest {
|
||||
return c;
|
||||
}
|
||||
|
||||
private static String packagePrefix(Class<?> c) {
|
||||
while (c.isArray()) c = c.getComponentType();
|
||||
String s = c.getName();
|
||||
assert(s.indexOf('/') < 0);
|
||||
return s.substring(0, s.lastIndexOf('.')+1);
|
||||
}
|
||||
|
||||
|
||||
private final TreeSet<LookupCase> CASES = new TreeSet<>();
|
||||
private final TreeMap<LookupCase,TreeSet<LookupCase>> CASE_EDGES = new TreeMap<>();
|
||||
private final ArrayList<ClassLoader> LOADERS = new ArrayList<>();
|
||||
|
@ -65,6 +65,10 @@ public class DropLookupModeTest {
|
||||
lookup = fullPowerLookup.dropLookupMode(PUBLIC);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == 0);
|
||||
|
||||
lookup = fullPowerLookup.dropLookupMode(UNCONDITIONAL);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,7 +112,7 @@ public class DropLookupModeTest {
|
||||
public void testPublicLookup() {
|
||||
final Lookup publicLookup = MethodHandles.publicLookup();
|
||||
final Class<?> lc = publicLookup.lookupClass();
|
||||
assertTrue(publicLookup.lookupModes() == PUBLIC);
|
||||
assertTrue(publicLookup.lookupModes() == (PUBLIC|UNCONDITIONAL));
|
||||
|
||||
Lookup lookup = publicLookup.dropLookupMode(PRIVATE);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
@ -129,6 +133,10 @@ public class DropLookupModeTest {
|
||||
lookup = publicLookup.dropLookupMode(PUBLIC);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == 0);
|
||||
|
||||
lookup = publicLookup.dropLookupMode(UNCONDITIONAL);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC);
|
||||
}
|
||||
|
||||
@DataProvider(name = "badInput")
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @build test/* m1/* m2/* m3/*
|
||||
* @build test/* m1/* m2/* m3/* Unnamed
|
||||
* @run testng/othervm test/p.PrivateLookupInTests
|
||||
* @summary Unit tests for MethodHandles.privateLookupIn
|
||||
*/
|
||||
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
public class Unnamed { }
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 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
|
||||
@ -126,6 +126,26 @@ public class PrivateLookupInTests {
|
||||
Object obj = mh.invokeExact();
|
||||
}
|
||||
|
||||
// test target class in unnamed module
|
||||
public void testTargetClassInUnnamedModule() throws Throwable {
|
||||
Class<?> clazz = Class.forName("Unnamed");
|
||||
assertFalse(clazz.getModule().isNamed());
|
||||
|
||||
// thisModule does not read the unnamed module
|
||||
Module thisModule = getClass().getModule();
|
||||
assertFalse(thisModule.canRead(clazz.getModule()));
|
||||
try {
|
||||
MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
|
||||
assertTrue(false);
|
||||
} catch (IllegalAccessException expected) { }
|
||||
|
||||
// thisModule reads the unnamed module
|
||||
thisModule.addReads(clazz.getModule());
|
||||
Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
|
||||
assertTrue(lookup.lookupClass() == clazz);
|
||||
assertTrue(lookup.hasPrivateAccess());
|
||||
}
|
||||
|
||||
// test does not read m2, m2 opens p2 to test
|
||||
@Test(expectedExceptions = {IllegalAccessException.class})
|
||||
public void testCallerDoesNotRead() throws Throwable {
|
||||
|
29
jdk/test/java/lang/invoke/modules/Driver.java
Normal file
29
jdk/test/java/lang/invoke/modules/Driver.java
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @build m1/* m2/* Unnamed
|
||||
* @run testng/othervm m1/p1.Main
|
||||
* @summary Basic test case for module access checks and Lookup.in.
|
||||
*/
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static jdk.testlibrary.ProcessTools.executeTestJava;
|
||||
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @library /lib/testlibrary
|
||||
* @modules jdk.compiler
|
||||
* @build CompilerUtils jdk.testlibrary.*
|
||||
* @run testng ModuleAccessControlTest
|
||||
* @summary Driver for testing module access checking by MethodHandles.Lookup
|
||||
*/
|
||||
|
||||
public class ModuleAccessControlTest {
|
||||
|
||||
private static final String TEST_SRC = System.getProperty("test.src");
|
||||
|
||||
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
|
||||
private static final Path MODS_DIR = Paths.get("mods");
|
||||
|
||||
// the names of the modules in this test
|
||||
private static List<String> modules = Arrays.asList("m1", "m2");
|
||||
|
||||
|
||||
/**
|
||||
* Compiles all modules used by the test
|
||||
*/
|
||||
@BeforeTest
|
||||
public void compileAll() throws Exception {
|
||||
for (String mn : modules) {
|
||||
Path msrc = SRC_DIR.resolve(mn);
|
||||
assertTrue(CompilerUtils
|
||||
.compile(msrc, MODS_DIR, "--module-source-path", SRC_DIR.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the test
|
||||
*/
|
||||
@Test
|
||||
public void runTest() throws Exception {
|
||||
int exitValue = executeTestJava("--module-path", MODS_DIR.toString(),
|
||||
"-m", "m1/p1.Main")
|
||||
.outputTo(System.out)
|
||||
.errorTo(System.out)
|
||||
.getExitValue();
|
||||
|
||||
assertTrue(exitValue == 0);
|
||||
}
|
||||
|
||||
}
|
24
jdk/test/java/lang/invoke/modules/Unnamed.java
Normal file
24
jdk/test/java/lang/invoke/modules/Unnamed.java
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
public class Unnamed { }
|
@ -22,5 +22,6 @@
|
||||
*/
|
||||
module m1 {
|
||||
requires m2;
|
||||
requires testng;
|
||||
exports p1;
|
||||
}
|
367
jdk/test/java/lang/invoke/modules/m1/p1/Main.java
Normal file
367
jdk/test/java/lang/invoke/modules/m1/p1/Main.java
Normal file
@ -0,0 +1,367 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package p1;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Layer;
|
||||
import java.lang.reflect.Module;
|
||||
|
||||
import static java.lang.invoke.MethodHandles.Lookup.*;
|
||||
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/**
|
||||
* Basic test case for module access checks and Lookup.in.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public class Main {
|
||||
|
||||
private Class<?> p1_Type1; // m1, exported
|
||||
private Class<?> p2_Type2; // m1, not exported
|
||||
private Class<?> q1_Type1; // m2, exported
|
||||
private Class<?> q2_Type2; // m2, not exported
|
||||
private Class<?> x500NameClass; // java.base, not exported
|
||||
private Class<?> unnamedClass; // class in unnamed module
|
||||
|
||||
@BeforeTest
|
||||
public void setup() throws Exception {
|
||||
try {
|
||||
p1_Type1 = Class.forName("p1.Type1");
|
||||
p2_Type2 = Class.forName("p2.Type2");
|
||||
q1_Type1 = Class.forName("q1.Type1");
|
||||
q2_Type2 = Class.forName("q2.Type2");
|
||||
x500NameClass = Class.forName("sun.security.x509.X500Name");
|
||||
unnamedClass = Class.forName("Unnamed");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
// check setup
|
||||
Module m1 = Layer.boot().findModule("m1").orElse(null);
|
||||
assertNotNull(m1);
|
||||
assertTrue(p1_Type1.getModule() == m1);
|
||||
assertTrue(p2_Type2.getModule() == m1);
|
||||
assertTrue(m1.isExported("p1"));
|
||||
assertFalse(m1.isExported("p2"));
|
||||
|
||||
Module m2 = Layer.boot().findModule("m2").orElse(null);
|
||||
assertNotNull(m2);
|
||||
assertTrue(q1_Type1.getModule() == m2);
|
||||
assertTrue(q2_Type2.getModule() == m2);
|
||||
assertTrue(m2.isExported("q1"));
|
||||
assertFalse(m2.isExported("q2"));
|
||||
|
||||
Module unnamedModule = unnamedClass.getModule();
|
||||
assertFalse(unnamedModule.isNamed());
|
||||
|
||||
// m1 needs to read unnamed module
|
||||
Main.class.getModule().addReads(unnamedModule);
|
||||
}
|
||||
|
||||
/**
|
||||
* MethodHandles.lookup()
|
||||
*
|
||||
* [A0] has module access
|
||||
* [A1] can access all public types in m1
|
||||
* [A2] can access public types in packages exported by modules that m1 reads
|
||||
* [A3] cannot access public types in non-exported modules of modules that m1 reads
|
||||
*/
|
||||
public void testLookup() throws Exception {
|
||||
Lookup lookup = MethodHandles.lookup();
|
||||
assertTrue((lookup.lookupModes() & MODULE) == MODULE); // [A0]
|
||||
|
||||
// m1
|
||||
findConstructor(lookup, p1_Type1, void.class); // [A1]
|
||||
findConstructor(lookup, p2_Type2, void.class); // [A1]
|
||||
|
||||
// m2
|
||||
findConstructor(lookup, q1_Type1, void.class); // [A2]
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A3]
|
||||
|
||||
// java.base
|
||||
findConstructor(lookup, Object.class, void.class); // [A2]
|
||||
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // [A3]
|
||||
|
||||
// unnamed
|
||||
findConstructor(lookup, unnamedClass, void.class); // [A3]
|
||||
}
|
||||
|
||||
/**
|
||||
* Hop to lookup class in the same module
|
||||
*
|
||||
* [A0] module and public access is not lost
|
||||
*/
|
||||
public void testToSameModule() throws Exception {
|
||||
Lookup lookup = MethodHandles.lookup().in(p2_Type2);
|
||||
assertTrue(lookup.lookupModes() == (MODULE|PUBLIC)); // [A0]
|
||||
|
||||
// m1
|
||||
findConstructor(lookup, p1_Type1, void.class);
|
||||
findConstructor(lookup, p2_Type2, void.class);
|
||||
|
||||
// m2
|
||||
findConstructor(lookup, q1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class);
|
||||
|
||||
// java.base
|
||||
findConstructor(lookup, Object.class, void.class);
|
||||
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
|
||||
|
||||
// unnamed
|
||||
findConstructor(lookup, unnamedClass, void.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hop to lookup class in another named module
|
||||
*
|
||||
* [A0] has no access
|
||||
*/
|
||||
public void testFromNamedToNamedModule() throws Exception {
|
||||
Lookup lookup = MethodHandles.lookup().in(q1_Type1);
|
||||
assertTrue(lookup.lookupModes() == 0); // [A0]
|
||||
|
||||
// m1
|
||||
findConstructorExpectingIAE(lookup, p1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, p2_Type2, void.class);
|
||||
|
||||
// m2
|
||||
findConstructorExpectingIAE(lookup, q1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class);
|
||||
|
||||
// java.base
|
||||
findConstructorExpectingIAE(lookup, Object.class, void.class);
|
||||
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
|
||||
|
||||
// unnamed
|
||||
findConstructorExpectingIAE(lookup, unnamedClass, void.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hop to lookup class in an unnamed module
|
||||
*
|
||||
* [A0] has no access
|
||||
*/
|
||||
public void testFromNamedToUnnamedModule() throws Exception {
|
||||
Lookup lookup = MethodHandles.lookup().in(unnamedClass);
|
||||
assertTrue(lookup.lookupModes() == 0); // [A0]
|
||||
|
||||
// m1
|
||||
findConstructorExpectingIAE(lookup, p1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, p2_Type2, void.class);
|
||||
|
||||
// m2
|
||||
findConstructorExpectingIAE(lookup, q1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class);
|
||||
|
||||
// java.base
|
||||
findConstructorExpectingIAE(lookup, Object.class, void.class);
|
||||
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
|
||||
|
||||
// unnamed
|
||||
findConstructorExpectingIAE(lookup, unnamedClass, void.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hop from unnamed to named module.
|
||||
*
|
||||
* [A0] retains PUBLIC access
|
||||
*/
|
||||
public void testFromUnnamedToNamedModule() throws Exception {
|
||||
Lookup lookup = MethodHandles.lookup();
|
||||
lookup = MethodHandles.privateLookupIn(unnamedClass, lookup).in(p1_Type1);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC); // A0
|
||||
|
||||
// m1
|
||||
findConstructor(lookup, p1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, p2_Type2, void.class);
|
||||
|
||||
// m2
|
||||
findConstructor(lookup, q1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class);
|
||||
|
||||
// java.base
|
||||
findConstructor(lookup, Object.class, void.class);
|
||||
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
|
||||
|
||||
// unnamed
|
||||
findConstructor(lookup, unnamedClass, void.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* MethodHandles.publicLookup()
|
||||
*
|
||||
* [A0] has PUBLIC|UNCONDITIONAL access
|
||||
*/
|
||||
public void testPublicLookup() throws Exception {
|
||||
Lookup lookup = MethodHandles.publicLookup();
|
||||
assertTrue(lookup.lookupModes() == (PUBLIC|UNCONDITIONAL)); // A0
|
||||
|
||||
// m1
|
||||
findConstructor(lookup, p1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, p2_Type2, void.class);
|
||||
|
||||
// m2
|
||||
findConstructor(lookup, q1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class);
|
||||
|
||||
// java.base
|
||||
findConstructor(lookup, Object.class, void.class);
|
||||
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
|
||||
|
||||
// unnamed
|
||||
findConstructor(lookup, unnamedClass, void.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hop from publicLookup to accessible type in java.base
|
||||
*/
|
||||
public void testPublicLookupToBaseModule() throws Exception {
|
||||
Lookup lookup = MethodHandles.publicLookup().in(String.class);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC); // A0
|
||||
|
||||
// m1
|
||||
findConstructorExpectingIAE(lookup, p1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, p2_Type2, void.class);
|
||||
|
||||
// m2
|
||||
findConstructorExpectingIAE(lookup, q1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class);
|
||||
|
||||
// java.base
|
||||
findConstructor(lookup, Object.class, void.class);
|
||||
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
|
||||
|
||||
// unnamed
|
||||
findConstructorExpectingIAE(lookup, unnamedClass, void.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hop from publicLookup to accessible type in named module.
|
||||
*
|
||||
* [A0] has PUBLIC access
|
||||
*/
|
||||
public void testPublicLookupToAccessibleTypeInNamedModule() throws Exception {
|
||||
Lookup lookup = MethodHandles.publicLookup().in(p1_Type1);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC); // A0
|
||||
|
||||
// m1
|
||||
findConstructor(lookup, p1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, p2_Type2, void.class);
|
||||
|
||||
// m2
|
||||
findConstructor(lookup, q1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class);
|
||||
|
||||
// java.base
|
||||
findConstructor(lookup, Object.class, void.class);
|
||||
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
|
||||
|
||||
// unnamed
|
||||
findConstructor(lookup, unnamedClass, void.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleport from publicLookup to inaccessible type in named module.
|
||||
*
|
||||
* [A0] has no access
|
||||
*/
|
||||
public void testPublicLookupToInaccessibleTypeInNamedModule() throws Exception {
|
||||
Lookup lookup = MethodHandles.publicLookup().in(p2_Type2);
|
||||
assertTrue(lookup.lookupModes() == 0); // A0
|
||||
|
||||
// m1
|
||||
findConstructorExpectingIAE(lookup, p1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, p2_Type2, void.class);
|
||||
|
||||
// m2
|
||||
findConstructorExpectingIAE(lookup, q1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class);
|
||||
|
||||
// java.base
|
||||
findConstructorExpectingIAE(lookup, Object.class, void.class);
|
||||
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
|
||||
|
||||
// unnamed
|
||||
findConstructorExpectingIAE(lookup, unnamedClass, void.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleport from publicLookup to public type in unnamed module
|
||||
*
|
||||
* [A0] has PUBLIC access
|
||||
*/
|
||||
public void testPublicLookupToUnnamedModule() throws Exception {
|
||||
Lookup lookup = MethodHandles.publicLookup().in(unnamedClass);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC); // A0
|
||||
|
||||
// m1
|
||||
findConstructor(lookup, p1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, p2_Type2, void.class);
|
||||
|
||||
// m2
|
||||
findConstructor(lookup, q1_Type1, void.class);
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class);
|
||||
|
||||
// java.base
|
||||
findConstructor(lookup, Object.class, void.class);
|
||||
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
|
||||
|
||||
// unnamed
|
||||
findConstructor(lookup, unnamedClass, void.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes Lookup findConstructor with a method type constructored from the
|
||||
* given return and parameter types, expecting IllegalAccessException to be
|
||||
* thrown.
|
||||
*/
|
||||
static void findConstructorExpectingIAE(Lookup lookup,
|
||||
Class<?> clazz,
|
||||
Class<?> rtype,
|
||||
Class<?>... ptypes) throws Exception {
|
||||
try {
|
||||
findConstructor(lookup, clazz, rtype, ptypes);
|
||||
assertTrue(false);
|
||||
} catch (IllegalAccessException expected) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes Lookup findConstructor with a method type constructored from the
|
||||
* given return and parameter types.
|
||||
*/
|
||||
static MethodHandle findConstructor(Lookup lookup,
|
||||
Class<?> clazz,
|
||||
Class<?> rtype,
|
||||
Class<?>... ptypes) throws Exception {
|
||||
MethodType mt = MethodType.methodType(rtype, ptypes);
|
||||
return lookup.findConstructor(clazz, mt);
|
||||
}
|
||||
}
|
@ -1,225 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package p1;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
/**
|
||||
* Basic test case for module access check, supplements AccessControlTest.
|
||||
*
|
||||
* The tests consists of two modules:
|
||||
*
|
||||
* module m1 { requires m2; exports p1; }
|
||||
* module m2 { exports q1; }
|
||||
*
|
||||
* Both modules read java.base (as every module reads java.base)
|
||||
*
|
||||
* module m1 has public types in packages p1 and p2, p2 is not exported.
|
||||
* module m2 has public types in packages q1 and q2, q2 is not exported.
|
||||
*/
|
||||
|
||||
public class Main {
|
||||
|
||||
static final int MODULE = Lookup.MODULE;
|
||||
|
||||
// Use Class.forName to get classes for test because some
|
||||
// are not accessible at compile-time
|
||||
|
||||
static final Class<?> p1_Type1; // m1, exported
|
||||
static final Class<?> p2_Type2; // m1, not exported
|
||||
static final Class<?> q1_Type1; // m2, exported, m1 reads m2
|
||||
static final Class<?> q2_Type2; // m2, not exported, m1 reads m2
|
||||
static final Class<?> x500NameClass; // java.base, not exported
|
||||
|
||||
static {
|
||||
try {
|
||||
p1_Type1 = Class.forName("p1.Type1");
|
||||
p2_Type2 = Class.forName("p2.Type2");
|
||||
q1_Type1 = Class.forName("q1.Type1");
|
||||
q2_Type2 = Class.forName("q2.Type2");
|
||||
x500NameClass = Class.forName("sun.security.x509.X500Name");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Lookup lookup, lookup2;
|
||||
|
||||
/**
|
||||
* MethodHandles.lookup()
|
||||
* has module access [A0]
|
||||
* can access all public types in m1 [A1]
|
||||
* can access public types in packages exported by modules that m1 reads [A2]
|
||||
* cannot access public types in non-exported modules of modules that m1 reads [A3]
|
||||
*/
|
||||
lookup = MethodHandles.lookup();
|
||||
assertTrue((lookup.lookupModes() & MODULE) == MODULE); // [A0]
|
||||
findConstructor(lookup, p1_Type1, void.class); // [A1]
|
||||
findConstructor(lookup, p2_Type2, void.class); // [A1]
|
||||
findConstructor(lookup, q1_Type1, void.class); // [A2]
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A3]
|
||||
findConstructor(lookup, Object.class, void.class); // [A2]
|
||||
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // [A3]
|
||||
|
||||
/**
|
||||
* Teleport from MethodHandles.lookup() to lookup class in the same module
|
||||
* module access is retained [A0]
|
||||
* can access all public types in m1 [A1]
|
||||
* can access public types in packages exported by modules that m1 reads [A2]
|
||||
* cannot access public types in non-exported modules of modules that m1 reads [A3]
|
||||
*/
|
||||
lookup2 = lookup.in(p2_Type2);
|
||||
assertTrue((lookup2.lookupModes() & MODULE) == MODULE); // [A0]
|
||||
findConstructor(lookup2, p1_Type1, void.class); // [A1]
|
||||
findConstructor(lookup2, p2_Type2, void.class); // [A1]
|
||||
findConstructor(lookup2, q1_Type1, void.class); // [A2]
|
||||
findConstructorExpectingIAE(lookup2, q2_Type2, void.class); // [A3]
|
||||
findConstructor(lookup2, Object.class, void.class); // [A2]
|
||||
findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A3]
|
||||
|
||||
/**
|
||||
* Teleport from MethodHandles.lookup() to lookup class in another named module
|
||||
* has no access [A0]
|
||||
*/
|
||||
lookup2 = lookup.in(Object.class);
|
||||
assertTrue(lookup2.lookupModes() == 0); // [A0]
|
||||
findConstructorExpectingIAE(lookup2, Object.class, void.class); // [A0]
|
||||
|
||||
/**
|
||||
* Teleport from MethodHandles.lookup() to lookup class in an unnamed module
|
||||
* has no access [A0]
|
||||
*/
|
||||
Class<?> c = MethodHandles.publicLookup().lookupClass();
|
||||
assertTrue(!c.getModule().isNamed());
|
||||
lookup2 = lookup.in(c);
|
||||
assertTrue(lookup2.lookupModes() == 0); // [A0]
|
||||
findConstructorExpectingIAE(lookup2, Object.class, void.class);
|
||||
|
||||
/**
|
||||
* MethodHandles.publicLookup()
|
||||
* has no module access [A0]
|
||||
* can access public types in exported packages [A1]
|
||||
* cannot access public types in non-exported packages [A2]
|
||||
*/
|
||||
lookup = MethodHandles.publicLookup();
|
||||
assertTrue((lookup.lookupModes() & MODULE) == 0); // [A0]
|
||||
findConstructor(lookup, p1_Type1, void.class); // [A1]
|
||||
findConstructorExpectingIAE(lookup, p2_Type2, void.class); // [A1]
|
||||
findConstructor(lookup, q1_Type1, void.class); // [A1]
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2]
|
||||
findConstructor(lookup, Object.class, void.class); // [A1]
|
||||
findConstructorExpectingIAE(lookup, x500NameClass, void.class); // [A2]
|
||||
|
||||
/**
|
||||
* Teleport from MethodHandles.publicLookup() to lookup class in java.base
|
||||
* has no module access [A0]
|
||||
* can access public types in packages exported by java.base [A1]
|
||||
* cannot access public types in non-exported packages [A2]
|
||||
* no access to types in other named modules [A3]
|
||||
*/
|
||||
lookup2 = lookup.in(Object.class);
|
||||
assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0]
|
||||
findConstructor(lookup2, String.class, void.class); // [A1]
|
||||
findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A2]
|
||||
findConstructorExpectingIAE(lookup2, p1_Type1, void.class); // [A3]
|
||||
findConstructorExpectingIAE(lookup2, q1_Type1, void.class); // [A3]
|
||||
|
||||
/**
|
||||
* Teleport from MethodHandles.publicLookup() to lookup class in m1
|
||||
* has no module access [A0]
|
||||
* can access public types in packages exported by m1, m2 and java.base [A1]
|
||||
* cannot access public types is non-exported packages [A2]
|
||||
*/
|
||||
lookup2 = lookup.in(p1_Type1);
|
||||
assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0]
|
||||
findConstructor(lookup2, p1_Type1, void.class); // [A1]
|
||||
findConstructor(lookup2, q1_Type1, void.class); // [A1]
|
||||
findConstructor(lookup2, Object.class, void.class); // [A1]
|
||||
findConstructorExpectingIAE(lookup, p2_Type2, void.class); // [A2]
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2]
|
||||
findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A2]
|
||||
|
||||
/**
|
||||
* Teleport from MethodHandles.publicLookup() to lookup class in m2
|
||||
* has no module access [A0]
|
||||
* can access public types in packages exported by m2 and java.base [A1]
|
||||
* cannot access public types is non-exported packages or modules that m2 does
|
||||
* not read [A2]
|
||||
*/
|
||||
lookup2 = lookup.in(q1_Type1);
|
||||
assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0]
|
||||
findConstructor(lookup2, q1_Type1, void.class); // [A1]
|
||||
findConstructor(lookup2, Object.class, void.class); // [A1]
|
||||
findConstructorExpectingIAE(lookup2, p1_Type1, void.class); // [A2]
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2]
|
||||
findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A2]
|
||||
|
||||
/**
|
||||
* Teleport from MethodHandles.publicLookup() to lookup class that is not
|
||||
* in an exported package, should get no access [A0]
|
||||
*/
|
||||
lookup2 = lookup.in(p2_Type2);
|
||||
assertTrue(lookup2.lookupModes() == 0); // [A0]
|
||||
findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes Lookup findConstructor with a method type constructored from the
|
||||
* given return and parameter types, expecting IllegalAccessException to be
|
||||
* thrown.
|
||||
*/
|
||||
static MethodHandle findConstructorExpectingIAE(Lookup lookup,
|
||||
Class<?> clazz,
|
||||
Class<?> rtype,
|
||||
Class<?>... ptypes) throws Exception {
|
||||
try {
|
||||
findConstructor(lookup, clazz, rtype, ptypes);
|
||||
throw new RuntimeException("IllegalAccessError expected");
|
||||
} catch (IllegalAccessException expected) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes Lookup findConstructor with a method type constructored from the
|
||||
* given return and parameter types.
|
||||
*/
|
||||
static MethodHandle findConstructor(Lookup lookup,
|
||||
Class<?> clazz,
|
||||
Class<?> rtype,
|
||||
Class<?>... ptypes) throws Exception {
|
||||
MethodType mt = MethodType.methodType(rtype, ptypes);
|
||||
return lookup.findConstructor(clazz, mt);
|
||||
}
|
||||
|
||||
static void assertTrue(boolean condition) {
|
||||
if (!condition)
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
@ -33,10 +33,10 @@ import java.io.IOException;
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.FindException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleDescriptor.Exports;
|
||||
import java.lang.module.ModuleDescriptor.Requires.Modifier;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.lang.module.ResolutionException;
|
||||
import java.lang.module.ResolvedModule;
|
||||
import java.lang.reflect.Layer;
|
||||
import java.lang.reflect.Module;
|
||||
@ -137,6 +137,7 @@ public class AutomaticModulesTest {
|
||||
assertTrue(mref.isPresent(), mn + " not found");
|
||||
|
||||
ModuleDescriptor descriptor = mref.get().descriptor();
|
||||
assertTrue(descriptor.isAutomatic());
|
||||
assertEquals(descriptor.name(), mn);
|
||||
if (vs == null) {
|
||||
assertFalse(descriptor.version().isPresent());
|
||||
@ -175,17 +176,14 @@ public class AutomaticModulesTest {
|
||||
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"));
|
||||
|
||||
Set<String> exports = descriptor.exports().stream()
|
||||
.map(Exports::source)
|
||||
.collect(Collectors.toSet());
|
||||
assertTrue(exports.size() == 2);
|
||||
assertTrue(exports.contains("p"));
|
||||
assertTrue(exports.contains("q"));
|
||||
assertTrue(descriptor.exports().isEmpty());
|
||||
assertTrue(descriptor.opens().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -201,15 +199,13 @@ public class AutomaticModulesTest {
|
||||
assertTrue(mref.isPresent(), "m not found");
|
||||
|
||||
ModuleDescriptor descriptor = mref.get().descriptor();
|
||||
assertTrue(descriptor.isAutomatic());
|
||||
|
||||
assertTrue(descriptor.packages().size() == 1);
|
||||
assertTrue(descriptor.packages().contains("p"));
|
||||
|
||||
Set<String> exports = descriptor.exports().stream()
|
||||
.map(Exports::source)
|
||||
.collect(Collectors.toSet());
|
||||
assertTrue(exports.size() == 1);
|
||||
assertTrue(exports.contains("p"));
|
||||
assertTrue(descriptor.exports().isEmpty());
|
||||
assertTrue(descriptor.opens().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -229,10 +225,10 @@ public class AutomaticModulesTest {
|
||||
assertTrue(mref.isPresent(), "m not found");
|
||||
|
||||
ModuleDescriptor descriptor = mref.get().descriptor();
|
||||
assertTrue(descriptor.isAutomatic());
|
||||
|
||||
assertTrue(descriptor.packages().size() == 2);
|
||||
assertTrue(descriptor.packages().size() == 1);
|
||||
assertTrue(descriptor.packages().contains("p"));
|
||||
assertTrue(descriptor.packages().contains("p.resources"));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -254,9 +250,17 @@ public class AutomaticModulesTest {
|
||||
String provider = "p.S1";
|
||||
|
||||
Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");
|
||||
|
||||
// provider class
|
||||
Path providerClass = tmpdir.resolve(provider.replace('.', '/') + ".class");
|
||||
Files.createDirectories(providerClass.getParent());
|
||||
Files.createFile(providerClass);
|
||||
|
||||
// services configuration file
|
||||
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);
|
||||
|
||||
@ -314,7 +318,7 @@ public class AutomaticModulesTest {
|
||||
|
||||
// service type provider type
|
||||
{ "p.S", "-" },
|
||||
{ "p.S", ".S1" },
|
||||
{ "p.S", "p..S1" },
|
||||
{ "p.S", "S1." },
|
||||
};
|
||||
}
|
||||
@ -324,13 +328,41 @@ public class AutomaticModulesTest {
|
||||
* values or names.
|
||||
*/
|
||||
@Test(dataProvider = "badproviders", expectedExceptions = FindException.class)
|
||||
public void testBadProvideNames(String service, String provider)
|
||||
public void testBadProviderNames(String service, String provider)
|
||||
throws IOException
|
||||
{
|
||||
Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");
|
||||
|
||||
// provider class
|
||||
Path providerClass = tmpdir.resolve(provider.replace('.', '/') + ".class");
|
||||
Files.createDirectories(providerClass.getParent());
|
||||
Files.createFile(providerClass);
|
||||
|
||||
// services configuration file
|
||||
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);
|
||||
|
||||
// should throw FindException
|
||||
ModuleFinder.of(dir).findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test JAR file with META-INF/services configuration file listing a
|
||||
* provider that is not in the module.
|
||||
*/
|
||||
@Test(expectedExceptions = FindException.class)
|
||||
public void testMissingProviderPackage() throws IOException {
|
||||
Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");
|
||||
|
||||
// services configuration file
|
||||
Path services = tmpdir.resolve("META-INF").resolve("services");
|
||||
Files.createDirectories(services);
|
||||
Files.write(services.resolve("p.S"), Set.of("q.P"));
|
||||
|
||||
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
||||
JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir);
|
||||
|
||||
@ -352,7 +384,8 @@ public class AutomaticModulesTest {
|
||||
attrs.put(Attributes.Name.MAIN_CLASS, mainClass);
|
||||
|
||||
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
||||
createDummyJarFile(dir.resolve("m.jar"), man);
|
||||
String entry = mainClass.replace('.', '/') + ".class";
|
||||
createDummyJarFile(dir.resolve("m.jar"), man, entry);
|
||||
|
||||
ModuleFinder finder = ModuleFinder.of(dir);
|
||||
|
||||
@ -366,20 +399,21 @@ public class AutomaticModulesTest {
|
||||
}
|
||||
|
||||
|
||||
// Main-Class files that do not map to a legal Java identifier
|
||||
// Main-Class files that do not map to a legal qualified type name
|
||||
@DataProvider(name = "badmainclass")
|
||||
public Object[][] createBadMainClass() {
|
||||
return new Object[][]{
|
||||
|
||||
{ "Main", null },
|
||||
{ "p..Main", null },
|
||||
{ "p-.Main", null },
|
||||
{ ".Main", null }
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a JAR file with a Main-Class attribute that is not a valid
|
||||
* Java identifier
|
||||
* Test that a JAR file with a Main-Class attribute that is not a qualified
|
||||
* type name.
|
||||
*/
|
||||
@Test(dataProvider = "badmainclass", expectedExceptions = FindException.class)
|
||||
public void testBadMainClass(String mainClass, String ignore) throws IOException {
|
||||
@ -388,6 +422,24 @@ public class AutomaticModulesTest {
|
||||
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);
|
||||
|
||||
// should throw FindException
|
||||
ModuleFinder.of(dir).findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a JAR file with a Main-Class attribute that is not in the module
|
||||
*/
|
||||
@Test(expectedExceptions = FindException.class)
|
||||
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);
|
||||
|
||||
@ -405,7 +457,7 @@ public class AutomaticModulesTest {
|
||||
*/
|
||||
public void testConfiguration1() throws Exception {
|
||||
ModuleDescriptor descriptor1
|
||||
= ModuleDescriptor.module("a")
|
||||
= ModuleDescriptor.newModule("a")
|
||||
.requires("b")
|
||||
.requires("c")
|
||||
.requires("java.base")
|
||||
@ -465,13 +517,13 @@ public class AutomaticModulesTest {
|
||||
*/
|
||||
public void testInConfiguration2() throws IOException {
|
||||
ModuleDescriptor descriptor1
|
||||
= ModuleDescriptor.module("a")
|
||||
= ModuleDescriptor.newModule("a")
|
||||
.requires("b")
|
||||
.requires("java.base")
|
||||
.build();
|
||||
|
||||
ModuleDescriptor descriptor2
|
||||
= ModuleDescriptor.module("b")
|
||||
= ModuleDescriptor.newModule("b")
|
||||
.requires("c")
|
||||
.requires("java.base")
|
||||
.build();
|
||||
@ -538,13 +590,13 @@ public class AutomaticModulesTest {
|
||||
*/
|
||||
public void testInConfiguration3() throws IOException {
|
||||
ModuleDescriptor descriptor1
|
||||
= ModuleDescriptor.module("a")
|
||||
= ModuleDescriptor.newModule("a")
|
||||
.requires("b")
|
||||
.requires("java.base")
|
||||
.build();
|
||||
|
||||
ModuleDescriptor descriptor2
|
||||
= ModuleDescriptor.module("b")
|
||||
= ModuleDescriptor.newModule("b")
|
||||
.requires(Set.of(Modifier.TRANSITIVE), "c")
|
||||
.requires("java.base")
|
||||
.build();
|
||||
@ -608,12 +660,68 @@ public class AutomaticModulesTest {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Basic test of a configuration created with automatic modules
|
||||
* a requires b* and c*
|
||||
* b* contains p
|
||||
* c* contains p
|
||||
*/
|
||||
@Test(expectedExceptions = { ResolutionException.class })
|
||||
public void testDuplicateSuppliers1() throws IOException {
|
||||
ModuleDescriptor descriptor
|
||||
= ModuleDescriptor.newModule("a")
|
||||
.requires("b")
|
||||
.requires("c")
|
||||
.build();
|
||||
|
||||
// c and d are automatic modules with the same package
|
||||
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
||||
createDummyJarFile(dir.resolve("b.jar"), "p/T.class");
|
||||
createDummyJarFile(dir.resolve("c.jar"), "p/T.class");
|
||||
|
||||
// module finder locates 'a' and the modules in the directory
|
||||
ModuleFinder finder
|
||||
= ModuleFinder.compose(ModuleUtils.finderOf(descriptor),
|
||||
ModuleFinder.of(dir));
|
||||
|
||||
Configuration parent = Layer.boot().configuration();
|
||||
resolve(parent, finder, "a");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Basic test of a configuration created with automatic modules
|
||||
* a contains p, requires b*
|
||||
* b* contains p
|
||||
*/
|
||||
@Test(expectedExceptions = { ResolutionException.class })
|
||||
public void testDuplicateSuppliers2() throws IOException {
|
||||
ModuleDescriptor descriptor
|
||||
= ModuleDescriptor.newModule("a")
|
||||
.packages(Set.of("p"))
|
||||
.requires("b")
|
||||
.build();
|
||||
|
||||
// c and d are automatic modules with the same package
|
||||
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
||||
createDummyJarFile(dir.resolve("b.jar"), "p/T.class");
|
||||
|
||||
// module finder locates 'a' and the modules in the directory
|
||||
ModuleFinder finder
|
||||
= ModuleFinder.compose(ModuleUtils.finderOf(descriptor),
|
||||
ModuleFinder.of(dir));
|
||||
|
||||
Configuration parent = Layer.boot().configuration();
|
||||
resolve(parent, finder, "a");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Basic test of Layer containing automatic modules
|
||||
*/
|
||||
public void testInLayer() throws IOException {
|
||||
ModuleDescriptor descriptor
|
||||
= ModuleDescriptor.module("a")
|
||||
= ModuleDescriptor.newModule("a")
|
||||
.requires("b")
|
||||
.requires("c")
|
||||
.build();
|
||||
@ -664,7 +772,7 @@ public class AutomaticModulesTest {
|
||||
|
||||
// test miscellaneous methods
|
||||
assertTrue(m.isAutomatic());
|
||||
assertFalse(m.isSynthetic());
|
||||
assertFalse(m.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC));
|
||||
assertFalse(m.osName().isPresent());
|
||||
assertFalse(m.osArch().isPresent());
|
||||
assertFalse(m.osVersion().isPresent());
|
||||
@ -672,12 +780,12 @@ public class AutomaticModulesTest {
|
||||
|
||||
|
||||
/**
|
||||
* Invokes parent.resolveRequires to resolve the given root modules.
|
||||
* Invokes parent.resolve to resolve the given root modules.
|
||||
*/
|
||||
static Configuration resolve(Configuration parent,
|
||||
ModuleFinder finder,
|
||||
String... roots) {
|
||||
return parent.resolveRequires(finder, ModuleFinder.of(), Set.of(roots));
|
||||
return parent.resolve(finder, ModuleFinder.of(), Set.of(roots));
|
||||
}
|
||||
|
||||
/**
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -471,36 +471,10 @@ public class ModuleFinderTest {
|
||||
* Test ModuleFinder.of with a file path to a directory containing a file
|
||||
* that will not be recognized as a module.
|
||||
*/
|
||||
public void testOfWithUnrecognizedEntryInDirectory() throws Exception {
|
||||
public void testOfWithUnrecognizedEntryInDirectory1() throws Exception {
|
||||
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
||||
Files.createTempFile(dir, "m", ".junk");
|
||||
|
||||
ModuleFinder finder = ModuleFinder.of(dir);
|
||||
try {
|
||||
finder.find("java.rhubarb");
|
||||
assertTrue(false);
|
||||
} catch (FindException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
finder = ModuleFinder.of(dir);
|
||||
try {
|
||||
finder.findAll();
|
||||
assertTrue(false);
|
||||
} catch (FindException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test ModuleFinder.of with a file path to a directory containing a file
|
||||
* starting with ".", the file should be ignored.
|
||||
*/
|
||||
public void testOfWithHiddenEntryInDirectory() throws Exception {
|
||||
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
||||
Files.createTempFile(dir, ".marker", "");
|
||||
|
||||
ModuleFinder finder = ModuleFinder.of(dir);
|
||||
assertFalse(finder.find("java.rhubarb").isPresent());
|
||||
|
||||
@ -509,6 +483,24 @@ public class ModuleFinderTest {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test ModuleFinder.of with a file path to a directory containing a file
|
||||
* that will not be recognized as a module.
|
||||
*/
|
||||
public void testOfWithUnrecognizedEntryInDirectory2() throws Exception {
|
||||
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
||||
createModularJar(dir.resolve("m1.jar"), "m1");
|
||||
Files.createTempFile(dir, "m2", ".junk");
|
||||
|
||||
ModuleFinder finder = ModuleFinder.of(dir);
|
||||
assertTrue(finder.find("m1").isPresent());
|
||||
assertFalse(finder.find("m2").isPresent());
|
||||
|
||||
finder = ModuleFinder.of(dir);
|
||||
assertTrue(finder.findAll().size() == 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test ModuleFinder.of with a directory that contains two
|
||||
* versions of the same module
|
||||
@ -748,7 +740,7 @@ public class ModuleFinderTest {
|
||||
vs = mid.substring(i+1);
|
||||
}
|
||||
ModuleDescriptor.Builder builder
|
||||
= ModuleDescriptor.module(mn).requires("java.base");
|
||||
= ModuleDescriptor.newModule(mn).requires("java.base");
|
||||
if (vs != null)
|
||||
builder.version(vs);
|
||||
return builder.build();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user