extends Executable {
sb.append(getDeclaringClass().getTypeName());
}
+ @Override
+ String toShortString() {
+ StringBuilder sb = new StringBuilder("constructor ");
+ sb.append(getDeclaringClass().getTypeName());
+ sb.append('(');
+ StringJoiner sj = new StringJoiner(",");
+ for (Class> parameterType : getParameterTypes()) {
+ sj.add(parameterType.getTypeName());
+ }
+ sb.append(sj);
+ sb.append(')');
+ return sb.toString();
+ }
+
/**
* Returns a string describing this {@code Constructor},
* including type parameters. The string is formatted as the
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Field.java b/jdk/src/java.base/share/classes/java/lang/reflect/Field.java
index ef892714b03..1f1192f6a5b 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Field.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Field.java
@@ -324,6 +324,11 @@ class Field extends AccessibleObject implements Member {
+ getName());
}
+ @Override
+ String toShortString() {
+ return "field " + getDeclaringClass().getTypeName() + "." + getName();
+ }
+
/**
* Returns a string describing this {@code Field}, including
* its generic type. The format is the access modifiers for the
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java
index d6d89980aae..bd0036d7de3 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java
@@ -66,9 +66,7 @@ import sun.security.util.SecurityConstants;
* 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 {@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}.
+ * be in the same layer or a {@link #parents() parent} layer.
*
* The {@link #defineModulesWithOneLoader defineModulesWithOneLoader} and
* {@link #defineModulesWithManyLoaders defineModulesWithManyLoaders} methods
@@ -91,6 +89,28 @@ import sun.security.util.SecurityConstants;
* built-in into the Java virtual machine. The boot layer will often be
* the {@link #parents() parent} when creating additional layers.
*
+ * Each {@code Module} in a layer is created so that it {@link
+ * Module#isExported(String) exports} and {@link Module#isOpen(String) opens}
+ * the packages described by its {@link ModuleDescriptor}. Qualified exports
+ * (where a package is exported to a set of target modules rather than all
+ * modules) are reified when creating the layer as follows:
+ *
+ * - If module {@code X} exports a package to {@code Y}, and if the
+ * runtime {@code Module} {@code X} reads {@code Module} {@code Y}, then
+ * the package is exported to {@code Module} {@code Y} (which may be in
+ * the same layer as {@code X} or a parent layer).
+ *
+ * - If module {@code X} exports a package to {@code Y}, and if the
+ * runtime {@code Module} {@code X} does not read {@code Y} then target
+ * {@code Y} is located as if by invoking {@link #findModule(String)
+ * findModule} to find the module in the layer or its parent layers. If
+ * {@code Y} is found then the package is exported to the instance of
+ * {@code Y} that was found. If {@code Y} is not found then the qualified
+ * export is ignored.
+ *
+ *
+ * Qualified opens are handled in same way as qualified exports.
+ *
* As when creating a {@code Configuration},
* {@link ModuleDescriptor#isAutomatic() automatic} modules receive special
* treatment when creating a layer. An automatic module is created in the
@@ -193,7 +213,7 @@ public final class Layer {
}
private void ensureInLayer(Module source) {
- if (!layer.modules().contains(source))
+ if (source.getLayer() != layer)
throw new IllegalArgumentException(source + " not in layer");
}
@@ -220,9 +240,8 @@ public final class Layer {
* @see Module#addReads
*/
public Controller addReads(Module source, Module target) {
- Objects.requireNonNull(source);
- Objects.requireNonNull(target);
ensureInLayer(source);
+ Objects.requireNonNull(target);
Modules.addReads(source, target);
return this;
}
@@ -248,9 +267,9 @@ public final class Layer {
* @see Module#addOpens
*/
public Controller addOpens(Module source, String pn, Module target) {
- Objects.requireNonNull(source);
- Objects.requireNonNull(target);
ensureInLayer(source);
+ Objects.requireNonNull(pn);
+ Objects.requireNonNull(target);
Modules.addOpens(source, pn, target);
return this;
}
@@ -408,8 +427,8 @@ public final class Layer {
*
*
*
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.}".
+ * a module named "{@code java.base}", or a module contains a package named
+ * "{@code java}" or a package with a name starting with "{@code java.}".
*
* If there is a security manager then the class loader created by
* this method will load classes and resources with privileges that are
@@ -418,7 +437,7 @@ public final class Layer {
* @param cf
* The configuration for the layer
* @param parentLayers
- * The list parent layers in search order
+ * The list of parent layers in search order
* @param parentLoader
* The parent class loader for the class loader created by this
* method; may be {@code null} for the bootstrap class loader
@@ -485,7 +504,7 @@ public final class Layer {
* @param cf
* The configuration for the layer
* @param parentLayers
- * The list parent layers in search order
+ * The list of parent layers in search order
* @param parentLoader
* The parent class loader for each of the class loaders created by
* this method; may be {@code null} for the bootstrap class loader
@@ -497,8 +516,10 @@ public final class Layer {
* the parent layers, including order
* @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.}"
+ * a module named "{@code java.base}" or a module contains a package
+ * named "{@code java}" or a package with a name starting with
+ * "{@code java.}"
+ *
* @throws SecurityException
* If {@code RuntimePermission("createClassLoader")} or
* {@code RuntimePermission("getClassLoader")} is denied by
@@ -558,10 +579,11 @@ public final class Layer {
*
*
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}.
+ * with a package named "{@code java}" or a package name starting with
+ * "{@code java.}" and the module 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 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.
@@ -575,7 +597,7 @@ public final class Layer {
* @param cf
* The configuration for the layer
* @param parentLayers
- * The list parent layers in search order
+ * The list of parent layers in search order
* @param clf
* The function to map a module name to a class loader
*
@@ -754,10 +776,16 @@ public final class Layer {
* @return A possibly-empty unmodifiable set of the modules in this layer
*/
public Set modules() {
- return Collections.unmodifiableSet(
- nameToModule.values().stream().collect(Collectors.toSet()));
+ Set modules = this.modules;
+ if (modules == null) {
+ this.modules = modules =
+ Collections.unmodifiableSet(new HashSet<>(nameToModule.values()));
+ }
+ return modules;
}
+ private volatile Set modules;
+
/**
* Returns the module with the given name in this layer, or if not in this
@@ -776,6 +804,8 @@ public final class Layer {
*/
public Optional findModule(String name) {
Objects.requireNonNull(name);
+ if (this == EMPTY_LAYER)
+ return Optional.empty();
Module m = nameToModule.get(name);
if (m != null)
return Optional.of(m);
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Method.java b/jdk/src/java.base/share/classes/java/lang/reflect/Method.java
index 2208a5cbd81..b915b5524ae 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Method.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Method.java
@@ -42,6 +42,7 @@ import sun.reflect.annotation.AnnotationParser;
import java.lang.annotation.Annotation;
import java.lang.annotation.AnnotationFormatError;
import java.nio.ByteBuffer;
+import java.util.StringJoiner;
/**
* A {@code Method} provides information about, and access to, a single method
@@ -416,6 +417,21 @@ public final class Method extends Executable {
sb.append(getName());
}
+ @Override
+ String toShortString() {
+ StringBuilder sb = new StringBuilder("method ");
+ sb.append(getDeclaringClass().getTypeName()).append('.');
+ sb.append(getName());
+ sb.append('(');
+ StringJoiner sj = new StringJoiner(",");
+ for (Class> parameterType : getParameterTypes()) {
+ sj.add(parameterType.getTypeName());
+ }
+ sb.append(sj);
+ sb.append(')');
+ return sb.toString();
+ }
+
/**
* Returns a string describing this {@code Method}, including
* type parameters. The string is formatted as the method access
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java
index e70d9fbb872..23fddfaa557 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java
@@ -39,8 +39,10 @@ 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.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -51,11 +53,11 @@ import java.util.stream.Stream;
import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.loader.BootLoader;
-import jdk.internal.loader.ResourceHelper;
import jdk.internal.misc.JavaLangAccess;
import jdk.internal.misc.JavaLangReflectModuleAccess;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.module.ServicesCatalog;
+import jdk.internal.module.Resources;
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.ClassReader;
@@ -369,28 +371,19 @@ public final class Module implements AnnotatedElement {
* If {@code syncVM} is {@code true} then the VM is notified.
*/
private void implAddReads(Module other, boolean syncVM) {
- Objects.requireNonNull(other);
-
- // nothing to do
- if (other == this || !this.isNamed())
- return;
-
- // check if we already read this module
- Set reads = this.reads;
- if (reads != null && reads.contains(other))
- return;
-
- // update VM first, just in case it fails
- if (syncVM) {
- if (other == ALL_UNNAMED_MODULE) {
- addReads0(this, null);
- } else {
- addReads0(this, other);
+ if (!canRead(other)) {
+ // update VM first, just in case it fails
+ if (syncVM) {
+ if (other == ALL_UNNAMED_MODULE) {
+ addReads0(this, null);
+ } else {
+ addReads0(this, other);
+ }
}
- }
- // add reflective read
- reflectivelyReads.putIfAbsent(this, other, Boolean.TRUE);
+ // add reflective read
+ reflectivelyReads.putIfAbsent(this, other, Boolean.TRUE);
+ }
}
@@ -553,7 +546,7 @@ public final class Module implements AnnotatedElement {
* Returns {@code true} if this module exports or opens a package to
* the given module via its module declaration.
*/
- boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) {
+ private boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) {
// package is open to everyone or
Map> openPackages = this.openPackages;
if (openPackages != null) {
@@ -909,9 +902,7 @@ public final class Module implements AnnotatedElement {
* Returns an array of the package names of the packages in this module.
*
* For named modules, the returned array contains an element for each
- * package in the module. It may contain elements corresponding to packages
- * added to the module, dynamic modules
- * for example, after it was loaded.
+ * package in the module.
*
* For unnamed modules, this method is the equivalent to invoking the
* {@link ClassLoader#getDefinedPackages() getDefinedPackages} method of
@@ -949,15 +940,6 @@ public final class Module implements AnnotatedElement {
}
}
- /**
- * Add a package to this module.
- *
- * @apiNote This method is for Proxy use.
- */
- void addPackage(String pn) {
- implAddPackage(pn, true);
- }
-
/**
* Add a package to this module without notifying the VM.
*
@@ -1080,20 +1062,28 @@ public final class Module implements AnnotatedElement {
// reads
Set reads = new HashSet<>();
+
+ // name -> source Module when in parent layer
+ Map nameToSource = Collections.emptyMap();
+
for (ResolvedModule other : resolvedModule.reads()) {
Module m2 = null;
if (other.configuration() == cf) {
- String dn = other.reference().descriptor().name();
- m2 = nameToModule.get(dn);
+ // this configuration
+ m2 = nameToModule.get(other.name());
+ assert m2 != null;
} else {
+ // parent layer
for (Layer parent: layer.parents()) {
m2 = findModule(parent, other);
if (m2 != null)
break;
}
+ assert m2 != null;
+ if (nameToSource.isEmpty())
+ nameToSource = new HashMap<>();
+ nameToSource.put(other.name(), m2);
}
- assert m2 != null;
-
reads.add(m2);
// update VM view
@@ -1107,7 +1097,7 @@ public final class Module implements AnnotatedElement {
}
// exports and opens
- initExportsAndOpens(descriptor, nameToModule, m);
+ initExportsAndOpens(m, nameToSource, nameToModule, layer.parents());
}
// register the modules in the boot layer
@@ -1159,15 +1149,17 @@ public final class Module implements AnnotatedElement {
.orElse(null);
}
+
/**
* Initialize the maps of exported and open packages for module m.
*/
- private static void initExportsAndOpens(ModuleDescriptor descriptor,
+ private static void initExportsAndOpens(Module m,
+ Map nameToSource,
Map nameToModule,
- Module m)
- {
+ List parents) {
// The VM doesn't special case open or automatic modules so need to
// export all packages
+ ModuleDescriptor descriptor = m.getDescriptor();
if (descriptor.isOpen() || descriptor.isAutomatic()) {
assert descriptor.opens().isEmpty();
for (String source : descriptor.packages()) {
@@ -1187,8 +1179,7 @@ public final class Module implements AnnotatedElement {
// qualified opens
Set targets = new HashSet<>();
for (String target : opens.targets()) {
- // only open to modules that are in this configuration
- Module m2 = nameToModule.get(target);
+ Module m2 = findModule(target, nameToSource, nameToModule, parents);
if (m2 != null) {
addExports0(m, source, m2);
targets.add(m2);
@@ -1217,8 +1208,7 @@ public final class Module implements AnnotatedElement {
// qualified exports
Set targets = new HashSet<>();
for (String target : exports.targets()) {
- // only export to modules that are in this configuration
- Module m2 = nameToModule.get(target);
+ Module m2 = findModule(target, nameToSource, nameToModule, parents);
if (m2 != null) {
// skip qualified export if already open to m2
if (openToTargets == null || !openToTargets.contains(m2)) {
@@ -1244,6 +1234,32 @@ public final class Module implements AnnotatedElement {
m.exportedPackages = exportedPackages;
}
+ /**
+ * Find the runtime Module with the given name. The module name is the
+ * name of a target module in a qualified exports or opens directive.
+ *
+ * @param target The target module to find
+ * @param nameToSource The modules in parent layers that are read
+ * @param nameToModule The modules in the layer under construction
+ * @param parents The parent layers
+ */
+ private static Module findModule(String target,
+ Map nameToSource,
+ Map nameToModule,
+ List parents) {
+ Module m = nameToSource.get(target);
+ if (m == null) {
+ m = nameToModule.get(target);
+ if (m == null) {
+ for (Layer parent : parents) {
+ m = parent.findModule(target).orElse(null);
+ if (m != null) break;
+ }
+ }
+ }
+ return m;
+ }
+
// -- annotations --
@@ -1428,12 +1444,12 @@ public final class Module implements AnnotatedElement {
name = name.substring(1);
}
- if (isNamed() && !ResourceHelper.isSimpleResource(name)) {
+ if (isNamed() && Resources.canEncapsulate(name)) {
Module caller = Reflection.getCallerClass().getModule();
if (caller != this && caller != Object.class.getModule()) {
// ignore packages added for proxies via addPackage
Set packages = getDescriptor().packages();
- String pn = ResourceHelper.getPackageName(name);
+ String pn = Resources.toPackageName(name);
if (packages.contains(pn) && !isOpen(pn, caller)) {
// resource is in package not open to caller
return null;
@@ -1531,24 +1547,24 @@ public final class Module implements AnnotatedElement {
m.implAddReads(Module.ALL_UNNAMED_MODULE);
}
@Override
+ public void addExports(Module m, String pn) {
+ m.implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, false, true);
+ }
+ @Override
public void addExports(Module m, String pn, Module other) {
m.implAddExportsOrOpens(pn, other, false, true);
}
@Override
- public void addOpens(Module m, String pn, Module other) {
- m.implAddExportsOrOpens(pn, other, true, true);
+ public void addExportsToAllUnnamed(Module m, String pn) {
+ m.implAddExportsOrOpens(pn, Module.ALL_UNNAMED_MODULE, false, true);
}
@Override
- public void addExportsToAll(Module m, String pn) {
- m.implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, false, true);
- }
- @Override
- public void addOpensToAll(Module m, String pn) {
+ public void addOpens(Module m, String pn) {
m.implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, true, true);
}
@Override
- public void addExportsToAllUnnamed(Module m, String pn) {
- m.implAddExportsOrOpens(pn, Module.ALL_UNNAMED_MODULE, false, true);
+ public void addOpens(Module m, String pn, Module other) {
+ m.implAddExportsOrOpens(pn, other, true, true);
}
@Override
public void addOpensToAllUnnamed(Module m, String pn) {
@@ -1559,10 +1575,6 @@ public final class Module implements AnnotatedElement {
m.implAddUses(service);
}
@Override
- public void addPackage(Module m, String pn) {
- m.implAddPackage(pn, true);
- }
- @Override
public ServicesCatalog getServicesCatalog(Layer layer) {
return layer.getServicesCatalog();
}
@@ -1574,10 +1586,6 @@ public final class Module implements AnnotatedElement {
public Stream layers(ClassLoader loader) {
return Layer.layers(loader);
}
- @Override
- public boolean isStaticallyExported(Module module, String pn, Module other) {
- return module.isStaticallyExportedOrOpen(pn, other, false);
- }
});
}
}
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java b/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java
index 685aebff39a..b4b4a07c807 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -359,10 +359,11 @@ public class Proxy implements java.io.Serializable {
* @throws NullPointerException if the {@code interfaces} array
* argument or any of its elements are {@code null}
*
- * @deprecated Proxy classes generated in a named module are encapsulated and not
- * accessible to code outside its module.
- * {@link Constructor#newInstance(Object...) Constructor.newInstance} will throw
- * {@code IllegalAccessException} when it is called on an inaccessible proxy class.
+ * @deprecated Proxy classes generated in a named module are encapsulated
+ * and not accessible to code outside its module.
+ * {@link Constructor#newInstance(Object...) Constructor.newInstance}
+ * will throw {@code IllegalAccessException} when it is called on
+ * an inaccessible proxy class.
* Use {@link #newProxyInstance(ClassLoader, Class[], InvocationHandler)}
* to create a proxy instance instead.
*
@@ -511,17 +512,19 @@ public class Proxy implements java.io.Serializable {
"Unnamed package cannot be added to " + m);
}
- // add the package to the runtime module if not exists
if (m.isNamed()) {
- m.addPackage(proxyPkg);
+ if (!m.getDescriptor().packages().contains(proxyPkg)) {
+ throw new InternalError(proxyPkg + " not exist in " + m.getName());
+ }
}
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
- String proxyName = proxyPkg.isEmpty() ? proxyClassNamePrefix + num
- : proxyPkg + "." + proxyClassNamePrefix + num;
+ String proxyName = proxyPkg.isEmpty()
+ ? proxyClassNamePrefix + num
+ : proxyPkg + "." + proxyClassNamePrefix + num;
ClassLoader loader = getLoader(m);
trace(proxyName, m, loader, interfaces);
@@ -581,9 +584,13 @@ public class Proxy implements java.io.Serializable {
c.getModule().getName(), c.getName(), access, ld);
}
- static void trace(String cn, Module module, ClassLoader loader, List> interfaces) {
+ static void trace(String cn,
+ Module module,
+ ClassLoader loader,
+ List> interfaces) {
if (isDebug()) {
- System.out.format("PROXY: %s/%s defined by %s%n", module.getName(), cn, loader);
+ System.err.format("PROXY: %s/%s defined by %s%n",
+ module.getName(), cn, loader);
}
if (isDebug("debug")) {
interfaces.stream()
@@ -592,7 +599,7 @@ public class Proxy implements java.io.Serializable {
}
private static final String DEBUG =
- GetPropertyAction.privilegedGetProperty("jdk.proxy.debug", "");
+ GetPropertyAction.privilegedGetProperty("jdk.proxy.debug", "");
private static boolean isDebug() {
return !DEBUG.isEmpty();
@@ -603,15 +610,16 @@ public class Proxy implements java.io.Serializable {
// ProxyBuilder instance members start here....
- private final ClassLoader loader;
private final List> interfaces;
private final Module module;
ProxyBuilder(ClassLoader loader, List> interfaces) {
if (!VM.isModuleSystemInited()) {
- throw new InternalError("Proxy is not supported until module system is fully initialized");
+ throw new InternalError("Proxy is not supported until "
+ + "module system is fully initialized");
}
if (interfaces.size() > 65535) {
- throw new IllegalArgumentException("interface limit exceeded: " + interfaces.size());
+ throw new IllegalArgumentException("interface limit exceeded: "
+ + interfaces.size());
}
Set> refTypes = referencedTypes(loader, interfaces);
@@ -619,7 +627,6 @@ public class Proxy implements java.io.Serializable {
// IAE if violates any restrictions specified in newProxyInstance
validateProxyInterfaces(loader, interfaces, refTypes);
- this.loader = loader;
this.interfaces = interfaces;
this.module = mapToModule(loader, interfaces, refTypes);
assert getLoader(module) == loader;
@@ -659,8 +666,8 @@ public class Proxy implements java.io.Serializable {
* Validate the given proxy interfaces and the given referenced types
* are visible to the defining loader.
*
- * @throws IllegalArgumentException if it violates the restrictions specified
- * in {@link Proxy#newProxyInstance}
+ * @throws IllegalArgumentException if it violates the restrictions
+ * specified in {@link Proxy#newProxyInstance}
*/
private static void validateProxyInterfaces(ClassLoader loader,
List> interfaces,
@@ -731,9 +738,9 @@ public class Proxy implements java.io.Serializable {
* is in the same module of the package-private interface.
*
* If all proxy interfaces are public and at least one in a non-exported
- * package, then the proxy class is in a dynamic module in a non-exported
- * package. Reads edge and qualified exports are added for
- * dynamic module to access.
+ * package, then the proxy class is in a dynamic module in a
+ * non-exported package. Reads edge and qualified exports are added
+ * for dynamic module to access.
*/
private static Module mapToModule(ClassLoader loader,
List> interfaces,
@@ -752,11 +759,12 @@ public class Proxy implements java.io.Serializable {
}
}
- // all proxy interfaces are public and exported, the proxy class is in unnamed module
- // Such proxy class is accessible to any unnamed module and named module that
- // can read unnamed module
+ // all proxy interfaces are public and exported, the proxy class
+ // is in unnamed module. Such proxy class is accessible to
+ // any unnamed module and named module that can read unnamed module
if (packagePrivateTypes.isEmpty() && modulePrivateTypes.isEmpty()) {
- return loader != null ? loader.getUnnamedModule() : BootLoader.getUnnamedModule();
+ return loader != null ? loader.getUnnamedModule()
+ : BootLoader.getUnnamedModule();
}
if (packagePrivateTypes.size() > 0) {
@@ -778,7 +786,8 @@ public class Proxy implements java.io.Serializable {
Module target = null;
for (Module m : packagePrivateTypes.values()) {
if (getLoader(m) != loader) {
- // the specified loader is not the same class loader of the non-public interface
+ // the specified loader is not the same class loader
+ // of the non-public interface
throw new IllegalArgumentException(
"non-public interface is not defined by the given loader");
}
@@ -799,8 +808,9 @@ public class Proxy implements java.io.Serializable {
return target;
}
- // all proxy interfaces are public and at least one in a non-exported package
- // map to dynamic proxy module and add reads edge and qualified exports, if necessary
+ // All proxy interfaces are public and at least one in a non-exported
+ // package. So maps to a dynamic proxy module and add reads edge
+ // and qualified exports, if necessary
Module target = getDynamicModule(loader);
// set up proxy class access to proxy interfaces and types
@@ -856,8 +866,8 @@ public class Proxy implements java.io.Serializable {
private static final AtomicInteger counter = new AtomicInteger();
/*
- * Define a dynamic module for the generated proxy classes in a non-exported package
- * named com.sun.proxy.$MODULE.
+ * Define a dynamic module for the generated proxy classes in
+ * a non-exported package named com.sun.proxy.$MODULE.
*
* Each class loader will have one dynamic module.
*/
diff --git a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java
index 32611e65e46..b84139ca307 100644
--- a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java
+++ b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java
@@ -1007,6 +1007,7 @@ public final class ServiceLoader
{
static final String PREFIX = "META-INF/services/";
+ Set providerNames = new HashSet<>(); // to avoid duplicates
Enumeration configs;
Iterator pending;
Class> nextClass;
@@ -1016,7 +1017,7 @@ public final class ServiceLoader
/**
* Parse a single line from the given configuration file, adding the
- * name on the line to the names list.
+ * name on the line to set of names if not already seen.
*/
private int parseLine(URL u, BufferedReader r, int lc, Set names)
throws IOException
@@ -1041,7 +1042,9 @@ public final class ServiceLoader
if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
fail(service, u, lc, "Illegal provider-class name: " + ln);
}
- names.add(ln);
+ if (providerNames.add(ln)) {
+ names.add(ln);
+ }
}
return lc + 1;
}
@@ -1072,7 +1075,7 @@ public final class ServiceLoader
return true;
}
- Class> clazz = null;
+ Class> clazz;
do {
if (configs == null) {
try {
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java
index e95037c7b6e..0a78e71ed56 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java
@@ -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
@@ -59,7 +59,7 @@ public class JmodFile implements AutoCloseable {
bis.read(magic);
if (magic[0] != JMOD_MAGIC_NUMBER[0] ||
magic[1] != JMOD_MAGIC_NUMBER[1]) {
- throw new IOException("Invalid jmod file: " + file.toString());
+ throw new IOException("Invalid JMOD file: " + file.toString());
}
if (magic[2] > JMOD_MAJOR_VERSION ||
(magic[2] == JMOD_MAJOR_VERSION && magic[3] > JMOD_MINOR_VERSION)) {
@@ -130,6 +130,13 @@ public class JmodFile implements AutoCloseable {
return name;
}
+ /**
+ * Returns true if the entry is a directory in the JMOD file.
+ */
+ public boolean isDirectory() {
+ return zipEntry.isDirectory();
+ }
+
/**
* Returns the size of this entry.
*/
@@ -186,12 +193,12 @@ 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 || ze.isDirectory()) ? null : new Entry(ze);
+ return (ze != null) ? new Entry(ze) : null;
}
/**
* Opens an {@code InputStream} for reading the named entry of the given
- * section in this jmod file.
+ * section in this JMOD file.
*
* @throws IOException if the named entry is not found, or I/O error
* occurs when reading it
@@ -201,7 +208,7 @@ public class JmodFile implements AutoCloseable {
{
String entry = section.jmodDir() + "/" + name;
ZipEntry e = zipfile.getEntry(entry);
- if (e == null || e.isDirectory()) {
+ if (e == null) {
throw new IOException(name + " not found: " + file);
}
return zipfile.getInputStream(e);
@@ -217,11 +224,10 @@ public class JmodFile implements AutoCloseable {
}
/**
- * Returns a stream of non-directory entries in this jmod file.
+ * Returns a stream of entries in this JMOD file.
*/
public Stream stream() {
return zipfile.stream()
- .filter(e -> !e.isDirectory())
.map(Entry::new);
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java
index 4aed7a67285..12976035291 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java
@@ -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
@@ -65,14 +65,12 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
}
/**
- * Need FilePermission ${java.home}/-", "read" to create or get jrt:/
+ * Need RuntimePermission "accessSystemModules" to create or get jrt:/
*/
private void checkPermission() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
- String home = SystemImage.RUNTIME_HOME;
- FilePermission perm
- = new FilePermission(home + File.separator + "-", "read");
+ RuntimePermission perm = new RuntimePermission("accessSystemModules");
sm.checkPermission(perm);
}
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java
index f61b0716263..72148adb5bd 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java
@@ -95,6 +95,14 @@ public class BootLoader {
return CLASS_LOADER_VALUE_MAP;
}
+ /**
+ * Returns {@code true} if there is a class path associated with the
+ * BootLoader.
+ */
+ public static boolean hasClassPath() {
+ return ClassLoaders.bootLoader().hasClassPath();
+ }
+
/**
* Register a module with this class loader so that its classes (and
* resources) become visible via this class loader.
@@ -187,14 +195,6 @@ public class BootLoader {
.map(name -> getDefinedPackage(name.replace('/', '.')));
}
- /**
- * Returns {@code true} if there is a class path associated with the
- * BootLoader.
- */
- public static boolean hasClassPath() {
- return ClassLoaders.bootLoader().hasClassPath();
- }
-
/**
* Helper class to define {@code Package} objects for packages in modules
* defined to the boot loader.
diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java
index 77358ba8eeb..ce3bb67e8dd 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java
@@ -60,6 +60,7 @@ import java.util.stream.Stream;
import jdk.internal.misc.VM;
import jdk.internal.module.ModulePatcher.PatchedModuleReader;
import jdk.internal.module.SystemModules;
+import jdk.internal.module.Resources;
/**
@@ -162,6 +163,14 @@ public class BuiltinClassLoader
this.moduleToReader = new ConcurrentHashMap<>();
}
+ /**
+ * Returns {@code true} if there is a class path associated with this
+ * class loader.
+ */
+ boolean hasClassPath() {
+ return ucp != null;
+ }
+
/**
* Register a module this this class loader. This has the effect of making
* the types in the module visible.
@@ -248,18 +257,24 @@ public class BuiltinClassLoader
*/
@Override
public URL findResource(String name) {
- String pn = ResourceHelper.getPackageName(name);
+ String pn = Resources.toPackageName(name);
LoadedModule module = packageToModule.get(pn);
if (module != null) {
// resource is in a package of a module defined to this loader
- if (module.loader() == this
- && (name.endsWith(".class") || isOpen(module.mref(), pn))) {
+ if (module.loader() == this) {
+ URL url;
try {
- return findResource(module.name(), name); // checks URL
+ url = findResource(module.name(), name); // checks URL
} catch (IOException ioe) {
return null;
}
+ if (url != null
+ && (name.endsWith(".class")
+ || url.toString().endsWith("/")
+ || isOpen(module.mref(), pn))) {
+ return url;
+ }
}
} else {
@@ -293,15 +308,17 @@ public class BuiltinClassLoader
public Enumeration findResources(String name) throws IOException {
List checked = new ArrayList<>(); // list of checked URLs
- String pn = ResourceHelper.getPackageName(name);
+ String pn = Resources.toPackageName(name);
LoadedModule module = packageToModule.get(pn);
if (module != null) {
// resource is in a package of a module defined to this loader
- if (module.loader() == this
- && (name.endsWith(".class") || isOpen(module.mref(), pn))) {
- URL url = findResource(module.name(), name); // checks URL
- if (url != null) {
+ if (module.loader() == this) {
+ URL url = findResource(module.name(), name); // checks URL
+ if (url != null
+ && (name.endsWith(".class")
+ || url.toString().endsWith("/")
+ || isOpen(module.mref(), pn))) {
checked.add(url);
}
}
@@ -351,11 +368,13 @@ public class BuiltinClassLoader
new PrivilegedExceptionAction<>() {
@Override
public List run() throws IOException {
- List result = new ArrayList<>();
+ List result = null;
for (ModuleReference mref : nameToModule.values()) {
URI u = moduleReaderFor(mref).find(name).orElse(null);
if (u != null) {
try {
+ if (result == null)
+ result = new ArrayList<>();
result.add(u.toURL());
} catch (MalformedURLException |
IllegalArgumentException e) {
@@ -375,7 +394,7 @@ public class BuiltinClassLoader
map = new ConcurrentHashMap<>();
this.resourceCache = new SoftReference<>(map);
}
- if (urls.isEmpty())
+ if (urls == null)
urls = Collections.emptyList();
map.putIfAbsent(name, urls);
}
@@ -869,14 +888,6 @@ public class BuiltinClassLoader
sealBase);
}
- /**
- * Returns {@code true} if there is a class path associated with this
- * class loader.
- */
- boolean hasClassPath() {
- return ucp != null;
- }
-
/**
* Returns {@code true} if the specified package name is sealed according to
* the given manifest.
@@ -975,7 +986,7 @@ public class BuiltinClassLoader
*/
private boolean isOpen(ModuleReference mref, String pn) {
ModuleDescriptor descriptor = mref.descriptor();
- if (descriptor.isOpen())
+ if (descriptor.isOpen() || descriptor.isAutomatic())
return true;
for (ModuleDescriptor.Opens opens : descriptor.opens()) {
String source = opens.source();
diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java
index 04285cc4cf1..ca90e80a1ea 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java
@@ -60,6 +60,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.Resources;
/**
@@ -356,45 +357,52 @@ public final class Loader extends SecureClassLoader {
@Override
public URL findResource(String name) {
- URL url = null;
- String pn = ResourceHelper.getPackageName(name);
+ String pn = Resources.toPackageName(name);
LoadedModule module = localPackageToModule.get(pn);
+
if (module != null) {
- if (name.endsWith(".class") || isOpen(module.mref(), pn)) {
- try {
- url = findResource(module.name(), name);
- } catch (IOException ioe) {
- // ignore
+ try {
+ URL url = findResource(module.name(), name);
+ if (url != null
+ && (name.endsWith(".class")
+ || url.toString().endsWith("/")
+ || isOpen(module.mref(), pn))) {
+ return url;
}
+ } catch (IOException ioe) {
+ // ignore
}
+
} else {
for (ModuleReference mref : nameToModule.values()) {
try {
- url = findResource(mref.descriptor().name(), name);
- if (url != null)
- break;
+ URL url = findResource(mref.descriptor().name(), name);
+ if (url != null) return url;
} catch (IOException ioe) {
// ignore
}
}
}
- return url;
+
+ return null;
}
@Override
public Enumeration findResources(String name) throws IOException {
List urls = new ArrayList<>();
- String pn = ResourceHelper.getPackageName(name);
+ String pn = Resources.toPackageName(name);
LoadedModule module = localPackageToModule.get(pn);
if (module != null) {
- if (name.endsWith(".class") || isOpen(module.mref(), pn)) {
- try {
- URL url = findResource(module.name(), name);
- if (url != null)
- urls.add(url);
- } catch (IOException ioe) {
- // ignore
+ try {
+ URL url = findResource(module.name(), name);
+ if (url != null
+ && (name.endsWith(".class")
+ || url.toString().endsWith("/")
+ || isOpen(module.mref(), pn))) {
+ urls.add(url);
}
+ } catch (IOException ioe) {
+ // ignore
}
} else {
for (ModuleReference mref : nameToModule.values()) {
@@ -643,7 +651,7 @@ public final class Loader extends SecureClassLoader {
*/
private boolean isOpen(ModuleReference mref, String pn) {
ModuleDescriptor descriptor = mref.descriptor();
- if (descriptor.isOpen())
+ if (descriptor.isOpen() || descriptor.isAutomatic())
return true;
for (ModuleDescriptor.Opens opens : descriptor.opens()) {
String source = opens.source();
diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java b/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java
deleted file mode 100644
index 18a42b7b6f3..00000000000
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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
- * 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 jdk.internal.loader;
-
-import java.io.File;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import jdk.internal.module.Checks;
-
-/**
- * Helper class for Class#getResource, Module#getResourceAsStream, and other
- * methods that locate a resource in a module.
- */
-public final class ResourceHelper {
- private ResourceHelper() { }
-
- /**
- * Returns the package name 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('/');
- if (index != -1) {
- return name.substring(0, index).replace("/", ".");
- } else {
- return "";
- }
- }
-
- /**
- * Returns true if the resource is a simple resource. 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.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;
- }
-
-}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java
index 7cb2c1e74a4..5d5e27d3e2b 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java
@@ -33,6 +33,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Module;
import java.net.URL;
import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
@@ -149,6 +150,11 @@ public interface JavaLangAccess {
*/
ConcurrentHashMap, ?> createOrGetClassLoaderValueMap(ClassLoader cl);
+ /**
+ * Defines a class with the given name to a class loader.
+ */
+ Class> defineClass(ClassLoader cl, String name, byte[] b, ProtectionDomain pd, String source);
+
/**
* Returns a class loaded by the bootstrap class loader.
*/
diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java
index 53e8b4c82c7..9ad1d5cf0ef 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java
@@ -73,7 +73,7 @@ public interface JavaLangModuleAccess {
void requires(ModuleDescriptor.Builder builder,
Set ms,
String mn,
- String compiledVersion);
+ String rawCompiledVersion);
/**
* Returns a {@code ModuleDescriptor.Requires} of the given modifiers
@@ -127,9 +127,6 @@ public interface JavaLangModuleAccess {
Set provides,
Set packages,
String mainClass,
- String osName,
- String osArch,
- String osVersion,
int hashCode);
/**
diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java
index 7bf6a1f3977..c8a2039d3ce 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java
@@ -65,6 +65,11 @@ public interface JavaLangReflectModuleAccess {
*/
void addReadsAllUnnamed(Module m);
+ /**
+ * Update module m to export a package to all modules.
+ */
+ void addExports(Module m, String pn);
+
/**
* Updates module m1 to export a package to module m2. The export does
* not result in a strong reference to m2 (m2 can be GC'ed).
@@ -72,25 +77,20 @@ public interface JavaLangReflectModuleAccess {
void addExports(Module m1, String pkg, Module m2);
/**
- * Updates module m1 to open a package to module m2. Opening the
- * package does not result in a strong reference to m2 (m2 can be GC'ed).
+ * Updates a module m to export a package to all unnamed modules.
*/
- void addOpens(Module m1, String pkg, Module m2);
-
- /**
- * Updates a module m to export a package to all modules.
- */
- void addExportsToAll(Module m, String pkg);
+ void addExportsToAllUnnamed(Module m, String pkg);
/**
* Updates a module m to open a package to all modules.
*/
- void addOpensToAll(Module m, String pkg);
+ void addOpens(Module m, String pkg);
/**
- * Updates a module m to export a package to all unnamed modules.
+ * Updates module m1 to open a package to module m2. Opening the
+ * package does not result in a strong reference to m2 (m2 can be GC'ed).
*/
- void addExportsToAllUnnamed(Module m, String pkg);
+ void addOpens(Module m1, String pkg, Module m2);
/**
* Updates a module m to open a package to all unnamed modules.
@@ -102,11 +102,6 @@ public interface JavaLangReflectModuleAccess {
*/
void addUses(Module m, Class> service);
- /**
- * Add a package to the given module.
- */
- void addPackage(Module m, String pkg);
-
/**
* Returns the ServicesCatalog for the given Layer.
*/
@@ -123,12 +118,4 @@ public interface JavaLangReflectModuleAccess {
* given class loader.
*/
Stream layers(ClassLoader loader);
-
- /**
- * Tests if a module exports a package at least {@code other} via its
- * module declaration.
- *
- * @apiNote This is a temporary method for debugging features.
- */
- boolean isStaticallyExported(Module module, String pn, Module other);
}
\ No newline at end of file
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java
index 9196f39ff77..2792ccca19f 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java
@@ -145,9 +145,6 @@ final class Builder {
Set provides;
Version version;
String mainClass;
- String osName;
- String osArch;
- String osVersion;
Builder(String name) {
this.name = name;
@@ -247,30 +244,6 @@ final class Builder {
return this;
}
- /**
- * Sets the OS name.
- */
- public Builder osName(String name) {
- this.osName = name;
- return this;
- }
-
- /**
- * Sets the OS arch.
- */
- public Builder osArch(String arch) {
- this.osArch = arch;
- return this;
- }
-
- /**
- * Sets the OS version.
- */
- public Builder osVersion(String version) {
- this.osVersion = version;
- return this;
- }
-
/**
* Returns an immutable set of the module modifiers derived from the flags.
*/
@@ -305,9 +278,6 @@ final class Builder {
provides,
packages,
mainClass,
- osName,
- osArch,
- osVersion,
hashCode);
}
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java
index e19e6528ce0..32712834c0a 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java
@@ -180,41 +180,38 @@ public final class Checks {
}
/**
- * Returns {@code true} if the last character of the given name is legal
- * as the last character of a module name.
- *
- * @throws IllegalArgumentException if name is empty
+ * Returns {@code true} if a given legal module name contains an identifier
+ * that doesn't end with a Java letter.
*/
- public static boolean hasLegalModuleNameLastCharacter(String name) {
- if (name.isEmpty())
- throw new IllegalArgumentException("name is empty");
- int len = name.length();
- if (isASCIIString(name)) {
- char c = name.charAt(len-1);
- return Character.isJavaIdentifierStart(c);
- } else {
- int i = 0;
- int cp = -1;
- while (i < len) {
- cp = name.codePointAt(i);
- i += Character.charCount(cp);
- }
- return Character.isJavaIdentifierStart(cp);
- }
- }
-
- /**
- * Returns true if the given string only contains ASCII characters.
- */
- private static boolean isASCIIString(String s) {
+ public static boolean hasJavaIdentifierWithTrailingDigit(String name) {
+ // quick scan to allow names that are just ASCII without digits
+ boolean needToParse = false;
int i = 0;
- while (i < s.length()) {
- int c = s.charAt(i);
- if (c > 0x7F)
- return false;
+ while (i < name.length()) {
+ int c = name.charAt(i);
+ if (c > 0x7F || (c >= '0' && c <= '9')) {
+ needToParse = true;
+ break;
+ }
i++;
}
- return true;
+ if (!needToParse)
+ return false;
+
+ // slow path
+ int next;
+ int off = 0;
+ while ((next = name.indexOf('.', off)) != -1) {
+ int last = isJavaIdentifier(name, off, (next - off));
+ if (!Character.isJavaIdentifierStart(last))
+ return true;
+ off = next+1;
+ }
+ int last = isJavaIdentifier(name, off, name.length() - off);
+ if (!Character.isJavaIdentifierStart(last))
+ return true;
+ return false;
+
}
/**
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java
index fc3c3904850..6d8816237dd 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java
@@ -292,11 +292,11 @@ public final class ClassFileAttributes {
attr.putShort(module_flags);
// module_version
- Version v = descriptor.version().orElse(null);
- if (v == null) {
+ String vs = descriptor.rawVersion().orElse(null);
+ if (vs == null) {
attr.putShort(0);
} else {
- int module_version_index = cw.newUTF8(v.toString());
+ int module_version_index = cw.newUTF8(vs);
attr.putShort(module_version_index);
}
@@ -320,11 +320,11 @@ public final class ClassFileAttributes {
attr.putShort(requires_flags);
int requires_version_index;
- v = r.compiledVersion().orElse(null);
- if (v == null) {
+ vs = r.rawCompiledVersion().orElse(null);
+ if (vs == null) {
requires_version_index = 0;
} else {
- requires_version_index = cw.newUTF8(v.toString());
+ requires_version_index = cw.newUTF8(vs);
}
attr.putShort(requires_version_index);
}
@@ -553,8 +553,6 @@ public final class ClassFileAttributes {
* u2 os_name_index;
* // index to CONSTANT_utf8_info structure with the OS arch
* u2 os_arch_index
- * // index to CONSTANT_utf8_info structure with the OS version
- * u2 os_version_index;
* }
*
* }
@@ -562,17 +560,23 @@ public final class ClassFileAttributes {
public static class ModuleTargetAttribute extends Attribute {
private final String osName;
private final String osArch;
- private final String osVersion;
- public ModuleTargetAttribute(String osName, String osArch, String osVersion) {
+ public ModuleTargetAttribute(String osName, String osArch) {
super(MODULE_TARGET);
this.osName = osName;
this.osArch = osArch;
- this.osVersion = osVersion;
}
public ModuleTargetAttribute() {
- this(null, null, null);
+ this(null, null);
+ }
+
+ public String osName() {
+ return osName;
+ }
+
+ public String osArch() {
+ return osArch;
}
@Override
@@ -586,7 +590,6 @@ public final class ClassFileAttributes {
String osName = null;
String osArch = null;
- String osVersion = null;
int name_index = cr.readUnsignedShort(off);
if (name_index != 0)
@@ -598,12 +601,7 @@ public final class ClassFileAttributes {
osArch = cr.readUTF8(off, buf);
off += 2;
- int version_index = cr.readUnsignedShort(off);
- if (version_index != 0)
- osVersion = cr.readUTF8(off, buf);
- off += 2;
-
- return new ModuleTargetAttribute(osName, osArch, osVersion);
+ return new ModuleTargetAttribute(osName, osArch);
}
@Override
@@ -625,11 +623,6 @@ public final class ClassFileAttributes {
arch_index = cw.newUTF8(osArch);
attr.putShort(arch_index);
- int version_index = 0;
- if (osVersion != null && osVersion.length() > 0)
- version_index = cw.newUTF8(osVersion);
- attr.putShort(version_index);
-
return attr;
}
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/IllegalAccessLogger.java b/jdk/src/java.base/share/classes/jdk/internal/module/IllegalAccessLogger.java
new file mode 100644
index 00000000000..23e3ed2a7a0
--- /dev/null
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/IllegalAccessLogger.java
@@ -0,0 +1,318 @@
+/*
+ * 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 jdk.internal.module;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Module;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+/**
+ * Supports logging of access to members of API packages that are exported or
+ * opened via backdoor mechanisms to code in unnamed modules.
+ */
+
+public final class IllegalAccessLogger {
+
+ // true to print stack trace
+ private static final boolean PRINT_STACK_TRACE;
+ static {
+ String s = System.getProperty("sun.reflect.debugModuleAccessChecks");
+ PRINT_STACK_TRACE = "access".equals(s);
+ }
+
+ private static final StackWalker STACK_WALKER
+ = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
+
+ // the maximum number of frames to capture
+ private static final int MAX_STACK_FRAMES = 32;
+
+ // lock to avoid interference when printing stack traces
+ private static final Object OUTPUT_LOCK = new Object();
+
+ // caller -> usages
+ private final Map, Set> callerToUsages = new WeakHashMap<>();
+
+ // module -> (package name -> CLI option)
+ private final Map> exported;
+ private final Map> opened;
+
+ private IllegalAccessLogger(Map> exported,
+ Map> opened) {
+ this.exported = deepCopy(exported);
+ this.opened = deepCopy(opened);
+ }
+
+ /**
+ * Returns that a Builder that is seeded with the packages known to this logger.
+ */
+ public Builder toBuilder() {
+ return new Builder(exported, opened);
+ }
+
+ /**
+ * Logs access to the member of a target class by a caller class if the class
+ * is in a package that is exported via a backdoor mechanism.
+ *
+ * The {@code whatSupplier} supplies the message that describes the member.
+ */
+ public void logIfExportedByBackdoor(Class> caller,
+ Class> target,
+ Supplier whatSupplier) {
+ Map packages = exported.get(target.getModule());
+ if (packages != null) {
+ String how = packages.get(target.getPackageName());
+ if (how != null) {
+ log(caller, whatSupplier.get(), how);
+ }
+ }
+ }
+
+ /**
+ * Logs access to the member of a target class by a caller class if the class
+ * is in a package that is opened via a backdoor mechanism.
+ *
+ * The {@code what} parameter supplies the message that describes the member.
+ */
+ public void logIfOpenedByBackdoor(Class> caller,
+ Class> target,
+ Supplier whatSupplier) {
+ Map packages = opened.get(target.getModule());
+ if (packages != null) {
+ String how = packages.get(target.getPackageName());
+ if (how != null) {
+ log(caller, whatSupplier.get(), how);
+ }
+ }
+ }
+
+ /**
+ * Logs access by a caller class. The {@code what} parameter describes
+ * the member is accessed, the {@code how} parameter is the means by which
+ * access is allocated (CLI option for example).
+ */
+ private void log(Class> caller, String what, String how) {
+ log(caller, what, () -> {
+ PrivilegedAction pa = caller::getProtectionDomain;
+ CodeSource cs = AccessController.doPrivileged(pa).getCodeSource();
+ URL url = (cs != null) ? cs.getLocation() : null;
+ String source = caller.getName();
+ if (url != null)
+ source += " (" + url + ")";
+ return "WARNING: Illegal access by " + source + " to " + what
+ + " (permitted by " + how + ")";
+ });
+ }
+
+
+ /**
+ * Logs access to caller class if the class is in a package that is opened via
+ * a backdoor mechanism.
+ */
+ public void logIfOpenedByBackdoor(MethodHandles.Lookup caller, Class> target) {
+ Map packages = opened.get(target.getModule());
+ if (packages != null) {
+ String how = packages.get(target.getPackageName());
+ if (how != null) {
+ log(caller.lookupClass(), target.getName(), () ->
+ "WARNING: Illegal access using Lookup on " + caller.lookupClass()
+ + " to " + target + " (permitted by " + how + ")");
+ }
+ }
+ }
+
+ /**
+ * Log access by a caller. The {@code what} parameter describes the class or
+ * member that is being accessed. The {@code msgSupplier} supplies the log
+ * message.
+ *
+ * To reduce output, this method only logs the access if it hasn't been seen
+ * previously. "Seen previously" is implemented as a map of caller class -> Usage,
+ * where a Usage is the "what" and a hash of the stack trace. The map has weak
+ * keys so it can be expunged when the caller is GC'ed/unloaded.
+ */
+ private void log(Class> caller, String what, Supplier msgSupplier) {
+ // stack trace without the top-most frames in java.base
+ List stack = STACK_WALKER.walk(s ->
+ s.dropWhile(this::isJavaBase)
+ .limit(MAX_STACK_FRAMES)
+ .collect(Collectors.toList())
+ );
+
+ // check if the access has already been recorded
+ Usage u = new Usage(what, hash(stack));
+ boolean firstUsage;
+ synchronized (this) {
+ firstUsage = callerToUsages.computeIfAbsent(caller, k -> new HashSet<>()).add(u);
+ }
+
+ // log message if first usage
+ if (firstUsage) {
+ String msg = msgSupplier.get();
+ if (PRINT_STACK_TRACE) {
+ synchronized (OUTPUT_LOCK) {
+ System.err.println(msg);
+ stack.forEach(f -> System.err.println("\tat " + f));
+ }
+ } else {
+ System.err.println(msg);
+ }
+ }
+ }
+
+ private static class Usage {
+ private final String what;
+ private final int stack;
+ Usage(String what, int stack) {
+ this.what = what;
+ this.stack = stack;
+ }
+ @Override
+ public int hashCode() {
+ return what.hashCode() ^ stack;
+ }
+ @Override
+ public boolean equals(Object ob) {
+ if (ob instanceof Usage) {
+ Usage that = (Usage)ob;
+ return what.equals(that.what) && stack == (that.stack);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Returns true if the stack frame is for a class in java.base.
+ */
+ private boolean isJavaBase(StackWalker.StackFrame frame) {
+ Module caller = frame.getDeclaringClass().getModule();
+ return "java.base".equals(caller.getName());
+ }
+
+ /**
+ * Computes a hash code for the give stack frames. The hash code is based
+ * on the class, method name, and BCI.
+ */
+ private int hash(List stack) {
+ int hash = 0;
+ for (StackWalker.StackFrame frame : stack) {
+ hash = (31 * hash) + Objects.hash(frame.getDeclaringClass(),
+ frame.getMethodName(),
+ frame.getByteCodeIndex());
+ }
+ return hash;
+ }
+
+ // system-wide IllegalAccessLogger
+ private static volatile IllegalAccessLogger logger;
+
+ /**
+ * Sets the system-wide IllegalAccessLogger
+ */
+ public static void setIllegalAccessLogger(IllegalAccessLogger l) {
+ if (l.exported.isEmpty() && l.opened.isEmpty()) {
+ logger = null;
+ } else {
+ logger = l;
+ }
+ }
+
+ /**
+ * Returns the system-wide IllegalAccessLogger or {@code null} if there is
+ * no logger.
+ */
+ public static IllegalAccessLogger illegalAccessLogger() {
+ return logger;
+ }
+
+ /**
+ * A builder for IllegalAccessLogger objects.
+ */
+ public static class Builder {
+ private Map> exported;
+ private Map> opened;
+
+ public Builder() { }
+
+ public Builder(Map> exported,
+ Map> opened) {
+ this.exported = deepCopy(exported);
+ this.opened = deepCopy(opened);
+ }
+
+ public void logAccessToExportedPackage(Module m, String pn, String how) {
+ if (!m.isExported(pn)) {
+ if (exported == null)
+ exported = new HashMap<>();
+ exported.computeIfAbsent(m, k -> new HashMap<>()).putIfAbsent(pn, how);
+ }
+ }
+
+ public void logAccessToOpenPackage(Module m, String pn, String how) {
+ // opens implies exported at run-time.
+ logAccessToExportedPackage(m, pn, how);
+
+ if (!m.isOpen(pn)) {
+ if (opened == null)
+ opened = new HashMap<>();
+ opened.computeIfAbsent(m, k -> new HashMap<>()).putIfAbsent(pn, how);
+ }
+ }
+
+ /**
+ * Builds the logger.
+ */
+ public IllegalAccessLogger build() {
+ return new IllegalAccessLogger(exported, opened);
+ }
+ }
+
+
+ static Map> deepCopy(Map> map) {
+ if (map == null || map.isEmpty()) {
+ return new HashMap<>();
+ } else {
+ Map> newMap = new HashMap<>();
+ for (Map.Entry> e : map.entrySet()) {
+ newMap.put(e.getKey(), new HashMap<>(e.getValue()));
+ }
+ return newMap;
+ }
+ }
+}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
index b2c1b4b3548..0136da0f581 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
@@ -33,6 +33,7 @@ import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
import java.lang.module.ResolvedModule;
import java.lang.reflect.Layer;
+import java.lang.reflect.LayerInstantiationException;
import java.lang.reflect.Module;
import java.net.URI;
import java.nio.file.Path;
@@ -46,7 +47,6 @@ 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;
@@ -327,8 +327,9 @@ public final class ModuleBootstrap {
for (String p : descriptor.packages()) {
String other = packageToModule.putIfAbsent(p, name);
if (other != null) {
- fail("Package " + p + " in both module "
- + name + " and module " + other);
+ String msg = "Package " + p + " in both module "
+ + name + " and module " + other;
+ throw new LayerInstantiationException(msg);
}
}
}
@@ -359,7 +360,7 @@ public final class ModuleBootstrap {
PerfCounters.loadModulesTime.addElapsedTimeFrom(t5);
- // --add-reads, -add-exports/-add-opens
+ // --add-reads, --add-exports/--add-opens
addExtraReads(bootLayer);
addExtraExportsAndOpens(bootLayer);
@@ -514,26 +515,44 @@ public final class ModuleBootstrap {
* additional packages specified on the command-line.
*/
private static void addExtraExportsAndOpens(Layer bootLayer) {
+ IllegalAccessLogger.Builder builder = new IllegalAccessLogger.Builder();
// --add-exports
String prefix = "jdk.module.addexports.";
Map> extraExports = decode(prefix);
if (!extraExports.isEmpty()) {
- addExtraExportsOrOpens(bootLayer, extraExports, false);
+ addExtraExportsOrOpens(bootLayer, extraExports, false, builder);
}
// --add-opens
prefix = "jdk.module.addopens.";
Map> extraOpens = decode(prefix);
if (!extraOpens.isEmpty()) {
- addExtraExportsOrOpens(bootLayer, extraOpens, true);
+ addExtraExportsOrOpens(bootLayer, extraOpens, true, builder);
}
+ // --permit-illegal-access
+ if (getAndRemoveProperty("jdk.module.permitIllegalAccess") != null) {
+ warn("--permit-illegal-access will be removed in the next major release");
+ bootLayer.modules().stream().forEach(m -> {
+ m.getDescriptor()
+ .packages()
+ .stream()
+ .filter(pn -> !m.isOpen(pn))
+ .forEach(pn -> {
+ builder.logAccessToOpenPackage(m, pn, "--permit-illegal-access");
+ Modules.addOpensToAllUnnamed(m, pn);
+ });
+ });
+ }
+
+ IllegalAccessLogger.setIllegalAccessLogger(builder.build());
}
private static void addExtraExportsOrOpens(Layer bootLayer,
Map> map,
- boolean opens)
+ boolean opens,
+ IllegalAccessLogger.Builder builder)
{
String option = opens ? ADD_OPENS : ADD_EXPORTS;
for (Map.Entry> e : map.entrySet()) {
@@ -542,12 +561,12 @@ public final class ModuleBootstrap {
String key = e.getKey();
String[] s = key.split("/");
if (s.length != 2)
- fail(unableToParse(option, "/", key));
+ fail(unableToParse(option, "/", key));
String mn = s[0];
String pn = s[1];
if (mn.isEmpty() || pn.isEmpty())
- fail(unableToParse(option, "/", key));
+ fail(unableToParse(option, "/", key));
// The exporting module is in the boot layer
Module m;
@@ -581,8 +600,10 @@ public final class ModuleBootstrap {
}
if (allUnnamed) {
if (opens) {
+ builder.logAccessToOpenPackage(m, pn, option);
Modules.addOpensToAllUnnamed(m, pn);
} else {
+ builder.logAccessToExportedPackage(m, pn, option);
Modules.addExportsToAllUnnamed(m, pn);
}
} else {
@@ -632,7 +653,7 @@ public final class ModuleBootstrap {
// value is (,)* or ()*
if (!allowDuplicates && map.containsKey(key))
- fail(key + " specified more than once in " + option(prefix));
+ fail(key + " specified more than once to " + option(prefix));
List values = map.computeIfAbsent(key, k -> new ArrayList<>());
int ntargets = 0;
for (String s : rhs.split(regex)) {
@@ -676,10 +697,6 @@ public final class ModuleBootstrap {
ModuleReference mref = rm.reference();
String mn = mref.descriptor().name();
- // emit warning if module name ends with a non-Java letter
- if (!Checks.hasLegalModuleNameLastCharacter(mn))
- warn("Module name \"" + mn + "\" may soon be illegal");
-
// emit warning if the WARN_INCUBATING module resolution bit set
if (ModuleResolution.hasIncubatingWarning(mref)) {
if (incubating == null) {
@@ -705,7 +722,7 @@ public final class ModuleBootstrap {
}
static void warnUnknownModule(String option, String mn) {
- warn("Unknown module: " + mn + " specified in " + option);
+ warn("Unknown module: " + mn + " specified to " + option);
}
static String unableToParse(String option, String text, String value) {
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java
index b58c717affe..b589e2923f0 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java
@@ -89,18 +89,24 @@ public final class ModuleInfo {
*/
public static final class Attributes {
private final ModuleDescriptor descriptor;
+ private final ModuleTarget target;
private final ModuleHashes recordedHashes;
private final ModuleResolution moduleResolution;
Attributes(ModuleDescriptor descriptor,
+ ModuleTarget target,
ModuleHashes recordedHashes,
ModuleResolution moduleResolution) {
this.descriptor = descriptor;
+ this.target = target;
this.recordedHashes = recordedHashes;
this.moduleResolution = moduleResolution;
}
public ModuleDescriptor descriptor() {
return descriptor;
}
+ public ModuleTarget target() {
+ return target;
+ }
public ModuleHashes recordedHashes() {
return recordedHashes;
}
@@ -221,8 +227,8 @@ public final class ModuleInfo {
Builder builder = null;
Set allPackages = null;
String mainClass = null;
- String[] osValues = null;
- ModuleHashes hashes = null;
+ ModuleTarget moduleTarget = null;
+ ModuleHashes moduelHashes = null;
ModuleResolution moduleResolution = null;
for (int i = 0; i < attributes_count ; i++) {
@@ -251,12 +257,12 @@ public final class ModuleInfo {
break;
case MODULE_TARGET :
- osValues = readModuleTargetAttribute(in, cpool);
+ moduleTarget = readModuleTargetAttribute(in, cpool);
break;
case MODULE_HASHES :
if (parseHashes) {
- hashes = readModuleHashesAttribute(in, cpool);
+ moduelHashes = readModuleHashesAttribute(in, cpool);
} else {
in.skipBytes(length);
}
@@ -282,15 +288,10 @@ public final class ModuleInfo {
throw invalidModuleDescriptor(MODULE + " attribute not found");
}
- // ModuleMainClass and ModuleTarget attributes
+ // ModuleMainClass attribute
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
@@ -323,7 +324,10 @@ public final class ModuleInfo {
}
ModuleDescriptor descriptor = builder.build();
- return new Attributes(descriptor, hashes, moduleResolution);
+ return new Attributes(descriptor,
+ moduleTarget,
+ moduelHashes,
+ moduleResolution);
}
/**
@@ -422,7 +426,11 @@ public final class ModuleInfo {
Set targets = new HashSet<>(exports_to_count);
for (int j=0; j targets = new HashSet<>(open_to_count);
for (int j=0; j cw.visitAttribute(new ModuleMainClassAttribute(mc)));
- // write ModuleTarget attribute if have any of OS name/arch/version
- String osName = md.osName().orElse(null);
- String osArch = md.osArch().orElse(null);
- String osVersion = md.osVersion().orElse(null);
- if (osName != null || osArch != null || osVersion != null) {
- cw.visitAttribute(new ModuleTargetAttribute(osName, osArch, osVersion));
+ // write ModuleTarget if there is a platform OS/arch
+ if (target != null) {
+ cw.visitAttribute(new ModuleTargetAttribute(target.osName(),
+ target.osArch()));
}
cw.visitEnd();
return cw.toByteArray();
}
+ /**
+ * Writes a module descriptor to the given output stream as a
+ * module-info.class.
+ */
+ public static void write(ModuleDescriptor descriptor,
+ ModuleTarget target,
+ OutputStream out)
+ throws IOException
+ {
+ byte[] bytes = toModuleInfo(descriptor, target);
+ out.write(bytes);
+ }
+
/**
* Writes a module descriptor to the given output stream as a
* module-info.class.
@@ -85,8 +96,7 @@ public final class ModuleInfoWriter {
public static void write(ModuleDescriptor descriptor, OutputStream out)
throws IOException
{
- byte[] bytes = toModuleInfo(descriptor);
- out.write(bytes);
+ write(descriptor, null, out);
}
/**
@@ -94,8 +104,7 @@ public final class ModuleInfoWriter {
* in module-info.class format.
*/
public static ByteBuffer toByteBuffer(ModuleDescriptor descriptor) {
- byte[] bytes = toModuleInfo(descriptor);
+ byte[] bytes = toModuleInfo(descriptor, null);
return ByteBuffer.wrap(bytes);
}
-
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java
index fe3f8930ad2..5321d2a36d3 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java
@@ -55,7 +55,6 @@ 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;
@@ -165,9 +164,6 @@ public final class ModulePatcher {
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());
@@ -179,10 +175,12 @@ public final class ModulePatcher {
// return a module reference to the patched module
URI location = mref.location().orElse(null);
+ ModuleTarget target = null;
ModuleHashes recordedHashes = null;
ModuleResolution mres = null;
if (mref instanceof ModuleReferenceImpl) {
ModuleReferenceImpl impl = (ModuleReferenceImpl)mref;
+ target = impl.moduleTarget();
recordedHashes = impl.recordedHashes();
mres = impl.moduleResolution();
}
@@ -191,6 +189,7 @@ public final class ModulePatcher {
location,
() -> new PatchedModuleReader(paths, mref),
this,
+ target,
recordedHashes,
null,
mres);
@@ -226,7 +225,7 @@ public final class ModulePatcher {
private volatile ModuleReader delegate;
/**
- * Creates the ModuleReader to reads resources a patched module.
+ * Creates the ModuleReader to reads resources in a patched module.
*/
PatchedModuleReader(List patches, ModuleReference mref) {
List finders = new ArrayList<>();
@@ -291,13 +290,16 @@ public final class ModulePatcher {
}
/**
- * Finds a resources in the patch locations. Returns null if not found.
+ * Finds a resources in the patch locations. Returns null if not found
+ * or the name is "module-info.class" as that cannot be overridden.
*/
private Resource findResourceInPatch(String name) throws IOException {
- for (ResourceFinder finder : finders) {
- Resource r = finder.find(name);
- if (r != null)
- return r;
+ if (!name.equals("module-info.class")) {
+ for (ResourceFinder finder : finders) {
+ Resource r = finder.find(name);
+ if (r != null)
+ return r;
+ }
}
return null;
}
@@ -478,9 +480,7 @@ public final class ModulePatcher {
@Override
public Stream list() throws IOException {
- return jf.stream()
- .filter(e -> !e.isDirectory())
- .map(JarEntry::getName);
+ return jf.stream().map(JarEntry::getName);
}
}
@@ -500,14 +500,12 @@ public final class ModulePatcher {
@Override
public Resource find(String name) throws IOException {
- Path path = ResourceHelper.toFilePath(name);
- if (path != null) {
- Path file = dir.resolve(path);
- if (Files.isRegularFile(file)) {
- return newResource(name, dir, file);
- }
+ Path file = Resources.toFilePath(dir, name);
+ if (file != null) {
+ return newResource(name, dir, file);
+ } else {
+ return null;
}
- return null;
}
private Resource newResource(String name, Path top, Path file) {
@@ -550,11 +548,9 @@ public final class ModulePatcher {
@Override
public Stream list() throws IOException {
- return Files.find(dir, Integer.MAX_VALUE,
- (path, attrs) -> attrs.isRegularFile())
- .map(f -> dir.relativize(f)
- .toString()
- .replace(File.separatorChar, '/'));
+ return Files.walk(dir, Integer.MAX_VALUE)
+ .map(f -> Resources.toResourceName(dir, f))
+ .filter(s -> s.length() > 0);
}
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java
index ae337423965..89e81d178f7 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java
@@ -513,7 +513,7 @@ public class ModulePath implements ModuleFinder {
String pn = packageName(cn);
if (!packages.contains(pn)) {
String msg = "Provider class " + cn + " not in module";
- throw new IOException(msg);
+ throw new InvalidModuleDescriptorException(msg);
}
providerClasses.add(cn);
}
@@ -533,7 +533,7 @@ public class ModulePath implements ModuleFinder {
String pn = packageName(mainClass);
if (!packages.contains(pn)) {
String msg = "Main-Class " + mainClass + " not in module";
- throw new IOException(msg);
+ throw new InvalidModuleDescriptorException(msg);
}
builder.mainClass(mainClass);
}
@@ -609,11 +609,10 @@ public class ModulePath implements ModuleFinder {
// no module-info.class so treat it as automatic module
try {
ModuleDescriptor md = deriveModuleDescriptor(jf);
- attrs = new ModuleInfo.Attributes(md, null, null);
- } catch (IllegalArgumentException e) {
- throw new FindException(
- "Unable to derive module descriptor for: "
- + jf.getName(), e);
+ attrs = new ModuleInfo.Attributes(md, null, null, null);
+ } catch (RuntimeException e) {
+ throw new FindException("Unable to derive module descriptor for "
+ + jf.getName(), e);
}
} else {
@@ -672,18 +671,18 @@ public class ModulePath implements ModuleFinder {
/**
* Maps the name of an entry in a JAR or ZIP file to a package name.
*
- * @throws IllegalArgumentException if the name is a class file in
- * the top-level directory of the JAR/ZIP file (and it's
- * not module-info.class)
+ * @throws InvalidModuleDescriptorException if the name is a class file in
+ * the top-level directory of the JAR/ZIP file (and it's not
+ * module-info.class)
*/
private Optional toPackageName(String name) {
assert !name.endsWith("/");
int index = name.lastIndexOf("/");
if (index == -1) {
if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
- throw new IllegalArgumentException(name
- + " found in top-level directory"
- + " (unnamed package not allowed in module)");
+ String msg = name + " found in top-level directory"
+ + " (unnamed package not allowed in module)";
+ throw new InvalidModuleDescriptorException(msg);
}
return Optional.empty();
}
@@ -701,8 +700,8 @@ public class ModulePath implements ModuleFinder {
* Maps the relative path of an entry in an exploded module to a package
* name.
*
- * @throws IllegalArgumentException if the name is a class file in
- * the top-level directory (and it's not module-info.class)
+ * @throws InvalidModuleDescriptorException if the name is a class file in
+ * the top-level directory (and it's not module-info.class)
*/
private Optional toPackageName(Path file) {
assert file.getRoot() == null;
@@ -711,9 +710,9 @@ public class ModulePath implements ModuleFinder {
if (parent == null) {
String name = file.toString();
if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
- throw new IllegalArgumentException(name
- + " found in top-level directory"
- + " (unnamed package not allowed in module)");
+ String msg = name + " found in top-level directory"
+ + " (unnamed package not allowed in module)";
+ throw new InvalidModuleDescriptorException(msg);
}
return Optional.empty();
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java
index f861b294aef..002930907ba 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java
@@ -46,6 +46,9 @@ public class ModuleReferenceImpl extends ModuleReference {
// non-null if the module is patched
private final ModulePatcher patcher;
+ // ModuleTarget if the module is OS/architecture specific
+ private final ModuleTarget target;
+
// the hashes of other modules recorded in this module
private final ModuleHashes recordedHashes;
@@ -65,6 +68,7 @@ public class ModuleReferenceImpl extends ModuleReference {
URI location,
Supplier readerSupplier,
ModulePatcher patcher,
+ ModuleTarget target,
ModuleHashes recordedHashes,
ModuleHashes.HashSupplier hasher,
ModuleResolution moduleResolution)
@@ -72,6 +76,7 @@ public class ModuleReferenceImpl extends ModuleReference {
super(descriptor, Objects.requireNonNull(location));
this.readerSupplier = readerSupplier;
this.patcher = patcher;
+ this.target = target;
this.recordedHashes = recordedHashes;
this.hasher = hasher;
this.moduleResolution = moduleResolution;
@@ -93,6 +98,13 @@ public class ModuleReferenceImpl extends ModuleReference {
return (patcher != null);
}
+ /**
+ * Returns the ModuleTarget or {@code null} if the no target platform.
+ */
+ public ModuleTarget moduleTarget() {
+ return target;
+ }
+
/**
* Returns the hashes recorded in this module or {@code null} if there
* are no hashes recorded.
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java
index 2e2af727599..450cc5ce6d2 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java
@@ -25,7 +25,6 @@
package jdk.internal.module;
-import java.io.File;
import java.io.IOError;
import java.io.IOException;
import java.io.InputStream;
@@ -50,7 +49,6 @@ import java.util.stream.Stream;
import java.util.zip.ZipFile;
import jdk.internal.jmod.JmodFile;
-import jdk.internal.loader.ResourceHelper;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.module.ModuleHashes.HashSupplier;
import jdk.internal.util.jar.VersionedStream;
@@ -78,6 +76,7 @@ class ModuleReferences {
uri,
supplier,
null,
+ attrs.target(),
attrs.recordedHashes(),
hasher,
attrs.moduleResolution());
@@ -242,8 +241,7 @@ class ModuleReferences {
}
private JarEntry getEntry(String name) {
- JarEntry entry = jf.getJarEntry(Objects.requireNonNull(name));
- return (entry == null || entry.isDirectory()) ? null : entry;
+ return jf.getJarEntry(Objects.requireNonNull(name));
}
@Override
@@ -252,6 +250,8 @@ class ModuleReferences {
if (je != null) {
if (jf.isMultiRelease())
name = SharedSecrets.javaUtilJarAccess().getRealName(jf, je);
+ if (je.isDirectory() && !name.endsWith("/"))
+ name += "/";
String encodedPath = ParseUtil.encodePath(name, false);
String uris = "jar:" + uri + "!/" + encodedPath;
return Optional.of(URI.create(uris));
@@ -274,7 +274,6 @@ class ModuleReferences {
Stream implList() throws IOException {
// take snapshot to avoid async close
List names = VersionedStream.stream(jf)
- .filter(e -> !e.isDirectory())
.map(JarEntry::getName)
.collect(Collectors.toList());
return names.stream();
@@ -316,6 +315,8 @@ class ModuleReferences {
Optional implFind(String name) {
JmodFile.Entry je = getEntry(name);
if (je != null) {
+ if (je.isDirectory() && !name.endsWith("/"))
+ name += "/";
String encodedPath = ParseUtil.encodePath(name, false);
String uris = "jmod:" + uri + "!/" + encodedPath;
return Optional.of(URI.create(uris));
@@ -376,26 +377,10 @@ 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 find(String name) throws IOException {
ensureOpen();
- Path path = toFilePath(name);
+ Path path = Resources.toFilePath(dir, name);
if (path != null) {
try {
return Optional.of(path.toUri());
@@ -410,7 +395,7 @@ class ModuleReferences {
@Override
public Optional open(String name) throws IOException {
ensureOpen();
- Path path = toFilePath(name);
+ Path path = Resources.toFilePath(dir, name);
if (path != null) {
return Optional.of(Files.newInputStream(path));
} else {
@@ -421,7 +406,7 @@ class ModuleReferences {
@Override
public Optional read(String name) throws IOException {
ensureOpen();
- Path path = toFilePath(name);
+ Path path = Resources.toFilePath(dir, name);
if (path != null) {
return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
} else {
@@ -432,12 +417,9 @@ class ModuleReferences {
@Override
public Stream list() throws IOException {
ensureOpen();
- // sym links not followed
- return Files.find(dir, Integer.MAX_VALUE,
- (path, attrs) -> attrs.isRegularFile())
- .map(f -> dir.relativize(f)
- .toString()
- .replace(File.separatorChar, '/'));
+ return Files.walk(dir, Integer.MAX_VALUE)
+ .map(f -> Resources.toResourceName(dir, f))
+ .filter(s -> s.length() > 0);
}
@Override
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleTarget.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleTarget.java
new file mode 100644
index 00000000000..dcfe8ac8b58
--- /dev/null
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleTarget.java
@@ -0,0 +1,46 @@
+/*
+ * 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 jdk.internal.module;
+
+public final class ModuleTarget {
+
+ private final String osName;
+ private final String osArch;
+
+ public ModuleTarget(String osName, String osArch) {
+ this.osName = osName;
+ this.osArch = osArch;
+ }
+
+ public String osName() {
+ return osName;
+ }
+
+ public String osArch() {
+ return osArch;
+ }
+
+}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java
index 485d2e130b5..696aa64b3a5 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java
@@ -31,7 +31,6 @@ import java.lang.reflect.Module;
import java.net.URI;
import java.security.AccessController;
import java.security.PrivilegedAction;
-import java.util.Set;
import jdk.internal.loader.BootLoader;
import jdk.internal.loader.ClassLoaders;
@@ -39,10 +38,10 @@ import jdk.internal.misc.JavaLangReflectModuleAccess;
import jdk.internal.misc.SharedSecrets;
/**
- * A helper class to allow JDK classes create dynamic modules and to update
- * modules, exports and the readability graph. It is also invoked by the VM
- * to add read edges when agents are instrumenting code that need to link
- * to supporting classes.
+ * A helper class for creating and updating modules. This class is intended to
+ * support command-line options, tests, and the instrumentation API. It is also
+ * used by the VM to add read edges when agents are instrumenting code that
+ * need to link to supporting classes.
*
* The parameters that are package names in this API are the fully-qualified
* names of the packages as defined in section 6.5.3 of The Java™
@@ -72,25 +71,7 @@ public class Modules {
}
/**
- * Define a new module to the VM. The module has the given set of
- * packages and is defined to the given class loader.
- *
- * The resulting Module is in a larval state in that it does not not read
- * any other module and does not have any exports.
- */
- public static Module defineModule(ClassLoader loader,
- String name,
- Set packages)
- {
- ModuleDescriptor descriptor = ModuleDescriptor.newModule(name)
- .packages(packages)
- .build();
-
- return JLRMA.defineModule(loader, descriptor, null);
- }
-
- /**
- * Adds a read-edge so that module {@code m1} reads module {@code m1}.
+ * Updates m1 to read m2.
* Same as m1.addReads(m2) but without a caller check.
*/
public static void addReads(Module m1, Module m2) {
@@ -98,20 +79,45 @@ public class Modules {
}
/**
- * Update module {@code m} to read all unnamed modules.
+ * Update module m to read all unnamed modules.
*/
public static void addReadsAllUnnamed(Module m) {
JLRMA.addReadsAllUnnamed(m);
}
+ /**
+ * Update module m to export a package to all modules.
+ *
+ * This method is for intended for use by tests only.
+ */
+ public static void addExports(Module m, String pn) {
+ JLRMA.addExports(m, pn);
+ }
+
/**
* Updates module m1 to export a package to module m2.
- * Same as m1.addExports(pn, m2) but without a caller check.
+ * Same as m1.addExports(pn, m2) but without a caller check
*/
public static void addExports(Module m1, String pn, Module m2) {
JLRMA.addExports(m1, pn, m2);
}
+ /**
+ * Updates module m to export a package to all unnamed modules.
+ */
+ public static void addExportsToAllUnnamed(Module m, String pn) {
+ JLRMA.addExportsToAllUnnamed(m, pn);
+ }
+
+ /**
+ * Update module m to open a package to all modules.
+ *
+ * This method is for intended for use by tests only.
+ */
+ public static void addOpens(Module m, String pn) {
+ JLRMA.addOpens(m, pn);
+ }
+
/**
* Updates module m1 to open a package to module m2.
* Same as m1.addOpens(pn, m2) but without a caller check.
@@ -120,27 +126,6 @@ public class Modules {
JLRMA.addOpens(m1, pn, m2);
}
- /**
- * Updates a module m to export a package to all modules.
- */
- public static void addExportsToAll(Module m, String pn) {
- JLRMA.addExportsToAll(m, pn);
- }
-
- /**
- * Updates a module m to open a package to all modules.
- */
- public static void addOpensToAll(Module m, String pn) {
- JLRMA.addOpensToAll(m, pn);
- }
-
- /**
- * Updates module m to export a package to all unnamed modules.
- */
- public static void addExportsToAllUnnamed(Module m, String pn) {
- JLRMA.addExportsToAllUnnamed(m, pn);
- }
-
/**
* Updates module m to open a package to all unnamed modules.
*/
@@ -149,7 +134,8 @@ public class Modules {
}
/**
- * Updates module m to use a service
+ * Updates module m to use a service.
+ * Same as m2.addUses(service) but without a caller check.
*/
public static void addUses(Module m, Class> service) {
JLRMA.addUses(m, service);
@@ -182,16 +168,6 @@ public class Modules {
}
}
- /**
- * Adds a package to a module's content.
- *
- * 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);
- }
-
/**
* Called by the VM when code in the given Module has been transformed by
* an agent and so may have been instrumented to call into supporting
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Resources.java b/jdk/src/java.base/share/classes/jdk/internal/module/Resources.java
new file mode 100644
index 00000000000..4498682f0b9
--- /dev/null
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Resources.java
@@ -0,0 +1,167 @@
+/*
+ * 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
+ * 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 jdk.internal.module;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+
+/**
+ * A helper class to support working with resources in modules. Also provides
+ * support for translating resource names to file paths.
+ */
+public final class Resources {
+ private Resources() { }
+
+ /**
+ * Return true if a resource can be encapsulated. Resource with names
+ * ending in ".class" or "/" cannot be encapsulated. Resource names
+ * that map to a legal package name can be encapsulated.
+ */
+ public static boolean canEncapsulate(String name) {
+ int len = name.length();
+ if (len > 6 && name.endsWith(".class")) {
+ return false;
+ } else {
+ return Checks.isPackageName(toPackageName(name));
+ }
+ }
+
+ /**
+ * Derive a package name for a resource. The package name
+ * returned by this method may not be a legal package name. This method
+ * returns null if the the resource name ends with a "/" (a directory)
+ * or the resource name does not contain a "/".
+ */
+ public static String toPackageName(String name) {
+ int index = name.lastIndexOf('/');
+ if (index == -1 || index == name.length()-1) {
+ return "";
+ } else {
+ return name.substring(0, index).replace("/", ".");
+ }
+ }
+
+ /**
+ * Returns a resource name corresponding to the relative file path
+ * between {@code dir} and {@code file}. If the file is a directory
+ * then the name will end with a "/", except the top-level directory
+ * where the empty string is returned.
+ */
+ public static String toResourceName(Path dir, Path file) {
+ String s = dir.relativize(file)
+ .toString()
+ .replace(File.separatorChar, '/');
+ if (s.length() > 0 && Files.isDirectory(file))
+ s += "/";
+ return s;
+ }
+
+ /**
+ * Returns a file path to a resource in a file tree. If the resource
+ * name has a trailing "/" then the file path will locate a directory.
+ * Returns {@code null} if the resource does not map to a file in the
+ * tree file.
+ */
+ public static Path toFilePath(Path dir, String name) throws IOException {
+ boolean expectDirectory = name.endsWith("/");
+ if (expectDirectory) {
+ name = name.substring(0, name.length() - 1); // drop trailing "/"
+ }
+ Path path = toSafeFilePath(name);
+ if (path != null) {
+ Path file = dir.resolve(path);
+ try {
+ BasicFileAttributes attrs;
+ attrs = Files.readAttributes(file, BasicFileAttributes.class);
+ if (attrs.isDirectory()
+ || (!attrs.isDirectory() && !expectDirectory))
+ return file;
+ } catch (NoSuchFileException ignore) { }
+ }
+ return null;
+ }
+
+ /**
+ * Map a resource name to a "safe" file path. Returns {@code null} if
+ * the resource name cannot be converted into a "safe" file path.
+ *
+ * Resource names with empty elements, or elements that are "." or ".."
+ * are rejected, as are resource names that translates to a file path
+ * with a root component.
+ */
+ private static Path toSafeFilePath(String name) {
+ // scan elements of resource name
+ 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;
+ }
+
+}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java
index a7ee7ffe74f..92c4c96cadb 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java
@@ -150,18 +150,21 @@ public class SystemModuleFinder implements ModuleFinder {
System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
ModuleDescriptor[] descriptors;
+ ModuleTarget[] targets;
ModuleHashes[] recordedHashes;
ModuleResolution[] moduleResolutions;
// fast loading of ModuleDescriptor of system modules
if (isFastPathSupported() && !disabled) {
descriptors = SystemModules.descriptors();
+ targets = SystemModules.targets();
recordedHashes = SystemModules.hashes();
moduleResolutions = SystemModules.moduleResolutions();
} else {
// if fast loading of ModuleDescriptors is disabled
// fallback to read module-info.class
descriptors = new ModuleDescriptor[n];
+ targets = new ModuleTarget[n];
recordedHashes = new ModuleHashes[n];
moduleResolutions = new ModuleResolution[n];
ImageReader imageReader = SystemImage.reader();
@@ -171,6 +174,7 @@ public class SystemModuleFinder implements ModuleFinder {
ModuleInfo.Attributes attrs =
ModuleInfo.read(imageReader.getResourceBuffer(loc), null);
descriptors[i] = attrs.descriptor();
+ targets[i] = attrs.target();
recordedHashes[i] = attrs.recordedHashes();
moduleResolutions[i] = attrs.moduleResolution();
}
@@ -206,6 +210,7 @@ public class SystemModuleFinder implements ModuleFinder {
// create the ModuleReference
ModuleReference mref = toModuleReference(md,
+ targets[i],
recordedHashes[i],
hashSupplier(names[i]),
moduleResolutions[i]);
@@ -233,6 +238,7 @@ public class SystemModuleFinder implements ModuleFinder {
}
private ModuleReference toModuleReference(ModuleDescriptor md,
+ ModuleTarget target,
ModuleHashes recordedHashes,
HashSupplier hasher,
ModuleResolution mres) {
@@ -246,9 +252,14 @@ public class SystemModuleFinder implements ModuleFinder {
}
};
- ModuleReference mref =
- new ModuleReferenceImpl(md, uri, readerSupplier, null,
- recordedHashes, hasher, mres);
+ ModuleReference mref = new ModuleReferenceImpl(md,
+ uri,
+ readerSupplier,
+ null,
+ target,
+ recordedHashes,
+ hasher,
+ mres);
// may need a reference to a patched module if --patch-module specified
mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java
index 596bb697238..06e21ba2967 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java
@@ -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
@@ -27,7 +27,7 @@ package jdk.internal.module;
import java.lang.module.ModuleDescriptor;
-/*
+/**
* SystemModules class will be generated at link time to create
* ModuleDescriptor for the system modules directly to improve
* the module descriptor reconstitution time.
@@ -65,7 +65,7 @@ public final class SystemModules {
}
/**
- * Returns a non-empty array of ModuleDescriptors in the run-time image.
+ * Returns a non-empty array of ModuleDescriptor objects in the run-time image.
*
* When running an exploded image it returns an empty array.
*/
@@ -73,6 +73,15 @@ public final class SystemModules {
throw new InternalError("expected to be overridden at link time");
}
+ /**
+ * Returns a non-empty array of ModuleTarget objects in the run-time image.
+ *
+ * When running an exploded image it returns an empty array.
+ */
+ public static ModuleTarget[] targets() {
+ throw new InternalError("expected to be overridden at link time");
+ }
+
/**
* Returns a non-empty array of ModuleHashes recorded in each module
* in the run-time image.
diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java
index 4d91a001690..a3c58f2990c 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java
@@ -2508,7 +2508,7 @@ public class ClassReader {
}
/**
- * Reads a CONSTANT_Pakcage_info item in {@code b}. This method is
+ * Reads a CONSTANT_Package_info item in {@code b}. This method is
* intended for {@link Attribute} sub slasses, and is normally not needed
* by class generators or adapters.
*
diff --git a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java
index 61969590d92..0d0ba6209e3 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java
@@ -31,9 +31,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import jdk.internal.HotSpotIntrinsicCandidate;
-import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.VM;
-import sun.security.action.GetPropertyAction;
/** Common utility routines used by both java.lang and
java.lang.reflect */
@@ -104,39 +102,40 @@ public class Reflection {
int modifiers)
throws IllegalAccessException
{
- if (currentClass == null || memberClass == null) {
- throw new InternalError();
- }
-
if (!verifyMemberAccess(currentClass, memberClass, targetClass, modifiers)) {
- throwIllegalAccessException(currentClass, memberClass, targetClass, modifiers);
+ throw newIllegalAccessException(currentClass, memberClass, targetClass, modifiers);
}
}
/**
- * Verify access to a member, returning {@code false} if no access
+ * Verify access to a member and return {@code true} if it is granted.
+ *
+ * @param currentClass the class performing the access
+ * @param memberClass the declaring class of the member being accessed
+ * @param targetClass the class of target object if accessing instance
+ * field or method;
+ * or the declaring class if accessing constructor;
+ * or null if accessing static field or method
+ * @param modifiers the member's access modifiers
+ * @return {@code true} if access to member is granted
*/
public static boolean verifyMemberAccess(Class> currentClass,
Class> memberClass,
Class> targetClass,
int modifiers)
{
- // Verify that currentClass can access a field, method, or
- // constructor of memberClass, where that member's access bits are
- // "modifiers".
-
- boolean gotIsSameClassPackage = false;
- boolean isSameClassPackage = false;
-
if (currentClass == memberClass) {
// Always succeeds
return true;
}
- if (!verifyModuleAccess(currentClass, memberClass)) {
+ if (!verifyModuleAccess(currentClass.getModule(), memberClass)) {
return false;
}
+ boolean gotIsSameClassPackage = false;
+ boolean isSameClassPackage = false;
+
if (!Modifier.isPublic(getClassAccessFlags(memberClass))) {
isSameClassPackage = isSameClassPackage(currentClass, memberClass);
gotIsSameClassPackage = true;
@@ -196,31 +195,20 @@ public class Reflection {
}
/**
- * Returns {@code true} if memberClass's's module exports memberClass's
- * package to currentClass's module.
+ * Returns {@code true} if memberClass's module exports memberClass's
+ * package to currentModule.
*/
- public static boolean verifyModuleAccess(Class> currentClass,
- Class> memberClass) {
- return verifyModuleAccess(currentClass.getModule(), memberClass);
- }
-
public static boolean verifyModuleAccess(Module currentModule, Class> memberClass) {
Module memberModule = memberClass.getModule();
-
- // module may be null during startup (initLevel 0)
- if (currentModule == memberModule)
- return true; // same module (named or unnamed)
-
- String pkg = memberClass.getPackageName();
- boolean allowed = memberModule.isExported(pkg, currentModule);
- if (allowed && memberModule.isNamed() && printStackTraceWhenAccessSucceeds()) {
- if (!SharedSecrets.getJavaLangReflectModuleAccess()
- .isStaticallyExported(memberModule, pkg, currentModule)) {
- String msg = currentModule + " allowed access to member of " + memberClass;
- new Exception(msg).printStackTrace(System.err);
- }
+ if (currentModule == memberModule) {
+ // same module (named or unnamed) or both null if called
+ // before module system is initialized, which means we are
+ // dealing with java.base only.
+ return true;
+ } else {
+ String pkg = memberClass.getPackageName();
+ return memberModule.isExported(pkg, currentModule);
}
- return allowed;
}
/**
@@ -344,46 +332,14 @@ public class Reflection {
return false;
}
-
- // true to print a stack trace when access fails
- private static volatile boolean printStackWhenAccessFails;
-
- // true to print a stack trace when access succeeds
- private static volatile boolean printStackWhenAccessSucceeds;
-
- // true if printStack* values are initialized
- private static volatile boolean printStackPropertiesSet;
-
- private static void ensurePrintStackPropertiesSet() {
- if (!printStackPropertiesSet && VM.initLevel() >= 1) {
- String s = GetPropertyAction.privilegedGetProperty(
- "sun.reflect.debugModuleAccessChecks");
- if (s != null) {
- printStackWhenAccessFails = !s.equalsIgnoreCase("false");
- printStackWhenAccessSucceeds = s.equalsIgnoreCase("access");
- }
- printStackPropertiesSet = true;
- }
- }
-
- public static boolean printStackTraceWhenAccessFails() {
- ensurePrintStackPropertiesSet();
- return printStackWhenAccessFails;
- }
-
- public static boolean printStackTraceWhenAccessSucceeds() {
- ensurePrintStackPropertiesSet();
- return printStackWhenAccessSucceeds;
- }
-
/**
- * Throws IllegalAccessException with the an exception message based on
+ * Returns an IllegalAccessException with an exception message based on
* the access that is denied.
*/
- private static void throwIllegalAccessException(Class> currentClass,
- Class> memberClass,
- Object target,
- int modifiers)
+ public static IllegalAccessException newIllegalAccessException(Class> currentClass,
+ Class> memberClass,
+ Class> targetClass,
+ int modifiers)
throws IllegalAccessException
{
String currentSuffix = "";
@@ -411,20 +367,6 @@ public class Reflection {
if (m2.isNamed()) msg += " to " + m1;
}
- throwIllegalAccessException(msg);
- }
-
- /**
- * Throws IllegalAccessException with the given exception message.
- */
- public static void throwIllegalAccessException(String msg)
- throws IllegalAccessException
- {
- IllegalAccessException e = new IllegalAccessException(msg);
- ensurePrintStackPropertiesSet();
- if (printStackWhenAccessFails) {
- e.printStackTrace(System.err);
- }
- throw e;
+ return new IllegalAccessException(msg);
}
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java
index 990de713fc6..50200fdeada 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2016, 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
@@ -44,6 +44,7 @@ import java.security.PrivilegedAction;
import java.util.Objects;
import java.util.Properties;
+import jdk.internal.misc.VM;
import sun.reflect.misc.ReflectUtil;
import sun.security.action.GetPropertyAction;
@@ -585,17 +586,10 @@ public class ReflectionFactory {
private static void checkInitted() {
if (initted) return;
- // Tests to ensure the system properties table is fully
- // initialized. This is needed because reflection code is
- // called very early in the initialization process (before
- // command-line arguments have been parsed and therefore
- // these user-settable properties installed.) We assume that
- // if System.out is non-null then the System class has been
- // fully initialized and that the bulk of the startup code
- // has been run.
-
- if (System.out == null) {
- // java.lang.System not yet fully initialized
+ // Defer initialization until module system is initialized so as
+ // to avoid inflation and spinning bytecode in unnamed modules
+ // during early startup.
+ if (!VM.isModuleSystemInited()) {
return;
}
diff --git a/jdk/src/java.base/share/classes/module-info.java b/jdk/src/java.base/share/classes/module-info.java
index 322f719ed6e..60b1512cbca 100644
--- a/jdk/src/java.base/share/classes/module-info.java
+++ b/jdk/src/java.base/share/classes/module-info.java
@@ -125,10 +125,9 @@ module java.base {
jdk.jlink;
exports jdk.internal.loader to
java.instrument,
- java.logging,
- jdk.jlink;
+ java.logging;
exports jdk.internal.jmod to
- jdk.compiler,
+ jdk.compiler, // reflective dependency
jdk.jlink;
exports jdk.internal.logger to
java.logging;
@@ -140,10 +139,7 @@ module java.base {
exports jdk.internal.org.objectweb.asm.tree to
jdk.jlink;
exports jdk.internal.org.objectweb.asm.util to
- jdk.jlink,
jdk.scripting.nashorn;
- exports jdk.internal.org.objectweb.asm.tree.analysis to
- jdk.jlink;
exports jdk.internal.org.objectweb.asm.commons to
jdk.scripting.nashorn;
exports jdk.internal.org.objectweb.asm.signature to
@@ -157,7 +153,6 @@ module java.base {
jdk.jlink;
exports jdk.internal.misc to
java.desktop,
- jdk.incubator.httpclient,
java.logging,
java.management,
java.naming,
@@ -166,8 +161,8 @@ module java.base {
java.sql,
java.xml,
jdk.charsets,
- jdk.compiler,
- jdk.jartool,
+ jdk.compiler, // reflective dependency
+ jdk.incubator.httpclient,
jdk.jdeps,
jdk.jlink,
jdk.jshell,
@@ -210,11 +205,10 @@ module java.base {
jdk.naming.dns;
exports sun.net.util to
java.desktop,
- jdk.jconsole,
- jdk.naming.dns;
+ jdk.jconsole;
exports sun.net.www to
- jdk.incubator.httpclient,
java.desktop,
+ jdk.incubator.httpclient,
jdk.jartool;
exports sun.net.www.protocol.http to
java.security.jgss;
diff --git a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java
index c3410489613..ed5524f7d86 100644
--- a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java
+++ b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java
@@ -85,6 +85,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.misc.VM;
+import jdk.internal.module.IllegalAccessLogger;
import jdk.internal.module.Modules;
@@ -428,14 +429,20 @@ public final class LauncherHelper {
abort(null, "java.launcher.jar.error3", jarname);
}
- // Add-Exports and Add-Opens to break encapsulation
+ // Add-Exports and Add-Opens to allow illegal access
String exports = mainAttrs.getValue(ADD_EXPORTS);
if (exports != null) {
- addExportsOrOpens(exports, false);
+ String warn = getLocalizedMessage("java.launcher.permitaccess.warning",
+ jarname, ADD_EXPORTS);
+ System.err.println(warn);
+ addExportsOrOpens(exports, false, ADD_EXPORTS);
}
String opens = mainAttrs.getValue(ADD_OPENS);
if (opens != null) {
- addExportsOrOpens(opens, true);
+ String warn = getLocalizedMessage("java.launcher.permitaccess.warning",
+ jarname, ADD_OPENS);
+ System.err.println(warn);
+ addExportsOrOpens(opens, true, ADD_OPENS);
}
/*
@@ -460,23 +467,36 @@ public final class LauncherHelper {
* Process the Add-Exports or Add-Opens value. The value is
* {@code / ( /)*}.
*/
- static void addExportsOrOpens(String value, boolean open) {
+ static void addExportsOrOpens(String value, boolean open, String how) {
+ IllegalAccessLogger.Builder builder;
+ IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger();
+ if (logger == null) {
+ builder = new IllegalAccessLogger.Builder();
+ } else {
+ builder = logger.toBuilder();
+ }
+
for (String moduleAndPackage : value.split(" ")) {
String[] s = moduleAndPackage.trim().split("/");
if (s.length == 2) {
String mn = s[0];
String pn = s[1];
+
Layer.boot().findModule(mn).ifPresent(m -> {
if (m.getDescriptor().packages().contains(pn)) {
if (open) {
+ builder.logAccessToOpenPackage(m, pn, how);
Modules.addOpensToAllUnnamed(m, pn);
} else {
+ builder.logAccessToExportedPackage(m, pn, how);
Modules.addExportsToAllUnnamed(m, pn);
}
}
});
}
}
+
+ IllegalAccessLogger.setIllegalAccessLogger(builder.build());
}
// From src/share/bin/java.c:
diff --git a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties
index 932a69c3bdf..d58496fa666 100644
--- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties
+++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties
@@ -24,12 +24,15 @@
#
# Translators please note do not translate the options themselves
-java.launcher.opt.header = Usage: {0} [options] class [args...]\n\
-\ (to execute a class)\n or {0} [options] -jar jarfile [args...]\n\
+java.launcher.opt.header = Usage: {0} [options] [args...]\n\
+\ (to execute a class)\n or {0} [options] -jar [args...]\n\
\ (to execute a jar file)\n\
-\ or {0} [options] -p -m [/] [args...]\n\
+\ or {0} [options] -m [/] [args...]\n\
+\ {0} [options] --module [/] [args...]\n\
\ (to execute the main class in a module)\n\n\
-where options include:\n\n
+\ Arguments following the main class, -jar , -m or --module\n\
+\ / are passed as the arguments to main class.\n\n\
+\ where options include:\n\n
java.launcher.opt.datamodel =\ -d{0}\t Deprecated, will be removed in a future release\n
java.launcher.opt.vmselect =\ {0}\t to select the "{1}" VM\n
@@ -49,10 +52,6 @@ java.launcher.opt.footer =\ -cp [/]\n\
-\ --module [/]\n\
-\ the initial module to resolve, and the name of the main class\n\
-\ to execute if not specified by the module\n\
\ --add-modules [,...]\n\
\ root modules to resolve in addition to the initial module.\n\
\ can also be ALL-DEFAULT, ALL-SYSTEM,\n\
@@ -157,6 +156,10 @@ java.launcher.X.usage=\n\
\ --add-opens /=(,)*\n\
\ updates to open to\n\
\ , regardless of module declaration.\n\
+\ --permit-illegal-access\n\
+\ permit illegal access to members of types in named modules\n\
+\ by code in unnamed modules. This compatibility option will\n\
+\ be removed in the next release.\n\
\ --disable-@files disable further argument file expansion\n\
\ --patch-module =({0})*\n\
\ Override or augment a module with classes and resources\n\
@@ -208,4 +211,6 @@ java.launcher.module.error2=\
java.launcher.module.error3=\
Error: Unable to load main class {0} from module {1}\n\
\t{2}
+java.launcher.permitaccess.warning=\
+ WARNING: Main manifest of {0} contains {1} attribute to permit illegal access
diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java
index 893bb55c10a..c7446082edd 100644
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 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,8 +26,6 @@
package sun.net.www.protocol.jrt;
import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FilePermission;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
@@ -44,7 +42,6 @@ import jdk.internal.loader.URLClassPath;
import jdk.internal.loader.Resource;
import sun.net.www.ParseUtil;
import sun.net.www.URLConnection;
-import sun.security.action.GetPropertyAction;
/**
* URLConnection implementation that can be used to connect to resources
@@ -66,9 +63,6 @@ public class JavaRuntimeURLConnection extends URLConnection {
// the Resource when connected
private volatile Resource resource;
- // the permission to access resources in the runtime image, created lazily
- private static volatile Permission permission;
-
JavaRuntimeURLConnection(URL url) throws IOException {
super(url);
String path = url.getPath();
@@ -164,14 +158,8 @@ public class JavaRuntimeURLConnection extends URLConnection {
}
@Override
- public Permission getPermission() throws IOException {
- Permission p = permission;
- if (p == null) {
- String home = GetPropertyAction.privilegedGetProperty("java.home");
- p = new FilePermission(home + File.separator + "-", "read");
- permission = p;
- }
- return p;
+ public Permission getPermission() {
+ return new RuntimePermission("accessSystemModules");
}
/**
diff --git a/jdk/src/java.base/share/native/libjava/ClassLoader.c b/jdk/src/java.base/share/native/libjava/ClassLoader.c
index 5a8d86156b9..f3803805c59 100644
--- a/jdk/src/java.base/share/native/libjava/ClassLoader.c
+++ b/jdk/src/java.base/share/native/libjava/ClassLoader.c
@@ -72,23 +72,9 @@ getUTF(JNIEnv *env, jstring str, char* localBuf, int bufSize)
return utfStr;
}
-// The existence or signature of this method is not guaranteed since it
-// supports a private method. This method will be changed in 1.7.
-JNIEXPORT jclass JNICALL
-Java_java_lang_ClassLoader_defineClass0(JNIEnv *env,
- jobject loader,
- jstring name,
- jbyteArray data,
- jint offset,
- jint length,
- jobject pd)
-{
- return Java_java_lang_ClassLoader_defineClass1(env, loader, name, data, offset,
- length, pd, NULL);
-}
-
JNIEXPORT jclass JNICALL
Java_java_lang_ClassLoader_defineClass1(JNIEnv *env,
+ jclass cls,
jobject loader,
jstring name,
jbyteArray data,
@@ -163,6 +149,7 @@ Java_java_lang_ClassLoader_defineClass1(JNIEnv *env,
JNIEXPORT jclass JNICALL
Java_java_lang_ClassLoader_defineClass2(JNIEnv *env,
+ jclass cls,
jobject loader,
jstring name,
jobject data,
diff --git a/jdk/src/java.base/share/native/libjava/Module.c b/jdk/src/java.base/share/native/libjava/Module.c
index 26067555a33..083671da206 100644
--- a/jdk/src/java.base/share/native/libjava/Module.c
+++ b/jdk/src/java.base/share/native/libjava/Module.c
@@ -73,30 +73,32 @@ Java_java_lang_reflect_Module_defineModule0(JNIEnv *env, jclass cls, jobject mod
jstring location, jobjectArray packages)
{
char** pkgs = NULL;
- jsize idx;
jsize num_packages = (*env)->GetArrayLength(env, packages);
if (num_packages != 0 && (pkgs = calloc(num_packages, sizeof(char*))) == NULL) {
JNU_ThrowOutOfMemoryError(env, NULL);
return;
- } else {
- int valid = 1;
+ } else if ((*env)->EnsureLocalCapacity(env, (jint)num_packages) == 0) {
+ jboolean failed = JNI_FALSE;
+ int idx;
for (idx = 0; idx < num_packages; idx++) {
jstring pkg = (*env)->GetObjectArrayElement(env, packages, idx);
- pkgs[idx] = GetInternalPackageName(env, pkg, NULL, 0);
- if (pkgs[idx] == NULL) {
- valid = 0;
+ char* name = GetInternalPackageName(env, pkg, NULL, 0);
+ if (name != NULL) {
+ pkgs[idx] = name;
+ } else {
+ failed = JNI_TRUE;
break;
}
}
-
- if (valid != 0) {
+ if (!failed) {
JVM_DefineModule(env, module, is_open, version, location,
- (const char* const*)pkgs, num_packages);
+ (const char* const*)pkgs, num_packages);
}
}
if (num_packages > 0) {
+ int idx;
for (idx = 0; idx < num_packages; idx++) {
if (pkgs[idx] != NULL) {
free(pkgs[idx]);
diff --git a/jdk/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java b/jdk/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java
index ab0d540f9c8..e0e0309468e 100644
--- a/jdk/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java
+++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java
@@ -191,6 +191,9 @@ public interface ClassFileTransformer {
* if the input does not represent a well-formed class file
* @return a well-formed class file buffer (the result of the transform),
* or {@code null} if no transform is performed
+ *
+ * @revised 9
+ * @spec JPMS
*/
default byte[]
transform( ClassLoader loader,
diff --git a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java
index 67dcb9952fc..b616bdb4b41 100644
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java
@@ -63,6 +63,7 @@ import jdk.internal.module.ModuleHashesBuilder;
import jdk.internal.module.ModuleInfo;
import jdk.internal.module.ModuleInfoExtender;
import jdk.internal.module.ModuleResolution;
+import jdk.internal.module.ModuleTarget;
import jdk.internal.util.jar.JarIndex;
import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
@@ -1780,6 +1781,7 @@ public class Main {
{
ModuleInfo.Attributes attrs = ModuleInfo.read(entryInputStream, null);
ModuleDescriptor md = attrs.descriptor();
+ ModuleTarget target = attrs.target();
ModuleHashes hashes = attrs.recordedHashes();
StringBuilder sb = new StringBuilder();
@@ -1824,11 +1826,14 @@ public class Main {
md.mainClass().ifPresent(v -> sb.append("\n main-class " + v));
- md.osName().ifPresent(v -> sb.append("\n operating-system-name " + v));
-
- md.osArch().ifPresent(v -> sb.append("\n operating-system-architecture " + v));
-
- md.osVersion().ifPresent(v -> sb.append("\n operating-system-version " + v));
+ if (target != null) {
+ String osName = target.osName();
+ if (osName != null)
+ sb.append("\n operating-system-name " + osName);
+ String osArch = target.osArch();
+ if (osArch != null)
+ sb.append("\n operating-system-architecture " + osArch);
+ }
if (hashes != null) {
hashes.names().stream().sorted().forEach(
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java
index 3081a631496..2ab6f18cd52 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java
@@ -151,16 +151,8 @@ public final class DefaultImageBuilder implements ImageBuilder {
@Override
public void storeFiles(ResourcePool files) {
try {
- // populate targetOsName field up-front because it's used elsewhere.
- Optional javaBase = files.moduleView().findModule("java.base");
- javaBase.ifPresent(mod -> {
- // fill release information available from transformed "java.base" module!
- ModuleDescriptor desc = mod.descriptor();
- desc.osName().ifPresent(s -> {
- this.targetOsName = s;
- });
- });
-
+ this.targetOsName = files.moduleView().
+ findModule("java.base").get().osName();
if (this.targetOsName == null) {
throw new PluginException("ModuleTarget attribute is missing for java.base module");
}
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java
index f9d1f81fba0..ad780558a8c 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java
@@ -43,6 +43,8 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.jimage.decompressor.Decompressor;
+import jdk.internal.module.ModuleInfo.Attributes;
+import jdk.internal.module.ModuleTarget;
import jdk.tools.jlink.plugin.Plugin;
import jdk.tools.jlink.builder.ImageBuilder;
import jdk.tools.jlink.plugin.PluginException;
@@ -298,6 +300,7 @@ public final class ImagePluginStack {
final ResourcePoolModule module;
// lazily initialized
ModuleDescriptor descriptor;
+ ModuleTarget target;
LastModule(ResourcePoolModule module) {
this.module = module;
@@ -316,12 +319,30 @@ public final class ImagePluginStack {
@Override
public ModuleDescriptor descriptor() {
- if (descriptor == null) {
- descriptor = ResourcePoolManager.readModuleDescriptor(this);
- }
+ initModuleAttributes();
return descriptor;
}
+ @Override
+ public String osName() {
+ initModuleAttributes();
+ return target != null? target.osName() : null;
+ }
+
+ @Override
+ public String osArch() {
+ initModuleAttributes();
+ return target != null? target.osArch() : null;
+ }
+
+ private void initModuleAttributes() {
+ if (this.descriptor == null) {
+ Attributes attr = ResourcePoolManager.readModuleAttributes(this);
+ this.descriptor = attr.descriptor();
+ this.target = attr.target();
+ }
+ }
+
@Override
public Set packages() {
return module.packages();
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java
index 40413d491ca..42032b6ab00 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java
@@ -54,7 +54,6 @@ import jdk.tools.jlink.internal.ImagePluginStack.ImageProvider;
import jdk.tools.jlink.plugin.PluginException;
import jdk.tools.jlink.builder.DefaultImageBuilder;
import jdk.tools.jlink.plugin.Plugin;
-import jdk.internal.module.Checks;
import jdk.internal.module.ModulePath;
import jdk.internal.module.ModuleResolution;
@@ -423,13 +422,6 @@ public class JlinkTask {
ModuleFinder.of(),
roots);
- // emit warning for modules that end with a digit
- cf.modules().stream()
- .map(ResolvedModule::name)
- .filter(mn -> !Checks.hasLegalModuleNameLastCharacter(mn))
- .forEach(mn -> System.err.println("WARNING: Module name \""
- + mn + "\" may soon be illegal"));
-
// emit a warning for any incubating modules in the configuration
if (log != null) {
String im = cf.modules()
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java
index 737b234f6c8..66ab836aa99 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java
@@ -66,9 +66,6 @@ final class ResourcePoolConfiguration {
md.version().ifPresent(builder::version);
md.mainClass().ifPresent(builder::mainClass);
- md.osName().ifPresent(builder::osName);
- md.osArch().ifPresent(builder::osArch);
- md.osVersion().ifPresent(builder::osVersion);
return builder.build();
}
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java
index e3b046172f7..e6b084392eb 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java
@@ -35,7 +35,10 @@ import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import jdk.internal.jimage.decompressor.CompressedResourceHeader;
-import jdk.internal.loader.ResourceHelper;
+import jdk.internal.module.Resources;
+import jdk.internal.module.ModuleInfo;
+import jdk.internal.module.ModuleInfo.Attributes;
+import jdk.internal.module.ModuleTarget;
import jdk.tools.jlink.plugin.ResourcePool;
import jdk.tools.jlink.plugin.ResourcePoolBuilder;
import jdk.tools.jlink.plugin.ResourcePoolEntry;
@@ -47,8 +50,8 @@ import jdk.tools.jlink.plugin.PluginException;
* A manager for pool of resources.
*/
public class ResourcePoolManager {
- // utility to read ModuleDescriptor of the given ResourcePoolModule
- static ModuleDescriptor readModuleDescriptor(ResourcePoolModule mod) {
+ // utility to read Module Attributes of the given ResourcePoolModule
+ static Attributes readModuleAttributes(ResourcePoolModule mod) {
String p = "/" + mod.name() + "/module-info.class";
Optional content = mod.findEntry(p);
if (!content.isPresent()) {
@@ -57,9 +60,9 @@ public class ResourcePoolManager {
}
ByteBuffer bb = ByteBuffer.wrap(content.get().contentBytes());
try {
- return ModuleDescriptor.read(bb);
+ return ModuleInfo.read(bb, null);
} catch (RuntimeException re) {
- throw new RuntimeException("module descriptor cannot be read for " + mod.name(), re);
+ throw new RuntimeException("module info cannot be read for " + mod.name(), re);
}
}
@@ -68,7 +71,7 @@ public class ResourcePoolManager {
*/
public static boolean isNamedPackageResource(String path) {
return (path.endsWith(".class") && !path.endsWith("module-info.class")) ||
- !ResourceHelper.isSimpleResource(path);
+ Resources.canEncapsulate(path);
}
class ResourcePoolModuleImpl implements ResourcePoolModule {
@@ -76,6 +79,8 @@ public class ResourcePoolManager {
final Map moduleContent = new LinkedHashMap<>();
// lazily initialized
private ModuleDescriptor descriptor;
+ private ModuleTarget target;
+
final String name;
private ResourcePoolModuleImpl(String name) {
@@ -100,12 +105,30 @@ public class ResourcePoolManager {
@Override
public ModuleDescriptor descriptor() {
- if (descriptor == null) {
- descriptor = readModuleDescriptor(this);
- }
+ initModuleAttributes();
return descriptor;
}
+ @Override
+ public String osName() {
+ initModuleAttributes();
+ return target != null? target.osName() : null;
+ }
+
+ @Override
+ public String osArch() {
+ initModuleAttributes();
+ return target != null? target.osArch() : null;
+ }
+
+ private void initModuleAttributes() {
+ if (this.descriptor == null) {
+ Attributes attr = readModuleAttributes(this);
+ this.descriptor = attr.descriptor();
+ this.target = attr.target();
+ }
+ }
+
@Override
public Set packages() {
Set pkgs = new HashSet<>();
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java
index ab0af0182d6..be14cc9c528 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java
@@ -115,7 +115,7 @@ public final class ExcludeVMPlugin implements Plugin {
@Override
public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
ResourcePoolModule javaBase = in.moduleView().findModule("java.base").get();
- String[] jvmlibs = jvmlibs(javaBase.descriptor().osName().get());
+ String[] jvmlibs = jvmlibs(javaBase.osName());
TreeSet existing = new TreeSet<>(new JvmComparator());
TreeSet removed = new TreeSet<>(new JvmComparator());
if (!keepAll) {
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java
index 4332a869a8f..e778733cd06 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java
@@ -137,15 +137,13 @@ public final class ReleaseInfoPlugin implements Plugin {
javaBase.ifPresent(mod -> {
// fill release information available from transformed "java.base" module!
ModuleDescriptor desc = mod.descriptor();
- desc.osName().ifPresent(s -> {
- release.put("OS_NAME", quote(s));
- });
- desc.osVersion().ifPresent(s -> release.put("OS_VERSION", quote(s)));
- desc.osArch().ifPresent(s -> release.put("OS_ARCH", quote(s)));
desc.version().ifPresent(s -> release.put("JAVA_VERSION",
quote(parseVersion(s.toString()))));
desc.version().ifPresent(s -> release.put("JAVA_FULL_VERSION",
quote(s.toString())));
+
+ release.put("OS_NAME", quote(mod.osName()));
+ release.put("OS_ARCH", quote(mod.osArch()));
});
// put topological sorted module names separated by space
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java
index c5819a65f08..e5c66a84594 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java
@@ -52,6 +52,7 @@ import jdk.internal.module.ModuleHashes;
import jdk.internal.module.ModuleInfo.Attributes;
import jdk.internal.module.ModuleInfoExtender;
import jdk.internal.module.ModuleResolution;
+import jdk.internal.module.ModuleTarget;
import jdk.internal.module.SystemModules;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.ClassReader;
@@ -206,12 +207,12 @@ public final class SystemModulesPlugin implements Plugin {
// add ModulePackages attribute if this module contains some packages
// and ModulePackages is not present
this.addModulePackages = packages.size() > 0 && !hasModulePackages();
+
// drop target attribute only if any OS property is present
- if (dropModuleTarget) {
- this.dropModuleTarget =
- descriptor.osName().isPresent() ||
- descriptor.osArch().isPresent() ||
- descriptor.osVersion().isPresent();
+ ModuleTarget target = attrs.target();
+ if (dropModuleTarget && target != null) {
+ this.dropModuleTarget = (target.osName() != null)
+ || (target.osArch() != null);
} else {
this.dropModuleTarget = false;
}
@@ -230,6 +231,10 @@ public final class SystemModulesPlugin implements Plugin {
return packages;
}
+ ModuleTarget target() {
+ return attrs.target();
+ }
+
ModuleHashes recordedHashes() {
return attrs.recordedHashes();
}
@@ -372,7 +377,7 @@ public final class SystemModulesPlugin implements Plugin {
}
void dropModuleTarget() {
- extender.targetPlatform("", "", "");
+ extender.targetPlatform("", "");
}
byte[] getBytes() throws IOException {
@@ -399,6 +404,10 @@ public final class SystemModulesPlugin implements Plugin {
"java/lang/module/ModuleDescriptor$Exports$Modifier";
private static final String OPENS_MODIFIER_CLASSNAME =
"java/lang/module/ModuleDescriptor$Opens$Modifier";
+ private static final String MODULE_TARGET_CLASSNAME =
+ "jdk/internal/module/ModuleTarget";
+ private static final String MODULE_TARGET_ARRAY_SIGNATURE =
+ "[Ljdk/internal/module/ModuleTarget;";
private static final String MODULE_HASHES_ARRAY_SIGNATURE =
"[Ljdk/internal/module/ModuleHashes;";
private static final String MODULE_RESOLUTION_CLASSNAME =
@@ -414,6 +423,7 @@ public final class SystemModulesPlugin implements Plugin {
private final int BUILDER_VAR = 0;
private final int MD_VAR = 1; // variable for ModuleDescriptor
+ private final int MT_VAR = 1; // variable for ModuleTarget
private final int MH_VAR = 1; // variable for ModuleHashes
private int nextLocalVar = 2; // index to next local variable
@@ -515,11 +525,10 @@ public final class SystemModulesPlugin implements Plugin {
if (entry.moduleName().equals("java.base")) {
moduleInfo = new ModuleInfo(entry.contentBytes(), packages, false);
ModuleDescriptor md = moduleInfo.descriptor;
- // drop Moduletarget attribute only if java.base has all OS properties
- // otherwise, retain it
- if (dropModuleTarget &&
- md.osName().isPresent() && md.osArch().isPresent() &&
- md.osVersion().isPresent()) {
+ // drop ModuleTarget attribute if java.base has all OS properties
+ ModuleTarget target = moduleInfo.target();
+ if (dropModuleTarget
+ && (target.osName() != null) && (target.osArch() != null)) {
dropModuleTarget = true;
} else {
dropModuleTarget = false;
@@ -584,15 +593,20 @@ public final class SystemModulesPlugin implements Plugin {
// generate SystemModules::descriptors
genDescriptorsMethod();
+
+ // generate SystemModules::targets
+ genTargetsMethod();
+
// generate SystemModules::hashes
genHashesMethod();
+
// generate SystemModules::moduleResolutions
genModuleResolutionsMethod();
return cw;
}
- /*
+ /**
* Generate bytecode for SystemModules::descriptors method
*/
private void genDescriptorsMethod() {
@@ -616,10 +630,47 @@ public final class SystemModulesPlugin implements Plugin {
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
-
}
- /*
+ /**
+ * Generate bytecode for SystemModules::targets method
+ */
+ private void genTargetsMethod() {
+ MethodVisitor mv = cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
+ "targets",
+ "()" + MODULE_TARGET_ARRAY_SIGNATURE,
+ "()" + MODULE_TARGET_ARRAY_SIGNATURE,
+ null);
+ mv.visitCode();
+ pushInt(mv, moduleInfos.size());
+ mv.visitTypeInsn(ANEWARRAY, MODULE_TARGET_CLASSNAME);
+ mv.visitVarInsn(ASTORE, MT_VAR);
+
+ for (int index=0; index < moduleInfos.size(); index++) {
+ ModuleInfo minfo = moduleInfos.get(index);
+ if (minfo.target() != null && !minfo.dropModuleTarget) {
+ mv.visitVarInsn(ALOAD, MT_VAR);
+ pushInt(mv, index);
+
+ // new ModuleTarget(String, String)
+ mv.visitTypeInsn(NEW, MODULE_TARGET_CLASSNAME);
+ mv.visitInsn(DUP);
+ mv.visitLdcInsn(minfo.target().osName());
+ mv.visitLdcInsn(minfo.target().osArch());
+ mv.visitMethodInsn(INVOKESPECIAL, MODULE_TARGET_CLASSNAME,
+ "", "(Ljava/lang/String;Ljava/lang/String;)V", false);
+
+ mv.visitInsn(AASTORE);
+ }
+ }
+
+ mv.visitVarInsn(ALOAD, MT_VAR);
+ mv.visitInsn(ARETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
* Generate bytecode for SystemModules::hashes method
*/
private void genHashesMethod() {
@@ -647,10 +698,9 @@ public final class SystemModulesPlugin implements Plugin {
hmv.visitInsn(ARETURN);
hmv.visitMaxs(0, 0);
hmv.visitEnd();
-
}
- /*
+ /**
* Generate bytecode for SystemModules::methodResoultions method
*/
private void genModuleResolutionsMethod() {
@@ -749,6 +799,7 @@ public final class SystemModulesPlugin implements Plugin {
final ModuleDescriptor md;
final Set packages;
final int index;
+
ModuleDescriptorBuilder(ModuleDescriptor md, Set packages, int index) {
if (md.isAutomatic()) {
throw new InternalError("linking automatic module is not supported");
@@ -786,11 +837,6 @@ public final class SystemModulesPlugin implements Plugin {
// main class
md.mainClass().ifPresent(this::mainClass);
- // os name, arch, version
- targetPlatform(md.osName().orElse(null),
- md.osArch().orElse(null),
- md.osVersion().orElse(null));
-
putModuleDescriptor();
}
@@ -1088,25 +1134,6 @@ public final class SystemModulesPlugin implements Plugin {
mv.visitInsn(POP);
}
- /*
- * Invoke Builder.osName(String name)
- * Builder.osArch(String arch)
- * Builder.osVersion(String version)
- */
- void targetPlatform(String osName, String osArch, String osVersion) {
- if (osName != null) {
- invokeBuilderMethod("osName", osName);
- }
-
- if (osArch != null) {
- invokeBuilderMethod("osArch", osArch);
- }
-
- if (osVersion != null) {
- invokeBuilderMethod("osVersion", osVersion);
- }
- }
-
void invokeBuilderMethod(String methodName, String value) {
mv.visitVarInsn(ALOAD, BUILDER_VAR);
mv.visitLdcInsn(value);
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ResourcePoolModule.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ResourcePoolModule.java
index 449d580dbc3..b4a736d72f2 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ResourcePoolModule.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ResourcePoolModule.java
@@ -28,6 +28,7 @@ import java.lang.module.ModuleDescriptor;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
+import jdk.internal.module.ModuleTarget;
/**
* Link-time representation of a module.
@@ -56,6 +57,20 @@ public interface ResourcePoolModule {
*/
public ModuleDescriptor descriptor();
+ /**
+ * The module target OS name for this module.
+ *
+ * @return The module target OS name
+ */
+ public String osName();
+
+ /**
+ * The module target OS arch for this module.
+ *
+ * @return The module target OS arch
+ */
+ public String osArch();
+
/**
* Retrieves all the packages located in this module.
*
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java
index be88c492297..69be83d6912 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java
@@ -96,13 +96,14 @@ import jdk.internal.joptsimple.OptionParser;
import jdk.internal.joptsimple.OptionSet;
import jdk.internal.joptsimple.OptionSpec;
import jdk.internal.joptsimple.ValueConverter;
-import jdk.internal.loader.ResourceHelper;
import jdk.internal.module.ModuleHashes;
import jdk.internal.module.ModuleHashesBuilder;
import jdk.internal.module.ModuleInfo;
import jdk.internal.module.ModuleInfoExtender;
import jdk.internal.module.ModulePath;
import jdk.internal.module.ModuleResolution;
+import jdk.internal.module.ModuleTarget;
+import jdk.internal.module.Resources;
import jdk.tools.jlink.internal.Utils;
import static java.util.stream.Collectors.joining;
@@ -178,7 +179,6 @@ public class JmodTask {
String mainClass;
String osName;
String osArch;
- String osVersion;
Pattern modulesToHash;
ModuleResolution moduleResolution;
boolean dryrun;
@@ -311,7 +311,9 @@ public class JmodTask {
try (JmodFile jf = new JmodFile(options.jmodFile)) {
try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
ModuleInfo.Attributes attrs = ModuleInfo.read(in, null);
- printModuleDescriptor(attrs.descriptor(), attrs.recordedHashes());
+ printModuleDescriptor(attrs.descriptor(),
+ attrs.target(),
+ attrs.recordedHashes());
return true;
} catch (IOException e) {
throw new CommandException("err.module.descriptor.not.found");
@@ -325,7 +327,9 @@ public class JmodTask {
.collect(joining(" "));
}
- private void printModuleDescriptor(ModuleDescriptor md, ModuleHashes hashes)
+ private void printModuleDescriptor(ModuleDescriptor md,
+ ModuleTarget target,
+ ModuleHashes hashes)
throws IOException
{
StringBuilder sb = new StringBuilder();
@@ -365,11 +369,14 @@ public class JmodTask {
md.mainClass().ifPresent(v -> sb.append("\n main-class " + v));
- md.osName().ifPresent(v -> sb.append("\n operating-system-name " + v));
-
- md.osArch().ifPresent(v -> sb.append("\n operating-system-architecture " + v));
-
- md.osVersion().ifPresent(v -> sb.append("\n operating-system-version " + v));
+ if (target != null) {
+ String osName = target.osName();
+ if (osName != null)
+ sb.append("\n operating-system-name " + osName);
+ String osArch = target.osArch();
+ if (osArch != null)
+ sb.append("\n operating-system-architecture " + osArch);
+ }
if (hashes != null) {
hashes.names().stream().sorted().forEach(
@@ -432,7 +439,6 @@ public class JmodTask {
final String mainClass = options.mainClass;
final String osName = options.osName;
final String osArch = options.osArch;
- final String osVersion = options.osVersion;
final List excludes = options.excludes;
final ModuleResolution moduleResolution = options.moduleResolution;
@@ -528,9 +534,9 @@ public class JmodTask {
if (mainClass != null)
extender.mainClass(mainClass);
- // --os-name, --os-arch, --os-version
- if (osName != null || osArch != null || osVersion != null)
- extender.targetPlatform(osName, osArch, osVersion);
+ // --os-name, --os-arch
+ if (osName != null || osArch != null)
+ extender.targetPlatform(osName, osArch);
// --module-version
if (moduleVersion != null)
@@ -675,7 +681,7 @@ public class JmodTask {
*/
boolean isResource(String name) {
name = name.replace(File.separatorChar, '/');
- return name.endsWith(".class") || !ResourceHelper.isSimpleResource(name);
+ return name.endsWith(".class") || Resources.canEncapsulate(name);
}
@@ -1331,11 +1337,6 @@ public class JmodTask {
.withRequiredArg()
.describedAs(getMessage("main.opt.os-arch.arg"));
- OptionSpec osVersion
- = parser.accepts("os-version", getMessage("main.opt.os-version"))
- .withRequiredArg()
- .describedAs(getMessage("main.opt.os-version.arg"));
-
OptionSpec doNotResolveByDefault
= parser.accepts("do-not-resolve-by-default",
getMessage("main.opt.do-not-resolve-by-default"));
@@ -1403,8 +1404,6 @@ public class JmodTask {
options.osName = getLastElement(opts.valuesOf(osName));
if (opts.has(osArch))
options.osArch = getLastElement(opts.valuesOf(osArch));
- if (opts.has(osVersion))
- options.osVersion = getLastElement(opts.valuesOf(osVersion));
if (opts.has(warnIfResolved))
options.moduleResolution = getLastElement(opts.valuesOf(warnIfResolved));
if (opts.has(doNotResolveByDefault)) {
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties
index 51daee12ed3..acc7710889c 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties
@@ -68,8 +68,6 @@ main.opt.os-name=Operating system name
main.opt.os-name.arg=os-name
main.opt.os-arch=Operating system architecture
main.opt.os-arch.arg=os-arch
-main.opt.os-version=Operating system version
-main.opt.os-version.arg=os-version
main.opt.module-path=Module path
main.opt.hash-modules=Compute and record hashes to tie a packaged module\
\ with modules matching the given and depending upon it directly\
diff --git a/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java b/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java
index 641fa2f06cb..a77109ce49c 100644
--- a/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java
+++ b/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java
@@ -813,6 +813,7 @@ public final class Unsafe {
/**
* Tells the VM to define a class, without security checks. By default, the
* class loader and protection domain come from the caller's class.
+ * @see java.lang.invoke.MethodHandles.Lookup#defineClass(byte[])
*/
@ForceInline
public Class> defineClass(String name, byte[] b, int off, int len,
diff --git a/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java b/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java
index 90a34a58d6b..5ea706de1ee 100644
--- a/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java
+++ b/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java
@@ -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
@@ -380,6 +380,7 @@ public class FieldSetAccessibleTest {
permissions.add(new RuntimePermission("closeClassLoader"));
permissions.add(new RuntimePermission("getClassLoader"));
permissions.add(new RuntimePermission("accessDeclaredMembers"));
+ permissions.add(new RuntimePermission("accessSystemModules"));
permissions.add(new ReflectPermission("suppressAccessChecks"));
permissions.add(new PropertyPermission("*", "read"));
permissions.add(new FilePermission("<>", "read"));
diff --git a/jdk/test/java/lang/ClassLoader/getResource/automaticmodules/Driver.java b/jdk/test/java/lang/ClassLoader/getResource/automaticmodules/Driver.java
new file mode 100644
index 00000000000..da56df06291
--- /dev/null
+++ b/jdk/test/java/lang/ClassLoader/getResource/automaticmodules/Driver.java
@@ -0,0 +1,88 @@
+/*
+ * 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
+ * @library /lib/testlibrary
+ * @build Driver Main JarUtils jdk.testlibrary.ProcessTools
+ * @run main Driver
+ * @summary Test ClassLoader.getResourceXXX to locate resources in an automatic
+ * module
+ */
+
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import jdk.testlibrary.ProcessTools;
+
+/**
+ * The driver creates a JAR file containing p/Foo.class, p/foo.properties,
+ * and p/resources/bar.properties. This ensures there are is a resource in
+ * a module package and a resource that is not in the module package. The
+ * test is then launched to locate every resource in the JAR file.
+ */
+
+public class Driver {
+
+ private static final String TEST_CLASSES = System.getProperty("test.classes");
+
+ public static void main(String[] args) throws Exception {
+ // create content for JAR file
+ Path dir = Files.createTempDirectory("classes");
+ Path p = Files.createDirectory(dir.resolve("p"));
+ Files.createFile(p.resolve("Foo.class"));
+ Files.createFile(p.resolve("foo.properties"));
+ Path resources = Files.createDirectory(p.resolve("resources"));
+ Files.createFile(resources.resolve("bar.properties"));
+
+ // create the JAR file, including a manifest
+ Path jarFile = Paths.get("library-1.0.jar");
+ Manifest man = new Manifest();
+ Attributes attrs = man.getMainAttributes();
+ attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
+ JarUtils.createJarFile(jarFile, man, dir, p);
+
+ // get the module name
+ ModuleFinder finder = ModuleFinder.of(jarFile);
+ ModuleReference mref = finder.findAll().stream().findAny().orElse(null);
+ if (mref == null)
+ throw new RuntimeException("Module not found!!!");
+ String name = mref.descriptor().name();
+
+ // launch the test with the JAR file on the module path
+ if (ProcessTools.executeTestJava("-p", jarFile.toString(),
+ "--add-modules", name,
+ "-cp", TEST_CLASSES,
+ "Main", name)
+ .outputTo(System.out)
+ .errorTo(System.out)
+ .getExitValue() != 0)
+ throw new RuntimeException("Test failed - see output");
+ }
+
+}
diff --git a/jdk/test/java/lang/ClassLoader/getResource/automaticmodules/Main.java b/jdk/test/java/lang/ClassLoader/getResource/automaticmodules/Main.java
new file mode 100644
index 00000000000..afde3d56bf5
--- /dev/null
+++ b/jdk/test/java/lang/ClassLoader/getResource/automaticmodules/Main.java
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.Layer;
+import java.net.URL;
+import java.util.Enumeration;
+
+/**
+ * Usage: Main $MODULE
+ *
+ * Finds $MODULE in the boot layer and then tests that it can locate every
+ * resource in the module content (JAR file).
+ */
+
+public class Main {
+
+ static void testFind(String name) throws Exception {
+ // getResource
+ URL url = Main.class.getClassLoader().getResource(name);
+ if (url == null)
+ throw new RuntimeException("Unable to locate: " + name);
+ System.out.println(name + " => " + url);
+
+ // getResources
+ Enumeration urls = Main.class.getClassLoader().getResources(name);
+ if (!urls.hasMoreElements())
+ throw new RuntimeException("Unable to locate: " + name);
+ URL first = urls.nextElement();
+ if (!first.toURI().equals(url.toURI()))
+ throw new RuntimeException("found " + first + " ???");
+
+ // getResourceAsStream
+ if (!url.toString().endsWith("/")) {
+ InputStream in = Main.class.getClassLoader().getResourceAsStream(name);
+ if (in == null)
+ throw new RuntimeException("Unable to locate: " + name);
+ in.close();
+ }
+ }
+
+ static void testFindUnchecked(String name) {
+ try {
+ testFind(name);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ String mn = args[0];
+
+ ModuleReference mref = Layer.boot()
+ .configuration()
+ .findModule(mn)
+ .map(ResolvedModule::reference)
+ .orElseThrow(() -> new RuntimeException(mn + " not resolved!!"));
+
+ try (ModuleReader reader = mref.open()) {
+ reader.list().forEach(name -> {
+ testFindUnchecked(name);
+
+ // if the resource is a directory then find without trailing slash
+ if (name.endsWith("/")) {
+ testFindUnchecked(name.substring(0, name.length() - 1));
+ }
+ });
+ }
+ }
+}
diff --git a/jdk/test/java/lang/invoke/DefineClassTest.java b/jdk/test/java/lang/invoke/DefineClassTest.java
new file mode 100644
index 00000000000..456eaf6fad9
--- /dev/null
+++ b/jdk/test/java/lang/invoke/DefineClassTest.java
@@ -0,0 +1,352 @@
+/*
+ * 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
+ * @modules java.base/java.lang:open
+ * java.base/jdk.internal.org.objectweb.asm
+ * @run testng/othervm test.DefineClassTest
+ * @summary Basic test for java.lang.invoke.MethodHandles.Lookup.defineClass
+ */
+
+package test;
+
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodHandles.Lookup.*;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+public class DefineClassTest {
+ private static final String THIS_PACKAGE = DefineClassTest.class.getPackageName();
+
+ /**
+ * Test that a class has the same class loader, and is in the same package and
+ * protection domain, as a lookup class.
+ */
+ void testSameAbode(Class> clazz, Class> lc) {
+ assertTrue(clazz.getClassLoader() == lc.getClassLoader());
+ assertEquals(clazz.getPackageName(), lc.getPackageName());
+ assertTrue(clazz.getProtectionDomain() == lc.getProtectionDomain());
+ }
+
+ /**
+ * Tests that a class is discoverable by name using Class.forName and
+ * lookup.findClass
+ */
+ void testDiscoverable(Class> clazz, Lookup lookup) throws Exception {
+ String cn = clazz.getName();
+ ClassLoader loader = clazz.getClassLoader();
+ assertTrue(Class.forName(cn, false, loader) == clazz);
+ assertTrue(lookup.findClass(cn) == clazz);
+ }
+
+ /**
+ * Basic test of defineClass to define a class in the same package as test.
+ */
+ @Test
+ public void testDefineClass() throws Exception {
+ final String CLASS_NAME = THIS_PACKAGE + ".Foo";
+ Lookup lookup = lookup().dropLookupMode(PRIVATE);
+ Class> clazz = lookup.defineClass(generateClass(CLASS_NAME));
+
+ // test name
+ assertEquals(clazz.getName(), CLASS_NAME);
+
+ // test loader/package/protection-domain
+ testSameAbode(clazz, lookup.lookupClass());
+
+ // test discoverable
+ testDiscoverable(clazz, lookup);
+
+ // attempt defineClass again
+ try {
+ lookup.defineClass(generateClass(CLASS_NAME));
+ assertTrue(false);
+ } catch (LinkageError expected) { }
+ }
+
+ /**
+ * Test public/package/protected/private access from class defined with defineClass.
+ */
+ @Test
+ public void testAccess() throws Exception {
+ final String THIS_CLASS = this.getClass().getName();
+ final String CLASS_NAME = THIS_PACKAGE + ".Runner";
+ Lookup lookup = lookup().dropLookupMode(PRIVATE);
+
+ // public
+ byte[] classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method1");
+ testInvoke(lookup.defineClass(classBytes));
+
+ // package
+ classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method2");
+ testInvoke(lookup.defineClass(classBytes));
+
+ // protected (same package)
+ classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method3");
+ testInvoke(lookup.defineClass(classBytes));
+
+ // private
+ classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method4");
+ Class> clazz = lookup.defineClass(classBytes);
+ Runnable r = (Runnable) clazz.newInstance();
+ try {
+ r.run();
+ assertTrue(false);
+ } catch (IllegalAccessError expected) { }
+ }
+
+ public static void method1() { }
+ static void method2() { }
+ protected static void method3() { }
+ private static void method4() { }
+
+ void testInvoke(Class> clazz) throws Exception {
+ Object obj = clazz.newInstance();
+ ((Runnable) obj).run();
+ }
+
+ /**
+ * Test that defineClass does not run the class initializer
+ */
+ @Test
+ public void testInitializerNotRun() throws Exception {
+ final String THIS_CLASS = this.getClass().getName();
+ final String CLASS_NAME = THIS_PACKAGE + ".ClassWithClinit";
+
+ byte[] classBytes = generateClassWithInitializer(CLASS_NAME, THIS_CLASS, "fail");
+ Lookup lookup = lookup().dropLookupMode(PRIVATE);
+
+ Class> clazz = lookup.defineClass(classBytes);
+ // trigger initializer to run
+ try {
+ clazz.newInstance();
+ assertTrue(false);
+ } catch (ExceptionInInitializerError e) {
+ assertTrue(e.getCause() instanceof IllegalCallerException);
+ }
+ }
+
+ static void fail() { throw new IllegalCallerException(); }
+
+
+ /**
+ * Test defineClass to define classes in a package containing classes with
+ * different protection domains.
+ */
+ @Test
+ public void testTwoProtectionDomains() throws Exception {
+ // p.C1 in one exploded directory
+ Path dir1 = Files.createTempDirectory("classes");
+ Path p = Files.createDirectory(dir1.resolve("p"));
+ Files.write(p.resolve("C1.class"), generateClass("p.C1"));
+ URL url1 = dir1.toUri().toURL();
+
+ // p.C2 in another exploded directory
+ Path dir2 = Files.createTempDirectory("classes");
+ p = Files.createDirectory(dir2.resolve("p"));
+ Files.write(p.resolve("C2.class"), generateClass("p.C2"));
+ URL url2 = dir2.toUri().toURL();
+
+ // load p.C1 and p.C2
+ ClassLoader loader = new URLClassLoader(new URL[] { url1, url2 });
+ Class> target1 = Class.forName("p.C1", false, loader);
+ Class> target2 = Class.forName("p.C2", false, loader);
+ assertTrue(target1.getClassLoader() == loader);
+ assertTrue(target1.getClassLoader() == loader);
+ assertNotEquals(target1.getProtectionDomain(), target2.getProtectionDomain());
+
+ // protection domain 1
+ Lookup lookup1 = privateLookupIn(target1, lookup()).dropLookupMode(PRIVATE);
+
+ Class> clazz = lookup1.defineClass(generateClass("p.Foo"));
+ testSameAbode(clazz, lookup1.lookupClass());
+ testDiscoverable(clazz, lookup1);
+
+ // protection domain 2
+ Lookup lookup2 = privateLookupIn(target2, lookup()).dropLookupMode(PRIVATE);
+
+ clazz = lookup2.defineClass(generateClass("p.Bar"));
+ testSameAbode(clazz, lookup2.lookupClass());
+ testDiscoverable(clazz, lookup2);
+ }
+
+ /**
+ * Test defineClass defining a class to the boot loader
+ */
+ @Test
+ public void testBootLoader() throws Exception {
+ Lookup lookup = privateLookupIn(Thread.class, lookup()).dropLookupMode(PRIVATE);
+ assertTrue(lookup.getClass().getClassLoader() == null);
+
+ Class> clazz = lookup.defineClass(generateClass("java.lang.Foo"));
+ assertEquals(clazz.getName(), "java.lang.Foo");
+ testSameAbode(clazz, Thread.class);
+ testDiscoverable(clazz, lookup);
+ }
+
+ @Test(expectedExceptions = { IllegalArgumentException.class })
+ public void testWrongPackage() throws Exception {
+ Lookup lookup = lookup().dropLookupMode(PRIVATE);
+ lookup.defineClass(generateClass("other.C"));
+ }
+
+ @Test(expectedExceptions = { IllegalAccessException.class })
+ public void testNoPackageAccess() throws Exception {
+ Lookup lookup = lookup().dropLookupMode(PACKAGE);
+ lookup.defineClass(generateClass(THIS_PACKAGE + ".C"));
+ }
+
+ @Test(expectedExceptions = { UnsupportedOperationException.class })
+ public void testHasPrivateAccess() throws Exception {
+ Lookup lookup = lookup();
+ assertTrue(lookup.hasPrivateAccess());
+ lookup.defineClass(generateClass(THIS_PACKAGE + ".C"));
+ }
+
+ @Test(expectedExceptions = { ClassFormatError.class })
+ public void testTruncatedClassFile() throws Exception {
+ Lookup lookup = lookup().dropLookupMode(PRIVATE);
+ lookup.defineClass(new byte[0]);
+ }
+
+ @Test(expectedExceptions = { NullPointerException.class })
+ public void testNull() throws Exception {
+ Lookup lookup = lookup().dropLookupMode(PRIVATE);
+ lookup.defineClass(null);
+ }
+
+ /**
+ * Generates a class file with the given class name
+ */
+ byte[] generateClass(String className) {
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+ + ClassWriter.COMPUTE_FRAMES);
+ cw.visit(V1_9,
+ ACC_PUBLIC + ACC_SUPER,
+ className.replace(".", "/"),
+ null,
+ "java/lang/Object",
+ null);
+
+ //
+ MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false);
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+
+ cw.visitEnd();
+ return cw.toByteArray();
+ }
+
+ /**
+ * Generate a class file with the given class name. The class implements Runnable
+ * with a run method to invokestatic the given targetClass/targetMethod.
+ */
+ byte[] generateRunner(String className,
+ String targetClass,
+ String targetMethod) throws Exception {
+
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+ + ClassWriter.COMPUTE_FRAMES);
+ cw.visit(V1_9,
+ ACC_PUBLIC + ACC_SUPER,
+ className.replace(".", "/"),
+ null,
+ "java/lang/Object",
+ new String[] { "java/lang/Runnable" });
+
+ //
+ MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false);
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+
+ // run()
+ String tc = targetClass.replace(".", "/");
+ mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null);
+ mv.visitMethodInsn(INVOKESTATIC, tc, targetMethod, "()V", false);
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+
+ cw.visitEnd();
+ return cw.toByteArray();
+ }
+
+ /**
+ * Generate a class file with the given class name. The class will initializer
+ * to invokestatic the given targetClass/targetMethod.
+ */
+ byte[] generateClassWithInitializer(String className,
+ String targetClass,
+ String targetMethod) throws Exception {
+
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+ + ClassWriter.COMPUTE_FRAMES);
+ cw.visit(V1_9,
+ ACC_PUBLIC + ACC_SUPER,
+ className.replace(".", "/"),
+ null,
+ "java/lang/Object",
+ null);
+
+ //
+ MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false);
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+
+ //
+ String tc = targetClass.replace(".", "/");
+ mv = cw.visitMethod(ACC_STATIC, "", "()V", null, null);
+ mv.visitMethodInsn(INVOKESTATIC, tc, targetMethod, "()V", false);
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+
+ cw.visitEnd();
+ return cw.toByteArray();
+ }
+
+ private int nextNumber() {
+ return ++nextNumber;
+ }
+
+ private int nextNumber;
+}
diff --git a/jdk/test/java/lang/module/AutomaticModulesTest.java b/jdk/test/java/lang/module/AutomaticModulesTest.java
index 1c020c309f2..81d68973ffe 100644
--- a/jdk/test/java/lang/module/AutomaticModulesTest.java
+++ b/jdk/test/java/lang/module/AutomaticModulesTest.java
@@ -773,9 +773,6 @@ public class AutomaticModulesTest {
// test miscellaneous methods
assertTrue(m.isAutomatic());
assertFalse(m.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC));
- assertFalse(m.osName().isPresent());
- assertFalse(m.osArch().isPresent());
- assertFalse(m.osVersion().isPresent());
}
diff --git a/jdk/test/java/lang/module/ConfigurationTest.java b/jdk/test/java/lang/module/ConfigurationTest.java
index 28f414736b1..d010ca30060 100644
--- a/jdk/test/java/lang/module/ConfigurationTest.java
+++ b/jdk/test/java/lang/module/ConfigurationTest.java
@@ -25,25 +25,31 @@
* @test
* @library /lib/testlibrary
* @modules java.base/jdk.internal.misc
+ * java.base/jdk.internal.module
* @build ConfigurationTest ModuleUtils
* @run testng ConfigurationTest
* @summary Basic tests for java.lang.module.Configuration
*/
+import java.io.IOException;
+import java.io.OutputStream;
import java.lang.module.Configuration;
import java.lang.module.FindException;
import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.Builder;
import java.lang.module.ModuleDescriptor.Requires;
import java.lang.module.ModuleFinder;
import java.lang.module.ResolutionException;
import java.lang.module.ResolvedModule;
import java.lang.reflect.Layer;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleInfoWriter;
+import jdk.internal.module.ModuleTarget;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@@ -437,70 +443,6 @@ public class ConfigurationTest {
}
- /**
- * Basic test of "requires transitive" with configurations.
- *
- * The test consists of three configurations:
- * - Configuration cf1: m1, m2 requires transitive m1
- * - Configuration cf2: m1, m3 requires transitive m1
- * - Configuration cf3(cf1,cf2): m4 requires m2, m3
- */
- public void testRequiresTransitive6() {
- ModuleDescriptor descriptor1 = newBuilder("m1")
- .build();
-
- ModuleDescriptor descriptor2 = newBuilder("m2")
- .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
- .build();
-
- ModuleDescriptor descriptor3 = newBuilder("m3")
- .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
- .build();
-
- ModuleDescriptor descriptor4 = newBuilder("m4")
- .requires("m2")
- .requires("m3")
- .build();
-
- ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
- Configuration cf1 = resolve(finder1, "m2");
- assertTrue(cf1.modules().size() == 2);
- assertTrue(cf1.findModule("m1").isPresent());
- assertTrue(cf1.findModule("m2").isPresent());
- assertTrue(cf1.parents().size() == 1);
- assertTrue(cf1.parents().get(0) == Configuration.empty());
-
- ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3);
- Configuration cf2 = resolve(finder2, "m3");
- assertTrue(cf2.modules().size() == 2);
- assertTrue(cf2.findModule("m3").isPresent());
- assertTrue(cf2.findModule("m1").isPresent());
- assertTrue(cf2.parents().size() == 1);
- assertTrue(cf2.parents().get(0) == Configuration.empty());
-
- ModuleFinder finder3 = ModuleUtils.finderOf(descriptor4);
- Configuration cf3 = Configuration.resolve(finder3,
- List.of(cf1, cf2),
- ModuleFinder.of(),
- Set.of("m4"));
- assertTrue(cf3.modules().size() == 1);
- assertTrue(cf3.findModule("m4").isPresent());
-
- ResolvedModule m1_l = cf1.findModule("m1").get();
- ResolvedModule m1_r = cf2.findModule("m1").get();
- ResolvedModule m2 = cf1.findModule("m2").get();
- ResolvedModule m3 = cf2.findModule("m3").get();
- ResolvedModule m4 = cf3.findModule("m4").get();
- assertTrue(m4.configuration() == cf3);
-
- assertTrue(m4.reads().size() == 4);
- assertTrue(m4.reads().contains(m1_l));
- assertTrue(m4.reads().contains(m1_r));
- assertTrue(m4.reads().contains(m2));
- assertTrue(m4.reads().contains(m3));
- }
-
-
/**
* Basic test of "requires static":
* m1 requires static m2
@@ -1602,6 +1544,76 @@ public class ConfigurationTest {
}
+ /**
+ * Basic test to detect reading a module with the same name as itself
+ *
+ * The test consists of three configurations:
+ * - Configuration cf1: m1, m2 requires transitive m1
+ * - Configuration cf2: m1 requires m2
+ */
+ @Test(expectedExceptions = { ResolutionException.class })
+ public void testReadModuleWithSameNameAsSelf() {
+ ModuleDescriptor descriptor1_v1 = newBuilder("m1")
+ .build();
+
+ ModuleDescriptor descriptor2 = newBuilder("m2")
+ .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
+ .build();
+
+ ModuleDescriptor descriptor1_v2 = newBuilder("m1")
+ .requires("m2")
+ .build();
+
+ ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1_v1, descriptor2);
+ Configuration cf1 = resolve(finder1, "m2");
+ assertTrue(cf1.modules().size() == 2);
+
+ // resolve should throw ResolutionException
+ ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1_v2);
+ resolve(cf1, finder2, "m1");
+ }
+
+
+ /**
+ * Basic test to detect reading two modules with the same name
+ *
+ * The test consists of three configurations:
+ * - Configuration cf1: m1, m2 requires transitive m1
+ * - Configuration cf2: m1, m3 requires transitive m1
+ * - Configuration cf3(cf1,cf2): m4 requires m2, m3
+ */
+ @Test(expectedExceptions = { ResolutionException.class })
+ public void testReadTwoModuleWithSameName() {
+ ModuleDescriptor descriptor1 = newBuilder("m1")
+ .build();
+
+ ModuleDescriptor descriptor2 = newBuilder("m2")
+ .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
+ .build();
+
+ ModuleDescriptor descriptor3 = newBuilder("m3")
+ .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
+ .build();
+
+ ModuleDescriptor descriptor4 = newBuilder("m4")
+ .requires("m2")
+ .requires("m3")
+ .build();
+
+ ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+ Configuration cf1 = resolve(finder1, "m2");
+ assertTrue(cf1.modules().size() == 2);
+
+ ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3);
+ Configuration cf2 = resolve(finder2, "m3");
+ assertTrue(cf2.modules().size() == 2);
+
+ // should throw ResolutionException as m4 will read modules named "m1".
+ ModuleFinder finder3 = ModuleUtils.finderOf(descriptor4);
+ Configuration.resolve(finder3, List.of(cf1, cf2), ModuleFinder.of(), Set.of("m4"));
+ }
+
+
/**
* Test two modules exporting package p to a module that reads both.
*/
@@ -1832,26 +1844,17 @@ public class ConfigurationTest {
public Object[][] createPlatformMatches() {
return new Object[][]{
- { "linux-*-*", "*-*-*" },
- { "*-arm-*", "*-*-*" },
- { "*-*-2.6", "*-*-*" },
+ { "linux-arm", "*-*" },
+ { "linux-*", "*-*" },
+ { "*-arm", "*-*" },
- { "linux-arm-*", "*-*-*" },
- { "linux-*-2.6", "*-*-*" },
- { "*-arm-2.6", "*-*-*" },
+ { "linux-*", "linux-*" },
+ { "linux-arm", "linux-*" },
- { "linux-arm-2.6", "*-*-*" },
+ { "*-arm", "*-arm" },
+ { "linux-arm", "*-arm" },
- { "linux-*-*", "linux-*-*" },
- { "*-arm-*", "*-arm-*" },
- { "*-*-2.6", "*-*-2.6" },
-
- { "linux-arm-*", "linux-arm-*" },
- { "linux-arm-*", "linux-*-*" },
- { "linux-*-2.6", "linux-*-2.6" },
- { "linux-*-2.6", "linux-arm-*" },
-
- { "linux-arm-2.6", "linux-arm-2.6" },
+ { "linux-arm", "linux-arm" },
};
@@ -1861,9 +1864,10 @@ public class ConfigurationTest {
public Object[][] createBad() {
return new Object[][] {
- { "linux-*-*", "solaris-*-*" },
- { "linux-x86-*", "linux-arm-*" },
- { "linux-*-2.4", "linux-x86-2.6" },
+ { "linux-*", "solaris-*" },
+ { "*-arm", "*-sparc" },
+ { "linux-x86", "solaris-sparc" },
+
};
}
@@ -1871,21 +1875,25 @@ public class ConfigurationTest {
* Test creating a configuration containing platform specific modules.
*/
@Test(dataProvider = "platformmatch")
- public void testPlatformMatch(String s1, String s2) {
+ public void testPlatformMatch(String s1, String s2) throws IOException {
- Builder builder = newBuilder("m1").requires("m2");
- addPlatformConstraints(builder, s1);
- ModuleDescriptor descriptor1 = builder.build();
+ ModuleDescriptor base = ModuleDescriptor.newModule("java.base").build();
+ Path system = writeModule(base, "*-*");
- builder = newBuilder("m2");
- addPlatformConstraints(builder, s2);
- ModuleDescriptor descriptor2 = builder.build();
+ ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1")
+ .requires("m2")
+ .build();
+ Path dir1 = writeModule(descriptor1, s1);
- ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+ ModuleDescriptor descriptor2 = ModuleDescriptor.newModule("m2").build();
+ Path dir2 = writeModule(descriptor2, s2);
+
+ ModuleFinder finder = ModuleFinder.of(system, dir1, dir2);
Configuration cf = resolve(finder, "m1");
- assertTrue(cf.modules().size() == 2);
+ assertTrue(cf.modules().size() == 3);
+ assertTrue(cf.findModule("java.base").isPresent());
assertTrue(cf.findModule("m1").isPresent());
assertTrue(cf.findModule("m2").isPresent());
}
@@ -1896,11 +1904,10 @@ public class ConfigurationTest {
*/
@Test(dataProvider = "platformmismatch",
expectedExceptions = FindException.class )
- public void testPlatformMisMatch(String s1, String s2) {
+ public void testPlatformMisMatch(String s1, String s2) throws IOException {
testPlatformMatch(s1, s2);
}
-
// no parents
@Test(expectedExceptions = { IllegalArgumentException.class })
@@ -1917,21 +1924,23 @@ public class ConfigurationTest {
// parents with modules for specific platforms
-
@Test(dataProvider = "platformmatch")
- public void testResolveRequiresWithCompatibleParents(String s1, String s2) {
- Builder builder = newBuilder("m1");
- addPlatformConstraints(builder, s1);
- ModuleDescriptor descriptor1 = builder.build();
+ public void testResolveRequiresWithCompatibleParents(String s1, String s2)
+ throws IOException
+ {
+ ModuleDescriptor base = ModuleDescriptor.newModule("java.base").build();
+ Path system = writeModule(base, "*-*");
- builder = newBuilder("m2");
- addPlatformConstraints(builder, s2);
- ModuleDescriptor descriptor2 = builder.build();
+ ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1").build();
+ Path dir1 = writeModule(descriptor1, s1);
- ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+ ModuleDescriptor descriptor2 = ModuleDescriptor.newModule("m2").build();
+ Path dir2 = writeModule(descriptor2, s2);
+
+ ModuleFinder finder1 = ModuleFinder.of(system, dir1);
Configuration cf1 = resolve(finder1, "m1");
- ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
+ ModuleFinder finder2 = ModuleFinder.of(system, dir2);
Configuration cf2 = resolve(finder2, "m2");
Configuration cf3 = Configuration.resolve(ModuleFinder.of(),
@@ -1941,32 +1950,16 @@ public class ConfigurationTest {
assertTrue(cf3.parents().size() == 2);
}
+
@Test(dataProvider = "platformmismatch",
expectedExceptions = IllegalArgumentException.class )
- public void testResolveRequiresWithConflictingParents(String s1, String s2) {
- Builder builder = newBuilder("m1");
- addPlatformConstraints(builder, s1);
- ModuleDescriptor descriptor1 = builder.build();
-
- builder = newBuilder("m2");
- addPlatformConstraints(builder, s2);
- ModuleDescriptor descriptor2 = builder.build();
-
- ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
- Configuration cf1 = resolve(finder1, "m1");
-
- ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
- Configuration cf2 = resolve(finder2, "m2");
-
- // should throw IAE
- Configuration.resolve(ModuleFinder.of(),
- List.of(cf1, cf2),
- ModuleFinder.of(),
- Set.of());
+ public void testResolveRequiresWithConflictingParents(String s1, String s2)
+ throws IOException
+ {
+ testResolveRequiresWithCompatibleParents(s1, s2);
}
-
// null handling
// finder1, finder2, roots
@@ -2120,31 +2113,24 @@ public class ConfigurationTest {
}
- /**
- * Returns {@code true} if the configuration contains module mn1
- * that reads module mn2.
- */
- static boolean reads(Configuration cf, String mn1, String mn2) {
- Optional om1 = cf.findModule(mn1);
- if (!om1.isPresent())
- return false;
-
- return om1.get().reads().stream()
- .map(ResolvedModule::name)
- .anyMatch(mn2::equals);
- }
-
/**
* Decodes the platform string and calls the builder osName/osArch/osVersion
* methods to set the platform constraints.
*/
- static void addPlatformConstraints(Builder builder, String platformString) {
+ static Path writeModule(ModuleDescriptor descriptor, String platformString)
+ throws IOException
+ {
String[] s = platformString.split("-");
- if (!s[0].equals("*"))
- builder.osName(s[0]);
- if (!s[1].equals("*"))
- builder.osArch(s[1]);
- if (!s[2].equals("*"))
- builder.osVersion(s[2]);
+ String osName = !s[0].equals("*") ? s[0] : null;
+ String osArch = !s[1].equals("*") ? s[1] : null;
+ ModuleTarget target = new ModuleTarget(osName, osArch);
+
+ String name = descriptor.name();
+ Path dir = Files.createTempDirectory(name);
+ Path mi = dir.resolve("module-info.class");
+ try (OutputStream out = Files.newOutputStream(mi)) {
+ ModuleInfoWriter.write(descriptor, target, out);
+ }
+ return dir;
}
}
diff --git a/jdk/test/java/lang/module/ModuleDescriptorTest.java b/jdk/test/java/lang/module/ModuleDescriptorTest.java
index b16b9e66e92..2bd63497141 100644
--- a/jdk/test/java/lang/module/ModuleDescriptorTest.java
+++ b/jdk/test/java/lang/module/ModuleDescriptorTest.java
@@ -50,11 +50,13 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
+import jdk.internal.misc.JavaLangModuleAccess;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.module.ModuleInfoWriter;
import org.testng.annotations.DataProvider;
@@ -988,6 +990,107 @@ public class ModuleDescriptorTest {
}
+ @DataProvider(name = "unparseableVersions")
+ public Object[][] unparseableVersions() {
+ return new Object[][]{
+
+ { null, "A1" }, // no version < unparseable
+ { "A1", "A2" }, // unparseable < unparseable
+ { "A1", "1.0" }, // unparseable < parseable
+
+ };
+ }
+
+ /**
+ * Basic test for unparseable module versions
+ */
+ @Test(dataProvider = "unparseableVersions")
+ public void testUnparseableModuleVersion(String vs1, String vs2) {
+ ModuleDescriptor descriptor1 = newModule("m", vs1);
+ ModuleDescriptor descriptor2 = newModule("m", vs2);
+
+ if (vs1 != null && !isParsableVersion(vs1)) {
+ assertFalse(descriptor1.version().isPresent());
+ assertTrue(descriptor1.rawVersion().isPresent());
+ assertEquals(descriptor1.rawVersion().get(), vs1);
+ }
+
+ if (vs2 != null && !isParsableVersion(vs2)) {
+ assertFalse(descriptor2.version().isPresent());
+ assertTrue(descriptor2.rawVersion().isPresent());
+ assertEquals(descriptor2.rawVersion().get(), vs2);
+ }
+
+ assertFalse(descriptor1.equals(descriptor2));
+ assertFalse(descriptor2.equals(descriptor1));
+ assertTrue(descriptor1.compareTo(descriptor2) == -1);
+ assertTrue(descriptor2.compareTo(descriptor1) == 1);
+ }
+
+ /**
+ * Basic test for requiring a module with an unparseable version recorded
+ * at compile version.
+ */
+ @Test(dataProvider = "unparseableVersions")
+ public void testUnparseableCompiledVersion(String vs1, String vs2) {
+ Requires r1 = newRequires("m", vs1);
+ Requires r2 = newRequires("m", vs2);
+
+ if (vs1 != null && !isParsableVersion(vs1)) {
+ assertFalse(r1.compiledVersion().isPresent());
+ assertTrue(r1.rawCompiledVersion().isPresent());
+ assertEquals(r1.rawCompiledVersion().get(), vs1);
+ }
+
+ if (vs2 != null && !isParsableVersion(vs2)) {
+ assertFalse(r2.compiledVersion().isPresent());
+ assertTrue(r2.rawCompiledVersion().isPresent());
+ assertEquals(r2.rawCompiledVersion().get(), vs2);
+ }
+
+ assertFalse(r1.equals(r2));
+ assertFalse(r2.equals(r1));
+ assertTrue(r1.compareTo(r2) == -1);
+ assertTrue(r2.compareTo(r1) == 1);
+ }
+
+ private ModuleDescriptor newModule(String name, String vs) {
+ JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
+ Builder builder = JLMA.newModuleBuilder(name, false, Set.of());
+ if (vs != null)
+ builder.version(vs);
+ builder.requires("java.base");
+ ByteBuffer bb = ModuleInfoWriter.toByteBuffer(builder.build());
+ return ModuleDescriptor.read(bb);
+ }
+
+ private Requires newRequires(String name, String vs) {
+ JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
+ Builder builder = JLMA.newModuleBuilder("foo", false, Set.of());
+ if (vs == null) {
+ builder.requires(name);
+ } else {
+ JLMA.requires(builder, Set.of(), name, vs);
+ }
+ Set requires = builder.build().requires();
+ Iterator iterator = requires.iterator();
+ ModuleDescriptor.Requires r = iterator.next();
+ if (r.name().equals("java.base")) {
+ r = iterator.next();
+ }
+ return r;
+ }
+
+ private boolean isParsableVersion(String vs) {
+ try {
+ Version.parse(vs);
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+
+
// toNameAndVersion
public void testToNameAndVersion() {
@@ -1170,59 +1273,6 @@ public class ModuleDescriptorTest {
}
- // osName
-
- public void testOsName() {
- String osName = ModuleDescriptor.newModule("foo").osName("Linux").build().osName().get();
- assertEquals(osName, "Linux");
- }
-
- @Test(expectedExceptions = IllegalArgumentException.class)
- public void testNullOsName() {
- ModuleDescriptor.newModule("foo").osName(null);
- }
-
- @Test(expectedExceptions = IllegalArgumentException.class)
- public void testEmptyOsName() {
- ModuleDescriptor.newModule("foo").osName("");
- }
-
-
- // osArch
-
- public void testOsArch() {
- String osArch = ModuleDescriptor.newModule("foo").osName("arm").build().osName().get();
- assertEquals(osArch, "arm");
- }
-
- @Test(expectedExceptions = IllegalArgumentException.class)
- public void testNullOsArch() {
- ModuleDescriptor.newModule("foo").osArch(null);
- }
-
- @Test(expectedExceptions = IllegalArgumentException.class)
- public void testEmptyOsArch() {
- ModuleDescriptor.newModule("foo").osArch("");
- }
-
-
- // osVersion
-
- public void testOsVersion() {
- String osVersion = ModuleDescriptor.newModule("foo").osName("11.2").build().osName().get();
- assertEquals(osVersion, "11.2");
- }
-
- @Test(expectedExceptions = IllegalArgumentException.class)
- public void testNullOsVersion() {
- ModuleDescriptor.newModule("foo").osVersion(null);
- }
-
- @Test(expectedExceptions = IllegalArgumentException.class)
- public void testEmptyOsVersion() {
- ModuleDescriptor.newModule("foo").osVersion("");
- }
-
// reads
private static InputStream EMPTY_INPUT_STREAM = new InputStream() {
@@ -1239,7 +1289,9 @@ public class ModuleDescriptorTest {
}
};
- // basic test reading module-info.class
+ /**
+ * Basic test reading module-info.class
+ */
public void testRead() throws Exception {
Module base = Object.class.getModule();
@@ -1256,6 +1308,7 @@ public class ModuleDescriptorTest {
assertEquals(descriptor.name(), "java.base");
}
}
+
/**
* Test ModuleDescriptor with a packager finder
*/
diff --git a/jdk/test/java/lang/module/ModuleFinderTest.java b/jdk/test/java/lang/module/ModuleFinderTest.java
index 29d8f234c8b..3f87883277e 100644
--- a/jdk/test/java/lang/module/ModuleFinderTest.java
+++ b/jdk/test/java/lang/module/ModuleFinderTest.java
@@ -373,7 +373,7 @@ public class ModuleFinderTest {
/**
- * Test ModuleModule with a JAR file containing a .class file in the top
+ * Test ModuleFinder with a JAR file containing a .class file in the top
* level directory.
*/
public void testOfOneJarFileWithTopLevelClass() throws Exception {
@@ -386,6 +386,7 @@ public class ModuleFinderTest {
assertTrue(false);
} catch (FindException e) {
assertTrue(e.getCause() instanceof InvalidModuleDescriptorException);
+ assertTrue(e.getCause().getMessage().contains("Mojo.class"));
}
finder = ModuleFinder.of(jar);
@@ -394,11 +395,12 @@ public class ModuleFinderTest {
assertTrue(false);
} catch (FindException e) {
assertTrue(e.getCause() instanceof InvalidModuleDescriptorException);
+ assertTrue(e.getCause().getMessage().contains("Mojo.class"));
}
}
/**
- * Test ModuleModule with a JAR file containing a .class file in the top
+ * Test ModuleFinder with a JAR file containing a .class file in the top
* level directory.
*/
public void testOfOneExplodedModuleWithTopLevelClass() throws Exception {
@@ -411,6 +413,7 @@ public class ModuleFinderTest {
assertTrue(false);
} catch (FindException e) {
assertTrue(e.getCause() instanceof InvalidModuleDescriptorException);
+ assertTrue(e.getCause().getMessage().contains("Mojo.class"));
}
finder = ModuleFinder.of(m_dir);
@@ -419,6 +422,7 @@ public class ModuleFinderTest {
assertTrue(false);
} catch (FindException e) {
assertTrue(e.getCause() instanceof InvalidModuleDescriptorException);
+ assertTrue(e.getCause().getMessage().contains("Mojo.class"));
}
}
diff --git a/jdk/test/java/lang/module/ModuleFinderWithSecurityManager.java b/jdk/test/java/lang/module/ModuleFinderWithSecurityManager.java
new file mode 100644
index 00000000000..0fe6a0b6467
--- /dev/null
+++ b/jdk/test/java/lang/module/ModuleFinderWithSecurityManager.java
@@ -0,0 +1,70 @@
+/*
+ * 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
+ * @run main/othervm ModuleFinderWithSecurityManager allow
+ * @run main/othervm ModuleFinderWithSecurityManager deny
+ * @summary Basic test for ModuleFinder.ofSystem() with security manager
+ */
+
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Set;
+
+public class ModuleFinderWithSecurityManager {
+ public static void main(String[] args) throws Exception {
+ boolean allow = args[0].equals("allow");
+
+ // set security policy to allow access
+ if (allow) {
+ String testSrc = System.getProperty("test.src");
+ if (testSrc == null)
+ testSrc = ".";
+ Path policyFile = Paths.get(testSrc, "java.policy");
+ System.setProperty("java.security.policy", policyFile.toString());
+ }
+
+ System.setSecurityManager(new SecurityManager());
+
+ ModuleFinder finder = null;
+ try {
+ finder = ModuleFinder.ofSystem();
+ if (!allow) throw new RuntimeException("SecurityException expected");
+ } catch (SecurityException e) {
+ if (allow) throw new RuntimeException("SecurityException not expected");
+ }
+
+ // no additional permissions should be required to locate modules
+ if (finder != null) {
+ ModuleReference base = finder.find("java.base").orElse(null);
+ if (base == null)
+ throw new RuntimeException("java.base not found");
+ Set allModules = finder.findAll();
+ if (!allModules.contains(base))
+ throw new RuntimeException("java.base not in all modules");
+ }
+ }
+}
diff --git a/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java
index 12e53b0f5fb..6e895354357 100644
--- a/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java
+++ b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java
@@ -79,17 +79,21 @@ public class ModuleReaderTest {
"java/lang/Object.class"
};
- // resource names that should not be found in the base module
- private static final String[] BAD_BASE_RESOURCES = {
- "NotFound",
+ // (directory) resources that may be in the base module
+ private static final String[] MAYBE_BASE_RESOURCES = {
"java",
- "/java",
- "//java",
"java/",
"java/lang",
+ "java/lang/",
+ };
+
+ // resource names that should not be found in the base module
+ private static final String[] NOT_BASE_RESOURCES = {
+ "NotFound",
+ "/java",
+ "//java",
"/java/lang",
"//java/lang",
- "java/lang/",
"java//lang",
"/java/lang/Object.class",
"//java/lang/Object.class",
@@ -109,13 +113,17 @@ public class ModuleReaderTest {
"p/Main.class"
};
- // resource names that should not be found in the test module
- private static final String[] BAD_TEST_RESOURCES = {
- "NotFound",
+ // (directory) resources that may be in the test module
+ private static final String[] MAYBE_TEST_RESOURCES = {
"p",
+ "p/"
+ };
+
+ // resource names that should not be found in the test module
+ private static final String[] NOT_TEST_RESOURCES = {
+ "NotFound",
"/p",
"//p",
- "p/",
"/p/Main.class",
"//p/Main.class",
"p/Main.class/",
@@ -160,11 +168,19 @@ public class ModuleReaderTest {
testOpen(reader, name, expectedBytes);
testRead(reader, name, expectedBytes);
testList(reader, name);
-
}
- // test "not found"
- for (String name : BAD_BASE_RESOURCES) {
+ // test resources that may be in the base module
+ for (String name : MAYBE_BASE_RESOURCES) {
+ Optional ouri = reader.find(name);
+ ouri.ifPresent(uri -> {
+ if (name.endsWith("/"))
+ assertTrue(uri.toString().endsWith("/"));
+ });
+ }
+
+ // test "not found" in java.base module
+ for (String name : NOT_BASE_RESOURCES) {
assertFalse(reader.find(name).isPresent());
assertFalse(reader.open(name).isPresent());
assertFalse(reader.read(name).isPresent());
@@ -261,7 +277,7 @@ public class ModuleReaderTest {
try (reader) {
- // test each of the known resources in the module
+ // test resources in test module
for (String name : TEST_RESOURCES) {
byte[] expectedBytes
= Files.readAllBytes(MODS_DIR
@@ -274,8 +290,18 @@ public class ModuleReaderTest {
testList(reader, name);
}
- // test "not found"
- for (String name : BAD_TEST_RESOURCES) {
+ // test resources that may be in the test module
+ for (String name : MAYBE_TEST_RESOURCES) {
+ System.out.println(name);
+ Optional ouri = reader.find(name);
+ ouri.ifPresent(uri -> {
+ if (name.endsWith("/"))
+ assertTrue(uri.toString().endsWith("/"));
+ });
+ }
+
+ // test "not found" in test module
+ for (String name : NOT_TEST_RESOURCES) {
assertFalse(reader.find(name).isPresent());
assertFalse(reader.open(name).isPresent());
assertFalse(reader.read(name).isPresent());
@@ -394,9 +420,6 @@ public class ModuleReaderTest {
for (String e : names) {
assertTrue(reader.find(e).isPresent());
}
-
- // should not contain directories
- names.forEach(e -> assertFalse(e.endsWith("/")));
}
}
diff --git a/jdk/test/java/lang/module/java.policy b/jdk/test/java/lang/module/java.policy
new file mode 100644
index 00000000000..179334bc98a
--- /dev/null
+++ b/jdk/test/java/lang/module/java.policy
@@ -0,0 +1,4 @@
+grant {
+ // ModuleFinder.ofSystem() needs this
+ permission java.lang.RuntimePermission "accessSystemModules";
+};
diff --git a/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java b/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java
index 1bb04d9c12e..9478cac7861 100644
--- a/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java
+++ b/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java
@@ -45,6 +45,8 @@ import java.util.Set;
import java.util.stream.Collectors;
import jdk.internal.misc.SharedSecrets;
+
+import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@@ -669,6 +671,258 @@ public class BasicLayerTest {
}
+ /**
+ * Test layers with a qualified export. The module exporting the package
+ * does not read the target module.
+ *
+ * m1 { exports p to m2 }
+ * m2 { }
+ */
+ public void testQualifiedExports1() {
+ ModuleDescriptor descriptor1 = newBuilder("m1").
+ exports("p", Set.of("m2"))
+ .build();
+
+ ModuleDescriptor descriptor2 = newBuilder("m2")
+ .build();
+
+ ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+ Configuration cf = resolve(finder1, "m1", "m2");
+
+ ClassLoader cl = new ClassLoader() { };
+ Layer layer = Layer.empty().defineModules(cf, mn -> cl);
+ assertTrue(layer.modules().size() == 2);
+
+ Module m1 = layer.findModule("m1").get();
+ Module m2 = layer.findModule("m2").get();
+
+ // check m1 exports p to m2
+ assertFalse(m1.isExported("p"));
+ assertTrue(m1.isExported("p", m2));
+ assertFalse(m1.isOpen("p", m2));
+ }
+
+
+ /**
+ * Test layers with a qualified export. The module exporting the package
+ * reads the target module.
+ *
+ * m1 { exports p to m2; }
+ * m2 { requires m1; }
+ */
+ public void testQualifiedExports2() {
+ ModuleDescriptor descriptor1 = newBuilder("m1")
+ .exports("p", Set.of("m2"))
+ .build();
+
+ ModuleDescriptor descriptor2 = newBuilder("m2")
+ .requires("m1")
+ .build();
+
+ ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+ Configuration cf = resolve(finder1, "m2");
+ ClassLoader cl = new ClassLoader() { };
+ Layer layer = Layer.empty().defineModules(cf, mn -> cl);
+ assertTrue(layer.modules().size() == 2);
+
+ Module m1 = layer.findModule("m1").get();
+ Module m2 = layer.findModule("m2").get();
+
+ // check m1 exports p to m2
+ assertFalse(m1.isExported("p"));
+ assertTrue(m1.isExported("p", m2));
+ assertFalse(m1.isOpen("p", m2));
+ }
+
+
+ /**
+ * Test layers with a qualified export. The module exporting the package
+ * does not read the target module in the parent layer.
+ *
+ * - Configuration/layer1: m1 { }
+ * - Configuration/layer2: m2 { exports p to m1; }
+ */
+ public void testQualifiedExports3() {
+ // create layer1 with m1
+ ModuleDescriptor descriptor1 = newBuilder("m1").build();
+ ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+ Configuration cf1 = resolve(finder1, "m1");
+ ClassLoader cl1 = new ClassLoader() { };
+ Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1);
+ assertTrue(layer1.modules().size() == 1);
+
+ // create layer2 with m2
+ ModuleDescriptor descriptor2 = newBuilder("m2")
+ .exports("p", Set.of("m1"))
+ .build();
+ ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
+ Configuration cf2 = resolve(cf1, finder2, "m2");
+ ClassLoader cl2 = new ClassLoader() { };
+ Layer layer2 = layer1.defineModules(cf2, mn -> cl2);
+ assertTrue(layer2.modules().size() == 1);
+
+ Module m1 = layer1.findModule("m1").get();
+ Module m2 = layer2.findModule("m2").get();
+
+ // check m2 exports p to layer1/m1
+ assertFalse(m2.isExported("p"));
+ assertTrue(m2.isExported("p", m1));
+ assertFalse(m2.isOpen("p", m1));
+ }
+
+
+ /**
+ * Test layers with a qualified export. The module exporting the package
+ * reads the target module in the parent layer.
+ *
+ * - Configuration/layer1: m1 { }
+ * - Configuration/layer2: m2 { requires m1; exports p to m1; }
+ */
+ public void testQualifiedExports4() {
+ // create layer1 with m1
+ ModuleDescriptor descriptor1 = newBuilder("m1").build();
+ ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+ Configuration cf1 = resolve(finder1, "m1");
+ ClassLoader cl1 = new ClassLoader() { };
+ Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1);
+ assertTrue(layer1.modules().size() == 1);
+
+ // create layer2 with m2
+ ModuleDescriptor descriptor2 = newBuilder("m2")
+ .requires("m1")
+ .exports("p", Set.of("m1"))
+ .build();
+ ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
+ Configuration cf2 = resolve(cf1, finder2, "m2");
+ ClassLoader cl2 = new ClassLoader() { };
+ Layer layer2 = layer1.defineModules(cf2, mn -> cl2);
+ assertTrue(layer2.modules().size() == 1);
+
+ Module m1 = layer1.findModule("m1").get();
+ Module m2 = layer2.findModule("m2").get();
+
+ // check m2 exports p to layer1/m1
+ assertFalse(m2.isExported("p"));
+ assertTrue(m2.isExported("p", m1));
+ assertFalse(m2.isOpen("p", m1));
+ }
+
+ /**
+ * Test layers with a qualified export. The module exporting the package
+ * does not read the target module.
+ *
+ * - Configuration/layer1: m1
+ * - Configuration/layer2: m1, m2 { exports p to m1; }
+ */
+ public void testQualifiedExports5() {
+ // create layer1 with m1
+ ModuleDescriptor descriptor1 = newBuilder("m1").build();
+ ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+ Configuration cf1 = resolve(finder1, "m1");
+ ClassLoader cl1 = new ClassLoader() { };
+ Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1);
+ assertTrue(layer1.modules().size() == 1);
+
+ // create layer2 with m1 and m2
+ ModuleDescriptor descriptor2 = newBuilder("m2").exports("p", Set.of("m1")).build();
+ ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor2);
+ Configuration cf2 = resolve(cf1, finder2, "m1", "m2");
+ ClassLoader cl2 = new ClassLoader() { };
+ Layer layer2 = layer1.defineModules(cf2, mn -> cl2);
+ assertTrue(layer2.modules().size() == 2);
+
+ Module m1_v1 = layer1.findModule("m1").get();
+ Module m1_v2 = layer2.findModule("m1").get();
+ Module m2 = layer2.findModule("m2").get();
+
+ // check m2 exports p to layer2/m2
+ assertFalse(m2.isExported("p"));
+ assertTrue(m2.isExported("p", m1_v2));
+ assertFalse(m2.isExported("p", m1_v1));
+ }
+
+
+ /**
+ * Test layers with a qualified export. The module exporting the package
+ * reads the target module in the parent layer (due to requires transitive).
+ *
+ * - Configuration/layer1: m1, m2 { requires transitive m1; }
+ * - Configuration/layer2: m1, m3 { requires m2; exports p to m1; }
+ */
+ public void testQualifiedExports6() {
+ // create layer1 with m1 and m2
+ ModuleDescriptor descriptor1 = newBuilder("m1").build();
+ ModuleDescriptor descriptor2 = newBuilder("m2")
+ .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
+ .build();
+ ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+ Configuration cf1 = resolve(finder1, "m2");
+ ClassLoader loader1 = new ClassLoader() { };
+ Layer layer1 = Layer.empty().defineModules(cf1, mn -> loader1);
+ assertTrue(layer1.modules().size() == 2);
+
+ // create layer2 with m1 and m3
+ ModuleDescriptor descriptor3 = newBuilder("m3")
+ .requires("m2")
+ .exports("p", Set.of("m1"))
+ .build();
+ ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3);
+ Configuration cf2 = resolve(cf1, finder2, "m1", "m3");
+ ClassLoader loader2 = new ClassLoader() { };
+ Layer layer2 = layer1.defineModules(cf2, mn -> loader2);
+ assertTrue(layer2.modules().size() == 2);
+
+ Module m1_v1 = layer1.findModule("m1").get();
+ Module m2 = layer1.findModule("m2").get();
+
+ Module m1_v2 = layer2.findModule("m1").get();
+ Module m3 = layer2.findModule("m3").get();
+
+ assertTrue(m3.canRead(m1_v1));
+ assertFalse(m3.canRead(m1_v2));
+
+ assertFalse(m3.isExported("p"));
+ assertTrue(m3.isExported("p", m1_v1));
+ assertFalse(m3.isExported("p", m1_v2));
+ assertFalse(m3.isExported("p", m2));
+ }
+
+
+ /**
+ * Test layers with a qualified export. The target module is not in any layer.
+ *
+ * - Configuration/layer1: m1 { }
+ * - Configuration/layer2: m2 { exports p to m3; }
+ */
+ public void testQualifiedExports7() {
+ // create layer1 with m1
+ ModuleDescriptor descriptor1 = newBuilder("m1").build();
+ ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+ Configuration cf1 = resolve(finder1, "m1");
+ ClassLoader cl1 = new ClassLoader() { };
+ Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1);
+ assertTrue(layer1.modules().size() == 1);
+
+ // create layer2 with m2
+ ModuleDescriptor descriptor2 = newBuilder("m2")
+ .exports("p", Set.of("m3"))
+ .build();
+ ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
+ Configuration cf2 = resolve(cf1, finder2, "m2");
+ ClassLoader cl2 = new ClassLoader() { };
+ Layer layer2 = layer1.defineModules(cf2, mn -> cl2);
+ assertTrue(layer2.modules().size() == 1);
+
+ Module m1 = layer1.findModule("m1").get();
+ Module m2 = layer2.findModule("m2").get();
+
+ // check m2 does not export p to anyone
+ assertFalse(m2.isExported("p"));
+ assertFalse(m2.isExported("p", m1));
+ }
+
/**
* Attempt to use Layer defineModules to create a layer with a module
* defined to a class loader that already has a module of the same name
@@ -796,29 +1050,31 @@ public class BasicLayerTest {
}
+ @DataProvider(name = "javaPackages")
+ public Object[][] javaPackages() {
+ return new Object[][] { { "m1", "java" }, { "m2", "java.x" } };
+ }
+
/**
- * Attempt to create a Layer with a module containing a "java." package.
+ * Attempt to create a Layer with a module containing a "java" package.
* This should only be allowed when the module is defined to the platform
* class loader.
*/
- @Test(enabled = false)
- public void testLayerWithJavaPackage() {
- ModuleDescriptor descriptor = newBuilder("foo")
- .packages(Set.of("java.foo"))
- .build();
-
+ @Test(dataProvider = "javaPackages")
+ public void testLayerWithJavaPackage(String mn, String pn) {
+ ModuleDescriptor descriptor = newBuilder(mn).packages(Set.of(pn)).build();
ModuleFinder finder = ModuleUtils.finderOf(descriptor);
Configuration cf = Layer.boot()
.configuration()
- .resolve(finder, ModuleFinder.of(), Set.of("foo"));
+ .resolve(finder, ModuleFinder.of(), Set.of(mn));
assertTrue(cf.modules().size() == 1);
ClassLoader pcl = ClassLoader.getPlatformClassLoader();
ClassLoader scl = ClassLoader.getSystemClassLoader();
try {
- Layer.boot().defineModules(cf, mn -> new ClassLoader() { });
+ Layer.boot().defineModules(cf, _mn -> new ClassLoader() { });
assertTrue(false);
} catch (LayerInstantiationException e) { }
@@ -833,13 +1089,13 @@ public class BasicLayerTest {
} catch (LayerInstantiationException e) { }
// create layer with module defined to platform class loader
- Layer layer = Layer.boot().defineModules(cf, mn -> pcl);
- Optional om = layer.findModule("foo");
+ Layer layer = Layer.boot().defineModules(cf, _mn -> pcl);
+ Optional om = layer.findModule(mn);
assertTrue(om.isPresent());
Module foo = om.get();
assertTrue(foo.getClassLoader() == pcl);
assertTrue(foo.getPackages().length == 1);
- assertTrue(foo.getPackages()[0].equals("java.foo"));
+ assertTrue(foo.getPackages()[0].equals(pn));
}
diff --git a/jdk/test/java/lang/reflect/Module/allow.policy b/jdk/test/java/lang/reflect/Module/allow.policy
index 08998cfa728..51db5b92828 100644
--- a/jdk/test/java/lang/reflect/Module/allow.policy
+++ b/jdk/test/java/lang/reflect/Module/allow.policy
@@ -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
@@ -23,5 +23,6 @@
grant {
permission java.lang.RuntimePermission "getClassLoader";
- permission java.io.FilePermission "${java.home}/-", "read";
+ permission java.lang.RuntimePermission "accessSystemModules";
+ permission java.io.FilePermission "${java.home}/modules/-", "read"; // exploded build
};
diff --git a/jdk/test/java/util/ServiceLoader/basic/basic.sh b/jdk/test/java/util/ServiceLoader/basic/basic.sh
index 4ffd56a4411..1a3a34864d2 100644
--- a/jdk/test/java/util/ServiceLoader/basic/basic.sh
+++ b/jdk/test/java/util/ServiceLoader/basic/basic.sh
@@ -76,6 +76,7 @@ if [ \! -d $EXTD ]; then
(cd $JARD; "$JAR" ${TESTTOOLVMOPTS} -cf ../p$n.jar *)
done
+ cp p2.jar p2dup.jar
mv p3.jar $EXTD
cp $TESTCLASSES/Load.class $TESTD
@@ -117,6 +118,8 @@ go "$TESTD" "" FooProvider1
go ".${SEP}p2.jar" "" FooProvider2
+go ".${SEP}p2.jar${SEP}p2dup.jar" "" FooProvider2
+
go "${P3JAR}${SEP}p2.jar" "" FooProvider3 FooProvider2
go "$TESTD${SEP}p2.jar" "" FooProvider1 FooProvider2
diff --git a/jdk/test/jdk/internal/jrtfs/java.policy b/jdk/test/jdk/internal/jrtfs/java.policy
index 5df300aa905..276543b8208 100644
--- a/jdk/test/jdk/internal/jrtfs/java.policy
+++ b/jdk/test/jdk/internal/jrtfs/java.policy
@@ -1,3 +1,3 @@
grant {
- permission java.io.FilePermission "${java.home}/-", "read";
+ permission java.lang.RuntimePermission "accessSystemModules";
};
diff --git a/jdk/test/lib/testlibrary/ModuleTargetHelper.java b/jdk/test/lib/testlibrary/ModuleTargetHelper.java
new file mode 100644
index 00000000000..b01e1844fe3
--- /dev/null
+++ b/jdk/test/lib/testlibrary/ModuleTargetHelper.java
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import jdk.internal.module.ClassFileConstants;
+import jdk.internal.module.ClassFileAttributes;
+import jdk.internal.module.ClassFileAttributes.ModuleTargetAttribute;
+import jdk.internal.org.objectweb.asm.Attribute;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
+public class ModuleTargetHelper {
+ private ModuleTargetHelper() {}
+
+ public static final class ModuleTarget {
+ private String osName, osArch;
+
+ public ModuleTarget(String osName, String osArch) {
+ this.osName = osName;
+ this.osArch = osArch;
+ }
+
+ public String osName() {
+ return osName;
+ }
+
+ public String osArch() {
+ return osArch;
+ }
+ }
+
+ public static ModuleTarget getJavaBaseTarget() throws IOException {
+ Path p = Paths.get(URI.create("jrt:/modules/java.base/module-info.class"));
+ try (InputStream in = Files.newInputStream(p)) {
+ return read(in);
+ }
+ }
+
+ public static ModuleTarget read(InputStream in) throws IOException {
+ ModuleTargetAttribute[] modTargets = new ModuleTargetAttribute[1];
+ ClassVisitor cv = new ClassVisitor(Opcodes.ASM5) {
+ @Override
+ public void visitAttribute(Attribute attr) {
+ if (attr instanceof ModuleTargetAttribute) {
+ modTargets[0] = (ModuleTargetAttribute)attr;
+ }
+ }
+ };
+
+ // prototype of attributes that should be parsed
+ Attribute[] attrs = new Attribute[] {
+ new ModuleTargetAttribute()
+ };
+
+ // parse module-info.class
+ ClassReader cr = new ClassReader(in);
+ cr.accept(cv, attrs, 0);
+ if (modTargets[0] != null) {
+ return new ModuleTarget(modTargets[0].osName(), modTargets[0].osArch());
+ }
+
+ return null;
+ }
+
+ public static ModuleTarget read(ModuleReference modRef) throws IOException {
+ ModuleReader reader = modRef.open();
+ try (InputStream in = reader.open("module-info.class").get()) {
+ return read(in);
+ } finally {
+ reader.close();
+ }
+ }
+}
diff --git a/jdk/test/sun/net/www/protocol/jrt/java.policy b/jdk/test/sun/net/www/protocol/jrt/java.policy
index 5df300aa905..276543b8208 100644
--- a/jdk/test/sun/net/www/protocol/jrt/java.policy
+++ b/jdk/test/sun/net/www/protocol/jrt/java.policy
@@ -1,3 +1,3 @@
grant {
- permission java.io.FilePermission "${java.home}/-", "read";
+ permission java.lang.RuntimePermission "accessSystemModules";
};
diff --git a/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java b/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java
index 38d9910893b..1447d81cdd2 100644
--- a/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java
+++ b/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java
@@ -28,6 +28,7 @@
* java.security.jgss/sun.security.krb5.internal:+open
* java.security.jgss/sun.security.jgss
* java.security.jgss/sun.security.krb5:+open
+ * java.security.jgss/sun.security.krb5.internal.ccache
* java.security.jgss/sun.security.krb5.internal.crypto
* java.security.jgss/sun.security.krb5.internal.ktab
* jdk.security.auth
diff --git a/jdk/test/tools/jlink/IntegrationTest.java b/jdk/test/tools/jlink/IntegrationTest.java
index b968d6e4da0..c3059051986 100644
--- a/jdk/test/tools/jlink/IntegrationTest.java
+++ b/jdk/test/tools/jlink/IntegrationTest.java
@@ -214,7 +214,8 @@ public class IntegrationTest {
checkReleaseProperty(props, "JAVA_FULL_VERSION");
checkReleaseProperty(props, "OS_NAME");
checkReleaseProperty(props, "OS_ARCH");
- checkReleaseProperty(props, "OS_VERSION");
+ // OS_VERSION is added from makefile. We're testing API-way to create image here!
+ // checkReleaseProperty(props, "OS_VERSION");
if (!Files.exists(output.resolve("toto.txt"))) {
throw new AssertionError("Post processing not called");
diff --git a/jdk/test/tools/jlink/JLinkNegativeTest.java b/jdk/test/tools/jlink/JLinkNegativeTest.java
index ab1c568c06b..d02ecbbc0fe 100644
--- a/jdk/test/tools/jlink/JLinkNegativeTest.java
+++ b/jdk/test/tools/jlink/JLinkNegativeTest.java
@@ -193,7 +193,7 @@ public class JLinkNegativeTest {
.output(imageFile)
.addMods("not_zip")
.modulePath(helper.defaultModulePath())
- .call().assertFailure("Error: java.io.IOException: Invalid jmod file");
+ .call().assertFailure("Error: java.io.IOException: Invalid JMOD file");
} finally {
deleteDirectory(jmod);
}
diff --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/CompiledVersionTest.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/CompiledVersionTest.java
index fb7f5569e06..36f82a9ddc4 100644
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/CompiledVersionTest.java
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/CompiledVersionTest.java
@@ -81,9 +81,13 @@ public class CompiledVersionTest {
Path msrc = SRC_DIR.resolve(mn);
if (version.equals("0")) {
assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
+ "--add-exports", "java.base/jdk.internal.module=m1",
+ "--add-exports", "java.base/jdk.internal.org.objectweb.asm=m1",
"--module-source-path", SRC_DIR.toString()));
} else {
assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
+ "--add-exports", "java.base/jdk.internal.module=m1",
+ "--add-exports", "java.base/jdk.internal.org.objectweb.asm=m1",
"--module-source-path", SRC_DIR.toString(),
"--module-version", version));
}
diff --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java
index ce25cd762bc..b2d6d9bc6f3 100644
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java
@@ -25,6 +25,8 @@ import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleDescriptor.*;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
+import java.io.IOException;
+import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -40,7 +42,11 @@ import static org.testng.Assert.*;
/**
* @test
* @bug 8142968 8173381
+ * @library /lib/testlibrary
* @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.module
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ * @build ModuleTargetHelper
* @run testng SystemModulesTest
* @summary Verify the properties of ModuleDescriptor created
* by SystemModules
@@ -62,7 +68,6 @@ public class SystemModulesTest {
return;
ModuleFinder.ofSystem().findAll().stream()
- .map(ModuleReference::descriptor)
.forEach(this::checkAttributes);
}
@@ -72,9 +77,7 @@ public class SystemModulesTest {
if (name.equals(OS_NAME))
return true;
- if (OS_NAME.equals("Mac OS X")) {
- return name.equals("Darwin");
- } else if (OS_NAME.startsWith("Windows")) {
+ if (OS_NAME.startsWith("Windows")) {
return name.startsWith("Windows");
} else {
System.err.println("ERROR: " + name + " but expected: " + OS_NAME);
@@ -89,28 +92,28 @@ public class SystemModulesTest {
switch (OS_ARCH) {
case "i386":
case "x86":
- return name.equals("i586");
+ return name.equals("x86");
+ case "amd64":
+ return name.equals("x86_64");
default:
System.err.println("ERROR: " + name + " but expected: " + OS_ARCH);
return false;
}
}
- private void checkAttributes(ModuleDescriptor md) {
- System.out.format("%s %s %s %s%n", md.name(),
- md.osName(), md.osArch(), md.osVersion());
-
- if (md.name().equals("java.base")) {
- assertTrue(checkOSName(md.osName().get()));
- assertTrue(checkOSArch(md.osArch().get()));
- assertTrue(md.osVersion().isPresent());
- } else {
- // target platform attribute is dropped by jlink plugin
- assertFalse(md.osName().isPresent());
- assertFalse(md.osArch().isPresent());
- assertFalse(md.osVersion().isPresent());
- assertTrue(md.packages().size() > 0
- || EMPTY_MODULES.contains(md.name()), md.name());
+ private void checkAttributes(ModuleReference modRef) {
+ try {
+ if (modRef.descriptor().name().equals("java.base")) {
+ ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
+ assertTrue(checkOSName(mt.osName()));
+ assertTrue(checkOSArch(mt.osArch()));
+ } else {
+ // target platform attribute is dropped by jlink plugin for other modules
+ ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
+ assertTrue(mt == null || (mt.osName() == null && mt.osArch() == null));
+ }
+ } catch (IOException exp) {
+ throw new UncheckedIOException(exp);
}
}
diff --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java
index c63309c2a5e..7128e1cfacd 100644
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java
@@ -38,7 +38,6 @@ import jdk.testlibrary.FileUtils;
import static jdk.testlibrary.ProcessTools.*;
-
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@@ -48,7 +47,9 @@ import static org.testng.Assert.*;
* @bug 8142968 8173381 8174740
* @library /lib/testlibrary
* @modules jdk.compiler jdk.jlink
- * @build UserModuleTest CompilerUtils jdk.testlibrary.FileUtils jdk.testlibrary.ProcessTools
+ * @modules java.base/jdk.internal.module
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ * @build ModuleTargetHelper UserModuleTest CompilerUtils jdk.testlibrary.FileUtils jdk.testlibrary.ProcessTools
* @run testng UserModuleTest
*/
@@ -85,7 +86,9 @@ public class UserModuleTest {
for (String mn : modules) {
Path msrc = SRC_DIR.resolve(mn);
assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
- "--module-source-path", SRC_DIR.toString()));
+ "--module-source-path", SRC_DIR.toString(),
+ "--add-exports", "java.base/jdk.internal.module=" + mn,
+ "--add-exports", "java.base/jdk.internal.org.objectweb.asm=" + mn));
}
if (Files.exists(IMAGE)) {
@@ -106,7 +109,10 @@ public class UserModuleTest {
if (!hasJmods()) return;
Path java = IMAGE.resolve("bin").resolve("java");
- assertTrue(executeProcess(java.toString(), "-m", MAIN_MID)
+ assertTrue(executeProcess(java.toString(),
+ "--add-exports", "java.base/jdk.internal.module=m1,m4",
+ "--add-exports", "java.base/jdk.internal.org.objectweb.asm=m1,m4",
+ "-m", MAIN_MID)
.outputTo(System.out)
.errorTo(System.out)
.getExitValue() == 0);
@@ -136,6 +142,8 @@ public class UserModuleTest {
Path java = IMAGE.resolve("bin").resolve("java");
assertTrue(executeProcess(java.toString(),
+ "--add-exports", "java.base/jdk.internal.module=m1,m4",
+ "--add-exports", "java.base/jdk.internal.org.objectweb.asm=m1,m4",
"-Djdk.system.module.finder.disabledFastPath",
"-m", MAIN_MID)
.outputTo(System.out)
@@ -154,7 +162,10 @@ public class UserModuleTest {
Path dir = Paths.get("dedupSetTest");
createImage(dir, "m1", "m2", "m3", "m4");
Path java = dir.resolve("bin").resolve("java");
- assertTrue(executeProcess(java.toString(), "-m", MAIN_MID)
+ assertTrue(executeProcess(java.toString(),
+ "--add-exports", "java.base/jdk.internal.module=m1,m4",
+ "--add-exports", "java.base/jdk.internal.org.objectweb.asm=m1,m4",
+ "-m", MAIN_MID)
.outputTo(System.out)
.errorTo(System.out)
.getExitValue() == 0);
@@ -205,11 +216,13 @@ public class UserModuleTest {
}
private void createJmods(String... modules) throws IOException {
- // use the same target platform as in java.base
- ModuleDescriptor md = Layer.boot().findModule("java.base").get()
- .getDescriptor();
- String osName = md.osName().get();
- String osArch = md.osArch().get();
+ ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.getJavaBaseTarget();
+ if (mt == null) {
+ throw new RuntimeException("ModuleTarget is missing for java.base");
+ }
+
+ String osName = mt.osName();
+ String osArch = mt.osArch();
// create JMOD files
Files.createDirectories(JMODS_DIR);
@@ -246,6 +259,8 @@ public class UserModuleTest {
// verify ModuleDescriptor
Path java = dir.resolve("bin").resolve("java");
assertTrue(executeProcess(java.toString(),
+ "--add-exports", "java.base/jdk.internal.module=m1,m4",
+ "--add-exports", "java.base/jdk.internal.org.objectweb.asm=m1,m4",
"--add-modules=m1", "-m", "m4")
.outputTo(System.out)
.errorTo(System.out)
@@ -275,6 +290,8 @@ public class UserModuleTest {
// verify ModuleDescriptor
Path java = dir.resolve("bin").resolve("java");
assertTrue(executeProcess(java.toString(),
+ "--add-exports", "java.base/jdk.internal.module=m1,m4",
+ "--add-exports", "java.base/jdk.internal.org.objectweb.asm=m1,m4",
"--add-modules=m1", "-m", "m4", "retainModuleTarget")
.outputTo(System.out)
.errorTo(System.out)
diff --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java
index 4b4bf359304..9d3a769eefa 100644
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java
@@ -23,6 +23,7 @@
package p1;
+import java.io.InputStream;
import java.io.IOException;
import java.lang.module.ModuleDescriptor;
import java.lang.reflect.Layer;
@@ -35,7 +36,38 @@ import java.nio.file.Path;
import java.util.Collections;
import java.util.Set;
+import jdk.internal.module.ClassFileAttributes;
+import jdk.internal.module.ClassFileAttributes.ModuleTargetAttribute;
+import jdk.internal.module.ClassFileConstants;
+import jdk.internal.org.objectweb.asm.Attribute;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
public class Main {
+ private static boolean hasModuleTarget(InputStream in) throws IOException {
+ ModuleTargetAttribute[] modTargets = new ModuleTargetAttribute[1];
+ ClassVisitor cv = new ClassVisitor(Opcodes.ASM5) {
+ @Override
+ public void visitAttribute(Attribute attr) {
+ if (attr instanceof ModuleTargetAttribute) {
+ modTargets[0] = (ModuleTargetAttribute)attr;
+ }
+ }
+ };
+
+ // prototype of attributes that should be parsed
+ Attribute[] attrs = new Attribute[] {
+ new ModuleTargetAttribute()
+ };
+
+ // parse module-info.class
+ ClassReader cr = new ClassReader(in);
+ cr.accept(cv, attrs, 0);
+ return modTargets[0] != null &&
+ (modTargets[0].osName() != null || modTargets[0].osArch() != null);
+ }
+
public static void main(String... args) throws Exception {
// load another package
p2.T.test();
@@ -44,12 +76,13 @@ public class Main {
validate(Main.class.getModule());
// validate the Moduletarget attribute for java.base
- ModuleDescriptor md = Layer.boot().findModule("java.base").get()
- .getDescriptor();
- if (!md.osName().isPresent() || !md.osArch().isPresent() ||
- !md.osVersion().isPresent()) {
- throw new RuntimeException("java.base: " + md.osName() + " " +
- md.osArch() + " " + md.osVersion());
+ FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"),
+ Collections.emptyMap());
+ Path path = fs.getPath("/", "modules", "java.base", "module-info.class");
+ try (InputStream in = Files.newInputStream(path)) {
+ if (! hasModuleTarget(in)) {
+ throw new RuntimeException("Missing ModuleTarget for java.base");
+ }
}
}
@@ -67,9 +100,9 @@ public class Main {
checkPackages(md.packages(), "p1", "p2");
checkPackages(md1.packages(), "p1", "p2");
- // check ModuleTarget attribute
- checkModuleTargetAttribute(md);
- checkModuleTargetAttribute(md1);
+ try (InputStream in = Files.newInputStream(path)) {
+ checkModuleTargetAttribute(in, "p1");
+ }
}
static void checkPackages(Set pkgs, String... expected) {
@@ -78,10 +111,9 @@ public class Main {
}
}
- static void checkModuleTargetAttribute(ModuleDescriptor md) {
- if (md.osName().isPresent() || md.osArch().isPresent() ||
- md.osVersion().isPresent()) {
- throw new RuntimeException(md.osName() + " " + md.osArch() + " " + md.osVersion());
+ static void checkModuleTargetAttribute(InputStream in, String modName) throws IOException {
+ if (hasModuleTarget(in)) {
+ throw new RuntimeException("ModuleTarget present for " + modName);
}
}
}
diff --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Main.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Main.java
index d4ca677a758..66e18604913 100644
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Main.java
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Main.java
@@ -36,7 +36,47 @@ import java.nio.file.Path;
import java.util.Collections;
import java.util.Set;
+import jdk.internal.module.ClassFileAttributes;
+import jdk.internal.module.ClassFileAttributes.ModuleTargetAttribute;
+import jdk.internal.module.ClassFileConstants;
+import jdk.internal.org.objectweb.asm.Attribute;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
public class Main {
+ private static boolean hasModuleTarget(InputStream in) throws IOException {
+ ModuleTargetAttribute[] modTargets = new ModuleTargetAttribute[1];
+ ClassVisitor cv = new ClassVisitor(Opcodes.ASM5) {
+ @Override
+ public void visitAttribute(Attribute attr) {
+ if (attr instanceof ModuleTargetAttribute) {
+ modTargets[0] = (ModuleTargetAttribute)attr;
+ }
+ }
+ };
+
+ // prototype of attributes that should be parsed
+ Attribute[] attrs = new Attribute[] {
+ new ModuleTargetAttribute()
+ };
+
+ // parse module-info.class
+ ClassReader cr = new ClassReader(in);
+ cr.accept(cv, attrs, 0);
+ return modTargets[0] != null &&
+ (modTargets[0].osName() != null || modTargets[0].osArch() != null);
+ }
+
+ private static boolean hasModuleTarget(String modName) throws IOException {
+ FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"),
+ Collections.emptyMap());
+ Path path = fs.getPath("/", "modules", modName, "module-info.class");
+ try (InputStream in = Files.newInputStream(path)) {
+ return hasModuleTarget(in);
+ }
+ }
+
// the system module plugin by default drops ModuleTarget attribute
private static boolean expectModuleTarget = false;
public static void main(String... args) throws IOException {
@@ -49,13 +89,8 @@ public class Main {
}
// java.base is packaged with osName/osArch/osVersion
- ModuleDescriptor md = Layer.boot().findModule("java.base").get()
- .getDescriptor();
- if (!md.osName().isPresent() ||
- !md.osArch().isPresent() ||
- !md.osVersion().isPresent()) {
- throw new RuntimeException("osName/osArch/osVersion is missing: " +
- md.osName() + " " + md.osArch() + " " + md.osVersion());
+ if (! hasModuleTarget("java.base")) {
+ throw new RuntimeException("ModuleTarget absent for java.base");
}
// verify module-info.class for m1 and m4
@@ -82,7 +117,7 @@ public class Main {
checkModuleDescriptor(ModuleDescriptor.read(Files.newInputStream(path)), packages);
}
- static void checkModuleDescriptor(ModuleDescriptor md, String... packages) {
+ static void checkModuleDescriptor(ModuleDescriptor md, String... packages) throws IOException {
String mainClass = md.name().replace('m', 'p') + ".Main";
if (!md.mainClass().get().equals(mainClass)) {
throw new RuntimeException(md.mainClass().toString());
@@ -90,22 +125,16 @@ public class Main {
if (expectModuleTarget) {
// ModuleTarget attribute is retained
- if (!md.osName().isPresent() || !md.osArch().isPresent()) {
- throw new RuntimeException("osName or osArch is missing: " +
- md.osName() + " " + md.osArch());
+ if (! hasModuleTarget(md.name())) {
+ throw new RuntimeException("ModuleTarget missing for " + md.name());
}
} else {
// by default ModuleTarget attribute is dropped
- if (md.osName().isPresent() || md.osArch().isPresent()) {
- throw new RuntimeException("osName and osArch should not be set: " +
- md.osName() + " " + md.osArch());
+ if (hasModuleTarget(md.name())) {
+ throw new RuntimeException("ModuleTarget present for " + md.name());
}
}
- if (md.osVersion().isPresent()) {
- throw new RuntimeException("Expected no osVersion set: " + md.osVersion());
- }
-
Set pkgs = md.packages();
if (!pkgs.equals(Set.of(packages))) {
throw new RuntimeException(pkgs + " expected: " + Set.of(packages));
diff --git a/jdk/test/tools/launcher/modules/addexports/AddExportsTestWarningError.java b/jdk/test/tools/launcher/modules/addexports/AddExportsTestWarningError.java
index ed2f7c0d7a8..0a20fec711a 100644
--- a/jdk/test/tools/launcher/modules/addexports/AddExportsTestWarningError.java
+++ b/jdk/test/tools/launcher/modules/addexports/AddExportsTestWarningError.java
@@ -134,16 +134,16 @@ public class AddExportsTestWarningError {
return new Object[][]{
// source not found
- {"DoesNotExist/p=m1", "WARNING: Unknown module: DoesNotExist specified in --add-exports"},
+ {"DoesNotExist/p=m1", "WARNING: Unknown module: DoesNotExist specified to --add-exports"},
{"m1/DoesNotExist=m2", "WARNING: package DoesNotExist not in m1"},
// target not found
- {"m1/p1=DoesNotExist", "WARNING: Unknown module: DoesNotExist specified in --add-exports"},
+ {"m1/p1=DoesNotExist", "WARNING: Unknown module: DoesNotExist specified to --add-exports"},
// bad names
- {"m*/p1=m2", "WARNING: Unknown module: m* specified in --add-exports"},
+ {"m*/p1=m2", "WARNING: Unknown module: m* specified to --add-exports"},
{"m1/p!=m2", "WARNING: package p! not in m1"},
- {"m1/p1=m!", "WARNING: Unknown module: m! specified in --add-exports"},
+ {"m1/p1=m!", "WARNING: Unknown module: m! specified to --add-exports"},
};
}
diff --git a/jdk/test/tools/launcher/modules/addreads/AddReadsTestWarningError.java b/jdk/test/tools/launcher/modules/addreads/AddReadsTestWarningError.java
index 5b8558350ef..6c9ee5634eb 100644
--- a/jdk/test/tools/launcher/modules/addreads/AddReadsTestWarningError.java
+++ b/jdk/test/tools/launcher/modules/addreads/AddReadsTestWarningError.java
@@ -168,14 +168,14 @@ public class AddReadsTestWarningError {
return new Object[][]{
// source not found
- {"DoesNotExist=m2", "WARNING: Unknown module: DoesNotExist specified in --add-reads"},
+ {"DoesNotExist=m2", "WARNING: Unknown module: DoesNotExist specified to --add-reads"},
// target not found
- {"m2=DoesNotExist", "WARNING: Unknown module: DoesNotExist specified in --add-reads"},
+ {"m2=DoesNotExist", "WARNING: Unknown module: DoesNotExist specified to --add-reads"},
// bad names
- {"m*=m2", "WARNING: Unknown module: m* specified in --add-reads"},
- {"m2=m!", "WARNING: Unknown module: m! specified in --add-reads"},
+ {"m*=m2", "WARNING: Unknown module: m* specified to --add-reads"},
+ {"m2=m!", "WARNING: Unknown module: m! specified to --add-reads"},
};
}
diff --git a/jdk/test/tools/launcher/modules/basic/InitErrors.java b/jdk/test/tools/launcher/modules/basic/InitErrors.java
new file mode 100644
index 00000000000..dd3a9837939
--- /dev/null
+++ b/jdk/test/tools/launcher/modules/basic/InitErrors.java
@@ -0,0 +1,116 @@
+/*
+ * 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
+ * @library /lib/testlibrary
+ * @build InitErrors jdk.testlibrary.*
+ * @run testng InitErrors
+ * @summary Basic test to ensure that module system initialization errors
+ * go the right stream and with the right level of verbosity
+ */
+
+
+import java.util.Arrays;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.OutputAnalyzer;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+public class InitErrors {
+
+ // the option to cause module initialization to fail
+ private static final String ADD_UNKNOWN_MODULE = "--add-modules=XXX";
+
+ // the expected error message
+ private static final String UNKNOWN_MODULE_NOT_FOUND= "Module XXX not found";
+
+ // output expected in the stack trace when using -Xlog:init=debug
+ private static final String STACK_FRAME = "java.base/java.lang.System.initPhase2";
+
+
+ /**
+ * Default behavior, send error message to stdout
+ */
+ @Test
+ public void testDefaultOutput() throws Exception {
+ expectFail(showVersion(ADD_UNKNOWN_MODULE)
+ .stdoutShouldContain(UNKNOWN_MODULE_NOT_FOUND)
+ .stdoutShouldNotContain(STACK_FRAME)
+ .stderrShouldNotContain(UNKNOWN_MODULE_NOT_FOUND)
+ .stderrShouldNotContain(STACK_FRAME));
+ }
+
+ /**
+ * -XX:+DisplayVMOutputToStderr should send error message to stderr
+ */
+ @Test
+ public void testOutputToStderr() throws Exception {
+ expectFail(showVersion(ADD_UNKNOWN_MODULE, "-XX:+DisplayVMOutputToStderr")
+ .stdoutShouldNotContain(UNKNOWN_MODULE_NOT_FOUND)
+ .stdoutShouldNotContain(STACK_FRAME)
+ .stderrShouldContain(UNKNOWN_MODULE_NOT_FOUND)
+ .stderrShouldNotContain(STACK_FRAME));
+ }
+
+ /**
+ * -Xlog:init=debug should print stack trace to stdout
+ */
+ @Test
+ public void testStackTrace() throws Exception {
+ expectFail(showVersion(ADD_UNKNOWN_MODULE, "-Xlog:init=debug")
+ .stdoutShouldContain(UNKNOWN_MODULE_NOT_FOUND)
+ .stdoutShouldContain(STACK_FRAME)
+ .stderrShouldNotContain(UNKNOWN_MODULE_NOT_FOUND)
+ .stderrShouldNotContain(STACK_FRAME));
+ }
+
+ /**
+ * -Xlog:init=debug -XX:+DisplayVMOutputToStderr should print stack trace
+ * to stderr
+ */
+ @Test
+ public void testStackTraceToStderr() throws Exception {
+ expectFail(showVersion(ADD_UNKNOWN_MODULE,
+ "-Xlog:init=debug",
+ "-XX:+DisplayVMOutputToStderr")
+ .stdoutShouldNotContain(UNKNOWN_MODULE_NOT_FOUND)
+ .stdoutShouldNotContain(STACK_FRAME)
+ .stderrShouldContain(UNKNOWN_MODULE_NOT_FOUND)
+ .stderrShouldContain(STACK_FRAME));
+ }
+
+ private OutputAnalyzer showVersion(String... args) throws Exception {
+ int len = args.length;
+ args = Arrays.copyOf(args, len+1);
+ args[len] = "-version";
+ return ProcessTools.executeTestJava(args)
+ .outputTo(System.out)
+ .errorTo(System.out);
+ }
+
+ private void expectFail(OutputAnalyzer output) {
+ assertFalse(output.getExitValue() == 0);
+ }
+
+}
diff --git a/jdk/test/tools/launcher/modules/patch/basic/PatchTestWarningError.java b/jdk/test/tools/launcher/modules/patch/basic/PatchTestWarningError.java
index 5ada5888d92..2d5b14bb858 100644
--- a/jdk/test/tools/launcher/modules/patch/basic/PatchTestWarningError.java
+++ b/jdk/test/tools/launcher/modules/patch/basic/PatchTestWarningError.java
@@ -179,7 +179,7 @@ public class PatchTestWarningError {
"-m", "test/jdk.test.Main", arg)
.outputTo(System.out)
.errorTo(System.out)
- .shouldContain("WARNING: Unknown module: DoesNotExist specified in --patch-module")
+ .shouldContain("WARNING: Unknown module: DoesNotExist specified to --patch-module")
.getExitValue();
assertTrue(exitValue == 0);
diff --git a/jdk/test/tools/launcher/modules/permit/AttemptAccess.java b/jdk/test/tools/launcher/modules/permit/AttemptAccess.java
new file mode 100644
index 00000000000..900dfb12f72
--- /dev/null
+++ b/jdk/test/tools/launcher/modules/permit/AttemptAccess.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * Launched by PermitIllegalAccess to attempt illegal access.
+ */
+
+public class AttemptAccess {
+
+ public static void main(String[] args) throws Exception {
+ String action = args[0];
+ int count = Integer.parseInt(args[1]);
+
+ for (int i=0; i clazz = Class.forName("sun.security.x509.X500Name");
+ Constructor> ctor = clazz.getConstructor(String.class);
+ Object name = ctor.newInstance("CN=user");
+ }
+
+ static void trySetAccessible() throws Exception {
+ Method find = ClassLoader.class.getDeclaredMethod("findClass", String.class);
+ find.setAccessible(true);
+ }
+
+ static void tryTrySetAccessible() throws Exception {
+ Method find = ClassLoader.class.getDeclaredMethod("findClass", String.class);
+ find.trySetAccessible();
+ }
+
+}
diff --git a/jdk/test/tools/launcher/modules/permit/PermitIllegalAccess.java b/jdk/test/tools/launcher/modules/permit/PermitIllegalAccess.java
new file mode 100644
index 00000000000..d334282bcc1
--- /dev/null
+++ b/jdk/test/tools/launcher/modules/permit/PermitIllegalAccess.java
@@ -0,0 +1,208 @@
+/*
+ * 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
+ * @library /lib/testlibrary
+ * @build PermitIllegalAccess AttemptAccess jdk.testlibrary.*
+ * @run testng PermitIllegalAccess
+ * @summary Basic test for java --permit-illegal-access
+ */
+
+import java.util.List;
+
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.OutputAnalyzer;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * Basic test of --permit-illegal-access to ensure that it permits access
+ * via core reflection and setAccessible/trySetAccessible.
+ */
+
+@Test
+public class PermitIllegalAccess {
+
+ static final String TEST_CLASSES = System.getProperty("test.classes");
+ static final String TEST_MAIN = "AttemptAccess";
+
+ static final String WARNING = "WARNING";
+ static final String STARTUP_WARNING =
+ "WARNING: --permit-illegal-access will be removed in the next major release";
+ static final String ILLEGAL_ACCESS_WARNING =
+ "WARNING: Illegal access by " + TEST_MAIN;
+
+ /**
+ * Launches AttemptAccess to execute an action, returning the OutputAnalyzer
+ * to analyze the output/exitCode.
+ */
+ private OutputAnalyzer tryAction(String action, int count) throws Exception {
+ String arg = "" + count;
+ return ProcessTools
+ .executeTestJava("-cp", TEST_CLASSES, TEST_MAIN, action, arg)
+ .outputTo(System.out)
+ .errorTo(System.out);
+ }
+
+ /**
+ * Launches AttemptAccess with --permit-illegal-access to execute an action,
+ * returning the OutputAnalyzer to analyze the output/exitCode.
+ */
+ private OutputAnalyzer tryActionPermittingIllegalAccess(String action,
+ int count)
+ throws Exception
+ {
+ String arg = "" + count;
+ return ProcessTools
+ .executeTestJava("-cp", TEST_CLASSES, "--permit-illegal-access",
+ TEST_MAIN, action, arg)
+ .outputTo(System.out)
+ .errorTo(System.out);
+ }
+
+ /**
+ * Sanity check to ensure that IllegalAccessException is thrown.
+ */
+ public void testAccessFail() throws Exception {
+ int exitValue = tryAction("access", 1)
+ .stdoutShouldNotContain(WARNING)
+ .stdoutShouldNotContain("IllegalAccessException")
+ .stderrShouldNotContain(WARNING)
+ .stderrShouldContain("IllegalAccessException")
+ .getExitValue();
+ assertTrue(exitValue != 0);
+ }
+
+ /**
+ * Sanity check to ensure that InaccessibleObjectException is thrown.
+ */
+ public void testSetAccessibleFail() throws Exception {
+ int exitValue = tryAction("setAccessible", 1)
+ .stdoutShouldNotContain(WARNING)
+ .stdoutShouldNotContain("InaccessibleObjectException")
+ .stderrShouldNotContain(WARNING)
+ .stderrShouldContain("InaccessibleObjectException")
+ .getExitValue();
+ assertTrue(exitValue != 0);
+ }
+
+ /**
+ * Permit illegal access to succeed
+ */
+ public void testAccessPermitted() throws Exception {
+ tryActionPermittingIllegalAccess("access", 1)
+ .stdoutShouldNotContain(WARNING)
+ .stdoutShouldNotContain("IllegalAccessException")
+ .stderrShouldContain(STARTUP_WARNING)
+ .stderrShouldNotContain("IllegalAccessException")
+ .stderrShouldContain(ILLEGAL_ACCESS_WARNING)
+ .shouldHaveExitValue(0);
+ }
+
+ /**
+ * Permit repeated illegal access to succeed
+ */
+ public void testRepeatedAccessPermitted() throws Exception {
+ OutputAnalyzer outputAnalyzer = tryActionPermittingIllegalAccess("access", 10)
+ .stdoutShouldNotContain(WARNING)
+ .stdoutShouldNotContain("IllegalAccessException")
+ .stderrShouldContain(STARTUP_WARNING)
+ .stderrShouldNotContain("IllegalAccessException")
+ .stderrShouldContain(ILLEGAL_ACCESS_WARNING)
+ .shouldHaveExitValue(0);;
+
+ // should only have one illegal access warning
+ assertTrue(containsCount(outputAnalyzer.asLines(), ILLEGAL_ACCESS_WARNING) == 1);
+ }
+
+ /**
+ * Permit setAccessible to succeed
+ */
+ public void testSetAccessiblePermitted() throws Exception {
+ tryActionPermittingIllegalAccess("setAccessible", 1)
+ .stdoutShouldNotContain(WARNING)
+ .stdoutShouldNotContain("InaccessibleObjectException")
+ .stderrShouldContain(STARTUP_WARNING)
+ .stderrShouldNotContain("InaccessibleObjectException")
+ .stderrShouldContain(ILLEGAL_ACCESS_WARNING)
+ .shouldHaveExitValue(0);
+ }
+
+ /**
+ * Permit repeated calls to setAccessible to succeed
+ */
+ public void testRepeatedSetAccessiblePermitted() throws Exception {
+ OutputAnalyzer outputAnalyzer = tryActionPermittingIllegalAccess("setAccessible", 10)
+ .stdoutShouldNotContain(WARNING)
+ .stdoutShouldNotContain("InaccessibleObjectException")
+ .stderrShouldContain(STARTUP_WARNING)
+ .stderrShouldNotContain("InaccessibleObjectException")
+ .stderrShouldContain(ILLEGAL_ACCESS_WARNING)
+ .shouldHaveExitValue(0);
+
+ // should only have one illegal access warning
+ assertTrue(containsCount(outputAnalyzer.asLines(), ILLEGAL_ACCESS_WARNING) == 1);
+ }
+
+ /**
+ * Permit trySetAccessible to succeed
+ */
+ public void testTrySetAccessiblePermitted() throws Exception {
+ tryActionPermittingIllegalAccess("trySetAccessible", 1)
+ .stdoutShouldNotContain(WARNING)
+ .stderrShouldContain(STARTUP_WARNING)
+ .stderrShouldContain(ILLEGAL_ACCESS_WARNING)
+ .shouldHaveExitValue(0);
+ }
+
+ /**
+ * Permit repeated calls to trySetAccessible to succeed
+ */
+ public void testRepeatedTrySetAccessiblePermitted() throws Exception {
+ OutputAnalyzer outputAnalyzer = tryActionPermittingIllegalAccess("trySetAccessible", 10)
+ .stdoutShouldNotContain(WARNING)
+ .stdoutShouldNotContain("InaccessibleObjectException")
+ .stderrShouldContain(STARTUP_WARNING)
+ .stderrShouldNotContain("InaccessibleObjectException")
+ .stderrShouldContain(ILLEGAL_ACCESS_WARNING)
+ .shouldHaveExitValue(0);
+
+ // should only have one illegal access warning
+ assertTrue(containsCount(outputAnalyzer.asLines(), ILLEGAL_ACCESS_WARNING) == 1);
+
+ }
+
+ /**
+ * Returns the number of lines in the given input that contain the
+ * given char sequence.
+ */
+ private int containsCount(List lines, CharSequence cs) {
+ int count = 0;
+ for (String line : lines) {
+ if (line.contains(cs)) count++;
+ }
+ return count;
+ }
+}
diff --git a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java
index 97e5f767b6e..17fcf679358 100644
--- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java
+++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java
@@ -1544,7 +1544,6 @@ class AttributeVisitor implements Attribute.Visitor {
Element e = new Element(x.getCpString(attr.attribute_name_index));
e.add(x.getCpString(attr.os_name_index));
e.add(x.getCpString(attr.os_arch_index));
- e.add(x.getCpString(attr.os_version_index));
e.trimToSize();
p.add(e);
return null;