Merge
This commit is contained in:
commit
8c79e61d46
@ -317,7 +317,7 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer {
|
||||
this(null, je);
|
||||
}
|
||||
boolean isClassFile() {
|
||||
if (!name.endsWith(".class")) {
|
||||
if (!name.endsWith(".class") || name.endsWith("module-info.class")) {
|
||||
return false;
|
||||
}
|
||||
for (String prefix = name;;) {
|
||||
|
@ -14,15 +14,6 @@ pack.code.attribute.CharacterRangeTable = NH[PHPOHIIH]
|
||||
pack.class.attribute.SourceID = RUH
|
||||
pack.class.attribute.CompilationID = RUH
|
||||
|
||||
# Module attributes, supported by the tool and not JSR-200
|
||||
pack.class.attribute.Module = RUHFHNH[RUHFH]NH[RUHFHNH[RUH]]NH[RUHFHNH[RUH]]NH[RCH]NH[RCHNH[RCH]]
|
||||
pack.class.attribute.ModulePackages = NH[RUH]
|
||||
pack.class.attribute.ModuleVersion = RUH
|
||||
pack.class.attribute.ModuleMainClass = RCH
|
||||
pack.class.attribute.ModuleTarget = RUHRUHRUH
|
||||
pack.class.attribute.ModuleHashes = RUHNH[RUHNH[B]]
|
||||
|
||||
|
||||
# Note: Zero-length ("marker") attributes do not need to be specified here.
|
||||
# They are automatically defined to have an empty layout.
|
||||
#pack.class.attribute.Deprecated =
|
||||
|
@ -26,10 +26,13 @@
|
||||
package java.lang;
|
||||
|
||||
import jdk.internal.loader.BuiltinClassLoader;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.misc.VM;
|
||||
import jdk.internal.module.ModuleHashes;
|
||||
import jdk.internal.module.ModuleReferenceImpl;
|
||||
|
||||
import java.lang.module.ModuleDescriptor.Version;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.lang.module.ResolvedModule;
|
||||
import java.lang.reflect.Layer;
|
||||
import java.lang.reflect.Module;
|
||||
import java.util.HashSet;
|
||||
@ -477,13 +480,16 @@ public final class StackTraceElement implements java.io.Serializable {
|
||||
static Set<String> HASHED_MODULES = hashedModules();
|
||||
|
||||
static Set<String> hashedModules() {
|
||||
Module javaBase = Layer.boot().findModule("java.base").get();
|
||||
Optional<ModuleHashes> ohashes =
|
||||
SharedSecrets.getJavaLangModuleAccess()
|
||||
.hashes(javaBase.getDescriptor());
|
||||
|
||||
if (ohashes.isPresent()) {
|
||||
Set<String> names = new HashSet<>(ohashes.get().names());
|
||||
Optional<ResolvedModule> resolvedModule = Layer.boot()
|
||||
.configuration()
|
||||
.findModule("java.base");
|
||||
assert resolvedModule.isPresent();
|
||||
ModuleReference mref = resolvedModule.get().reference();
|
||||
assert mref instanceof ModuleReferenceImpl;
|
||||
ModuleHashes hashes = ((ModuleReferenceImpl)mref).recordedHashes();
|
||||
if (hashes != null) {
|
||||
Set<String> names = new HashSet<>(hashes.names());
|
||||
names.add("java.base");
|
||||
return names;
|
||||
}
|
||||
|
@ -172,6 +172,7 @@ public class MethodHandles {
|
||||
* @throws IllegalAccessException if the access check specified above fails
|
||||
* @throws SecurityException if denied by the security manager
|
||||
* @since 9
|
||||
* @see Lookup#dropLookupMode
|
||||
*/
|
||||
public static Lookup privateLookupIn(Class<?> targetClass, Lookup lookup) throws IllegalAccessException {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
@ -691,10 +692,15 @@ public class MethodHandles {
|
||||
* A lookup object on a new lookup class
|
||||
* {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
|
||||
* may have some mode bits set to zero.
|
||||
* Mode bits can also be
|
||||
* {@linkplain java.lang.invoke.MethodHandles.Lookup#dropLookupMode directly cleared}.
|
||||
* Once cleared, mode bits cannot be restored from the downgraded lookup object.
|
||||
* The purpose of this is to restrict access via the new lookup object,
|
||||
* so that it can access only names which can be reached by the original
|
||||
* lookup object, and also by the new lookup class.
|
||||
* @return the lookup modes, which limit the kinds of access performed by this lookup object
|
||||
* @see #in
|
||||
* @see #dropLookupMode
|
||||
*/
|
||||
public int lookupModes() {
|
||||
return allowedModes & ALL_MODES;
|
||||
@ -748,7 +754,8 @@ public class MethodHandles {
|
||||
* which may change due to this operation.
|
||||
*
|
||||
* @param requestedLookupClass the desired lookup class for the new lookup object
|
||||
* @return a lookup object which reports the desired lookup class
|
||||
* @return a lookup object which reports the desired lookup class, or the same object
|
||||
* if there is no change
|
||||
* @throws NullPointerException if the argument is null
|
||||
*/
|
||||
public Lookup in(Class<?> requestedLookupClass) {
|
||||
@ -788,6 +795,40 @@ public class MethodHandles {
|
||||
return new Lookup(requestedLookupClass, newModes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a lookup on the same lookup class which this lookup object
|
||||
* finds members, but with a lookup mode that has lost the given lookup mode.
|
||||
* The lookup mode to drop is one of {@link #PUBLIC PUBLIC}, {@link #MODULE
|
||||
* MODULE}, {@link #PACKAGE PACKAGE}, {@link #PROTECTED PROTECTED} or {@link #PRIVATE PRIVATE}.
|
||||
* {@link #PROTECTED PROTECTED} is always dropped and so the resulting lookup
|
||||
* mode will never have this access capability. When dropping {@code PACKAGE}
|
||||
* then the resulting lookup will not have {@code PACKAGE} or {@code PRIVATE}
|
||||
* access. When dropping {@code MODULE} then the resulting lookup will not
|
||||
* have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code
|
||||
* PUBLIC} is dropped then the resulting lookup has no access.
|
||||
* @param modeToDrop the lookup mode to drop
|
||||
* @return a lookup object which lacks the indicated mode, or the same object if there is no change
|
||||
* @throws IllegalArgumentException if {@code modeToDrop} is not one of {@code PUBLIC},
|
||||
* {@code MODULE}, {@code PACKAGE}, {@code PROTECTED} or {@code PRIVATE}
|
||||
* @since 9
|
||||
* @see MethodHandles#privateLookupIn
|
||||
*/
|
||||
public Lookup dropLookupMode(int modeToDrop) {
|
||||
int oldModes = lookupModes();
|
||||
int newModes = oldModes & ~(modeToDrop | PROTECTED);
|
||||
switch (modeToDrop) {
|
||||
case PUBLIC: newModes &= ~(ALL_MODES); break;
|
||||
case MODULE: newModes &= ~(PACKAGE | PRIVATE); break;
|
||||
case PACKAGE: newModes &= ~(PRIVATE); break;
|
||||
case PROTECTED:
|
||||
case PRIVATE: break;
|
||||
default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop");
|
||||
}
|
||||
if (newModes == oldModes) return this; // return self if no change
|
||||
return new Lookup(lookupClass(), newModes);
|
||||
}
|
||||
|
||||
// Make sure outer class is initialized first.
|
||||
static { IMPL_NAMES.getClass(); }
|
||||
|
||||
|
@ -29,7 +29,6 @@ import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
@ -38,7 +37,6 @@ import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@ -52,7 +50,7 @@ import static jdk.internal.module.Checks.*;
|
||||
import static java.util.Objects.*;
|
||||
|
||||
import jdk.internal.module.Checks;
|
||||
import jdk.internal.module.ModuleHashes;
|
||||
import jdk.internal.module.ModuleInfo;
|
||||
|
||||
|
||||
/**
|
||||
@ -123,8 +121,9 @@ public class ModuleDescriptor
|
||||
|
||||
private final Set<Modifier> mods;
|
||||
private final String name;
|
||||
private final Version compiledVersion;
|
||||
|
||||
private Requires(Set<Modifier> ms, String mn) {
|
||||
private Requires(Set<Modifier> ms, String mn, Version v) {
|
||||
if (ms.isEmpty()) {
|
||||
ms = Collections.emptySet();
|
||||
} else {
|
||||
@ -132,11 +131,13 @@ public class ModuleDescriptor
|
||||
}
|
||||
this.mods = ms;
|
||||
this.name = mn;
|
||||
this.compiledVersion = v;
|
||||
}
|
||||
|
||||
private Requires(Set<Modifier> ms, String mn, boolean unused) {
|
||||
private Requires(Set<Modifier> ms, String mn, Version v, boolean unused) {
|
||||
this.mods = ms;
|
||||
this.name = mn;
|
||||
this.compiledVersion = v;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -157,13 +158,27 @@ public class ModuleDescriptor
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the module if recorded at compile-time.
|
||||
*
|
||||
* @return The version of the module if recorded at compile-time
|
||||
*/
|
||||
public Optional<Version> compiledVersion() {
|
||||
return Optional.ofNullable(compiledVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this module dependence to another.
|
||||
*
|
||||
* <p> Two {@code Requires} objects are compared by comparing their
|
||||
* module name lexicographically. Where the module names are equal then
|
||||
* the sets of modifiers are compared based on a value computed from the
|
||||
* ordinal of each modifier. </p>
|
||||
* ordinal of each modifier. Where the module names are equal and the
|
||||
* set of modifiers are equal then the version of the modules recorded
|
||||
* at compile-time are compared. When comparing the versions recorded
|
||||
* at compile-time then a dependence that has a recorded version is
|
||||
* considered to succeed a dependence that does not have a recorded
|
||||
* version. </p>
|
||||
*
|
||||
* @return A negative integer, zero, or a positive integer if this module
|
||||
* dependence is less than, equal to, or greater than the given
|
||||
@ -174,8 +189,24 @@ public class ModuleDescriptor
|
||||
int c = this.name().compareTo(that.name());
|
||||
if (c != 0)
|
||||
return c;
|
||||
// same name, compare by modifiers
|
||||
return Long.compare(this.modsValue(), that.modsValue());
|
||||
|
||||
// modifiers
|
||||
c = Long.compare(this.modsValue(), that.modsValue());
|
||||
if (c != 0)
|
||||
return c;
|
||||
|
||||
// compiledVersion
|
||||
if (this.compiledVersion != null) {
|
||||
if (that.compiledVersion != null)
|
||||
c = this.compiledVersion.compareTo(that.compiledVersion);
|
||||
else
|
||||
c = 1;
|
||||
} else {
|
||||
if (that.compiledVersion != null)
|
||||
c = -1;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -195,7 +226,9 @@ public class ModuleDescriptor
|
||||
*
|
||||
* <p> If the given object is not a {@code Requires} then this method
|
||||
* returns {@code false}. Two module dependence objects are equal if
|
||||
* the module names are equal and set of modifiers are equal. </p>
|
||||
* the module names are equal, set of modifiers are equal, and the
|
||||
* compiled version of both modules is equal or not recorded for
|
||||
* both modules. </p>
|
||||
*
|
||||
* <p> This method satisfies the general contract of the {@link
|
||||
* java.lang.Object#equals(Object) Object.equals} method. </p>
|
||||
@ -211,21 +244,25 @@ public class ModuleDescriptor
|
||||
if (!(ob instanceof Requires))
|
||||
return false;
|
||||
Requires that = (Requires)ob;
|
||||
return (name.equals(that.name) && mods.equals(that.mods));
|
||||
return name.equals(that.name) && mods.equals(that.mods)
|
||||
&& Objects.equals(compiledVersion, that.compiledVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a hash code for this module dependence.
|
||||
*
|
||||
* <p> The hash code is based upon the module name and modifiers. It
|
||||
* satisfies the general contract of the {@link Object#hashCode
|
||||
* Object.hashCode} method. </p>
|
||||
* <p> The hash code is based upon the module name, modifiers, and the
|
||||
* module version if recorded at compile time. It satisfies the general
|
||||
* contract of the {@link Object#hashCode Object.hashCode} method. </p>
|
||||
*
|
||||
* @return The hash-code value for this module dependence
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode() * 43 + mods.hashCode();
|
||||
int hash = name.hashCode() * 43 + mods.hashCode();
|
||||
if (compiledVersion != null)
|
||||
hash = hash * 43 + compiledVersion.hashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -235,7 +272,13 @@ public class ModuleDescriptor
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return ModuleDescriptor.toString(mods, name);
|
||||
String what;
|
||||
if (compiledVersion != null) {
|
||||
what = name() + " (@" + compiledVersion + ")";
|
||||
} else {
|
||||
what = name();
|
||||
}
|
||||
return ModuleDescriptor.toString(mods, what);
|
||||
}
|
||||
}
|
||||
|
||||
@ -967,9 +1010,8 @@ public class ModuleDescriptor
|
||||
}
|
||||
|
||||
|
||||
|
||||
// From module declarations
|
||||
private final String name;
|
||||
private final Version version;
|
||||
private final boolean open;
|
||||
|
||||
// Indicates if synthesised for a JAR file found on the module path
|
||||
@ -984,17 +1026,16 @@ public class ModuleDescriptor
|
||||
private final Set<String> uses;
|
||||
private final Set<Provides> provides;
|
||||
|
||||
// "Extended" information, added post-compilation by tools
|
||||
private final Version version;
|
||||
// Added post-compilation by tools
|
||||
private final Set<String> packages;
|
||||
private final String mainClass;
|
||||
private final String osName;
|
||||
private final String osArch;
|
||||
private final String osVersion;
|
||||
private final Set<String> packages;
|
||||
private final ModuleHashes hashes;
|
||||
|
||||
|
||||
private ModuleDescriptor(String name,
|
||||
Version version,
|
||||
boolean open,
|
||||
boolean automatic,
|
||||
boolean synthetic,
|
||||
@ -1003,16 +1044,14 @@ public class ModuleDescriptor
|
||||
Set<Opens> opens,
|
||||
Set<String> uses,
|
||||
Set<Provides> provides,
|
||||
Version version,
|
||||
Set<String> packages,
|
||||
String mainClass,
|
||||
String osName,
|
||||
String osArch,
|
||||
String osVersion,
|
||||
Set<String> packages,
|
||||
ModuleHashes hashes)
|
||||
String osVersion)
|
||||
{
|
||||
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
this.open = open;
|
||||
this.automatic = automatic;
|
||||
this.synthetic = synthetic;
|
||||
@ -1020,18 +1059,16 @@ public class ModuleDescriptor
|
||||
assert (requires.stream().map(Requires::name).distinct().count()
|
||||
== requires.size());
|
||||
this.requires = emptyOrUnmodifiableSet(requires);
|
||||
|
||||
this.exports = emptyOrUnmodifiableSet(exports);
|
||||
this.opens = emptyOrUnmodifiableSet(opens);
|
||||
this.uses = emptyOrUnmodifiableSet(uses);
|
||||
this.provides = emptyOrUnmodifiableSet(provides);
|
||||
this.version = version;
|
||||
|
||||
this.packages = emptyOrUnmodifiableSet(packages);
|
||||
this.mainClass = mainClass;
|
||||
this.osName = osName;
|
||||
this.osArch = osArch;
|
||||
this.osVersion = osVersion;
|
||||
this.hashes = hashes;
|
||||
this.packages = emptyOrUnmodifiableSet(packages);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1039,6 +1076,7 @@ public class ModuleDescriptor
|
||||
*/
|
||||
ModuleDescriptor(ModuleDescriptor md, Set<String> pkgs) {
|
||||
this.name = md.name;
|
||||
this.version = md.version;
|
||||
this.open = md.open;
|
||||
this.automatic = md.automatic;
|
||||
this.synthetic = md.synthetic;
|
||||
@ -1049,16 +1087,14 @@ public class ModuleDescriptor
|
||||
this.uses = md.uses;
|
||||
this.provides = md.provides;
|
||||
|
||||
this.version = md.version;
|
||||
Set<String> packages = new HashSet<>(md.packages);
|
||||
packages.addAll(pkgs);
|
||||
this.packages = emptyOrUnmodifiableSet(packages);
|
||||
|
||||
this.mainClass = md.mainClass;
|
||||
this.osName = md.osName;
|
||||
this.osArch = md.osArch;
|
||||
this.osVersion = md.osVersion;
|
||||
this.hashes = null; // need to ignore
|
||||
|
||||
Set<String> packages = new HashSet<>(md.packages);
|
||||
packages.addAll(pkgs);
|
||||
this.packages = emptyOrUnmodifiableSet(packages);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1066,6 +1102,7 @@ public class ModuleDescriptor
|
||||
* The arguments are pre-validated and sets are unmodifiable sets.
|
||||
*/
|
||||
ModuleDescriptor(String name,
|
||||
Version version,
|
||||
boolean open,
|
||||
boolean automatic,
|
||||
boolean synthetic,
|
||||
@ -1074,16 +1111,15 @@ public class ModuleDescriptor
|
||||
Set<Opens> opens,
|
||||
Set<String> uses,
|
||||
Set<Provides> provides,
|
||||
Version version,
|
||||
Set<String> packages,
|
||||
String mainClass,
|
||||
String osName,
|
||||
String osArch,
|
||||
String osVersion,
|
||||
Set<String> packages,
|
||||
ModuleHashes hashes,
|
||||
int hashCode,
|
||||
boolean unused) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
this.open = open;
|
||||
this.automatic = automatic;
|
||||
this.synthetic = synthetic;
|
||||
@ -1093,12 +1129,10 @@ public class ModuleDescriptor
|
||||
this.uses = uses;
|
||||
this.provides = provides;
|
||||
this.packages = packages;
|
||||
this.version = version;
|
||||
this.mainClass = mainClass;
|
||||
this.osName = osName;
|
||||
this.osArch = osArch;
|
||||
this.osVersion = osVersion;
|
||||
this.hashes = hashes;
|
||||
this.hash = hashCode;
|
||||
}
|
||||
|
||||
@ -1284,13 +1318,6 @@ public class ModuleDescriptor
|
||||
return packages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object with the hashes of other modules
|
||||
*/
|
||||
Optional<ModuleHashes> hashes() {
|
||||
return Optional.ofNullable(hashes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A builder used for building {@link ModuleDescriptor} objects.
|
||||
@ -1317,15 +1344,13 @@ public class ModuleDescriptor
|
||||
public static final class Builder {
|
||||
final String name;
|
||||
final boolean strict; // true if module names are checked
|
||||
boolean open;
|
||||
final boolean open;
|
||||
final boolean synthetic;
|
||||
boolean automatic;
|
||||
boolean synthetic;
|
||||
final Map<String, Requires> requires = new HashMap<>();
|
||||
|
||||
final Map<String, Exports> exports = new HashMap<>();
|
||||
final Map<String, Opens> opens = new HashMap<>();
|
||||
final Set<String> concealedPackages = new HashSet<>();
|
||||
|
||||
final Set<String> uses = new HashSet<>();
|
||||
final Map<String, Provides> provides = new HashMap<>();
|
||||
Version version;
|
||||
@ -1333,7 +1358,6 @@ public class ModuleDescriptor
|
||||
String osArch;
|
||||
String osVersion;
|
||||
String mainClass;
|
||||
ModuleHashes hashes;
|
||||
|
||||
/**
|
||||
* Initializes a new builder with the given module name.
|
||||
@ -1341,14 +1365,11 @@ public class ModuleDescriptor
|
||||
* @param strict
|
||||
* Indicates whether module names are checked or not
|
||||
*/
|
||||
Builder(String name, boolean strict) {
|
||||
this.strict = strict;
|
||||
Builder(String name, boolean strict, boolean open, boolean synthetic) {
|
||||
this.name = (strict) ? requireModuleName(name) : name;
|
||||
}
|
||||
|
||||
/* package */ Builder open(boolean open) {
|
||||
this.strict = strict;
|
||||
this.open = open;
|
||||
return this;
|
||||
this.synthetic = synthetic;
|
||||
}
|
||||
|
||||
/* package */ Builder automatic(boolean automatic) {
|
||||
@ -1356,10 +1377,20 @@ public class ModuleDescriptor
|
||||
return this;
|
||||
}
|
||||
|
||||
/* package */ boolean isOpen() { return open; }
|
||||
/**
|
||||
* Returns the set of packages that are exported (unconditionally or
|
||||
* unconditionally).
|
||||
*/
|
||||
/* package */ Set<String> exportedPackages() {
|
||||
return exports.keySet();
|
||||
}
|
||||
|
||||
/* package */ boolean isAutomatic() {
|
||||
return automatic;
|
||||
/**
|
||||
* Returns the set of packages that are opened (unconditionally or
|
||||
* unconditionally).
|
||||
*/
|
||||
/* package */Set<String> openPackages() {
|
||||
return opens.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1387,6 +1418,36 @@ public class ModuleDescriptor
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a dependence on a module with the given (and possibly empty)
|
||||
* set of modifiers. The dependence includes the version of the
|
||||
* module that that was recorded at compile-time.
|
||||
*
|
||||
* @param ms
|
||||
* The set of modifiers
|
||||
* @param mn
|
||||
* The module name
|
||||
* @param compiledVersion
|
||||
* The version of the module recorded at compile-time
|
||||
*
|
||||
* @return This builder
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* If the module name is {@code null}, is not a legal Java
|
||||
* identifier, or is equal to the module name that this builder
|
||||
* was initialized to build
|
||||
* @throws IllegalStateException
|
||||
* If the dependence on the module has already been declared
|
||||
*/
|
||||
public Builder requires(Set<Requires.Modifier> ms,
|
||||
String mn,
|
||||
Version compiledVersion) {
|
||||
Objects.requireNonNull(compiledVersion);
|
||||
if (strict)
|
||||
mn = requireModuleName(mn);
|
||||
return requires(new Requires(ms, mn, compiledVersion));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a dependence on a module with the given (and possibly empty)
|
||||
* set of modifiers.
|
||||
@ -1408,7 +1469,7 @@ public class ModuleDescriptor
|
||||
public Builder requires(Set<Requires.Modifier> ms, String mn) {
|
||||
if (strict)
|
||||
mn = requireModuleName(mn);
|
||||
return requires(new Requires(ms, mn));
|
||||
return requires(new Requires(ms, mn, null));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1705,17 +1766,6 @@ public class ModuleDescriptor
|
||||
return opens(Collections.emptySet(), pn);
|
||||
}
|
||||
|
||||
|
||||
// Used by ModuleInfo, after a packageFinder is invoked
|
||||
/* package */ Set<String> exportedAndOpenPackages() {
|
||||
if (opens.isEmpty())
|
||||
return exports.keySet();
|
||||
Set<String> result = new HashSet<>();
|
||||
result.addAll(exports.keySet());
|
||||
result.addAll(opens.keySet());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a service dependence.
|
||||
*
|
||||
@ -1789,7 +1839,6 @@ public class ModuleDescriptor
|
||||
if (providerNames.isEmpty())
|
||||
throw new IllegalArgumentException("Empty providers set");
|
||||
providerNames.forEach(Checks::requireServiceProviderName);
|
||||
|
||||
provides.put(service, p);
|
||||
return this;
|
||||
}
|
||||
@ -1914,7 +1963,7 @@ public class ModuleDescriptor
|
||||
* If {@code mainClass} is null or is not a legal Java identifier
|
||||
*/
|
||||
public Builder mainClass(String mc) {
|
||||
mainClass = requireJavaIdentifier("main class name", mc);
|
||||
mainClass = requireBinaryName("main class name", mc);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -1972,16 +2021,6 @@ public class ModuleDescriptor
|
||||
return this;
|
||||
}
|
||||
|
||||
/* package */ Builder hashes(ModuleHashes hashes) {
|
||||
this.hashes = hashes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/* package */ Builder synthetic(boolean v) {
|
||||
this.synthetic = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns a {@code ModuleDescriptor} from its components.
|
||||
*
|
||||
@ -1990,7 +2029,9 @@ public class ModuleDescriptor
|
||||
public ModuleDescriptor build() {
|
||||
Set<Requires> requires = new HashSet<>(this.requires.values());
|
||||
|
||||
Set<String> packages = new HashSet<>(exportedAndOpenPackages());
|
||||
Set<String> packages = new HashSet<>();
|
||||
packages.addAll(exports.keySet());
|
||||
packages.addAll(opens.keySet());
|
||||
packages.addAll(concealedPackages);
|
||||
|
||||
Set<Exports> exports = new HashSet<>(this.exports.values());
|
||||
@ -1999,6 +2040,7 @@ public class ModuleDescriptor
|
||||
Set<Provides> provides = new HashSet<>(this.provides.values());
|
||||
|
||||
return new ModuleDescriptor(name,
|
||||
version,
|
||||
open,
|
||||
automatic,
|
||||
synthetic,
|
||||
@ -2007,13 +2049,11 @@ public class ModuleDescriptor
|
||||
opens,
|
||||
uses,
|
||||
provides,
|
||||
version,
|
||||
packages,
|
||||
mainClass,
|
||||
osName,
|
||||
osArch,
|
||||
osVersion,
|
||||
packages,
|
||||
hashes);
|
||||
osVersion);
|
||||
}
|
||||
|
||||
}
|
||||
@ -2088,8 +2128,7 @@ public class ModuleDescriptor
|
||||
&& Objects.equals(osName, that.osName)
|
||||
&& Objects.equals(osArch, that.osArch)
|
||||
&& Objects.equals(osVersion, that.osVersion)
|
||||
&& Objects.equals(packages, that.packages)
|
||||
&& Objects.equals(hashes, that.hashes));
|
||||
&& Objects.equals(packages, that.packages));
|
||||
}
|
||||
|
||||
private transient int hash; // cached hash code
|
||||
@ -2122,7 +2161,6 @@ public class ModuleDescriptor
|
||||
hc = hc * 43 + Objects.hashCode(osArch);
|
||||
hc = hc * 43 + Objects.hashCode(osVersion);
|
||||
hc = hc * 43 + Objects.hashCode(packages);
|
||||
hc = hc * 43 + Objects.hashCode(hashes);
|
||||
if (hc == 0)
|
||||
hc = -1;
|
||||
hash = hc;
|
||||
@ -2145,7 +2183,7 @@ public class ModuleDescriptor
|
||||
if (!requires.isEmpty())
|
||||
sb.append(", ").append(requires);
|
||||
if (!uses.isEmpty())
|
||||
sb.append(", ").append(uses);
|
||||
sb.append(", uses: ").append(uses);
|
||||
if (!exports.isEmpty())
|
||||
sb.append(", exports: ").append(exports);
|
||||
if (!opens.isEmpty())
|
||||
@ -2171,7 +2209,7 @@ public class ModuleDescriptor
|
||||
* identifier
|
||||
*/
|
||||
public static Builder module(String name) {
|
||||
return new Builder(name, true);
|
||||
return new Builder(name, true, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2199,7 +2237,7 @@ public class ModuleDescriptor
|
||||
* identifier
|
||||
*/
|
||||
public static Builder openModule(String name) {
|
||||
return new Builder(name, true).open(true);
|
||||
return new Builder(name, true, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2221,7 +2259,7 @@ public class ModuleDescriptor
|
||||
* @see ModuleFinder#of(Path[])
|
||||
*/
|
||||
public static Builder automaticModule(String name) {
|
||||
return new Builder(name, true).automatic(true);
|
||||
return new Builder(name, true, false, false).automatic(true);
|
||||
}
|
||||
|
||||
|
||||
@ -2263,7 +2301,7 @@ public class ModuleDescriptor
|
||||
Supplier<Set<String>> packageFinder)
|
||||
throws IOException
|
||||
{
|
||||
return ModuleInfo.read(in, requireNonNull(packageFinder));
|
||||
return ModuleInfo.read(in, requireNonNull(packageFinder)).descriptor();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2281,7 +2319,7 @@ public class ModuleDescriptor
|
||||
* If an I/O error occurs reading from the input stream
|
||||
*/
|
||||
public static ModuleDescriptor read(InputStream in) throws IOException {
|
||||
return ModuleInfo.read(in, null);
|
||||
return ModuleInfo.read(in, null).descriptor();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2320,7 +2358,7 @@ public class ModuleDescriptor
|
||||
public static ModuleDescriptor read(ByteBuffer bb,
|
||||
Supplier<Set<String>> packageFinder)
|
||||
{
|
||||
return ModuleInfo.read(bb, requireNonNull(packageFinder));
|
||||
return ModuleInfo.read(bb, requireNonNull(packageFinder)).descriptor();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2336,7 +2374,7 @@ public class ModuleDescriptor
|
||||
* If an invalid module descriptor is detected
|
||||
*/
|
||||
public static ModuleDescriptor read(ByteBuffer bb) {
|
||||
return ModuleInfo.read(bb, null);
|
||||
return ModuleInfo.read(bb, null).descriptor();
|
||||
}
|
||||
|
||||
private static <K,V> Map<K,V> emptyOrUnmodifiableMap(Map<K,V> map) {
|
||||
@ -2377,18 +2415,26 @@ public class ModuleDescriptor
|
||||
jdk.internal.misc.SharedSecrets
|
||||
.setJavaLangModuleAccess(new jdk.internal.misc.JavaLangModuleAccess() {
|
||||
@Override
|
||||
public Builder newModuleBuilder(String mn, boolean strict) {
|
||||
return new Builder(mn, strict);
|
||||
public Builder newModuleBuilder(String mn,
|
||||
boolean strict,
|
||||
boolean open,
|
||||
boolean synthetic) {
|
||||
return new Builder(mn, strict, open, synthetic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder newOpenModuleBuilder(String mn, boolean strict) {
|
||||
return new Builder(mn, strict).open(true);
|
||||
public Set<String> exportedPackages(ModuleDescriptor.Builder builder) {
|
||||
return builder.exportedPackages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Requires newRequires(Set<Requires.Modifier> ms, String mn) {
|
||||
return new Requires(ms, mn, true);
|
||||
public Set<String> openPackages(ModuleDescriptor.Builder builder) {
|
||||
return builder.openPackages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Requires newRequires(Set<Requires.Modifier> ms, String mn, Version v) {
|
||||
return new Requires(ms, mn, v, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2433,6 +2479,7 @@ public class ModuleDescriptor
|
||||
|
||||
@Override
|
||||
public ModuleDescriptor newModuleDescriptor(String name,
|
||||
Version version,
|
||||
boolean open,
|
||||
boolean automatic,
|
||||
boolean synthetic,
|
||||
@ -2441,15 +2488,14 @@ public class ModuleDescriptor
|
||||
Set<Opens> opens,
|
||||
Set<String> uses,
|
||||
Set<Provides> provides,
|
||||
Version version,
|
||||
Set<String> packages,
|
||||
String mainClass,
|
||||
String osName,
|
||||
String osArch,
|
||||
String osVersion,
|
||||
Set<String> packages,
|
||||
ModuleHashes hashes,
|
||||
int hashCode) {
|
||||
return new ModuleDescriptor(name,
|
||||
version,
|
||||
open,
|
||||
automatic,
|
||||
synthetic,
|
||||
@ -2458,22 +2504,15 @@ public class ModuleDescriptor
|
||||
opens,
|
||||
uses,
|
||||
provides,
|
||||
version,
|
||||
packages,
|
||||
mainClass,
|
||||
osName,
|
||||
osArch,
|
||||
osVersion,
|
||||
packages,
|
||||
hashes,
|
||||
hashCode,
|
||||
false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ModuleHashes> hashes(ModuleDescriptor descriptor) {
|
||||
return descriptor.hashes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration resolveRequiresAndUses(ModuleFinder finder,
|
||||
Collection<String> roots,
|
||||
@ -2482,20 +2521,6 @@ public class ModuleDescriptor
|
||||
{
|
||||
return Configuration.resolveRequiresAndUses(finder, roots, check, traceOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleReference newPatchedModule(ModuleDescriptor descriptor,
|
||||
URI location,
|
||||
Supplier<ModuleReader> s) {
|
||||
return new ModuleReference(descriptor, location, s, true, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleFinder newModulePath(Runtime.Version version,
|
||||
boolean isLinkPhase,
|
||||
Path... entries) {
|
||||
return new ModulePath(version, isLinkPhase, entries);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,8 @@ import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.module.ModulePath;
|
||||
import jdk.internal.module.SystemModuleFinder;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
@ -137,7 +139,7 @@ public interface ModuleFinder {
|
||||
|
||||
/**
|
||||
* Returns a module finder that locates the <em>system modules</em>. The
|
||||
* system modules are typically linked into the Java run-time image.
|
||||
* system modules are the modules in the Java run-time image.
|
||||
* The module finder will always find {@code java.base}.
|
||||
*
|
||||
* <p> If there is a security manager set then its {@link
|
||||
@ -166,7 +168,7 @@ public interface ModuleFinder {
|
||||
|
||||
Path modules = Paths.get(home, "lib", "modules");
|
||||
if (Files.isRegularFile(modules)) {
|
||||
return new SystemModuleFinder();
|
||||
return SystemModuleFinder.getInstance();
|
||||
} else {
|
||||
Path mlib = Paths.get(home, "modules");
|
||||
if (Files.isDirectory(mlib)) {
|
||||
|
@ -26,96 +26,42 @@
|
||||
package java.lang.module;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URI;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jdk.internal.module.ModuleHashes.HashSupplier;
|
||||
|
||||
|
||||
/**
|
||||
* A reference to a module's content.
|
||||
*
|
||||
* <p> A module reference contains the module's descriptor and its location, if
|
||||
* known. It also has the ability to create a {@link ModuleReader} in order to
|
||||
* access the module's content, which may be inside the Java run-time system
|
||||
* itself or in an artifact such as a modular JAR file.
|
||||
* <p> A module reference is a concrete implementation of this class that
|
||||
* implements the abstract methods defined by this class. It contains the
|
||||
* module's descriptor and its location, if known. It also has the ability to
|
||||
* create a {@link ModuleReader} in order to access the module's content, which
|
||||
* may be inside the Java run-time system itself or in an artifact such as a
|
||||
* modular JAR file.
|
||||
*
|
||||
* @see ModuleFinder
|
||||
* @see ModuleReader
|
||||
* @since 9
|
||||
*/
|
||||
|
||||
public final class ModuleReference {
|
||||
public abstract class ModuleReference {
|
||||
|
||||
private final ModuleDescriptor descriptor;
|
||||
private final URI location;
|
||||
private final Supplier<ModuleReader> readerSupplier;
|
||||
|
||||
// true if this is a reference to a patched module
|
||||
private boolean patched;
|
||||
|
||||
// the function that computes the hash of this module reference
|
||||
private final HashSupplier hasher;
|
||||
|
||||
// cached hash to avoid needing to compute it many times
|
||||
private byte[] cachedHash;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new instance of this class.
|
||||
*/
|
||||
ModuleReference(ModuleDescriptor descriptor,
|
||||
URI location,
|
||||
Supplier<ModuleReader> readerSupplier,
|
||||
boolean patched,
|
||||
HashSupplier hasher)
|
||||
|
||||
{
|
||||
this.descriptor = Objects.requireNonNull(descriptor);
|
||||
this.location = location;
|
||||
this.readerSupplier = Objects.requireNonNull(readerSupplier);
|
||||
this.patched = patched;
|
||||
this.hasher = hasher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of this class.
|
||||
*/
|
||||
ModuleReference(ModuleDescriptor descriptor,
|
||||
URI location,
|
||||
Supplier<ModuleReader> readerSupplier,
|
||||
HashSupplier hasher)
|
||||
|
||||
{
|
||||
this(descriptor, location, readerSupplier, false, hasher);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new instance of this class.
|
||||
*
|
||||
* <p> The {@code readSupplier} parameter is the supplier of the {@link
|
||||
* ModuleReader} that may be used to read the module content. Its {@link
|
||||
* Supplier#get() get()} method throws {@link UncheckedIOException} if an
|
||||
* I/O error occurs opening the module content. The {@code get()} method
|
||||
* throws {@link SecurityException} if opening the module is denied by the
|
||||
* security manager.
|
||||
*
|
||||
* @param descriptor
|
||||
* The module descriptor
|
||||
* @param location
|
||||
* The module location or {@code null} if not known
|
||||
* @param readerSupplier
|
||||
* The {@code Supplier} of the {@code ModuleReader}
|
||||
*/
|
||||
public ModuleReference(ModuleDescriptor descriptor,
|
||||
URI location,
|
||||
Supplier<ModuleReader> readerSupplier)
|
||||
{
|
||||
this(descriptor, location, readerSupplier, false, null);
|
||||
protected ModuleReference(ModuleDescriptor descriptor, URI location) {
|
||||
this.descriptor = Objects.requireNonNull(descriptor);
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,11 +69,10 @@ public final class ModuleReference {
|
||||
*
|
||||
* @return The module descriptor
|
||||
*/
|
||||
public ModuleDescriptor descriptor() {
|
||||
public final ModuleDescriptor descriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the location of this module's content, if known.
|
||||
*
|
||||
@ -139,18 +84,13 @@ public final class ModuleReference {
|
||||
*
|
||||
* @return The location or an empty {@code Optional} if not known
|
||||
*/
|
||||
public Optional<URI> location() {
|
||||
public final Optional<URI> location() {
|
||||
return Optional.ofNullable(location);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opens the module content for reading.
|
||||
*
|
||||
* <p> This method opens the module content by invoking the {@link
|
||||
* Supplier#get() get()} method of the {@code readSupplier} specified at
|
||||
* construction time. </p>
|
||||
*
|
||||
* @return A {@code ModuleReader} to read the module
|
||||
*
|
||||
* @throws IOException
|
||||
@ -158,113 +98,5 @@ public final class ModuleReference {
|
||||
* @throws SecurityException
|
||||
* If denied by the security manager
|
||||
*/
|
||||
public ModuleReader open() throws IOException {
|
||||
try {
|
||||
return readerSupplier.get();
|
||||
} catch (UncheckedIOException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this module has been patched via --patch-module.
|
||||
*/
|
||||
boolean isPatched() {
|
||||
return patched;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash supplier for this module.
|
||||
*/
|
||||
HashSupplier hasher() {
|
||||
return hasher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the hash of this module. Returns {@code null} if the hash
|
||||
* cannot be computed.
|
||||
*
|
||||
* @throws java.io.UncheckedIOException if an I/O error occurs
|
||||
*/
|
||||
byte[] computeHash(String algorithm) {
|
||||
byte[] result = cachedHash;
|
||||
if (result != null)
|
||||
return result;
|
||||
if (hasher == null)
|
||||
return null;
|
||||
cachedHash = result = hasher.generate(algorithm);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a hash code for this module reference.
|
||||
*
|
||||
* <p> The hash code is based upon the components of the reference, and
|
||||
* satisfies the general contract of the {@link Object#hashCode
|
||||
* Object.hashCode} method. </p>
|
||||
*
|
||||
* @return The hash-code value for this module reference
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc = hash;
|
||||
if (hc == 0) {
|
||||
hc = descriptor.hashCode();
|
||||
hc = 43 * hc + readerSupplier.hashCode();
|
||||
hc = 43 * hc + Objects.hashCode(location);
|
||||
hc = 43 * hc + Objects.hashCode(hasher);
|
||||
hc = 43 * hc + Boolean.hashCode(patched);
|
||||
if (hc == 0)
|
||||
hc = -1;
|
||||
hash = hc;
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
private int hash;
|
||||
|
||||
/**
|
||||
* Tests this module reference for equality with the given object.
|
||||
*
|
||||
* <p> If the given object is not a {@code ModuleReference} then this
|
||||
* method returns {@code false}. Two module references are equal if their
|
||||
* module descriptors are equal, their locations are equal or both unknown,
|
||||
* and were created with equal supplier objects to access the module
|
||||
* content. </p>
|
||||
*
|
||||
* <p> This method satisfies the general contract of the {@link
|
||||
* java.lang.Object#equals(Object) Object.equals} method. </p>
|
||||
*
|
||||
* @param ob
|
||||
* the object to which this object is to be compared
|
||||
*
|
||||
* @return {@code true} if, and only if, the given object is a module
|
||||
* reference that is equal to this module reference
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object ob) {
|
||||
if (!(ob instanceof ModuleReference))
|
||||
return false;
|
||||
ModuleReference that = (ModuleReference)ob;
|
||||
|
||||
return Objects.equals(this.descriptor, that.descriptor)
|
||||
&& Objects.equals(this.location, that.location)
|
||||
&& Objects.equals(this.readerSupplier, that.readerSupplier)
|
||||
&& Objects.equals(this.hasher, that.hasher)
|
||||
&& this.patched == that.patched;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string describing this module reference.
|
||||
*
|
||||
* @return A string describing this module reference
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return ("[module " + descriptor().name()
|
||||
+ ", location=" + location + "]");
|
||||
}
|
||||
|
||||
public abstract ModuleReader open() throws IOException;
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ import java.util.StringJoiner;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jdk.internal.module.ModuleHashes;
|
||||
import jdk.internal.module.ModuleReferenceImpl;
|
||||
|
||||
/**
|
||||
* The resolver used by {@link Configuration#resolveRequires} and
|
||||
@ -438,24 +439,32 @@ final class Resolver {
|
||||
*/
|
||||
private void checkHashes() {
|
||||
for (ModuleReference mref : nameToReference.values()) {
|
||||
ModuleDescriptor descriptor = mref.descriptor();
|
||||
|
||||
// get map of module hashes
|
||||
Optional<ModuleHashes> ohashes = descriptor.hashes();
|
||||
if (!ohashes.isPresent())
|
||||
// get the recorded hashes, if any
|
||||
if (!(mref instanceof ModuleReferenceImpl))
|
||||
continue;
|
||||
ModuleHashes hashes = ((ModuleReferenceImpl)mref).recordedHashes();
|
||||
if (hashes == null)
|
||||
continue;
|
||||
ModuleHashes hashes = ohashes.get();
|
||||
|
||||
ModuleDescriptor descriptor = mref.descriptor();
|
||||
String algorithm = hashes.algorithm();
|
||||
for (String dn : hashes.names()) {
|
||||
ModuleReference other = nameToReference.get(dn);
|
||||
if (other == null) {
|
||||
ModuleReference mref2 = nameToReference.get(dn);
|
||||
if (mref2 == null) {
|
||||
ResolvedModule resolvedModule = findInParent(dn);
|
||||
if (resolvedModule != null)
|
||||
other = resolvedModule.reference();
|
||||
mref2 = resolvedModule.reference();
|
||||
}
|
||||
if (mref2 == null)
|
||||
continue;
|
||||
|
||||
if (!(mref2 instanceof ModuleReferenceImpl)) {
|
||||
fail("Unable to compute the hash of module %s", dn);
|
||||
}
|
||||
|
||||
// skip checking the hash if the module has been patched
|
||||
ModuleReferenceImpl other = (ModuleReferenceImpl)mref2;
|
||||
if (other != null && !other.isPatched()) {
|
||||
byte[] recordedHash = hashes.hashFor(dn);
|
||||
byte[] actualHash = other.computeHash(algorithm);
|
||||
|
@ -28,9 +28,11 @@ package java.lang.reflect;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.security.AccessController;
|
||||
|
||||
import jdk.internal.misc.VM;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
import jdk.internal.reflect.ReflectionFactory;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* The AccessibleObject class is the base class for Field, Method and
|
||||
@ -172,8 +174,10 @@ public class AccessibleObject implements AnnotatedElement {
|
||||
|
||||
// package is open to caller
|
||||
String pn = packageName(declaringClass);
|
||||
if (declaringModule.isOpen(pn, callerModule))
|
||||
if (declaringModule.isOpen(pn, callerModule)) {
|
||||
printStackTraceIfOpenedReflectively(declaringModule, pn, callerModule);
|
||||
return;
|
||||
}
|
||||
|
||||
// package is exported to caller and class/member is public
|
||||
boolean isExported = declaringModule.isExported(pn, callerModule);
|
||||
@ -185,8 +189,10 @@ public class AccessibleObject implements AnnotatedElement {
|
||||
modifiers = ((Field) this).getModifiers();
|
||||
}
|
||||
boolean isMemberPublic = Modifier.isPublic(modifiers);
|
||||
if (isExported && isClassPublic && isMemberPublic)
|
||||
if (isExported && isClassPublic && isMemberPublic) {
|
||||
printStackTraceIfExportedReflectively(declaringModule, pn, callerModule);
|
||||
return;
|
||||
}
|
||||
|
||||
// not accessible
|
||||
String msg = "Unable to make ";
|
||||
@ -198,7 +204,44 @@ public class AccessibleObject implements AnnotatedElement {
|
||||
else
|
||||
msg += "opens";
|
||||
msg += " " + pn + "\" to " + callerModule;
|
||||
Reflection.throwInaccessibleObjectException(msg);
|
||||
InaccessibleObjectException e = new InaccessibleObjectException(msg);
|
||||
if (Reflection.printStackTraceWhenAccessFails()) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
private void printStackTraceIfOpenedReflectively(Module module,
|
||||
String pn,
|
||||
Module other) {
|
||||
printStackTraceIfExposedReflectively(module, pn, other, true);
|
||||
}
|
||||
|
||||
private void printStackTraceIfExportedReflectively(Module module,
|
||||
String pn,
|
||||
Module other) {
|
||||
printStackTraceIfExposedReflectively(module, pn, other, false);
|
||||
}
|
||||
|
||||
private void printStackTraceIfExposedReflectively(Module module,
|
||||
String pn,
|
||||
Module other,
|
||||
boolean open)
|
||||
{
|
||||
if (Reflection.printStackTraceWhenAccessSucceeds()
|
||||
&& !module.isStaticallyExportedOrOpen(pn, other, open))
|
||||
{
|
||||
String msg = other + " allowed to invoke setAccessible on ";
|
||||
if (this instanceof Field)
|
||||
msg += "field ";
|
||||
msg += this;
|
||||
new Exception(msg) {
|
||||
private static final long serialVersionUID = 42L;
|
||||
public String toString() {
|
||||
return "WARNING: " + getMessage();
|
||||
}
|
||||
}.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -245,7 +245,6 @@ public final class Layer {
|
||||
* @see Module#addOpens
|
||||
*/
|
||||
public Controller addOpens(Module source, String pn, Module target) {
|
||||
Objects.requireNonNull(source);
|
||||
Objects.requireNonNull(source);
|
||||
Objects.requireNonNull(target);
|
||||
ensureInLayer(source);
|
||||
@ -541,7 +540,7 @@ public final class Layer {
|
||||
* {@link ClassLoader#registerAsParallelCapable parallel-capable} so as to
|
||||
* avoid deadlocks during class loading. In addition, the entity creating
|
||||
* a new layer with this method should arrange that the class loaders are
|
||||
* ready to load from these module before there are any attempts to load
|
||||
* ready to load from these modules before there are any attempts to load
|
||||
* classes or resources.
|
||||
*
|
||||
* <p> Creating a {@code Layer} can fail for the following reasons: </p>
|
||||
|
@ -559,7 +559,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.
|
||||
*/
|
||||
private boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) {
|
||||
boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) {
|
||||
// package is open to everyone or <other>
|
||||
Map<String, Set<Module>> openPackages = this.openPackages;
|
||||
if (openPackages != null) {
|
||||
@ -643,6 +643,12 @@ public final class Module implements AnnotatedElement {
|
||||
* <em>open</em>) to the given module. It also has no effect if
|
||||
* invoked on an {@link ModuleDescriptor#isOpen open} module. </p>
|
||||
*
|
||||
* @apiNote As specified in section 5.4.3 of the <cite>The Java™
|
||||
* Virtual Machine Specification </cite>, if an attempt to resolve a
|
||||
* symbolic reference fails because of a linkage error, then subsequent
|
||||
* attempts to resolve the reference always fail with the same error that
|
||||
* was thrown as a result of the initial resolution attempt.
|
||||
*
|
||||
* @param pn
|
||||
* The package name
|
||||
* @param other
|
||||
@ -656,6 +662,7 @@ public final class Module implements AnnotatedElement {
|
||||
* @throws IllegalStateException
|
||||
* If this is a named module and the caller is not this module
|
||||
*
|
||||
* @jvms 5.4.3 Resolution
|
||||
* @see #isExported(String,Module)
|
||||
*/
|
||||
@CallerSensitive
|
||||
@ -676,8 +683,8 @@ public final class Module implements AnnotatedElement {
|
||||
}
|
||||
|
||||
/**
|
||||
* If the caller's module is this module then update this module to
|
||||
* <em>open</em> the given package to the given module.
|
||||
* If this module has <em>opened</em> a package to at least the caller
|
||||
* module then update this module to open the package to the given module.
|
||||
* Opening a package with this method allows all types in the package,
|
||||
* and all their members, not just public types and their public members,
|
||||
* to be reflected on by the given module when using APIs that support
|
||||
@ -699,7 +706,8 @@ public final class Module implements AnnotatedElement {
|
||||
* If {@code pn} is {@code null}, or this is a named module and the
|
||||
* package {@code pn} is not a package in this module
|
||||
* @throws IllegalStateException
|
||||
* If this is a named module and the caller is not this module
|
||||
* If this is a named module and this module has not opened the
|
||||
* package to at least the caller
|
||||
*
|
||||
* @see #isOpen(String,Module)
|
||||
* @see AccessibleObject#setAccessible(boolean)
|
||||
@ -713,9 +721,8 @@ public final class Module implements AnnotatedElement {
|
||||
|
||||
if (isNamed() && !descriptor.isOpen()) {
|
||||
Module caller = Reflection.getCallerClass().getModule();
|
||||
if (caller != this) {
|
||||
throw new IllegalStateException(caller + " != " + this);
|
||||
}
|
||||
if (caller != this && !isOpen(pn, caller))
|
||||
throw new IllegalStateException(pn + " is not open to " + caller);
|
||||
implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true);
|
||||
}
|
||||
|
||||
@ -1568,6 +1575,10 @@ public final class Module implements AnnotatedElement {
|
||||
public Stream<Layer> layers(ClassLoader loader) {
|
||||
return Layer.layers(loader);
|
||||
}
|
||||
@Override
|
||||
public boolean isStaticallyExported(Module module, String pn, Module other) {
|
||||
return module.isStaticallyExportedOrOpen(pn, other, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -64,8 +64,10 @@ public class StringSharingDecompressor implements ResourceDecompressor {
|
||||
private static final int CONSTANT_MethodHandle = 15;
|
||||
private static final int CONSTANT_MethodType = 16;
|
||||
private static final int CONSTANT_InvokeDynamic = 18;
|
||||
private static final int CONSTANT_Module = 19;
|
||||
private static final int CONSTANT_Package = 20;
|
||||
|
||||
private static final int[] SIZES = new int[20];
|
||||
private static final int[] SIZES = new int[21];
|
||||
|
||||
static {
|
||||
|
||||
@ -83,6 +85,8 @@ public class StringSharingDecompressor implements ResourceDecompressor {
|
||||
SIZES[CONSTANT_MethodHandle] = 3;
|
||||
SIZES[CONSTANT_MethodType] = 2;
|
||||
SIZES[CONSTANT_InvokeDynamic] = 4;
|
||||
SIZES[CONSTANT_Module] = 2;
|
||||
SIZES[CONSTANT_Package] = 2;
|
||||
}
|
||||
|
||||
public static int[] getSizes() {
|
||||
|
@ -38,10 +38,8 @@ import java.lang.module.ModuleReader;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@ -59,21 +57,28 @@ public interface JavaLangModuleAccess {
|
||||
* @param strict
|
||||
* Indicates whether module names are checked or not
|
||||
*/
|
||||
ModuleDescriptor.Builder newModuleBuilder(String mn, boolean strict);
|
||||
ModuleDescriptor.Builder newModuleBuilder(String mn,
|
||||
boolean strict,
|
||||
boolean open,
|
||||
boolean synthetic);
|
||||
|
||||
/**
|
||||
* Creates a builder for building an open module with the given module name.
|
||||
*
|
||||
* @param strict
|
||||
* Indicates whether module names are checked or not
|
||||
* Returns the set of packages that are exported (unconditionally or
|
||||
* unconditionally).
|
||||
*/
|
||||
ModuleDescriptor.Builder newOpenModuleBuilder(String mn, boolean strict);
|
||||
Set<String> exportedPackages(ModuleDescriptor.Builder builder);
|
||||
|
||||
/**
|
||||
* Returns the set of packages that are opened (unconditionally or
|
||||
* unconditionally).
|
||||
*/
|
||||
Set<String> openPackages(ModuleDescriptor.Builder builder);
|
||||
|
||||
/**
|
||||
* Returns a {@code ModuleDescriptor.Requires} of the given modifiers
|
||||
* and module name.
|
||||
*/
|
||||
Requires newRequires(Set<Requires.Modifier> ms, String mn);
|
||||
Requires newRequires(Set<Requires.Modifier> ms, String mn, Version v);
|
||||
|
||||
/**
|
||||
* Returns an unqualified {@code ModuleDescriptor.Exports}
|
||||
@ -122,6 +127,7 @@ public interface JavaLangModuleAccess {
|
||||
* Returns a new {@code ModuleDescriptor} instance.
|
||||
*/
|
||||
ModuleDescriptor newModuleDescriptor(String name,
|
||||
Version version,
|
||||
boolean open,
|
||||
boolean automatic,
|
||||
boolean synthetic,
|
||||
@ -130,20 +136,13 @@ public interface JavaLangModuleAccess {
|
||||
Set<Opens> opens,
|
||||
Set<String> uses,
|
||||
Set<Provides> provides,
|
||||
Version version,
|
||||
Set<String> packages,
|
||||
String mainClass,
|
||||
String osName,
|
||||
String osArch,
|
||||
String osVersion,
|
||||
Set<String> packages,
|
||||
ModuleHashes hashes,
|
||||
int hashCode);
|
||||
|
||||
/**
|
||||
* Returns the object with the hashes of other modules
|
||||
*/
|
||||
Optional<ModuleHashes> hashes(ModuleDescriptor descriptor);
|
||||
|
||||
/**
|
||||
* Resolves a collection of root modules, with service binding
|
||||
* and the empty configuration as the parent. The post resolution
|
||||
@ -154,18 +153,4 @@ public interface JavaLangModuleAccess {
|
||||
boolean check,
|
||||
PrintStream traceOutput);
|
||||
|
||||
/**
|
||||
* Creates a ModuleReference to a "patched" module.
|
||||
*/
|
||||
ModuleReference newPatchedModule(ModuleDescriptor descriptor,
|
||||
URI location,
|
||||
Supplier<ModuleReader> readerSupplier);
|
||||
|
||||
/**
|
||||
* Creates a ModuleFinder for a module path.
|
||||
*/
|
||||
ModuleFinder newModulePath(Runtime.Version version,
|
||||
boolean isLinkPhase,
|
||||
Path... entries);
|
||||
|
||||
}
|
||||
|
@ -123,4 +123,12 @@ public interface JavaLangReflectModuleAccess {
|
||||
* given class loader.
|
||||
*/
|
||||
Stream<Layer> 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);
|
||||
}
|
@ -30,11 +30,8 @@ import java.lang.module.ModuleDescriptor.Opens;
|
||||
import java.lang.module.ModuleDescriptor.Provides;
|
||||
import java.lang.module.ModuleDescriptor.Requires;
|
||||
import java.lang.module.ModuleDescriptor.Version;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.misc.JavaLangModuleAccess;
|
||||
@ -52,7 +49,7 @@ import jdk.internal.misc.SharedSecrets;
|
||||
* SystemModules should contain modules for the boot layer.
|
||||
*/
|
||||
final class Builder {
|
||||
private static final JavaLangModuleAccess jlma =
|
||||
private static final JavaLangModuleAccess JLMA =
|
||||
SharedSecrets.getJavaLangModuleAccess();
|
||||
|
||||
// Static cache of the most recently seen Version to cheaply deduplicate
|
||||
@ -60,13 +57,36 @@ final class Builder {
|
||||
static Version cachedVersion;
|
||||
|
||||
/**
|
||||
* Returns a {@link Requires} for a dependence on a module
|
||||
* with the given (and possibly empty) set of modifiers.
|
||||
* Returns a {@link Requires} for a dependence on a module with the given
|
||||
* (and possibly empty) set of modifiers, and optionally the version
|
||||
* recorded at compile time.
|
||||
*/
|
||||
public static Requires newRequires(Set<Requires.Modifier> mods,
|
||||
String mn,
|
||||
String compiledVersion)
|
||||
{
|
||||
Version version = null;
|
||||
if (compiledVersion != null) {
|
||||
// use the cached version if the same version string
|
||||
Version ver = cachedVersion;
|
||||
if (ver != null && compiledVersion.equals(ver.toString())) {
|
||||
version = ver;
|
||||
} else {
|
||||
version = Version.parse(compiledVersion);
|
||||
}
|
||||
}
|
||||
return JLMA.newRequires(mods, mn, version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Requires} for a dependence on a module with the given
|
||||
* (and possibly empty) set of modifiers, and optionally the version
|
||||
* recorded at compile time.
|
||||
*/
|
||||
public static Requires newRequires(Set<Requires.Modifier> mods,
|
||||
String mn)
|
||||
{
|
||||
return jlma.newRequires(mods, mn);
|
||||
return newRequires(mods, mn, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,7 +97,7 @@ final class Builder {
|
||||
public static Exports newExports(Set<Exports.Modifier> ms,
|
||||
String pn,
|
||||
Set<String> targets) {
|
||||
return jlma.newExports(ms, pn, targets);
|
||||
return JLMA.newExports(ms, pn, targets);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,7 +105,7 @@ final class Builder {
|
||||
* modifiers.
|
||||
*/
|
||||
public static Opens newOpens(Set<Opens.Modifier> ms, String pn) {
|
||||
return jlma.newOpens(ms, pn);
|
||||
return JLMA.newOpens(ms, pn);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,7 +116,7 @@ final class Builder {
|
||||
public static Opens newOpens(Set<Opens.Modifier> ms,
|
||||
String pn,
|
||||
Set<String> targets) {
|
||||
return jlma.newOpens(ms, pn, targets);
|
||||
return JLMA.newOpens(ms, pn, targets);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,7 +124,7 @@ final class Builder {
|
||||
* of modifiers.
|
||||
*/
|
||||
public static Exports newExports(Set<Exports.Modifier> ms, String pn) {
|
||||
return jlma.newExports(ms, pn);
|
||||
return JLMA.newExports(ms, pn);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -112,7 +132,7 @@ final class Builder {
|
||||
* implementation classes.
|
||||
*/
|
||||
public static Provides newProvides(String st, List<String> pcs) {
|
||||
return jlma.newProvides(st, pcs);
|
||||
return JLMA.newProvides(st, pcs);
|
||||
}
|
||||
|
||||
final String name;
|
||||
@ -130,8 +150,6 @@ final class Builder {
|
||||
String osName;
|
||||
String osArch;
|
||||
String osVersion;
|
||||
String algorithm;
|
||||
Map<String, byte[]> hashes;
|
||||
|
||||
Builder(String name) {
|
||||
this.name = name;
|
||||
@ -274,35 +292,14 @@ final class Builder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the algorithm of the module hashes
|
||||
*/
|
||||
public Builder algorithm(String algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the module hash for the given module name
|
||||
*/
|
||||
public Builder moduleHash(String mn, byte[] hash) {
|
||||
if (hashes == null)
|
||||
hashes = new HashMap<>();
|
||||
|
||||
hashes.put(mn, hash);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@code ModuleDescriptor} from the components.
|
||||
*/
|
||||
public ModuleDescriptor build(int hashCode) {
|
||||
assert name != null;
|
||||
|
||||
ModuleHashes moduleHashes =
|
||||
hashes != null ? new ModuleHashes(algorithm, hashes) : null;
|
||||
|
||||
return jlma.newModuleDescriptor(name,
|
||||
return JLMA.newModuleDescriptor(name,
|
||||
version,
|
||||
open,
|
||||
automatic,
|
||||
synthetic,
|
||||
@ -311,13 +308,11 @@ final class Builder {
|
||||
opens,
|
||||
uses,
|
||||
provides,
|
||||
version,
|
||||
packages,
|
||||
mainClass,
|
||||
osName,
|
||||
osArch,
|
||||
osVersion,
|
||||
packages,
|
||||
moduleHashes,
|
||||
hashCode);
|
||||
}
|
||||
}
|
||||
|
@ -25,79 +25,200 @@
|
||||
|
||||
package jdk.internal.module;
|
||||
|
||||
/**
|
||||
* Utility class for checking module name and binary names.
|
||||
*/
|
||||
|
||||
public final class Checks {
|
||||
|
||||
private Checks() { }
|
||||
|
||||
private static void fail(String what, String id, int i) {
|
||||
throw new IllegalArgumentException(id
|
||||
+ ": Invalid " + what + ": "
|
||||
+ " Illegal character"
|
||||
+ " at index " + i);
|
||||
/**
|
||||
* Checks a name to ensure that it's a legal module name.
|
||||
*
|
||||
* @throws IllegalArgumentException if name is null or not a legal
|
||||
* module name
|
||||
*/
|
||||
public static String requireModuleName(String name) {
|
||||
if (name == null)
|
||||
throw new IllegalArgumentException("Null module name");
|
||||
int next;
|
||||
int off = 0;
|
||||
while ((next = name.indexOf('.', off)) != -1) {
|
||||
if (isJavaIdentifier(name, off, (next - off)) == -1) {
|
||||
String id = name.substring(off, next);
|
||||
throw new IllegalArgumentException(name + ": Invalid module name"
|
||||
+ ": '" + id + "' is not a Java identifier");
|
||||
}
|
||||
off = next+1;
|
||||
}
|
||||
int last = isJavaIdentifier(name, off, name.length() - off);
|
||||
if (last == -1) {
|
||||
String id = name.substring(off);
|
||||
throw new IllegalArgumentException(name + ": Invalid module name"
|
||||
+ ": '" + id + "' is not a Java identifier");
|
||||
}
|
||||
//if (!Character.isJavaIdentifierStart(last))
|
||||
// throw new IllegalArgumentException(name + ": Module name ends in digit");
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given identifier is a legal Java identifier.
|
||||
* Returns {@code true} if the given name is a legal module name.
|
||||
*/
|
||||
public static boolean isJavaIdentifier(String id) {
|
||||
int n = id.length();
|
||||
if (n == 0)
|
||||
return false;
|
||||
if (!Character.isJavaIdentifierStart(id.codePointAt(0)))
|
||||
return false;
|
||||
int cp = id.codePointAt(0);
|
||||
int i = Character.charCount(cp);
|
||||
for (; i < n; i += Character.charCount(cp)) {
|
||||
cp = id.codePointAt(i);
|
||||
if (!Character.isJavaIdentifierPart(cp) && id.charAt(i) != '.')
|
||||
public static boolean isModuleName(String name) {
|
||||
int next;
|
||||
int off = 0;
|
||||
while ((next = name.indexOf('.', off)) != -1) {
|
||||
if (isJavaIdentifier(name, off, (next - off)) == -1)
|
||||
return false;
|
||||
off = next+1;
|
||||
}
|
||||
if (cp == '.')
|
||||
int last = isJavaIdentifier(name, off, name.length() - off);
|
||||
if (last == -1)
|
||||
return false;
|
||||
|
||||
//if (!Character.isJavaIdentifierStart(last))
|
||||
// return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given identifier is a legal Java identifier.
|
||||
* Checks a name to ensure that it's a legal package name.
|
||||
*
|
||||
* @throws IllegalArgumentException if name is null or not a legal
|
||||
* package name
|
||||
*/
|
||||
public static String requireJavaIdentifier(String what, String id) {
|
||||
if (id == null)
|
||||
throw new IllegalArgumentException("Null " + what);
|
||||
int n = id.length();
|
||||
if (n == 0)
|
||||
throw new IllegalArgumentException("Empty " + what);
|
||||
if (!Character.isJavaIdentifierStart(id.codePointAt(0)))
|
||||
fail(what, id, 0);
|
||||
int cp = id.codePointAt(0);
|
||||
int i = Character.charCount(cp);
|
||||
int last = 0;
|
||||
for (; i < n; i += Character.charCount(cp)) {
|
||||
cp = id.codePointAt(i);
|
||||
if (!Character.isJavaIdentifierPart(cp) && id.charAt(i) != '.')
|
||||
fail(what, id, i);
|
||||
last = i;
|
||||
public static String requirePackageName(String name) {
|
||||
return requireBinaryName("package name", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a name to ensure that it's a legal type name.
|
||||
*
|
||||
* @throws IllegalArgumentException if name is null or not a legal
|
||||
* type name
|
||||
*/
|
||||
public static String requireServiceTypeName(String name) {
|
||||
return requireBinaryName("service type name", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a name to ensure that it's a legal type name.
|
||||
*
|
||||
* @throws IllegalArgumentException if name is null or not a legal
|
||||
* type name
|
||||
*/
|
||||
public static String requireServiceProviderName(String name) {
|
||||
return requireBinaryName("service provider name", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given name is a legal binary name.
|
||||
*/
|
||||
public static boolean isJavaIdentifier(String name) {
|
||||
return isBinaryName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given name is a legal binary name.
|
||||
*/
|
||||
public static boolean isBinaryName(String name) {
|
||||
int next;
|
||||
int off = 0;
|
||||
while ((next = name.indexOf('.', off)) != -1) {
|
||||
if (isJavaIdentifier(name, off, (next - off)) == -1)
|
||||
return false;
|
||||
off = next+1;
|
||||
}
|
||||
if (cp == '.')
|
||||
fail(what, id, last);
|
||||
|
||||
return id;
|
||||
int count = name.length() - off;
|
||||
return (isJavaIdentifier(name, off, count) != -1);
|
||||
}
|
||||
|
||||
public static String requireModuleName(String id) {
|
||||
return requireJavaIdentifier("module name", id);
|
||||
/**
|
||||
* Checks if the given name is a legal binary name.
|
||||
*
|
||||
* @throws IllegalArgumentException if name is null or not a legal
|
||||
* binary name
|
||||
*/
|
||||
public static String requireBinaryName(String what, String name) {
|
||||
if (name == null)
|
||||
throw new IllegalArgumentException("Null " + what);
|
||||
int next;
|
||||
int off = 0;
|
||||
while ((next = name.indexOf('.', off)) != -1) {
|
||||
if (isJavaIdentifier(name, off, (next - off)) == -1) {
|
||||
String id = name.substring(off, next);
|
||||
throw new IllegalArgumentException(name + ": Invalid " + what
|
||||
+ ": '" + id + "' is not a Java identifier");
|
||||
}
|
||||
off = next + 1;
|
||||
}
|
||||
if (isJavaIdentifier(name, off, name.length() - off) == -1) {
|
||||
String id = name.substring(off, name.length());
|
||||
throw new IllegalArgumentException(name + ": Invalid " + what
|
||||
+ ": '" + id + "' is not a Java identifier");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public static String requirePackageName(String id) {
|
||||
return requireJavaIdentifier("package name", id);
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public static String requireServiceTypeName(String id) {
|
||||
return requireJavaIdentifier("service type name", id);
|
||||
/**
|
||||
* Returns true if the given string only contains ASCII characters.
|
||||
*/
|
||||
private static boolean isASCIIString(String s) {
|
||||
int i = 0;
|
||||
while (i < s.length()) {
|
||||
int c = s.charAt(i);
|
||||
if (c > 0x7F)
|
||||
return false;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String requireServiceProviderName(String id) {
|
||||
return requireJavaIdentifier("service provider name", id);
|
||||
}
|
||||
/**
|
||||
* Checks if a char sequence is a legal Java identifier, returning the code
|
||||
* point of the last character if legal or {@code -1} if not legal.
|
||||
*/
|
||||
private static int isJavaIdentifier(CharSequence cs, int offset, int count) {
|
||||
if (count == 0)
|
||||
return -1;
|
||||
int first = Character.codePointAt(cs, offset);
|
||||
if (!Character.isJavaIdentifierStart(first))
|
||||
return -1;
|
||||
|
||||
int cp = first;
|
||||
int i = Character.charCount(first);
|
||||
while (i < count) {
|
||||
cp = Character.codePointAt(cs, offset+i);
|
||||
if (!Character.isJavaIdentifierPart(cp))
|
||||
return -1;
|
||||
i += Character.charCount(cp);
|
||||
}
|
||||
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
|
@ -68,12 +68,18 @@ public final class ClassFileAttributes {
|
||||
= SharedSecrets.getJavaLangModuleAccess();
|
||||
|
||||
private ModuleDescriptor descriptor;
|
||||
private Version replacementVersion;
|
||||
|
||||
public ModuleAttribute(ModuleDescriptor descriptor) {
|
||||
super(MODULE);
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
public ModuleAttribute(Version v) {
|
||||
super(MODULE);
|
||||
this.replacementVersion = v;
|
||||
}
|
||||
|
||||
public ModuleAttribute() {
|
||||
super(MODULE);
|
||||
}
|
||||
@ -86,46 +92,70 @@ public final class ClassFileAttributes {
|
||||
int codeOff,
|
||||
Label[] labels)
|
||||
{
|
||||
ModuleAttribute attr = new ModuleAttribute();
|
||||
|
||||
// module_name
|
||||
String mn = cr.readUTF8(off, buf).replace('/', '.');
|
||||
// module_name (CONSTANT_Module_info)
|
||||
String mn = cr.readModule(off, buf);
|
||||
off += 2;
|
||||
|
||||
// module_flags
|
||||
int module_flags = cr.readUnsignedShort(off);
|
||||
boolean open = ((module_flags & ACC_OPEN) != 0);
|
||||
boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
|
||||
off += 2;
|
||||
|
||||
ModuleDescriptor.Builder builder;
|
||||
if (open) {
|
||||
builder = JLMA.newOpenModuleBuilder(mn, false);
|
||||
} else {
|
||||
builder = JLMA.newModuleBuilder(mn, false);
|
||||
ModuleDescriptor.Builder builder = JLMA.newModuleBuilder(mn,
|
||||
false,
|
||||
open,
|
||||
synthetic);
|
||||
|
||||
// module_version
|
||||
String module_version = cr.readUTF8(off, buf);
|
||||
off += 2;
|
||||
if (replacementVersion != null) {
|
||||
builder.version(replacementVersion);
|
||||
} else if (module_version != null) {
|
||||
builder.version(module_version);
|
||||
}
|
||||
|
||||
// requires_count and requires[requires_count]
|
||||
int requires_count = cr.readUnsignedShort(off);
|
||||
off += 2;
|
||||
for (int i=0; i<requires_count; i++) {
|
||||
String dn = cr.readUTF8(off, buf).replace('/', '.');
|
||||
int flags = cr.readUnsignedShort(off + 2);
|
||||
// CONSTANT_Module_info
|
||||
String dn = cr.readModule(off, buf);
|
||||
off += 2;
|
||||
|
||||
// requires_flags
|
||||
int requires_flags = cr.readUnsignedShort(off);
|
||||
off += 2;
|
||||
Set<Requires.Modifier> mods;
|
||||
if (flags == 0) {
|
||||
if (requires_flags == 0) {
|
||||
mods = Collections.emptySet();
|
||||
} else {
|
||||
mods = new HashSet<>();
|
||||
if ((flags & ACC_TRANSITIVE) != 0)
|
||||
if ((requires_flags & ACC_TRANSITIVE) != 0)
|
||||
mods.add(Requires.Modifier.TRANSITIVE);
|
||||
if ((flags & ACC_STATIC_PHASE) != 0)
|
||||
if ((requires_flags & ACC_STATIC_PHASE) != 0)
|
||||
mods.add(Requires.Modifier.STATIC);
|
||||
if ((flags & ACC_SYNTHETIC) != 0)
|
||||
if ((requires_flags & ACC_SYNTHETIC) != 0)
|
||||
mods.add(Requires.Modifier.SYNTHETIC);
|
||||
if ((flags & ACC_MANDATED) != 0)
|
||||
if ((requires_flags & ACC_MANDATED) != 0)
|
||||
mods.add(Requires.Modifier.MANDATED);
|
||||
}
|
||||
builder.requires(mods, dn);
|
||||
off += 4;
|
||||
|
||||
|
||||
// requires_version
|
||||
Version compiledVersion = null;
|
||||
String requires_version = cr.readUTF8(off, buf);
|
||||
off += 2;
|
||||
if (requires_version != null) {
|
||||
compiledVersion = Version.parse(requires_version);
|
||||
}
|
||||
|
||||
if (compiledVersion == null) {
|
||||
builder.requires(mods, dn);
|
||||
} else {
|
||||
builder.requires(mods, dn, compiledVersion);
|
||||
}
|
||||
}
|
||||
|
||||
// exports_count and exports[exports_count]
|
||||
@ -133,19 +163,20 @@ public final class ClassFileAttributes {
|
||||
off += 2;
|
||||
if (exports_count > 0) {
|
||||
for (int i=0; i<exports_count; i++) {
|
||||
String pkg = cr.readUTF8(off, buf).replace('/', '.');
|
||||
// CONSTANT_Package_info
|
||||
String pkg = cr.readPackage(off, buf).replace('/', '.');
|
||||
off += 2;
|
||||
|
||||
int flags = cr.readUnsignedShort(off);
|
||||
int exports_flags = cr.readUnsignedShort(off);
|
||||
off += 2;
|
||||
Set<Exports.Modifier> mods;
|
||||
if (flags == 0) {
|
||||
if (exports_flags == 0) {
|
||||
mods = Collections.emptySet();
|
||||
} else {
|
||||
mods = new HashSet<>();
|
||||
if ((flags & ACC_SYNTHETIC) != 0)
|
||||
if ((exports_flags & ACC_SYNTHETIC) != 0)
|
||||
mods.add(Exports.Modifier.SYNTHETIC);
|
||||
if ((flags & ACC_MANDATED) != 0)
|
||||
if ((exports_flags & ACC_MANDATED) != 0)
|
||||
mods.add(Exports.Modifier.MANDATED);
|
||||
}
|
||||
|
||||
@ -154,7 +185,7 @@ public final class ClassFileAttributes {
|
||||
if (exports_to_count > 0) {
|
||||
Set<String> targets = new HashSet<>();
|
||||
for (int j=0; j<exports_to_count; j++) {
|
||||
String t = cr.readUTF8(off, buf).replace('/', '.');
|
||||
String t = cr.readModule(off, buf);
|
||||
off += 2;
|
||||
targets.add(t);
|
||||
}
|
||||
@ -170,19 +201,20 @@ public final class ClassFileAttributes {
|
||||
off += 2;
|
||||
if (open_count > 0) {
|
||||
for (int i=0; i<open_count; i++) {
|
||||
String pkg = cr.readUTF8(off, buf).replace('/', '.');
|
||||
// CONSTANT_Package_info
|
||||
String pkg = cr.readPackage(off, buf).replace('/', '.');
|
||||
off += 2;
|
||||
|
||||
int flags = cr.readUnsignedShort(off);
|
||||
int opens_flags = cr.readUnsignedShort(off);
|
||||
off += 2;
|
||||
Set<Opens.Modifier> mods;
|
||||
if (flags == 0) {
|
||||
if (opens_flags == 0) {
|
||||
mods = Collections.emptySet();
|
||||
} else {
|
||||
mods = new HashSet<>();
|
||||
if ((flags & ACC_SYNTHETIC) != 0)
|
||||
if ((opens_flags & ACC_SYNTHETIC) != 0)
|
||||
mods.add(Opens.Modifier.SYNTHETIC);
|
||||
if ((flags & ACC_MANDATED) != 0)
|
||||
if ((opens_flags & ACC_MANDATED) != 0)
|
||||
mods.add(Opens.Modifier.MANDATED);
|
||||
}
|
||||
|
||||
@ -191,7 +223,7 @@ public final class ClassFileAttributes {
|
||||
if (opens_to_count > 0) {
|
||||
Set<String> targets = new HashSet<>();
|
||||
for (int j=0; j<opens_to_count; j++) {
|
||||
String t = cr.readUTF8(off, buf).replace('/', '.');
|
||||
String t = cr.readModule(off, buf);
|
||||
off += 2;
|
||||
targets.add(t);
|
||||
}
|
||||
@ -232,8 +264,7 @@ public final class ClassFileAttributes {
|
||||
}
|
||||
}
|
||||
|
||||
attr.descriptor = builder.build();
|
||||
return attr;
|
||||
return new ModuleAttribute(builder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -248,7 +279,7 @@ public final class ClassFileAttributes {
|
||||
|
||||
// module_name
|
||||
String mn = descriptor.name();
|
||||
int module_name_index = cw.newUTF8(mn.replace('.', '/'));
|
||||
int module_name_index = cw.newModule(mn);
|
||||
attr.putShort(module_name_index);
|
||||
|
||||
// module_flags
|
||||
@ -259,66 +290,83 @@ public final class ClassFileAttributes {
|
||||
module_flags |= ACC_SYNTHETIC;
|
||||
attr.putShort(module_flags);
|
||||
|
||||
// module_version
|
||||
Version v = descriptor.version().orElse(null);
|
||||
if (v == null) {
|
||||
attr.putShort(0);
|
||||
} else {
|
||||
int module_version_index = cw.newUTF8(v.toString());
|
||||
attr.putShort(module_version_index);
|
||||
}
|
||||
|
||||
// requires_count
|
||||
attr.putShort(descriptor.requires().size());
|
||||
|
||||
// requires[requires_count]
|
||||
for (Requires md : descriptor.requires()) {
|
||||
String dn = md.name();
|
||||
int flags = 0;
|
||||
if (md.modifiers().contains(Requires.Modifier.TRANSITIVE))
|
||||
flags |= ACC_TRANSITIVE;
|
||||
if (md.modifiers().contains(Requires.Modifier.STATIC))
|
||||
flags |= ACC_STATIC_PHASE;
|
||||
if (md.modifiers().contains(Requires.Modifier.SYNTHETIC))
|
||||
flags |= ACC_SYNTHETIC;
|
||||
if (md.modifiers().contains(Requires.Modifier.MANDATED))
|
||||
flags |= ACC_MANDATED;
|
||||
int index = cw.newUTF8(dn.replace('.', '/'));
|
||||
attr.putShort(index);
|
||||
attr.putShort(flags);
|
||||
for (Requires r : descriptor.requires()) {
|
||||
int requires_index = cw.newModule(r.name());
|
||||
attr.putShort(requires_index);
|
||||
|
||||
int requires_flags = 0;
|
||||
if (r.modifiers().contains(Requires.Modifier.TRANSITIVE))
|
||||
requires_flags |= ACC_TRANSITIVE;
|
||||
if (r.modifiers().contains(Requires.Modifier.STATIC))
|
||||
requires_flags |= ACC_STATIC_PHASE;
|
||||
if (r.modifiers().contains(Requires.Modifier.SYNTHETIC))
|
||||
requires_flags |= ACC_SYNTHETIC;
|
||||
if (r.modifiers().contains(Requires.Modifier.MANDATED))
|
||||
requires_flags |= ACC_MANDATED;
|
||||
attr.putShort(requires_flags);
|
||||
|
||||
int requires_version_index;
|
||||
v = r.compiledVersion().orElse(null);
|
||||
if (v == null) {
|
||||
requires_version_index = 0;
|
||||
} else {
|
||||
requires_version_index = cw.newUTF8(v.toString());
|
||||
}
|
||||
attr.putShort(requires_version_index);
|
||||
}
|
||||
|
||||
// exports_count and exports[exports_count];
|
||||
attr.putShort(descriptor.exports().size());
|
||||
for (Exports e : descriptor.exports()) {
|
||||
String pkg = e.source().replace('.', '/');
|
||||
attr.putShort(cw.newUTF8(pkg));
|
||||
attr.putShort(cw.newPackage(pkg));
|
||||
|
||||
int flags = 0;
|
||||
int exports_flags = 0;
|
||||
if (e.modifiers().contains(Exports.Modifier.SYNTHETIC))
|
||||
flags |= ACC_SYNTHETIC;
|
||||
exports_flags |= ACC_SYNTHETIC;
|
||||
if (e.modifiers().contains(Exports.Modifier.MANDATED))
|
||||
flags |= ACC_MANDATED;
|
||||
attr.putShort(flags);
|
||||
exports_flags |= ACC_MANDATED;
|
||||
attr.putShort(exports_flags);
|
||||
|
||||
if (e.isQualified()) {
|
||||
Set<String> ts = e.targets();
|
||||
attr.putShort(ts.size());
|
||||
ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
|
||||
ts.forEach(target -> attr.putShort(cw.newModule(target)));
|
||||
} else {
|
||||
attr.putShort(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// opens_counts and opens[opens_counts]
|
||||
attr.putShort(descriptor.opens().size());
|
||||
for (Opens obj : descriptor.opens()) {
|
||||
String pkg = obj.source().replace('.', '/');
|
||||
attr.putShort(cw.newUTF8(pkg));
|
||||
attr.putShort(cw.newPackage(pkg));
|
||||
|
||||
int flags = 0;
|
||||
int opens_flags = 0;
|
||||
if (obj.modifiers().contains(Opens.Modifier.SYNTHETIC))
|
||||
flags |= ACC_SYNTHETIC;
|
||||
opens_flags |= ACC_SYNTHETIC;
|
||||
if (obj.modifiers().contains(Opens.Modifier.MANDATED))
|
||||
flags |= ACC_MANDATED;
|
||||
attr.putShort(flags);
|
||||
opens_flags |= ACC_MANDATED;
|
||||
attr.putShort(opens_flags);
|
||||
|
||||
if (obj.isQualified()) {
|
||||
Set<String> ts = obj.targets();
|
||||
attr.putShort(ts.size());
|
||||
ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
|
||||
ts.forEach(target -> attr.putShort(cw.newModule(target)));
|
||||
} else {
|
||||
attr.putShort(0);
|
||||
}
|
||||
@ -369,7 +417,7 @@ public final class ClassFileAttributes {
|
||||
*
|
||||
* // the number of entries in the packages table
|
||||
* u2 packages_count;
|
||||
* { // index to CONSTANT_CONSTANT_utf8_info structure with the package name
|
||||
* { // index to CONSTANT_Package_info structure with the package name
|
||||
* u2 package_index
|
||||
* } packages[package_count];
|
||||
*
|
||||
@ -402,7 +450,7 @@ public final class ClassFileAttributes {
|
||||
// packages
|
||||
Set<String> packages = new HashSet<>();
|
||||
for (int i=0; i<package_count; i++) {
|
||||
String pkg = cr.readUTF8(off, buf).replace('/', '.');
|
||||
String pkg = cr.readPackage(off, buf).replace('/', '.');
|
||||
packages.add(pkg);
|
||||
off += 2;
|
||||
}
|
||||
@ -427,68 +475,13 @@ public final class ClassFileAttributes {
|
||||
// packages
|
||||
packages.stream()
|
||||
.map(p -> p.replace('.', '/'))
|
||||
.forEach(p -> attr.putShort(cw.newUTF8(p)));
|
||||
.forEach(p -> attr.putShort(cw.newPackage(p)));
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ModuleVersion attribute.
|
||||
*
|
||||
* <pre> {@code
|
||||
*
|
||||
* ModuleVersion_attribute {
|
||||
* // index to CONSTANT_utf8_info structure in constant pool representing
|
||||
* // the string "ModuleVersion"
|
||||
* u2 attribute_name_index;
|
||||
* u4 attribute_length;
|
||||
*
|
||||
* // index to CONSTANT_CONSTANT_utf8_info structure with the version
|
||||
* u2 version_index;
|
||||
* }
|
||||
*
|
||||
* } </pre>
|
||||
*/
|
||||
public static class ModuleVersionAttribute extends Attribute {
|
||||
private final Version version;
|
||||
|
||||
public ModuleVersionAttribute(Version version) {
|
||||
super(MODULE_VERSION);
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public ModuleVersionAttribute() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Attribute read(ClassReader cr,
|
||||
int off,
|
||||
int len,
|
||||
char[] buf,
|
||||
int codeOff,
|
||||
Label[] labels)
|
||||
{
|
||||
String value = cr.readUTF8(off, buf);
|
||||
return new ModuleVersionAttribute(Version.parse(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteVector write(ClassWriter cw,
|
||||
byte[] code,
|
||||
int len,
|
||||
int maxStack,
|
||||
int maxLocals)
|
||||
{
|
||||
ByteVector attr = new ByteVector();
|
||||
int index = cw.newUTF8(version.toString());
|
||||
attr.putShort(index);
|
||||
return attr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ModuleMainClass attribute.
|
||||
*
|
||||
@ -526,7 +519,7 @@ public final class ClassFileAttributes {
|
||||
int codeOff,
|
||||
Label[] labels)
|
||||
{
|
||||
String value = cr.readClass(off, buf);
|
||||
String value = cr.readClass(off, buf).replace('/', '.');
|
||||
return new ModuleMainClassAttribute(value);
|
||||
}
|
||||
|
||||
@ -538,7 +531,7 @@ public final class ClassFileAttributes {
|
||||
int maxLocals)
|
||||
{
|
||||
ByteVector attr = new ByteVector();
|
||||
int index = cw.newClass(mainClass);
|
||||
int index = cw.newClass(mainClass.replace('.', '/'));
|
||||
attr.putShort(index);
|
||||
return attr;
|
||||
}
|
||||
@ -555,11 +548,11 @@ public final class ClassFileAttributes {
|
||||
* u2 attribute_name_index;
|
||||
* u4 attribute_length;
|
||||
*
|
||||
* // index to CONSTANT_CONSTANT_utf8_info structure with the OS name
|
||||
* // index to CONSTANT_utf8_info structure with the OS name
|
||||
* u2 os_name_index;
|
||||
* // index to CONSTANT_CONSTANT_utf8_info structure with the OS arch
|
||||
* // index to CONSTANT_utf8_info structure with the OS arch
|
||||
* u2 os_arch_index
|
||||
* // index to CONSTANT_CONSTANT_utf8_info structure with the OS version
|
||||
* // index to CONSTANT_utf8_info structure with the OS version
|
||||
* u2 os_version_index;
|
||||
* }
|
||||
*
|
||||
@ -656,7 +649,7 @@ public final class ClassFileAttributes {
|
||||
*
|
||||
* // the number of entries in the hashes table
|
||||
* u2 hashes_count;
|
||||
* { u2 module_name_index
|
||||
* { u2 module_name_index (index to CONSTANT_Module_info structure)
|
||||
* u2 hash_length;
|
||||
* u1 hash[hash_length];
|
||||
* } hashes[hashes_count];
|
||||
@ -691,7 +684,7 @@ public final class ClassFileAttributes {
|
||||
|
||||
Map<String, byte[]> map = new HashMap<>();
|
||||
for (int i=0; i<hashes_count; i++) {
|
||||
String mn = cr.readUTF8(off, buf).replace('/', '.');
|
||||
String mn = cr.readModule(off, buf);
|
||||
off += 2;
|
||||
|
||||
int hash_length = cr.readUnsignedShort(off);
|
||||
@ -728,7 +721,7 @@ public final class ClassFileAttributes {
|
||||
for (String mn : names) {
|
||||
byte[] hash = hashes.hashFor(mn);
|
||||
assert hash != null;
|
||||
attr.putShort(cw.newUTF8(mn.replace('.', '/')));
|
||||
attr.putShort(cw.newModule(mn));
|
||||
|
||||
attr.putShort(hash.length);
|
||||
for (byte b: hash) {
|
||||
@ -740,4 +733,58 @@ public final class ClassFileAttributes {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ModuleResolution_attribute {
|
||||
* u2 attribute_name_index; // "ModuleResolution"
|
||||
* u4 attribute_length; // 2
|
||||
* u2 resolution_flags;
|
||||
*
|
||||
* The value of the resolution_flags item is a mask of flags used to denote
|
||||
* properties of module resolution. The flags are as follows:
|
||||
*
|
||||
* // Optional
|
||||
* 0x0001 (DO_NOT_RESOLVE_BY_DEFAULT)
|
||||
*
|
||||
* // At most one of:
|
||||
* 0x0002 (WARN_DEPRECATED)
|
||||
* 0x0004 (WARN_DEPRECATED_FOR_REMOVAL)
|
||||
* 0x0008 (WARN_INCUBATING)
|
||||
*/
|
||||
static class ModuleResolutionAttribute extends Attribute {
|
||||
private final int value;
|
||||
|
||||
ModuleResolutionAttribute() {
|
||||
super(MODULE_RESOLUTION);
|
||||
value = 0;
|
||||
}
|
||||
|
||||
ModuleResolutionAttribute(int value) {
|
||||
super(MODULE_RESOLUTION);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Attribute read(ClassReader cr,
|
||||
int off,
|
||||
int len,
|
||||
char[] buf,
|
||||
int codeOff,
|
||||
Label[] labels)
|
||||
{
|
||||
int flags = cr.readUnsignedShort(off);
|
||||
return new ModuleResolutionAttribute(flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteVector write(ClassWriter cw,
|
||||
byte[] code,
|
||||
int len,
|
||||
int maxStack,
|
||||
int maxLocals)
|
||||
{
|
||||
ByteVector attr = new ByteVector();
|
||||
attr.putShort(value);
|
||||
return attr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,10 +38,10 @@ public class ClassFileConstants {
|
||||
public static final String SDE = "SourceDebugExtension";
|
||||
|
||||
public static final String MODULE_PACKAGES = "ModulePackages";
|
||||
public static final String MODULE_VERSION = "ModuleVersion";
|
||||
public static final String MODULE_MAIN_CLASS = "ModuleMainClass";
|
||||
public static final String MODULE_TARGET = "ModuleTarget";
|
||||
public static final String MODULE_HASHES = "ModuleHashes";
|
||||
public static final String MODULE_RESOLUTION = "ModuleResolution";
|
||||
|
||||
// access, requires, exports, and opens flags
|
||||
public static final int ACC_MODULE = 0x8000;
|
||||
@ -51,4 +51,10 @@ public class ClassFileConstants {
|
||||
public static final int ACC_SYNTHETIC = 0x1000;
|
||||
public static final int ACC_MANDATED = 0x8000;
|
||||
|
||||
// ModuleResolution_attribute resolution flags
|
||||
public static final int DO_NOT_RESOLVE_BY_DEFAULT = 0x0001;
|
||||
public static final int WARN_DEPRECATED = 0x0002;
|
||||
public static final int WARN_DEPRECATED_FOR_REMOVAL = 0x0004;
|
||||
public static final int WARN_INCUBATING = 0x0008;
|
||||
|
||||
}
|
||||
|
@ -195,7 +195,9 @@ public final class ModuleBootstrap {
|
||||
// module is the unnamed module of the application class loader. This
|
||||
// is implemented by resolving "java.se" and all (non-java.*) modules
|
||||
// that export an API. If "java.se" is not observable then all java.*
|
||||
// modules are resolved.
|
||||
// modules are resolved. Modules that have the DO_NOT_RESOLVE_BY_DEFAULT
|
||||
// bit set in their ModuleResolution attribute flags are excluded from
|
||||
// the default set of roots.
|
||||
if (mainModule == null || addAllDefaultModules) {
|
||||
boolean hasJava = false;
|
||||
if (systemModules.find(JAVA_SE).isPresent()) {
|
||||
@ -212,6 +214,9 @@ public final class ModuleBootstrap {
|
||||
if (hasJava && mn.startsWith("java."))
|
||||
continue;
|
||||
|
||||
if (ModuleResolution.doNotResolveByDefault(mref))
|
||||
continue;
|
||||
|
||||
// add as root if observable and exports at least one package
|
||||
if ((finder == systemModules || finder.find(mn).isPresent())) {
|
||||
ModuleDescriptor descriptor = mref.descriptor();
|
||||
@ -231,6 +236,7 @@ public final class ModuleBootstrap {
|
||||
ModuleFinder f = finder; // observable modules
|
||||
systemModules.findAll()
|
||||
.stream()
|
||||
.filter(mref -> !ModuleResolution.doNotResolveByDefault(mref))
|
||||
.map(ModuleReference::descriptor)
|
||||
.map(ModuleDescriptor::name)
|
||||
.filter(mn -> f.find(mn).isPresent()) // observable
|
||||
@ -277,6 +283,8 @@ public final class ModuleBootstrap {
|
||||
// time to create configuration
|
||||
PerfCounters.resolveTime.addElapsedTimeFrom(t3);
|
||||
|
||||
// check module names and incubating status
|
||||
checkModuleNamesAndStatus(cf);
|
||||
|
||||
// mapping of modules to class loaders
|
||||
Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
|
||||
@ -508,12 +516,12 @@ public final class ModuleBootstrap {
|
||||
String key = e.getKey();
|
||||
String[] s = key.split("/");
|
||||
if (s.length != 2)
|
||||
fail("Unable to parse: " + key);
|
||||
fail("Unable to parse as <module>/<package>: " + key);
|
||||
|
||||
String mn = s[0];
|
||||
String pn = s[1];
|
||||
if (mn.isEmpty() || pn.isEmpty())
|
||||
fail("Module and package name must be specified:" + key);
|
||||
fail("Module and package name must be specified: " + key);
|
||||
|
||||
// The exporting module is in the boot layer
|
||||
Module m;
|
||||
@ -585,7 +593,7 @@ public final class ModuleBootstrap {
|
||||
|
||||
int pos = value.indexOf('=');
|
||||
if (pos == -1)
|
||||
fail("Unable to parse: " + value);
|
||||
fail("Unable to parse as <module>=<value>: " + value);
|
||||
if (pos == 0)
|
||||
fail("Missing module name in: " + value);
|
||||
|
||||
@ -594,7 +602,7 @@ public final class ModuleBootstrap {
|
||||
|
||||
String rhs = value.substring(pos+1);
|
||||
if (rhs.isEmpty())
|
||||
fail("Unable to parse: " + value);
|
||||
fail("Unable to parse as <module>=<value>: " + value);
|
||||
|
||||
// value is <module>(,<module>)* or <file>(<pathsep><file>)*
|
||||
if (!allowDuplicates && map.containsKey(key))
|
||||
@ -626,6 +634,33 @@ public final class ModuleBootstrap {
|
||||
return (String)System.getProperties().remove(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the names and resolution bit of each module in the configuration,
|
||||
* emitting warnings if needed.
|
||||
*/
|
||||
private static void checkModuleNamesAndStatus(Configuration cf) {
|
||||
String incubating = null;
|
||||
for (ResolvedModule rm : cf.modules()) {
|
||||
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) {
|
||||
incubating = mn;
|
||||
} else {
|
||||
incubating += ", " + mn;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (incubating != null)
|
||||
warn("Using incubator modules: " + incubating);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a RuntimeException with the given message
|
||||
*/
|
||||
|
@ -35,6 +35,7 @@ import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -50,7 +51,6 @@ public final class ModuleHashes {
|
||||
byte[] generate(String algorithm);
|
||||
}
|
||||
|
||||
|
||||
private final String algorithm;
|
||||
private final Map<String, byte[]> nameToHash;
|
||||
|
||||
@ -142,4 +142,39 @@ public final class ModuleHashes {
|
||||
}
|
||||
return new ModuleHashes(algorithm, nameToHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used by jdk.internal.module.SystemModules class
|
||||
* generated at link time.
|
||||
*/
|
||||
public static class Builder {
|
||||
final String algorithm;
|
||||
Map<String, byte[]> nameToHash;
|
||||
|
||||
Builder(String algorithm) {
|
||||
this.algorithm = Objects.requireNonNull(algorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the module hash for the given module name
|
||||
*/
|
||||
public Builder hashForModule(String mn, byte[] hash) {
|
||||
if (nameToHash == null)
|
||||
nameToHash = new HashMap<>();
|
||||
|
||||
nameToHash.put(mn, hash);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@code ModuleHashes}.
|
||||
*/
|
||||
public ModuleHashes build() {
|
||||
if (nameToHash != null) {
|
||||
return new ModuleHashes(algorithm, nameToHash);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.module;
|
||||
package jdk.internal.module;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
@ -31,10 +31,13 @@ import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.module.InvalidModuleDescriptorException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleDescriptor.Builder;
|
||||
import java.lang.module.ModuleDescriptor.Requires;
|
||||
import java.lang.module.ModuleDescriptor.Exports;
|
||||
import java.lang.module.ModuleDescriptor.Opens;
|
||||
import java.lang.module.ModuleDescriptor.Version;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.util.ArrayList;
|
||||
@ -46,7 +49,9 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jdk.internal.module.ModuleHashes;
|
||||
import jdk.internal.misc.JavaLangModuleAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.module.ModuleResolution;
|
||||
|
||||
import static jdk.internal.module.ClassFileConstants.*;
|
||||
|
||||
@ -58,7 +63,10 @@ import static jdk.internal.module.ClassFileConstants.*;
|
||||
* and fine control over the throwing of InvalidModuleDescriptorException.
|
||||
*/
|
||||
|
||||
final class ModuleInfo {
|
||||
public final class ModuleInfo {
|
||||
|
||||
private static final JavaLangModuleAccess JLMA
|
||||
= SharedSecrets.getJavaLangModuleAccess();
|
||||
|
||||
// supplies the set of packages when ModulePackages attribute not present
|
||||
private final Supplier<Set<String>> packageFinder;
|
||||
@ -75,14 +83,42 @@ final class ModuleInfo {
|
||||
this(pf, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* A holder class for the ModuleDescriptor that is created by reading the
|
||||
* Module and other standard class file attributes. It also holds the objects
|
||||
* that represent the non-standard class file attributes that are read from
|
||||
* the class file.
|
||||
*/
|
||||
public static final class Attributes {
|
||||
private final ModuleDescriptor descriptor;
|
||||
private final ModuleHashes recordedHashes;
|
||||
private final ModuleResolution moduleResolution;
|
||||
Attributes(ModuleDescriptor descriptor,
|
||||
ModuleHashes recordedHashes,
|
||||
ModuleResolution moduleResolution) {
|
||||
this.descriptor = descriptor;
|
||||
this.recordedHashes = recordedHashes;
|
||||
this.moduleResolution = moduleResolution;
|
||||
}
|
||||
public ModuleDescriptor descriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
public ModuleHashes recordedHashes() {
|
||||
return recordedHashes;
|
||||
}
|
||||
public ModuleResolution moduleResolution() {
|
||||
return moduleResolution;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a {@code module-info.class} from the given input stream.
|
||||
*
|
||||
* @throws InvalidModuleDescriptorException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static ModuleDescriptor read(InputStream in,
|
||||
Supplier<Set<String>> pf)
|
||||
public static Attributes read(InputStream in, Supplier<Set<String>> pf)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
@ -100,9 +136,7 @@ final class ModuleInfo {
|
||||
* @throws InvalidModuleDescriptorException
|
||||
* @throws UncheckedIOException
|
||||
*/
|
||||
public static ModuleDescriptor read(ByteBuffer bb,
|
||||
Supplier<Set<String>> pf)
|
||||
{
|
||||
public static Attributes read(ByteBuffer bb, Supplier<Set<String>> pf) {
|
||||
try {
|
||||
return new ModuleInfo(pf).doRead(new DataInputWrapper(bb));
|
||||
} catch (IllegalArgumentException | IllegalStateException e) {
|
||||
@ -121,9 +155,7 @@ final class ModuleInfo {
|
||||
* @throws InvalidModuleDescriptorException
|
||||
* @throws UncheckedIOException
|
||||
*/
|
||||
static ModuleDescriptor readIgnoringHashes(ByteBuffer bb,
|
||||
Supplier<Set<String>> pf)
|
||||
{
|
||||
public static Attributes readIgnoringHashes(ByteBuffer bb, Supplier<Set<String>> pf) {
|
||||
try {
|
||||
return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb));
|
||||
} catch (IllegalArgumentException | IllegalStateException e) {
|
||||
@ -144,7 +176,7 @@ final class ModuleInfo {
|
||||
* because an identifier is not a legal Java identifier, duplicate
|
||||
* exports, and many other reasons
|
||||
*/
|
||||
private ModuleDescriptor doRead(DataInput in) throws IOException {
|
||||
private Attributes doRead(DataInput in) throws IOException {
|
||||
|
||||
int magic = in.readInt();
|
||||
if (magic != 0xCAFEBABE)
|
||||
@ -163,8 +195,9 @@ final class ModuleInfo {
|
||||
throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
|
||||
|
||||
int this_class = in.readUnsignedShort();
|
||||
if (this_class != 0)
|
||||
throw invalidModuleDescriptor("this_class must be 0");
|
||||
String mn = cpool.getClassName(this_class);
|
||||
if (!"module-info".equals(mn))
|
||||
throw invalidModuleDescriptor("this_class should be module-info");
|
||||
|
||||
int super_class = in.readUnsignedShort();
|
||||
if (super_class > 0)
|
||||
@ -189,10 +222,10 @@ final class ModuleInfo {
|
||||
|
||||
Builder builder = null;
|
||||
Set<String> packages = null;
|
||||
String version = null;
|
||||
String mainClass = null;
|
||||
String[] osValues = null;
|
||||
ModuleHashes hashes = null;
|
||||
ModuleResolution moduleResolution = null;
|
||||
|
||||
for (int i = 0; i < attributes_count ; i++) {
|
||||
int name_index = in.readUnsignedShort();
|
||||
@ -215,10 +248,6 @@ final class ModuleInfo {
|
||||
packages = readModulePackagesAttribute(in, cpool);
|
||||
break;
|
||||
|
||||
case MODULE_VERSION :
|
||||
version = readModuleVersionAttribute(in, cpool);
|
||||
break;
|
||||
|
||||
case MODULE_MAIN_CLASS :
|
||||
mainClass = readModuleMainClassAttribute(in, cpool);
|
||||
break;
|
||||
@ -235,6 +264,10 @@ final class ModuleInfo {
|
||||
}
|
||||
break;
|
||||
|
||||
case MODULE_RESOLUTION :
|
||||
moduleResolution = readModuleResolution(in, cpool);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isAttributeDisallowed(attribute_name)) {
|
||||
throw invalidModuleDescriptor(attribute_name
|
||||
@ -263,23 +296,33 @@ final class ModuleInfo {
|
||||
usedPackageFinder = true;
|
||||
}
|
||||
if (packages != null) {
|
||||
for (String pn : builder.exportedAndOpenPackages()) {
|
||||
if (!packages.contains(pn)) {
|
||||
String tail;
|
||||
if (usedPackageFinder) {
|
||||
tail = " not found by package finder";
|
||||
} else {
|
||||
tail = " missing from ModulePackages attribute";
|
||||
Set<String> exportedPackages = JLMA.exportedPackages(builder);
|
||||
Set<String> openPackages = JLMA.openPackages(builder);
|
||||
if (packages.containsAll(exportedPackages)
|
||||
&& packages.containsAll(openPackages)) {
|
||||
packages.removeAll(exportedPackages);
|
||||
packages.removeAll(openPackages);
|
||||
} else {
|
||||
// the set of packages is not complete
|
||||
Set<String> exportedAndOpenPackages = new HashSet<>();
|
||||
exportedAndOpenPackages.addAll(exportedPackages);
|
||||
exportedAndOpenPackages.addAll(openPackages);
|
||||
for (String pn : exportedAndOpenPackages) {
|
||||
if (!packages.contains(pn)) {
|
||||
String tail;
|
||||
if (usedPackageFinder) {
|
||||
tail = " not found by package finder";
|
||||
} else {
|
||||
tail = " missing from ModulePackages attribute";
|
||||
}
|
||||
throw invalidModuleDescriptor("Package " + pn + tail);
|
||||
}
|
||||
throw invalidModuleDescriptor("Package " + pn + tail);
|
||||
}
|
||||
packages.remove(pn);
|
||||
assert false; // should not get here
|
||||
}
|
||||
builder.contains(packages);
|
||||
}
|
||||
|
||||
if (version != null)
|
||||
builder.version(version);
|
||||
if (mainClass != null)
|
||||
builder.mainClass(mainClass);
|
||||
if (osValues != null) {
|
||||
@ -287,10 +330,9 @@ final class ModuleInfo {
|
||||
if (osValues[1] != null) builder.osArch(osValues[1]);
|
||||
if (osValues[2] != null) builder.osVersion(osValues[2]);
|
||||
}
|
||||
if (hashes != null)
|
||||
builder.hashes(hashes);
|
||||
|
||||
return builder.build();
|
||||
ModuleDescriptor descriptor = builder.build();
|
||||
return new Attributes(descriptor, hashes, moduleResolution);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -302,38 +344,55 @@ final class ModuleInfo {
|
||||
{
|
||||
// module_name
|
||||
int module_name_index = in.readUnsignedShort();
|
||||
String mn = cpool.getUtf8AsBinaryName(module_name_index);
|
||||
|
||||
Builder builder = new ModuleDescriptor.Builder(mn, /*strict*/ false);
|
||||
String mn = cpool.getModuleName(module_name_index);
|
||||
|
||||
int module_flags = in.readUnsignedShort();
|
||||
boolean open = ((module_flags & ACC_OPEN) != 0);
|
||||
if (open)
|
||||
builder.open(true);
|
||||
if ((module_flags & ACC_SYNTHETIC) != 0)
|
||||
builder.synthetic(true);
|
||||
boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
|
||||
|
||||
Builder builder = JLMA.newModuleBuilder(mn, false, open, synthetic);
|
||||
|
||||
int module_version_index = in.readUnsignedShort();
|
||||
if (module_version_index != 0) {
|
||||
String vs = cpool.getUtf8(module_version_index);
|
||||
builder.version(vs);
|
||||
}
|
||||
|
||||
int requires_count = in.readUnsignedShort();
|
||||
boolean requiresJavaBase = false;
|
||||
for (int i=0; i<requires_count; i++) {
|
||||
int index = in.readUnsignedShort();
|
||||
int flags = in.readUnsignedShort();
|
||||
String dn = cpool.getUtf8AsBinaryName(index);
|
||||
int requires_index = in.readUnsignedShort();
|
||||
String dn = cpool.getModuleName(requires_index);
|
||||
|
||||
int requires_flags = in.readUnsignedShort();
|
||||
Set<Requires.Modifier> mods;
|
||||
if (flags == 0) {
|
||||
if (requires_flags == 0) {
|
||||
mods = Collections.emptySet();
|
||||
} else {
|
||||
mods = new HashSet<>();
|
||||
if ((flags & ACC_TRANSITIVE) != 0)
|
||||
if ((requires_flags & ACC_TRANSITIVE) != 0)
|
||||
mods.add(Requires.Modifier.TRANSITIVE);
|
||||
if ((flags & ACC_STATIC_PHASE) != 0)
|
||||
if ((requires_flags & ACC_STATIC_PHASE) != 0)
|
||||
mods.add(Requires.Modifier.STATIC);
|
||||
if ((flags & ACC_SYNTHETIC) != 0)
|
||||
if ((requires_flags & ACC_SYNTHETIC) != 0)
|
||||
mods.add(Requires.Modifier.SYNTHETIC);
|
||||
if ((flags & ACC_MANDATED) != 0)
|
||||
if ((requires_flags & ACC_MANDATED) != 0)
|
||||
mods.add(Requires.Modifier.MANDATED);
|
||||
}
|
||||
builder.requires(mods, dn);
|
||||
|
||||
int requires_version_index = in.readUnsignedShort();
|
||||
Version compiledVersion = null;
|
||||
if (requires_version_index != 0) {
|
||||
String vs = cpool.getUtf8(requires_version_index);
|
||||
compiledVersion = Version.parse(vs);
|
||||
}
|
||||
|
||||
if (compiledVersion == null) {
|
||||
builder.requires(mods, dn);
|
||||
} else {
|
||||
builder.requires(mods, dn, compiledVersion);
|
||||
}
|
||||
|
||||
if (dn.equals("java.base"))
|
||||
requiresJavaBase = true;
|
||||
}
|
||||
@ -350,18 +409,18 @@ final class ModuleInfo {
|
||||
int exports_count = in.readUnsignedShort();
|
||||
if (exports_count > 0) {
|
||||
for (int i=0; i<exports_count; i++) {
|
||||
int index = in.readUnsignedShort();
|
||||
String pkg = cpool.getUtf8AsBinaryName(index);
|
||||
int exports_index = in.readUnsignedShort();
|
||||
String pkg = cpool.getPackageName(exports_index);
|
||||
|
||||
Set<Exports.Modifier> mods;
|
||||
int flags = in.readUnsignedShort();
|
||||
if (flags == 0) {
|
||||
int exports_flags = in.readUnsignedShort();
|
||||
if (exports_flags == 0) {
|
||||
mods = Collections.emptySet();
|
||||
} else {
|
||||
mods = new HashSet<>();
|
||||
if ((flags & ACC_SYNTHETIC) != 0)
|
||||
if ((exports_flags & ACC_SYNTHETIC) != 0)
|
||||
mods.add(Exports.Modifier.SYNTHETIC);
|
||||
if ((flags & ACC_MANDATED) != 0)
|
||||
if ((exports_flags & ACC_MANDATED) != 0)
|
||||
mods.add(Exports.Modifier.MANDATED);
|
||||
}
|
||||
|
||||
@ -370,7 +429,7 @@ final class ModuleInfo {
|
||||
Set<String> targets = new HashSet<>(exports_to_count);
|
||||
for (int j=0; j<exports_to_count; j++) {
|
||||
int exports_to_index = in.readUnsignedShort();
|
||||
targets.add(cpool.getUtf8AsBinaryName(exports_to_index));
|
||||
targets.add(cpool.getModuleName(exports_to_index));
|
||||
}
|
||||
builder.exports(mods, pkg, targets);
|
||||
} else {
|
||||
@ -386,18 +445,18 @@ final class ModuleInfo {
|
||||
+ " module must be 0 length");
|
||||
}
|
||||
for (int i=0; i<opens_count; i++) {
|
||||
int index = in.readUnsignedShort();
|
||||
String pkg = cpool.getUtf8AsBinaryName(index);
|
||||
int opens_index = in.readUnsignedShort();
|
||||
String pkg = cpool.getPackageName(opens_index);
|
||||
|
||||
Set<Opens.Modifier> mods;
|
||||
int flags = in.readUnsignedShort();
|
||||
if (flags == 0) {
|
||||
int opens_flags = in.readUnsignedShort();
|
||||
if (opens_flags == 0) {
|
||||
mods = Collections.emptySet();
|
||||
} else {
|
||||
mods = new HashSet<>();
|
||||
if ((flags & ACC_SYNTHETIC) != 0)
|
||||
if ((opens_flags & ACC_SYNTHETIC) != 0)
|
||||
mods.add(Opens.Modifier.SYNTHETIC);
|
||||
if ((flags & ACC_MANDATED) != 0)
|
||||
if ((opens_flags & ACC_MANDATED) != 0)
|
||||
mods.add(Opens.Modifier.MANDATED);
|
||||
}
|
||||
|
||||
@ -406,7 +465,7 @@ final class ModuleInfo {
|
||||
Set<String> targets = new HashSet<>(open_to_count);
|
||||
for (int j=0; j<open_to_count; j++) {
|
||||
int opens_to_index = in.readUnsignedShort();
|
||||
targets.add(cpool.getUtf8AsBinaryName(opens_to_index));
|
||||
targets.add(cpool.getModuleName(opens_to_index));
|
||||
}
|
||||
builder.opens(mods, pkg, targets);
|
||||
} else {
|
||||
@ -419,7 +478,7 @@ final class ModuleInfo {
|
||||
if (uses_count > 0) {
|
||||
for (int i=0; i<uses_count; i++) {
|
||||
int index = in.readUnsignedShort();
|
||||
String sn = cpool.getClassNameAsBinaryName(index);
|
||||
String sn = cpool.getClassName(index);
|
||||
builder.uses(sn);
|
||||
}
|
||||
}
|
||||
@ -428,12 +487,12 @@ final class ModuleInfo {
|
||||
if (provides_count > 0) {
|
||||
for (int i=0; i<provides_count; i++) {
|
||||
int index = in.readUnsignedShort();
|
||||
String sn = cpool.getClassNameAsBinaryName(index);
|
||||
String sn = cpool.getClassName(index);
|
||||
int with_count = in.readUnsignedShort();
|
||||
List<String> providers = new ArrayList<>(with_count);
|
||||
for (int j=0; j<with_count; j++) {
|
||||
index = in.readUnsignedShort();
|
||||
String pn = cpool.getClassNameAsBinaryName(index);
|
||||
String pn = cpool.getClassName(index);
|
||||
providers.add(pn);
|
||||
}
|
||||
builder.provides(sn, providers);
|
||||
@ -453,22 +512,16 @@ final class ModuleInfo {
|
||||
Set<String> packages = new HashSet<>(package_count);
|
||||
for (int i=0; i<package_count; i++) {
|
||||
int index = in.readUnsignedShort();
|
||||
String pn = cpool.getUtf8AsBinaryName(index);
|
||||
packages.add(pn);
|
||||
String pn = cpool.getPackageName(index);
|
||||
boolean added = packages.add(pn);
|
||||
if (!added) {
|
||||
throw invalidModuleDescriptor("Package " + pn + " in ModulePackages"
|
||||
+ "attribute more than once");
|
||||
}
|
||||
}
|
||||
return packages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the ModuleVersion attribute
|
||||
*/
|
||||
private String readModuleVersionAttribute(DataInput in, ConstantPool cpool)
|
||||
throws IOException
|
||||
{
|
||||
int index = in.readUnsignedShort();
|
||||
return cpool.getUtf8(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the ModuleMainClass attribute
|
||||
*/
|
||||
@ -476,7 +529,7 @@ final class ModuleInfo {
|
||||
throws IOException
|
||||
{
|
||||
int index = in.readUnsignedShort();
|
||||
return cpool.getClassNameAsBinaryName(index);
|
||||
return cpool.getClassName(index);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -516,7 +569,7 @@ final class ModuleInfo {
|
||||
Map<String, byte[]> map = new HashMap<>(hash_count);
|
||||
for (int i=0; i<hash_count; i++) {
|
||||
int module_name_index = in.readUnsignedShort();
|
||||
String mn = cpool.getUtf8AsBinaryName(module_name_index);
|
||||
String mn = cpool.getModuleName(module_name_index);
|
||||
int hash_length = in.readUnsignedShort();
|
||||
if (hash_length == 0) {
|
||||
throw invalidModuleDescriptor("hash_length == 0");
|
||||
@ -529,6 +582,31 @@ final class ModuleInfo {
|
||||
return new ModuleHashes(algorithm, map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the ModuleResolution attribute.
|
||||
*/
|
||||
private ModuleResolution readModuleResolution(DataInput in,
|
||||
ConstantPool cpool)
|
||||
throws IOException
|
||||
{
|
||||
int flags = in.readUnsignedShort();
|
||||
|
||||
int reason = 0;
|
||||
if ((flags & WARN_DEPRECATED) != 0)
|
||||
reason = WARN_DEPRECATED;
|
||||
if ((flags & WARN_DEPRECATED_FOR_REMOVAL) != 0) {
|
||||
if (reason != 0)
|
||||
throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
|
||||
reason = WARN_DEPRECATED_FOR_REMOVAL;
|
||||
}
|
||||
if ((flags & WARN_INCUBATING) != 0) {
|
||||
if (reason != 0)
|
||||
throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
|
||||
}
|
||||
|
||||
return new ModuleResolution(flags);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the given attribute can be present at most once
|
||||
@ -540,10 +618,10 @@ final class ModuleInfo {
|
||||
name.equals(SOURCE_FILE) ||
|
||||
name.equals(SDE) ||
|
||||
name.equals(MODULE_PACKAGES) ||
|
||||
name.equals(MODULE_VERSION) ||
|
||||
name.equals(MODULE_MAIN_CLASS) ||
|
||||
name.equals(MODULE_TARGET) ||
|
||||
name.equals(MODULE_HASHES))
|
||||
name.equals(MODULE_HASHES) ||
|
||||
name.equals(MODULE_RESOLUTION))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -604,6 +682,8 @@ final class ModuleInfo {
|
||||
static final int CONSTANT_MethodHandle = 15;
|
||||
static final int CONSTANT_MethodType = 16;
|
||||
static final int CONSTANT_InvokeDynamic = 18;
|
||||
static final int CONSTANT_Module = 19;
|
||||
static final int CONSTANT_Package = 20;
|
||||
|
||||
private static class Entry {
|
||||
protected Entry(int tag) {
|
||||
@ -653,6 +733,8 @@ final class ModuleInfo {
|
||||
break;
|
||||
|
||||
case CONSTANT_Class:
|
||||
case CONSTANT_Package:
|
||||
case CONSTANT_Module:
|
||||
case CONSTANT_String:
|
||||
int index = in.readUnsignedShort();
|
||||
pool[i] = new IndexEntry(tag, index);
|
||||
@ -715,14 +797,34 @@ final class ModuleInfo {
|
||||
throw invalidModuleDescriptor("CONSTANT_Class expected at entry: "
|
||||
+ index);
|
||||
}
|
||||
return getUtf8(((IndexEntry) e).index);
|
||||
String value = getUtf8(((IndexEntry) e).index);
|
||||
checkUnqualifiedName("CONSTANT_Class", index, value);
|
||||
return value.replace('/', '.'); // internal form -> binary name
|
||||
}
|
||||
|
||||
String getClassNameAsBinaryName(int index) {
|
||||
String value = getClassName(index);
|
||||
String getPackageName(int index) {
|
||||
checkIndex(index);
|
||||
Entry e = pool[index];
|
||||
if (e.tag != CONSTANT_Package) {
|
||||
throw invalidModuleDescriptor("CONSTANT_Package expected at entry: "
|
||||
+ index);
|
||||
}
|
||||
String value = getUtf8(((IndexEntry) e).index);
|
||||
checkUnqualifiedName("CONSTANT_Package", index, value);
|
||||
return value.replace('/', '.'); // internal form -> binary name
|
||||
}
|
||||
|
||||
String getModuleName(int index) {
|
||||
checkIndex(index);
|
||||
Entry e = pool[index];
|
||||
if (e.tag != CONSTANT_Module) {
|
||||
throw invalidModuleDescriptor("CONSTANT_Module expected at entry: "
|
||||
+ index);
|
||||
}
|
||||
String value = getUtf8(((IndexEntry) e).index);
|
||||
return decodeModuleName(index, value);
|
||||
}
|
||||
|
||||
String getUtf8(int index) {
|
||||
checkIndex(index);
|
||||
Entry e = pool[index];
|
||||
@ -733,15 +835,103 @@ final class ModuleInfo {
|
||||
return (String) (((ValueEntry) e).value);
|
||||
}
|
||||
|
||||
String getUtf8AsBinaryName(int index) {
|
||||
String value = getUtf8(index);
|
||||
return value.replace('/', '.'); // internal -> binary name
|
||||
}
|
||||
|
||||
void checkIndex(int index) {
|
||||
if (index < 1 || index >= pool.length)
|
||||
throw invalidModuleDescriptor("Index into constant pool out of range");
|
||||
}
|
||||
|
||||
void checkUnqualifiedName(String what, int index, String value) {
|
||||
int len = value.length();
|
||||
if (len == 0) {
|
||||
throw invalidModuleDescriptor(what + " at entry " + index
|
||||
+ " has zero length");
|
||||
}
|
||||
for (int i=0; i<len; i++) {
|
||||
char c = value.charAt(i);
|
||||
if (c == '.' || c == ';' || c == '[') {
|
||||
throw invalidModuleDescriptor(what + " at entry " + index
|
||||
+ " has illegal character: '"
|
||||
+ c + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "Decode" a module name that has been read from the constant pool.
|
||||
*/
|
||||
String decodeModuleName(int index, String value) {
|
||||
int len = value.length();
|
||||
if (len == 0) {
|
||||
throw invalidModuleDescriptor("CONSTANT_Module at entry "
|
||||
+ index + " is zero length");
|
||||
}
|
||||
int i = 0;
|
||||
while (i < len) {
|
||||
int cp = value.codePointAt(i);
|
||||
if (cp == ':' || cp == '@' || cp < 0x20) {
|
||||
throw invalidModuleDescriptor("CONSTANT_Module at entry "
|
||||
+ index + " has illegal character: "
|
||||
+ Character.getName(cp));
|
||||
}
|
||||
|
||||
// blackslash is the escape character
|
||||
if (cp == '\\')
|
||||
return decodeModuleName(index, i, value);
|
||||
|
||||
i += Character.charCount(cp);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* "Decode" a module name that has been read from the constant pool and
|
||||
* partly checked for illegal characters (up to position {@code i}).
|
||||
*/
|
||||
String decodeModuleName(int index, int i, String value) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
// copy the code points that have been checked
|
||||
int j = 0;
|
||||
while (j < i) {
|
||||
int cp = value.codePointAt(j);
|
||||
sb.appendCodePoint(cp);
|
||||
j += Character.charCount(cp);
|
||||
}
|
||||
|
||||
// decode from position {@code i} to end
|
||||
int len = value.length();
|
||||
while (i < len) {
|
||||
int cp = value.codePointAt(i);
|
||||
if (cp == ':' || cp == '@' || cp < 0x20) {
|
||||
throw invalidModuleDescriptor("CONSTANT_Module at entry "
|
||||
+ index + " has illegal character: "
|
||||
+ Character.getName(cp));
|
||||
}
|
||||
|
||||
// blackslash is the escape character
|
||||
if (cp == '\\') {
|
||||
j = i + Character.charCount(cp);
|
||||
if (j >= len) {
|
||||
throw invalidModuleDescriptor("CONSTANT_Module at entry "
|
||||
+ index + " has illegal "
|
||||
+ "escape sequence");
|
||||
}
|
||||
int next = value.codePointAt(j);
|
||||
if (next != '\\' && next != ':' && next != '@') {
|
||||
throw invalidModuleDescriptor("CONSTANT_Module at entry "
|
||||
+ index + " has illegal "
|
||||
+ "escape sequence");
|
||||
}
|
||||
sb.appendCodePoint(next);
|
||||
i += Character.charCount(next);
|
||||
} else {
|
||||
sb.appendCodePoint(cp);
|
||||
}
|
||||
|
||||
i += Character.charCount(cp);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
@ -70,6 +70,9 @@ public final class ModuleInfoExtender {
|
||||
// the hashes for the Hashes attribute
|
||||
private ModuleHashes hashes;
|
||||
|
||||
// the value of the ModuleResolution attribute
|
||||
private ModuleResolution moduleResolution;
|
||||
|
||||
private ModuleInfoExtender(InputStream in) {
|
||||
this.in = in;
|
||||
}
|
||||
@ -120,6 +123,14 @@ public final class ModuleInfoExtender {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value for the ModuleResolution attribute.
|
||||
*/
|
||||
public ModuleInfoExtender moduleResolution(ModuleResolution mres) {
|
||||
this.moduleResolution = mres;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A ClassVisitor that supports adding class file attributes. If an
|
||||
* attribute already exists then the first occurence of the attribute
|
||||
@ -183,21 +194,20 @@ public final class ModuleInfoExtender {
|
||||
|
||||
if (packages != null)
|
||||
cv.addAttribute(new ModulePackagesAttribute(packages));
|
||||
if (version != null)
|
||||
cv.addAttribute(new ModuleVersionAttribute(version));
|
||||
if (mainClass != null)
|
||||
cv.addAttribute(new ModuleMainClassAttribute(mainClass));
|
||||
if (osName != null || osArch != null || osVersion != null)
|
||||
cv.addAttribute(new ModuleTargetAttribute(osName, osArch, osVersion));
|
||||
if (hashes != null)
|
||||
cv.addAttribute(new ModuleHashesAttribute(hashes));
|
||||
if (moduleResolution != null)
|
||||
cv.addAttribute(new ModuleResolutionAttribute(moduleResolution.value()));
|
||||
|
||||
List<Attribute> attrs = new ArrayList<>();
|
||||
|
||||
// prototypes of attributes that should be parsed
|
||||
attrs.add(new ModuleAttribute());
|
||||
attrs.add(new ModuleAttribute(version));
|
||||
attrs.add(new ModulePackagesAttribute());
|
||||
attrs.add(new ModuleVersionAttribute());
|
||||
attrs.add(new ModuleMainClassAttribute());
|
||||
attrs.add(new ModuleTargetAttribute());
|
||||
attrs.add(new ModuleHashesAttribute());
|
||||
|
@ -49,13 +49,12 @@ public final class ModuleInfoWriter {
|
||||
* returning it in a byte array.
|
||||
*/
|
||||
private static byte[] toModuleInfo(ModuleDescriptor md) {
|
||||
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
cw.visit(Opcodes.V1_9, ACC_MODULE, null, null, null, null);
|
||||
cw.visit(Opcodes.V1_9, ACC_MODULE, "module-info", null, null, null);
|
||||
cw.visitAttribute(new ModuleAttribute(md));
|
||||
|
||||
// for tests: write the Packages attribute when there are packages that
|
||||
// aren't exported or open
|
||||
// for tests: write the ModulePackages attribute when there are packages
|
||||
// that aren't exported or open
|
||||
Stream<String> exported = md.exports().stream()
|
||||
.map(ModuleDescriptor.Exports::source);
|
||||
Stream<String> open = md.opens().stream()
|
||||
@ -64,10 +63,10 @@ public final class ModuleInfoWriter {
|
||||
if (md.packages().size() > exportedOrOpen)
|
||||
cw.visitAttribute(new ModulePackagesAttribute(md.packages()));
|
||||
|
||||
md.version().ifPresent(v -> cw.visitAttribute(new ModuleVersionAttribute(v)));
|
||||
// write ModuleMainClass if the module has a main class
|
||||
md.mainClass().ifPresent(mc -> cw.visitAttribute(new ModuleMainClassAttribute(mc)));
|
||||
|
||||
// write the TargetPlatform attribute if have any of OS name/arch/version
|
||||
// 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);
|
||||
@ -76,7 +75,6 @@ public final class ModuleInfoWriter {
|
||||
}
|
||||
|
||||
cw.visitEnd();
|
||||
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
|
@ -149,9 +149,22 @@ public final class ModulePatcher {
|
||||
|
||||
// return a module reference to the patched module
|
||||
URI location = mref.location().orElse(null);
|
||||
return JLMA.newPatchedModule(descriptor,
|
||||
location,
|
||||
() -> new PatchedModuleReader(paths, mref));
|
||||
|
||||
ModuleHashes recordedHashes = null;
|
||||
ModuleResolution mres = null;
|
||||
if (mref instanceof ModuleReferenceImpl) {
|
||||
ModuleReferenceImpl impl = (ModuleReferenceImpl)mref;
|
||||
recordedHashes = impl.recordedHashes();
|
||||
mres = impl.moduleResolution();
|
||||
}
|
||||
|
||||
return new ModuleReferenceImpl(descriptor,
|
||||
location,
|
||||
() -> new PatchedModuleReader(paths, mref),
|
||||
this,
|
||||
recordedHashes,
|
||||
null,
|
||||
mres);
|
||||
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.module;
|
||||
package jdk.internal.module;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
@ -32,7 +32,12 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.module.FindException;
|
||||
import java.lang.module.InvalidModuleDescriptorException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleDescriptor.Requires;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.net.URI;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
@ -59,7 +64,6 @@ import java.util.zip.ZipFile;
|
||||
|
||||
import jdk.internal.jmod.JmodFile;
|
||||
import jdk.internal.jmod.JmodFile.Section;
|
||||
import jdk.internal.module.Checks;
|
||||
import jdk.internal.perf.PerfCounter;
|
||||
import jdk.internal.util.jar.VersionedStream;
|
||||
|
||||
@ -74,7 +78,7 @@ import jdk.internal.util.jar.VersionedStream;
|
||||
* modules in JMOD files.
|
||||
*/
|
||||
|
||||
class ModulePath implements ModuleFinder {
|
||||
public class ModulePath implements ModuleFinder {
|
||||
private static final String MODULE_INFO = "module-info.class";
|
||||
|
||||
// the version to use for multi-release modular JARs
|
||||
@ -90,7 +94,7 @@ class ModulePath implements ModuleFinder {
|
||||
// map of module name to module reference map for modules already located
|
||||
private final Map<String, ModuleReference> cachedModules = new HashMap<>();
|
||||
|
||||
ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) {
|
||||
public ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) {
|
||||
this.releaseVersion = version;
|
||||
this.isLinkPhase = isLinkPhase;
|
||||
this.entries = entries.clone();
|
||||
@ -99,7 +103,7 @@ class ModulePath implements ModuleFinder {
|
||||
}
|
||||
}
|
||||
|
||||
ModulePath(Path... entries) {
|
||||
public ModulePath(Path... entries) {
|
||||
this(JarFile.runtimeVersion(), false, entries);
|
||||
}
|
||||
|
||||
@ -343,11 +347,11 @@ class ModulePath implements ModuleFinder {
|
||||
*/
|
||||
private ModuleReference readJMod(Path file) throws IOException {
|
||||
try (JmodFile jf = new JmodFile(file)) {
|
||||
ModuleDescriptor md;
|
||||
ModuleInfo.Attributes attrs;
|
||||
try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
|
||||
md = ModuleDescriptor.read(in, () -> jmodPackages(jf));
|
||||
attrs = ModuleInfo.read(in, () -> jmodPackages(jf));
|
||||
}
|
||||
return ModuleReferences.newJModModule(md, file);
|
||||
return ModuleReferences.newJModModule(attrs, file);
|
||||
}
|
||||
}
|
||||
|
||||
@ -557,13 +561,14 @@ class ModulePath implements ModuleFinder {
|
||||
ZipFile.OPEN_READ,
|
||||
releaseVersion))
|
||||
{
|
||||
ModuleDescriptor md;
|
||||
ModuleInfo.Attributes attrs;
|
||||
JarEntry entry = jf.getJarEntry(MODULE_INFO);
|
||||
if (entry == null) {
|
||||
|
||||
// no module-info.class so treat it as automatic module
|
||||
try {
|
||||
md = deriveModuleDescriptor(jf);
|
||||
ModuleDescriptor md = deriveModuleDescriptor(jf);
|
||||
attrs = new ModuleInfo.Attributes(md, null, null);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new FindException(
|
||||
"Unable to derive module descriptor for: "
|
||||
@ -571,11 +576,11 @@ class ModulePath implements ModuleFinder {
|
||||
}
|
||||
|
||||
} else {
|
||||
md = ModuleDescriptor.read(jf.getInputStream(entry),
|
||||
() -> jarPackages(jf));
|
||||
attrs = ModuleInfo.read(jf.getInputStream(entry),
|
||||
() -> jarPackages(jf));
|
||||
}
|
||||
|
||||
return ModuleReferences.newJarModule(md, file);
|
||||
return ModuleReferences.newJarModule(attrs, file);
|
||||
}
|
||||
}
|
||||
|
||||
@ -604,15 +609,15 @@ class ModulePath implements ModuleFinder {
|
||||
*/
|
||||
private ModuleReference readExplodedModule(Path dir) throws IOException {
|
||||
Path mi = dir.resolve(MODULE_INFO);
|
||||
ModuleDescriptor md;
|
||||
ModuleInfo.Attributes attrs;
|
||||
try (InputStream in = Files.newInputStream(mi)) {
|
||||
md = ModuleDescriptor.read(new BufferedInputStream(in),
|
||||
() -> explodedPackages(dir));
|
||||
attrs = ModuleInfo.read(new BufferedInputStream(in),
|
||||
() -> explodedPackages(dir));
|
||||
} catch (NoSuchFileException e) {
|
||||
// for now
|
||||
return null;
|
||||
}
|
||||
return ModuleReferences.newExplodedModule(md, dir);
|
||||
return ModuleReferences.newExplodedModule(attrs, dir);
|
||||
}
|
||||
|
||||
/**
|
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* 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.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleReader;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.net.URI;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A ModuleReference implementation that supports referencing a module that
|
||||
* is patched and/or can be tied to other modules by means of hashes.
|
||||
*/
|
||||
|
||||
public class ModuleReferenceImpl extends ModuleReference {
|
||||
|
||||
private final Supplier<ModuleReader> readerSupplier;
|
||||
|
||||
// non-null if the module is patched
|
||||
private final ModulePatcher patcher;
|
||||
|
||||
// the hashes of other modules recorded in this module
|
||||
private final ModuleHashes recordedHashes;
|
||||
|
||||
// the function that computes the hash of this module
|
||||
private final ModuleHashes.HashSupplier hasher;
|
||||
|
||||
// ModuleResolution flags
|
||||
private final ModuleResolution moduleResolution;
|
||||
|
||||
// cached hash of this module to avoid needing to compute it many times
|
||||
private byte[] cachedHash;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of this class.
|
||||
*/
|
||||
ModuleReferenceImpl(ModuleDescriptor descriptor,
|
||||
URI location,
|
||||
Supplier<ModuleReader> readerSupplier,
|
||||
ModulePatcher patcher,
|
||||
ModuleHashes recordedHashes,
|
||||
ModuleHashes.HashSupplier hasher,
|
||||
ModuleResolution moduleResolution)
|
||||
{
|
||||
super(descriptor, Objects.requireNonNull(location));
|
||||
this.readerSupplier = readerSupplier;
|
||||
this.patcher = patcher;
|
||||
this.recordedHashes = recordedHashes;
|
||||
this.hasher = hasher;
|
||||
this.moduleResolution = moduleResolution;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleReader open() throws IOException {
|
||||
try {
|
||||
return readerSupplier.get();
|
||||
} catch (UncheckedIOException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this module has been patched via --patch-module.
|
||||
*/
|
||||
public boolean isPatched() {
|
||||
return (patcher != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hashes recorded in this module or {@code null} if there
|
||||
* are no hashes recorded.
|
||||
*/
|
||||
public ModuleHashes recordedHashes() {
|
||||
return recordedHashes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the supplier that computes the hash of this module.
|
||||
*/
|
||||
ModuleHashes.HashSupplier hasher() {
|
||||
return hasher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ModuleResolution flags.
|
||||
*/
|
||||
public ModuleResolution moduleResolution() {
|
||||
return moduleResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the hash of this module. Returns {@code null} if the hash
|
||||
* cannot be computed.
|
||||
*
|
||||
* @throws java.io.UncheckedIOException if an I/O error occurs
|
||||
*/
|
||||
public byte[] computeHash(String algorithm) {
|
||||
byte[] result = cachedHash;
|
||||
if (result != null)
|
||||
return result;
|
||||
if (hasher == null)
|
||||
return null;
|
||||
cachedHash = result = hasher.generate(algorithm);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc = hash;
|
||||
if (hc == 0) {
|
||||
hc = descriptor().hashCode();
|
||||
hc = 43 * hc + Objects.hashCode(location());
|
||||
hc = 43 * hc + Objects.hashCode(patcher);
|
||||
if (hc == 0)
|
||||
hc = -1;
|
||||
hash = hc;
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
private int hash;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object ob) {
|
||||
if (!(ob instanceof ModuleReferenceImpl))
|
||||
return false;
|
||||
ModuleReferenceImpl that = (ModuleReferenceImpl)ob;
|
||||
|
||||
// assume module content, recorded hashes, etc. are the same
|
||||
// when the modules have equal module descriptors, are at the
|
||||
// same location, and are patched by the same patcher.
|
||||
return Objects.equals(this.descriptor(), that.descriptor())
|
||||
&& Objects.equals(this.location(), that.location())
|
||||
&& Objects.equals(this.patcher, that.patcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString();
|
||||
}
|
||||
|
||||
}
|
@ -23,13 +23,15 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.module;
|
||||
package jdk.internal.module;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.module.ModuleReader;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
@ -51,10 +53,7 @@ import java.util.zip.ZipFile;
|
||||
import jdk.internal.jmod.JmodFile;
|
||||
import jdk.internal.misc.JavaLangAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.module.ModuleBootstrap;
|
||||
import jdk.internal.module.ModuleHashes;
|
||||
import jdk.internal.module.ModuleHashes.HashSupplier;
|
||||
import jdk.internal.module.ModulePatcher;
|
||||
import jdk.internal.util.jar.VersionedStream;
|
||||
import sun.net.www.ParseUtil;
|
||||
|
||||
@ -75,12 +74,18 @@ class ModuleReferences {
|
||||
* Creates a ModuleReference to a module or to patched module when
|
||||
* creating modules for the boot Layer and --patch-module is specified.
|
||||
*/
|
||||
private static ModuleReference newModule(ModuleDescriptor md,
|
||||
private static ModuleReference newModule(ModuleInfo.Attributes attrs,
|
||||
URI uri,
|
||||
Supplier<ModuleReader> supplier,
|
||||
HashSupplier hasher) {
|
||||
|
||||
ModuleReference mref = new ModuleReference(md, uri, supplier, hasher);
|
||||
ModuleReference mref = new ModuleReferenceImpl(attrs.descriptor(),
|
||||
uri,
|
||||
supplier,
|
||||
null,
|
||||
attrs.recordedHashes(),
|
||||
hasher,
|
||||
attrs.moduleResolution());
|
||||
if (JLA.getBootLayer() == null)
|
||||
mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
|
||||
|
||||
@ -90,29 +95,29 @@ class ModuleReferences {
|
||||
/**
|
||||
* Creates a ModuleReference to a module packaged as a modular JAR.
|
||||
*/
|
||||
static ModuleReference newJarModule(ModuleDescriptor md, Path file) {
|
||||
static ModuleReference newJarModule(ModuleInfo.Attributes attrs, Path file) {
|
||||
URI uri = file.toUri();
|
||||
Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
|
||||
HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
|
||||
return newModule(md, uri, supplier, hasher);
|
||||
return newModule(attrs, uri, supplier, hasher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ModuleReference to a module packaged as a JMOD.
|
||||
*/
|
||||
static ModuleReference newJModModule(ModuleDescriptor md, Path file) {
|
||||
static ModuleReference newJModModule(ModuleInfo.Attributes attrs, Path file) {
|
||||
URI uri = file.toUri();
|
||||
Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
|
||||
HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
|
||||
return newModule(md, file.toUri(), supplier, hasher);
|
||||
return newModule(attrs, uri, supplier, hasher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ModuleReference to an exploded module.
|
||||
*/
|
||||
static ModuleReference newExplodedModule(ModuleDescriptor md, Path dir) {
|
||||
static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs, Path dir) {
|
||||
Supplier<ModuleReader> supplier = () -> new ExplodedModuleReader(dir);
|
||||
return newModule(md, dir.toUri(), supplier, null);
|
||||
return newModule(attrs, dir.toUri(), supplier, null);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* 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.module.ModuleReference;
|
||||
import static jdk.internal.module.ClassFileConstants.*;
|
||||
|
||||
/**
|
||||
* Represents the Module Resolution flags.
|
||||
*/
|
||||
public final class ModuleResolution {
|
||||
|
||||
final int value;
|
||||
|
||||
ModuleResolution(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static ModuleResolution empty() {
|
||||
return new ModuleResolution(0);
|
||||
}
|
||||
|
||||
public boolean doNotResolveByDefault() {
|
||||
return (value & DO_NOT_RESOLVE_BY_DEFAULT) != 0;
|
||||
}
|
||||
|
||||
public boolean hasDeprecatedWarning() {
|
||||
return (value & WARN_DEPRECATED) != 0;
|
||||
}
|
||||
|
||||
public boolean hasDeprecatedForRemovalWarning() {
|
||||
return (value & WARN_DEPRECATED_FOR_REMOVAL) != 0;
|
||||
}
|
||||
|
||||
public boolean hasIncubatingWarning() {
|
||||
return (value & WARN_INCUBATING) != 0;
|
||||
}
|
||||
|
||||
public ModuleResolution withDoNotResolveByDefault() {
|
||||
return new ModuleResolution(value | DO_NOT_RESOLVE_BY_DEFAULT);
|
||||
}
|
||||
|
||||
public ModuleResolution withDeprecated() {
|
||||
if ((value & (WARN_DEPRECATED_FOR_REMOVAL | WARN_INCUBATING)) != 0)
|
||||
throw new InternalError("cannot add deprecated to " + value);
|
||||
return new ModuleResolution(value | WARN_DEPRECATED);
|
||||
}
|
||||
|
||||
public ModuleResolution withDeprecatedForRemoval() {
|
||||
if ((value & (WARN_DEPRECATED | WARN_INCUBATING)) != 0)
|
||||
throw new InternalError("cannot add deprecated for removal to " + value);
|
||||
return new ModuleResolution(value | WARN_DEPRECATED_FOR_REMOVAL);
|
||||
}
|
||||
public ModuleResolution withIncubating() {
|
||||
if ((value & (WARN_DEPRECATED | WARN_DEPRECATED_FOR_REMOVAL)) != 0)
|
||||
throw new InternalError("cannot add incubating to " + value);
|
||||
return new ModuleResolution(value | WARN_INCUBATING);
|
||||
}
|
||||
|
||||
public int value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static boolean doNotResolveByDefault(ModuleReference mref) {
|
||||
// get the DO_NOT_RESOLVE_BY_DEFAULT flag, if any
|
||||
if (!(mref instanceof ModuleReferenceImpl))
|
||||
return false;
|
||||
|
||||
ModuleResolution mres = ((ModuleReferenceImpl)mref).moduleResolution();
|
||||
if (mres != null)
|
||||
return mres.doNotResolveByDefault();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasIncubatingWarning(ModuleReference mref) {
|
||||
if (!(mref instanceof ModuleReferenceImpl))
|
||||
return false;
|
||||
|
||||
ModuleResolution mres = ((ModuleReferenceImpl)mref).moduleResolution();
|
||||
if (mres != null)
|
||||
return mres.hasIncubatingWarning();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "[value=" + value + "]";
|
||||
}
|
||||
}
|
@ -23,12 +23,16 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.module;
|
||||
package jdk.internal.module;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReader;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.net.URI;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -36,7 +40,6 @@ import java.util.ArrayDeque;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@ -54,11 +57,7 @@ import jdk.internal.jimage.ImageReader;
|
||||
import jdk.internal.jimage.ImageReaderFactory;
|
||||
import jdk.internal.misc.JavaNetUriAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.module.ModuleBootstrap;
|
||||
import jdk.internal.module.ModuleHashes;
|
||||
import jdk.internal.module.ModuleHashes.HashSupplier;
|
||||
import jdk.internal.module.SystemModules;
|
||||
import jdk.internal.module.ModulePatcher;
|
||||
import jdk.internal.perf.PerfCounter;
|
||||
|
||||
/**
|
||||
@ -69,7 +68,7 @@ import jdk.internal.perf.PerfCounter;
|
||||
* Packages attribute.
|
||||
*/
|
||||
|
||||
class SystemModuleFinder implements ModuleFinder {
|
||||
public class SystemModuleFinder implements ModuleFinder {
|
||||
|
||||
private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
|
||||
|
||||
@ -84,11 +83,12 @@ class SystemModuleFinder implements ModuleFinder {
|
||||
// ImageReader used to access all modules in the image
|
||||
private static final ImageReader imageReader;
|
||||
|
||||
// the set of modules in the run-time image
|
||||
private static final Set<ModuleReference> modules;
|
||||
// singleton finder to find modules in the run-time images
|
||||
private static final SystemModuleFinder INSTANCE;
|
||||
|
||||
// maps module name to module reference
|
||||
private static final Map<String, ModuleReference> nameToModule;
|
||||
public static SystemModuleFinder getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* For now, the module references are created eagerly on the assumption
|
||||
@ -98,72 +98,11 @@ class SystemModuleFinder implements ModuleFinder {
|
||||
long t0 = System.nanoTime();
|
||||
imageReader = ImageReaderFactory.getImageReader();
|
||||
|
||||
String[] names = moduleNames();
|
||||
ModuleDescriptor[] descriptors = descriptors(names);
|
||||
|
||||
int n = names.length;
|
||||
moduleCount.add(n);
|
||||
|
||||
ModuleReference[] mods = new ModuleReference[n];
|
||||
|
||||
@SuppressWarnings(value = {"rawtypes", "unchecked"})
|
||||
Entry<String, ModuleReference>[] map
|
||||
= (Entry<String, ModuleReference>[])new Entry[n];
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
ModuleDescriptor md = descriptors[i];
|
||||
|
||||
// create the ModuleReference
|
||||
ModuleReference mref = toModuleReference(md, hashSupplier(i, names[i]));
|
||||
|
||||
mods[i] = mref;
|
||||
map[i] = Map.entry(names[i], mref);
|
||||
|
||||
// counters
|
||||
packageCount.add(md.packages().size());
|
||||
exportsCount.add(md.exports().size());
|
||||
}
|
||||
|
||||
modules = Set.of(mods);
|
||||
nameToModule = Map.ofEntries(map);
|
||||
INSTANCE = new SystemModuleFinder();
|
||||
|
||||
initTime.addElapsedTimeFrom(t0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns an array of ModuleDescriptor of the given module names.
|
||||
*
|
||||
* This obtains ModuleDescriptors from SystemModules class that is generated
|
||||
* from the jlink system-modules plugin. ModuleDescriptors have already
|
||||
* been validated at link time.
|
||||
*
|
||||
* If java.base is patched, or fastpath is disabled for troubleshooting
|
||||
* purpose, it will fall back to find system modules via jrt file system.
|
||||
*/
|
||||
private static ModuleDescriptor[] descriptors(String[] names) {
|
||||
// fastpath is enabled by default.
|
||||
// It can be disabled for troubleshooting purpose.
|
||||
boolean disabled =
|
||||
System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
|
||||
|
||||
// fast loading of ModuleDescriptor of system modules
|
||||
if (isFastPathSupported() && !disabled)
|
||||
return SystemModules.modules();
|
||||
|
||||
// if fast loading of ModuleDescriptors is disabled
|
||||
// fallback to read module-info.class
|
||||
ModuleDescriptor[] descriptors = new ModuleDescriptor[names.length];
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
String mn = names[i];
|
||||
ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
|
||||
descriptors[i] = ModuleDescriptor.read(imageReader.getResourceBuffer(loc));
|
||||
|
||||
// add the recorded hashes of tied modules
|
||||
Hashes.add(descriptors[i]);
|
||||
}
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private static boolean isFastPathSupported() {
|
||||
return SystemModules.MODULE_NAMES.length > 0;
|
||||
}
|
||||
@ -178,69 +117,83 @@ class SystemModuleFinder implements ModuleFinder {
|
||||
return imageReader.getModuleNames();
|
||||
}
|
||||
|
||||
private static ModuleReference toModuleReference(ModuleDescriptor md,
|
||||
HashSupplier hash)
|
||||
{
|
||||
String mn = md.name();
|
||||
URI uri = JNUA.create("jrt", "/".concat(mn));
|
||||
// the set of modules in the run-time image
|
||||
private final Set<ModuleReference> modules;
|
||||
|
||||
Supplier<ModuleReader> readerSupplier = new Supplier<>() {
|
||||
@Override
|
||||
public ModuleReader get() {
|
||||
return new ImageModuleReader(mn, uri);
|
||||
}
|
||||
};
|
||||
// maps module name to module reference
|
||||
private final Map<String, ModuleReference> nameToModule;
|
||||
|
||||
ModuleReference mref =
|
||||
new ModuleReference(md, uri, readerSupplier, hash);
|
||||
// module name to hashes
|
||||
private final Map<String, byte[]> hashes = new HashMap<>();
|
||||
|
||||
// may need a reference to a patched module if --patch-module specified
|
||||
mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
|
||||
private SystemModuleFinder() {
|
||||
String[] names = moduleNames();
|
||||
int n = names.length;
|
||||
moduleCount.add(n);
|
||||
|
||||
return mref;
|
||||
}
|
||||
// fastpath is enabled by default.
|
||||
// It can be disabled for troubleshooting purpose.
|
||||
boolean disabled =
|
||||
System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
|
||||
|
||||
private static HashSupplier hashSupplier(int index, String name) {
|
||||
if (isFastPathSupported()) {
|
||||
return new HashSupplier() {
|
||||
@Override
|
||||
public byte[] generate(String algorithm) {
|
||||
return SystemModules.MODULES_TO_HASH[index];
|
||||
}
|
||||
};
|
||||
ModuleDescriptor[] descriptors;
|
||||
ModuleHashes[] recordedHashes;
|
||||
ModuleResolution[] moduleResolutions;
|
||||
|
||||
// fast loading of ModuleDescriptor of system modules
|
||||
if (isFastPathSupported() && !disabled) {
|
||||
descriptors = SystemModules.descriptors();
|
||||
recordedHashes = SystemModules.hashes();
|
||||
moduleResolutions = SystemModules.moduleResolutions();
|
||||
} else {
|
||||
return Hashes.hashFor(name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This helper class is only used when SystemModules is patched.
|
||||
* It will get the recorded hashes from module-info.class.
|
||||
*/
|
||||
private static class Hashes {
|
||||
static Map<String, byte[]> hashes = new HashMap<>();
|
||||
|
||||
static void add(ModuleDescriptor descriptor) {
|
||||
Optional<ModuleHashes> ohashes = descriptor.hashes();
|
||||
if (ohashes.isPresent()) {
|
||||
hashes.putAll(ohashes.get().hashes());
|
||||
// if fast loading of ModuleDescriptors is disabled
|
||||
// fallback to read module-info.class
|
||||
descriptors = new ModuleDescriptor[n];
|
||||
recordedHashes = new ModuleHashes[n];
|
||||
moduleResolutions = new ModuleResolution[n];
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
String mn = names[i];
|
||||
ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
|
||||
ModuleInfo.Attributes attrs =
|
||||
ModuleInfo.read(imageReader.getResourceBuffer(loc), null);
|
||||
descriptors[i] = attrs.descriptor();
|
||||
recordedHashes[i] = attrs.recordedHashes();
|
||||
moduleResolutions[i] = attrs.moduleResolution();
|
||||
}
|
||||
}
|
||||
|
||||
static HashSupplier hashFor(String name) {
|
||||
if (!hashes.containsKey(name))
|
||||
return null;
|
||||
|
||||
return new HashSupplier() {
|
||||
@Override
|
||||
public byte[] generate(String algorithm) {
|
||||
return hashes.get(name);
|
||||
}
|
||||
};
|
||||
// record the hashes to build HashSupplier
|
||||
for (ModuleHashes mh : recordedHashes) {
|
||||
if (mh != null) {
|
||||
hashes.putAll(mh.hashes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SystemModuleFinder() { }
|
||||
ModuleReference[] mods = new ModuleReference[n];
|
||||
|
||||
@SuppressWarnings(value = {"rawtypes", "unchecked"})
|
||||
Entry<String, ModuleReference>[] map
|
||||
= (Entry<String, ModuleReference>[])new Entry[n];
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
ModuleDescriptor md = descriptors[i];
|
||||
|
||||
// create the ModuleReference
|
||||
ModuleReference mref = toModuleReference(md,
|
||||
recordedHashes[i],
|
||||
hashSupplier(names[i]),
|
||||
moduleResolutions[i]);
|
||||
mods[i] = mref;
|
||||
map[i] = Map.entry(names[i], mref);
|
||||
|
||||
// counters
|
||||
packageCount.add(md.packages().size());
|
||||
exportsCount.add(md.exports().size());
|
||||
}
|
||||
|
||||
modules = Set.of(mods);
|
||||
nameToModule = Map.ofEntries(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ModuleReference> find(String name) {
|
||||
@ -253,6 +206,41 @@ class SystemModuleFinder implements ModuleFinder {
|
||||
return modules;
|
||||
}
|
||||
|
||||
private ModuleReference toModuleReference(ModuleDescriptor md,
|
||||
ModuleHashes recordedHashes,
|
||||
HashSupplier hasher,
|
||||
ModuleResolution mres) {
|
||||
String mn = md.name();
|
||||
URI uri = JNUA.create("jrt", "/".concat(mn));
|
||||
|
||||
Supplier<ModuleReader> readerSupplier = new Supplier<>() {
|
||||
@Override
|
||||
public ModuleReader get() {
|
||||
return new ImageModuleReader(mn, uri);
|
||||
}
|
||||
};
|
||||
|
||||
ModuleReference mref =
|
||||
new ModuleReferenceImpl(md, uri, readerSupplier, null,
|
||||
recordedHashes, hasher, mres);
|
||||
|
||||
// may need a reference to a patched module if --patch-module specified
|
||||
mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
|
||||
|
||||
return mref;
|
||||
}
|
||||
|
||||
private HashSupplier hashSupplier(String name) {
|
||||
if (!hashes.containsKey(name))
|
||||
return null;
|
||||
|
||||
return new HashSupplier() {
|
||||
@Override
|
||||
public byte[] generate(String algorithm) {
|
||||
return hashes.get(name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A ModuleReader for reading resources from a module linked into the
|
@ -29,14 +29,14 @@ import java.lang.module.ModuleDescriptor;
|
||||
|
||||
/*
|
||||
* SystemModules class will be generated at link time to create
|
||||
* ModuleDescriptor for the installed modules directly to improve
|
||||
* ModuleDescriptor for the system modules directly to improve
|
||||
* the module descriptor reconstitution time.
|
||||
*
|
||||
* This will skip parsing of module-info.class file and validating
|
||||
* names such as module name, package name, service and provider type names.
|
||||
* It also avoids taking a defensive copy of any collection.
|
||||
*
|
||||
* @see jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin
|
||||
* @see jdk.tools.jlink.internal.plugins.SystemModulesPlugin
|
||||
*/
|
||||
public final class SystemModules {
|
||||
/**
|
||||
@ -48,11 +48,6 @@ public final class SystemModules {
|
||||
*/
|
||||
public static final String[] MODULE_NAMES = new String[0];
|
||||
|
||||
/**
|
||||
* Hash of system modules.
|
||||
*/
|
||||
public static byte[][] MODULES_TO_HASH = new byte[0][];
|
||||
|
||||
/**
|
||||
* Number of packages in the boot layer from the installed modules.
|
||||
*
|
||||
@ -66,8 +61,24 @@ public final class SystemModules {
|
||||
*
|
||||
* When running an exploded image it returns an empty array.
|
||||
*/
|
||||
public static ModuleDescriptor[] modules() {
|
||||
throw new InternalError("should not reach here");
|
||||
public static ModuleDescriptor[] descriptors() {
|
||||
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.
|
||||
*
|
||||
* When running an exploded image it returns an empty array.
|
||||
*/
|
||||
public static ModuleHashes[] hashes() {
|
||||
throw new InternalError("expected to be overridden at link time");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a non-empty array of ModuleResolutions in the run-time image.
|
||||
*/
|
||||
public static ModuleResolution[] moduleResolutions() {
|
||||
throw new InternalError("expected to be overridden at link time");
|
||||
}
|
||||
}
|
||||
|
@ -2490,6 +2490,40 @@ public class ClassReader {
|
||||
return readUTF8(items[readUnsignedShort(index)], buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a CONSTANT_Module_info item in {@code b}. This method is intended
|
||||
* for {@link Attribute} sub classes, and is normally not needed by class
|
||||
* generators or adapters.</i>
|
||||
*
|
||||
* @param index
|
||||
* the start index of an unsigned short value in {@link #b b},
|
||||
* whose value is the index of a module constant pool item.
|
||||
* @param buf
|
||||
* buffer to be used to read the item. This buffer must be
|
||||
* sufficiently large. It is not automatically resized.
|
||||
* @return the String corresponding to the specified module item.
|
||||
*/
|
||||
public String readModule(int index, char[] buf) {
|
||||
return readUTF8(items[readUnsignedShort(index)], buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a CONSTANT_Pakcage_info item in {@code b}. This method is
|
||||
* intended for {@link Attribute} sub slasses, and is normally not needed
|
||||
* by class generators or adapters.</i>
|
||||
*
|
||||
* @param index
|
||||
* the start index of an unsigned short value in {@link #b b},
|
||||
* whose value is the index of a package constant pool item.
|
||||
* @param buf
|
||||
* buffer to be used to read the item. This buffer must be
|
||||
* sufficiently large. It is not automatically resized.
|
||||
* @return the String corresponding to the specified package item.
|
||||
*/
|
||||
public String readPackage(int index, char[] buf) {
|
||||
return readUTF8(items[readUnsignedShort(index)], buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a numeric or string constant pool item in {@link #b b}. <i>This
|
||||
* method is intended for {@link Attribute} sub classes, and is normally not
|
||||
@ -2516,6 +2550,8 @@ public class ClassReader {
|
||||
case ClassWriter.DOUBLE:
|
||||
return Double.longBitsToDouble(readLong(index));
|
||||
case ClassWriter.CLASS:
|
||||
case ClassWriter.MODULE:
|
||||
case ClassWriter.PACKAGE:
|
||||
return Type.getObjectType(readUTF8(index, buf));
|
||||
case ClassWriter.STR:
|
||||
return readUTF8(index, buf);
|
||||
|
@ -271,6 +271,16 @@ public class ClassWriter extends ClassVisitor {
|
||||
*/
|
||||
static final int INDY = 18;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_Module constant pool items.
|
||||
*/
|
||||
static final int MODULE = 19;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_Package constant pool items.
|
||||
*/
|
||||
static final int PACKAGE = 20;
|
||||
|
||||
/**
|
||||
* The base value for all CONSTANT_MethodHandle constant pool items.
|
||||
* Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9
|
||||
@ -1160,6 +1170,50 @@ public class ClassWriter extends ClassVisitor {
|
||||
return newClassItem(value).index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a module name to the constant pool.
|
||||
*
|
||||
* Does nothing if the constant pool already contains a similar item.
|
||||
* <i>This method is intended for {@link Attribute} sub classes, and is
|
||||
* normally not needed by class generators or adapters.</i>
|
||||
*
|
||||
* @param value
|
||||
* the module name
|
||||
* @return the index of a new or already existing module reference item.
|
||||
*/
|
||||
public int newModule(String value) {
|
||||
key2.set(MODULE, value, null, null);
|
||||
Item result = get(key2);
|
||||
if (result == null) {
|
||||
pool.put12(MODULE, newUTF8(value));
|
||||
result = new Item(index++, key2);
|
||||
put(result);
|
||||
}
|
||||
return result.index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a package name to the constant pool.
|
||||
*
|
||||
* Does nothing if the constant pool already contains a similar item.
|
||||
* <i>This method is intended for {@link Attribute} sub classes, and is
|
||||
* normally not needed by class generators or adapters.</i>
|
||||
*
|
||||
* @param value
|
||||
* the internal name of the package.
|
||||
* @return the index of a new or already existing package reference item.
|
||||
*/
|
||||
public int newPackage(String value) {
|
||||
key2.set(PACKAGE, value, null, null);
|
||||
Item result = get(key2);
|
||||
if (result == null) {
|
||||
pool.put12(PACKAGE, newUTF8(value));
|
||||
result = new Item(index++, key2);
|
||||
put(result);
|
||||
}
|
||||
return result.index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a method type reference to the constant pool of the class being
|
||||
* build. Does nothing if the constant pool already contains a similar item.
|
||||
|
@ -239,6 +239,8 @@ final class Item {
|
||||
this.strVal3 = strVal3;
|
||||
switch (type) {
|
||||
case ClassWriter.CLASS:
|
||||
case ClassWriter.MODULE:
|
||||
case ClassWriter.PACKAGE:
|
||||
this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
|
||||
case ClassWriter.UTF8:
|
||||
case ClassWriter.STR:
|
||||
@ -311,6 +313,8 @@ final class Item {
|
||||
case ClassWriter.UTF8:
|
||||
case ClassWriter.STR:
|
||||
case ClassWriter.CLASS:
|
||||
case ClassWriter.MODULE:
|
||||
case ClassWriter.PACKAGE:
|
||||
case ClassWriter.MTYPE:
|
||||
case ClassWriter.TYPE_NORMAL:
|
||||
return i.strVal1.equals(strVal1);
|
||||
|
@ -31,6 +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;
|
||||
|
||||
@ -218,8 +219,16 @@ public class Reflection {
|
||||
if (c.isPrimitive())
|
||||
return true;
|
||||
|
||||
// check that memberModule exports the package to currentModule
|
||||
return memberModule.isExported(c.getPackageName(), currentModule);
|
||||
String pkg = c.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);
|
||||
}
|
||||
}
|
||||
return allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -348,25 +357,43 @@ public class Reflection {
|
||||
}
|
||||
|
||||
|
||||
// true to print a stack trace when IAE is thrown
|
||||
// true to print a stack trace when access fails
|
||||
private static volatile boolean printStackWhenAccessFails;
|
||||
|
||||
// true if printStackWhenAccessFails has been initialized
|
||||
private static volatile boolean printStackWhenAccessFailsSet;
|
||||
// true to print a stack trace when access succeeds
|
||||
private static volatile boolean printStackWhenAccessSucceeds;
|
||||
|
||||
private static void printStackTraceIfNeeded(Throwable e) {
|
||||
if (!printStackWhenAccessFailsSet && VM.initLevel() >= 1) {
|
||||
// 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");
|
||||
printStackWhenAccessFails =
|
||||
(s != null && !s.equalsIgnoreCase("false"));
|
||||
printStackWhenAccessFailsSet = true;
|
||||
}
|
||||
if (printStackWhenAccessFails) {
|
||||
e.printStackTrace();
|
||||
if (s != null) {
|
||||
printStackWhenAccessFails = !s.equalsIgnoreCase("false");
|
||||
printStackWhenAccessSucceeds = s.equalsIgnoreCase("access");
|
||||
}
|
||||
printStackPropertiesSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void enableStackTraces() {
|
||||
printStackWhenAccessFails = true;
|
||||
printStackWhenAccessSucceeds = true;
|
||||
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
|
||||
* the access that is denied.
|
||||
@ -416,17 +443,10 @@ public class Reflection {
|
||||
throws IllegalAccessException
|
||||
{
|
||||
IllegalAccessException e = new IllegalAccessException(msg);
|
||||
printStackTraceIfNeeded(e);
|
||||
ensurePrintStackPropertiesSet();
|
||||
if (printStackWhenAccessFails) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws InaccessibleObjectException with the given exception message.
|
||||
*/
|
||||
public static void throwInaccessibleObjectException(String msg) {
|
||||
InaccessibleObjectException e = new InaccessibleObjectException(msg);
|
||||
printStackTraceIfNeeded(e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
import jdk.internal.module.ModuleResolution;
|
||||
|
||||
/**
|
||||
* Parser for GNU Style Options.
|
||||
@ -158,6 +159,31 @@ class GNUStyleOptions {
|
||||
ModuleFinder.of(paths));
|
||||
}
|
||||
},
|
||||
new Option(false, OptionType.CREATE_UPDATE, "--do-not-resolve-by-default") {
|
||||
void process(Main jartool, String opt, String arg) {
|
||||
ModuleResolution mres = jartool.moduleResolution;
|
||||
jartool.moduleResolution = mres.withDoNotResolveByDefault();
|
||||
}
|
||||
boolean isExtra() { return true; }
|
||||
},
|
||||
new Option(true, OptionType.CREATE_UPDATE, "--warn-if-resolved") {
|
||||
void process(Main jartool, String opt, String arg) throws BadArgs {
|
||||
ModuleResolution mres = ModuleResolution.empty();
|
||||
if (jartool.moduleResolution.doNotResolveByDefault())
|
||||
mres.withDoNotResolveByDefault();
|
||||
|
||||
if (arg.equals("deprecated")) {
|
||||
jartool.moduleResolution = mres.withDeprecated();
|
||||
} else if (arg.equals("deprecated-for-removal")) {
|
||||
jartool.moduleResolution = mres.withDeprecatedForRemoval();
|
||||
} else if (arg.equals("incubating")) {
|
||||
jartool.moduleResolution = mres.withIncubating();
|
||||
} else {
|
||||
throw new BadArgs("error.bad.reason", arg);
|
||||
}
|
||||
}
|
||||
boolean isExtra() { return true; }
|
||||
},
|
||||
new Option(false, OptionType.CREATE_UPDATE_INDEX, "--no-compress", "-0") {
|
||||
void process(Main jartool, String opt, String arg) {
|
||||
jartool.flag0 = true;
|
||||
@ -175,17 +201,20 @@ class GNUStyleOptions {
|
||||
// Other options
|
||||
new Option(true, true, OptionType.OTHER, "--help", "-h") {
|
||||
void process(Main jartool, String opt, String arg) throws BadArgs {
|
||||
if (jartool.info == null) {
|
||||
if (arg == null) {
|
||||
jartool.info = Main.Info.HELP;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!arg.equals("compat"))
|
||||
throw new BadArgs("error.illegal.option", arg).showUsage(true);
|
||||
|
||||
jartool.info = Main.Info.COMPAT_HELP;
|
||||
if (arg == null) {
|
||||
jartool.info = Main.Info.HELP;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!arg.equals("compat"))
|
||||
throw new BadArgs("error.illegal.option", arg).showUsage(true);
|
||||
|
||||
jartool.info = Main.Info.COMPAT_HELP;
|
||||
}
|
||||
},
|
||||
new Option(false, OptionType.OTHER, "--help-extra") {
|
||||
void process(Main jartool, String opt, String arg) throws BadArgs {
|
||||
jartool.info = Main.Info.HELP_EXTRA;
|
||||
}
|
||||
},
|
||||
new Option(false, OptionType.OTHER, "--version") {
|
||||
@ -229,6 +258,8 @@ class GNUStyleOptions {
|
||||
|
||||
boolean isHidden() { return false; }
|
||||
|
||||
boolean isExtra() { return false; }
|
||||
|
||||
boolean matches(String opt) {
|
||||
for (String a : aliases) {
|
||||
if (a.equals(opt)) {
|
||||
@ -292,6 +323,14 @@ class GNUStyleOptions {
|
||||
}
|
||||
|
||||
static void printHelp(PrintWriter out) {
|
||||
printHelp(out, false);
|
||||
}
|
||||
|
||||
static void printHelpExtra(PrintWriter out) {
|
||||
printHelp(out, true);
|
||||
}
|
||||
|
||||
private static void printHelp(PrintWriter out, boolean printExtra) {
|
||||
out.format("%s%n", Main.getMsg("main.help.preopt"));
|
||||
for (OptionType type : OptionType.values()) {
|
||||
boolean typeHeadingWritten = false;
|
||||
@ -304,6 +343,9 @@ class GNUStyleOptions {
|
||||
if (o.isHidden() || name.equals("h")) {
|
||||
continue;
|
||||
}
|
||||
if (o.isExtra() && !printExtra) {
|
||||
continue;
|
||||
}
|
||||
if (!typeHeadingWritten) {
|
||||
out.format("%n%s%n", Main.getMsg("main.help.opt." + type.name));
|
||||
typeHeadingWritten = true;
|
||||
|
@ -47,7 +47,6 @@ import java.nio.file.StandardCopyOption;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@ -57,11 +56,11 @@ import java.util.jar.Pack200.*;
|
||||
import java.util.jar.Manifest;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import jdk.internal.misc.JavaLangModuleAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.module.Checks;
|
||||
import jdk.internal.module.ModuleHashes;
|
||||
import jdk.internal.module.ModuleInfo;
|
||||
import jdk.internal.module.ModuleInfoExtender;
|
||||
import jdk.internal.module.ModuleResolution;
|
||||
import jdk.internal.util.jar.JarIndex;
|
||||
|
||||
import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
|
||||
@ -211,6 +210,7 @@ class Main {
|
||||
/* To support additional GNU Style informational options */
|
||||
enum Info {
|
||||
HELP(GNUStyleOptions::printHelp),
|
||||
HELP_EXTRA(GNUStyleOptions::printHelpExtra),
|
||||
COMPAT_HELP(GNUStyleOptions::printCompatHelp),
|
||||
USAGE_TRYHELP(GNUStyleOptions::printUsageTryHelp),
|
||||
VERSION(GNUStyleOptions::printVersion);
|
||||
@ -225,6 +225,7 @@ class Main {
|
||||
/* Modular jar related options */
|
||||
Version moduleVersion;
|
||||
Pattern modulesToHash;
|
||||
ModuleResolution moduleResolution = ModuleResolution.empty();
|
||||
ModuleFinder moduleFinder = ModuleFinder.of();
|
||||
|
||||
private static final String MODULE_INFO = "module-info.class";
|
||||
@ -1991,12 +1992,13 @@ class Main {
|
||||
.collect(joining(" "));
|
||||
}
|
||||
|
||||
private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
|
||||
|
||||
private void printModuleDescriptor(InputStream entryInputStream)
|
||||
throws IOException
|
||||
{
|
||||
ModuleDescriptor md = ModuleDescriptor.read(entryInputStream);
|
||||
ModuleInfo.Attributes attrs = ModuleInfo.read(entryInputStream, null);
|
||||
ModuleDescriptor md = attrs.descriptor();
|
||||
ModuleHashes hashes = attrs.recordedHashes();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\n");
|
||||
if (md.isOpen())
|
||||
@ -2043,15 +2045,24 @@ class Main {
|
||||
|
||||
md.osVersion().ifPresent(v -> sb.append("\n operating-system-version " + v));
|
||||
|
||||
JLMA.hashes(md).ifPresent(hashes ->
|
||||
hashes.names().stream().sorted().forEach(
|
||||
if (hashes != null) {
|
||||
hashes.names().stream().sorted().forEach(
|
||||
mod -> sb.append("\n hashes ").append(mod).append(" ")
|
||||
.append(hashes.algorithm()).append(" ")
|
||||
.append(hashes.hashFor(mod))));
|
||||
.append(toHex(hashes.hashFor(mod))));
|
||||
}
|
||||
|
||||
output(sb.toString());
|
||||
}
|
||||
|
||||
private static String toHex(byte[] ba) {
|
||||
StringBuilder sb = new StringBuilder(ba.length);
|
||||
for (byte b: ba) {
|
||||
sb.append(String.format("%02x", b & 0xff));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String toBinaryName(String classname) {
|
||||
return (classname.replace('.', '/')) + ".class";
|
||||
}
|
||||
@ -2212,6 +2223,10 @@ class Main {
|
||||
}
|
||||
}
|
||||
|
||||
if (moduleResolution.value() != 0) {
|
||||
extender.moduleResolution(moduleResolution);
|
||||
}
|
||||
|
||||
extender.write(baos);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
@ -2228,13 +2243,12 @@ class Main {
|
||||
// Create a module finder that finds the modular JAR
|
||||
// being created/updated
|
||||
URI uri = Paths.get(fname).toUri();
|
||||
ModuleReference mref = new ModuleReference(descriptor, uri,
|
||||
new Supplier<>() {
|
||||
@Override
|
||||
public ModuleReader get() {
|
||||
throw new UnsupportedOperationException("should not reach here");
|
||||
}
|
||||
});
|
||||
ModuleReference mref = new ModuleReference(descriptor, uri) {
|
||||
@Override
|
||||
public ModuleReader open() {
|
||||
throw new UnsupportedOperationException("should not reach here");
|
||||
}
|
||||
};
|
||||
|
||||
// Compose a module finder with the module path and
|
||||
// the modular JAR being created or updated
|
||||
|
@ -46,6 +46,8 @@ error.bad.eflag=\
|
||||
together!
|
||||
error.bad.dflag=\
|
||||
'-d, --print-module-descriptor' option requires no input file(s) to be specified: {0}
|
||||
error.bad.reason=\
|
||||
bad reason: {0}, must be one of deprecated, deprecated-for-removal, or incubating
|
||||
error.nosuch.fileordir=\
|
||||
{0} : no such file or directory
|
||||
error.write.file=\
|
||||
@ -246,6 +248,12 @@ main.help.opt.create.update.hash-modules=\
|
||||
main.help.opt.create.update.module-path=\
|
||||
\ -p, --module-path Location of module dependence for generating\n\
|
||||
\ the hash
|
||||
main.help.opt.create.update.do-not-resolve-by-default=\
|
||||
\ --do-not-resolve-by-default Exclude from the default root set of modules
|
||||
main.help.opt.create.update.warn-if-resolved=\
|
||||
\ --warn-if-resolved Hint for a tool to issue a warning if the module\n\
|
||||
\ is resolved. One of deprecated, deprecated-for-removal,\n\
|
||||
\ or incubating
|
||||
main.help.opt.create.update.index=\
|
||||
\ Operation modifiers valid only in create, update, and generate-index mode:\n
|
||||
main.help.opt.create.update.index.no-compress=\
|
||||
@ -254,6 +262,8 @@ main.help.opt.other=\
|
||||
\ Other options:\n
|
||||
main.help.opt.other.help=\
|
||||
\ -?, --help[:compat] Give this, or optionally the compatibility, help
|
||||
main.help.opt.other.help-extra=\
|
||||
\ --help-extra Give help on extra options
|
||||
main.help.opt.other.version=\
|
||||
\ --version Print program version
|
||||
main.help.postopt=\
|
||||
|
@ -53,7 +53,9 @@ 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.misc.SharedSecrets;
|
||||
import jdk.internal.module.Checks;
|
||||
import jdk.internal.module.ModulePath;
|
||||
import jdk.internal.module.ModuleResolution;
|
||||
|
||||
/**
|
||||
* Implementation for the jlink tool.
|
||||
@ -260,7 +262,8 @@ public class JlinkTask {
|
||||
config.getModules(),
|
||||
config.getByteOrder(),
|
||||
null,
|
||||
IGNORE_SIGNING_DEFAULT);
|
||||
IGNORE_SIGNING_DEFAULT,
|
||||
null);
|
||||
|
||||
// Then create the Plugin Stack
|
||||
ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(plugins);
|
||||
@ -328,7 +331,8 @@ public class JlinkTask {
|
||||
roots,
|
||||
options.endian,
|
||||
options.packagedModulesPath,
|
||||
options.ignoreSigning);
|
||||
options.ignoreSigning,
|
||||
log);
|
||||
|
||||
// Then create the Plugin Stack
|
||||
ImagePluginStack stack = ImagePluginConfiguration.
|
||||
@ -344,9 +348,7 @@ public class JlinkTask {
|
||||
*/
|
||||
private ModuleFinder modulePathFinder() {
|
||||
Path[] entries = options.modulePath.toArray(new Path[0]);
|
||||
ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
|
||||
.newModulePath(Runtime.version(), true, entries);
|
||||
|
||||
ModuleFinder finder = new ModulePath(Runtime.version(), true, entries);
|
||||
if (!options.limitMods.isEmpty()) {
|
||||
finder = limitFinder(finder, options.limitMods, Collections.emptySet());
|
||||
}
|
||||
@ -364,8 +366,7 @@ public class JlinkTask {
|
||||
Set<String> roots)
|
||||
{
|
||||
Path[] entries = paths.toArray(new Path[0]);
|
||||
ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
|
||||
.newModulePath(Runtime.version(), true, entries);
|
||||
ModuleFinder finder = new ModulePath(Runtime.version(), true, entries);
|
||||
|
||||
// if limitmods is specified then limit the universe
|
||||
if (!limitMods.isEmpty()) {
|
||||
@ -386,7 +387,8 @@ public class JlinkTask {
|
||||
Set<String> roots,
|
||||
ByteOrder order,
|
||||
Path retainModulesPath,
|
||||
boolean ignoreSigning)
|
||||
boolean ignoreSigning,
|
||||
PrintWriter log)
|
||||
throws IOException
|
||||
{
|
||||
if (roots.isEmpty()) {
|
||||
@ -398,6 +400,27 @@ 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()
|
||||
.stream()
|
||||
.map(ResolvedModule::reference)
|
||||
.filter(ModuleResolution::hasIncubatingWarning)
|
||||
.map(ModuleReference::descriptor)
|
||||
.map(ModuleDescriptor::name)
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
if (!"".equals(im))
|
||||
log.println("WARNING: Using incubator modules: " + im);
|
||||
}
|
||||
|
||||
Map<String, Path> mods = cf.modules().stream()
|
||||
.collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation));
|
||||
return new ImageHelper(cf, mods, order, retainModulesPath, ignoreSigning);
|
||||
|
@ -28,6 +28,7 @@ package jdk.tools.jlink.internal;
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReader;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
@ -78,10 +79,12 @@ final class ResourcePoolConfiguration {
|
||||
}
|
||||
|
||||
private static ModuleReference moduleReference(ModuleDescriptor desc) {
|
||||
return new ModuleReference(desc, null, () -> {
|
||||
IOException ioe = new IOException("<module reader unsupported>");
|
||||
throw new UncheckedIOException(ioe);
|
||||
});
|
||||
return new ModuleReference(desc, null) {
|
||||
@Override
|
||||
public ModuleReader open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Map<String, ModuleReference> allModRefs(ResourcePool pool) {
|
||||
|
@ -58,7 +58,7 @@ import jdk.tools.jlink.internal.Jlink.PluginsConfiguration;
|
||||
import jdk.tools.jlink.internal.plugins.PluginsResourceBundle;
|
||||
import jdk.tools.jlink.internal.plugins.DefaultCompressPlugin;
|
||||
import jdk.tools.jlink.internal.plugins.StripDebugPlugin;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.module.ModulePath;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -765,9 +765,7 @@ public final class TaskHelper {
|
||||
static Layer createPluginsLayer(List<Path> paths) {
|
||||
|
||||
Path[] dirs = paths.toArray(new Path[0]);
|
||||
ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
|
||||
.newModulePath(Runtime.version(), true, dirs);
|
||||
|
||||
ModuleFinder finder = new ModulePath(Runtime.version(), true, dirs);
|
||||
Configuration bootConfiguration = Layer.boot().configuration();
|
||||
try {
|
||||
Configuration cf = bootConfiguration
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,17 +34,19 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
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.TreeSet;
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
import jdk.internal.misc.JavaLangModuleAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.module.Checks;
|
||||
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.SystemModules;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
@ -55,7 +57,6 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
import jdk.tools.jlink.plugin.PluginException;
|
||||
import jdk.tools.jlink.plugin.ResourcePool;
|
||||
import jdk.tools.jlink.plugin.Plugin;
|
||||
import jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin.SystemModulesClassGenerator.*;
|
||||
import jdk.tools.jlink.plugin.ResourcePoolBuilder;
|
||||
import jdk.tools.jlink.plugin.ResourcePoolEntry;
|
||||
|
||||
@ -67,10 +68,10 @@ import jdk.tools.jlink.plugin.ResourcePoolEntry;
|
||||
*
|
||||
* This plugin will override jdk.internal.module.SystemModules class
|
||||
*
|
||||
* @see java.lang.module.SystemModuleFinder
|
||||
* @see jdk.internal.module.SystemModuleFinder
|
||||
* @see SystemModules
|
||||
*/
|
||||
public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
public final class SystemModulesPlugin implements Plugin {
|
||||
private static final JavaLangModuleAccess JLMA =
|
||||
SharedSecrets.getJavaLangModuleAccess();
|
||||
|
||||
@ -79,7 +80,7 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
PluginsResourceBundle.getDescription(NAME);
|
||||
|
||||
private boolean enabled;
|
||||
public SystemModuleDescriptorPlugin() {
|
||||
public SystemModulesPlugin() {
|
||||
this.enabled = true;
|
||||
}
|
||||
|
||||
@ -126,20 +127,18 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
|
||||
assert module.name().equals(data.moduleName());
|
||||
try {
|
||||
ByteArrayInputStream bain = new ByteArrayInputStream(data.contentBytes());
|
||||
ModuleDescriptor md = ModuleDescriptor.read(bain);
|
||||
validateNames(md);
|
||||
ModuleInfo moduleInfo = new ModuleInfo(data.contentBytes(), module.packages());
|
||||
generator.addModule(moduleInfo);
|
||||
|
||||
Set<String> packages = module.packages();
|
||||
generator.addModule(md, module.packages());
|
||||
// link-time validation
|
||||
moduleInfo.validateNames();
|
||||
// check if any exported or open package is not present
|
||||
moduleInfo.validatePackages();
|
||||
|
||||
// add Packages attribute if not exist
|
||||
if (md.packages().isEmpty() && packages.size() > 0) {
|
||||
bain.reset();
|
||||
ModuleInfoRewriter minfoWriter =
|
||||
new ModuleInfoRewriter(bain, module.packages());
|
||||
// Packages attribute needs update
|
||||
if (moduleInfo.shouldAddPackagesAttribute()) {
|
||||
// replace with the overridden version
|
||||
data = data.copyWithContent(minfoWriter.getBytes());
|
||||
data = data.copyWithContent(moduleInfo.getBytes());
|
||||
}
|
||||
out.add(data);
|
||||
} catch (IOException e) {
|
||||
@ -164,61 +163,119 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
return out.build();
|
||||
}
|
||||
|
||||
/*
|
||||
* Add Packages attribute
|
||||
*/
|
||||
class ModuleInfoRewriter extends ByteArrayOutputStream {
|
||||
final ModuleInfoExtender extender;
|
||||
ModuleInfoRewriter(InputStream in, Set<String> packages) throws IOException {
|
||||
this.extender = ModuleInfoExtender.newExtender(in);
|
||||
// Add Packages attribute
|
||||
this.extender.packages(packages);
|
||||
this.extender.write(this);
|
||||
class ModuleInfo {
|
||||
final ModuleDescriptor descriptor;
|
||||
final ModuleHashes recordedHashes;
|
||||
final ModuleResolution moduleResolution;
|
||||
final Set<String> packages;
|
||||
final ByteArrayInputStream bain;
|
||||
|
||||
ModuleInfo(byte[] bytes, Set<String> packages) throws IOException {
|
||||
this.bain = new ByteArrayInputStream(bytes);
|
||||
this.packages = packages;
|
||||
|
||||
Attributes attrs = jdk.internal.module.ModuleInfo.read(bain, null);
|
||||
this.descriptor = attrs.descriptor();
|
||||
this.recordedHashes = attrs.recordedHashes();
|
||||
this.moduleResolution = attrs.moduleResolution();
|
||||
|
||||
if (descriptor.isAutomatic()) {
|
||||
throw new InternalError("linking automatic module is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
byte[] getBytes() {
|
||||
return buf;
|
||||
String moduleName() {
|
||||
return descriptor.name();
|
||||
}
|
||||
}
|
||||
|
||||
void validateNames(ModuleDescriptor md) {
|
||||
Checks.requireModuleName(md.name());
|
||||
for (Requires req : md.requires()) {
|
||||
Checks.requireModuleName(req.name());
|
||||
/**
|
||||
* Validates names in ModuleDescriptor
|
||||
*/
|
||||
void validateNames() {
|
||||
Checks.requireModuleName(descriptor.name());
|
||||
for (Requires req : descriptor.requires()) {
|
||||
Checks.requireModuleName(req.name());
|
||||
}
|
||||
for (Exports e : descriptor.exports()) {
|
||||
Checks.requirePackageName(e.source());
|
||||
if (e.isQualified())
|
||||
e.targets().forEach(Checks::requireModuleName);
|
||||
}
|
||||
for (Opens opens : descriptor.opens()) {
|
||||
Checks.requirePackageName(opens.source());
|
||||
if (opens.isQualified())
|
||||
opens.targets().forEach(Checks::requireModuleName);
|
||||
}
|
||||
for (Provides provides : descriptor.provides()) {
|
||||
Checks.requireServiceTypeName(provides.service());
|
||||
provides.providers().forEach(Checks::requireServiceProviderName);
|
||||
}
|
||||
for (String service : descriptor.uses()) {
|
||||
Checks.requireServiceTypeName(service);
|
||||
}
|
||||
for (String pn : descriptor.packages()) {
|
||||
Checks.requirePackageName(pn);
|
||||
}
|
||||
}
|
||||
for (Exports e : md.exports()) {
|
||||
Checks.requirePackageName(e.source());
|
||||
if (e.isQualified())
|
||||
e.targets().forEach(Checks::requireModuleName);
|
||||
}
|
||||
for (Opens opens : md.opens()) {
|
||||
Checks.requirePackageName(opens.source());
|
||||
if (opens.isQualified())
|
||||
opens.targets().forEach(Checks::requireModuleName);
|
||||
}
|
||||
for (Provides provides : md.provides()) {
|
||||
Checks.requireServiceTypeName(provides.service());
|
||||
provides.providers().forEach(Checks::requireServiceProviderName);
|
||||
}
|
||||
for (String service : md.uses()) {
|
||||
Checks.requireServiceTypeName(service);
|
||||
}
|
||||
for (String pn : md.packages()) {
|
||||
Checks.requirePackageName(pn);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the initial capacity for a new Set or Map of the given size
|
||||
* to avoid resizing.
|
||||
*/
|
||||
static final int initialCapacity(int size) {
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
// Adjust to try and get size/capacity as close to the
|
||||
// HashSet/HashMap default load factor without going over.
|
||||
return (int)(Math.ceil((double)size / 0.75));
|
||||
|
||||
/**
|
||||
* Validates if exported and open packages are present
|
||||
*/
|
||||
void validatePackages() {
|
||||
Set<String> nonExistPackages = new TreeSet<>();
|
||||
descriptor.exports().stream()
|
||||
.map(Exports::source)
|
||||
.filter(pn -> !packages.contains(pn))
|
||||
.forEach(nonExistPackages::add);
|
||||
|
||||
descriptor.opens().stream()
|
||||
.map(Opens::source)
|
||||
.filter(pn -> !packages.contains(pn))
|
||||
.forEach(nonExistPackages::add);
|
||||
|
||||
if (!nonExistPackages.isEmpty()) {
|
||||
throw new PluginException("Packages that are exported or open in "
|
||||
+ descriptor.name() + " are not present: " + nonExistPackages);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the PackagesAttribute should be written
|
||||
*/
|
||||
boolean shouldAddPackagesAttribute() {
|
||||
return descriptor.packages().isEmpty() && packages.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bytes for the module-info.class with PackagesAttribute
|
||||
* if it contains at least one package
|
||||
*/
|
||||
byte[] getBytes() throws IOException {
|
||||
bain.reset();
|
||||
|
||||
// add Packages attribute if not exist
|
||||
if (shouldAddPackagesAttribute()) {
|
||||
return new ModuleInfoRewriter(bain, packages).getBytes();
|
||||
} else {
|
||||
return bain.readAllBytes();
|
||||
}
|
||||
}
|
||||
|
||||
class ModuleInfoRewriter extends ByteArrayOutputStream {
|
||||
final ModuleInfoExtender extender;
|
||||
ModuleInfoRewriter(InputStream in, Set<String> packages) throws IOException {
|
||||
this.extender = ModuleInfoExtender.newExtender(in);
|
||||
// Add Packages attribute
|
||||
if (packages.size() > 0) {
|
||||
this.extender.packages(packages);
|
||||
}
|
||||
this.extender.write(this);
|
||||
}
|
||||
|
||||
byte[] getBytes() {
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,30 +296,31 @@ public final class SystemModuleDescriptorPlugin 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_HASHES_ARRAY_SIGNATURE =
|
||||
"[Ljdk/internal/module/ModuleHashes;";
|
||||
private static final String MODULE_RESOLUTION_CLASSNAME =
|
||||
"jdk/internal/module/ModuleResolution";
|
||||
private static final String MODULE_RESOLUTIONS_ARRAY_SIGNATURE =
|
||||
"[Ljdk/internal/module/ModuleResolution;";
|
||||
|
||||
// static variables in SystemModules class
|
||||
private static final String MODULE_NAMES = "MODULE_NAMES";
|
||||
private static final String MODULES_TO_HASH = "MODULES_TO_HASH";
|
||||
private static final String PACKAGE_COUNT = "PACKAGES_IN_BOOT_LAYER";
|
||||
|
||||
private static final int MAX_LOCAL_VARS = 256;
|
||||
|
||||
private final int BUILDER_VAR = 0;
|
||||
private final int MD_VAR = 1; // variable for ModuleDescriptor
|
||||
private final int MH_VAR = 1; // variable for ModuleHashes
|
||||
private int nextLocalVar = 2; // index to next local variable
|
||||
|
||||
private final ClassWriter cw;
|
||||
|
||||
// Method visitor for generating the SystemModules::modules() method
|
||||
private MethodVisitor mv;
|
||||
private int nextModulesIndex = 0;
|
||||
|
||||
// list of all ModuleDescriptorBuilders, invoked in turn when building.
|
||||
private final List<ModuleDescriptorBuilder> builders = new ArrayList<>();
|
||||
|
||||
// module name to hash
|
||||
private final Map<String, byte[]> modulesToHash = new HashMap<>();
|
||||
|
||||
// module name to index in MODULES_TO_HASH
|
||||
private final Map<String, Integer> modulesToHashIndex = new HashMap<>();
|
||||
private final List<ModuleInfo> moduleInfos = new ArrayList<>();
|
||||
|
||||
// A builder to create one single Set instance for a given set of
|
||||
// names or modifiers to reduce the footprint
|
||||
@ -293,66 +351,34 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
"[Ljava/lang/String;", null, null)
|
||||
.visitEnd();
|
||||
|
||||
// public static byte[][] MODULES_TO_HASH
|
||||
cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULES_TO_HASH,
|
||||
"[[B", null, null)
|
||||
.visitEnd();
|
||||
|
||||
// public static int PACKAGES_IN_BOOT_LAYER;
|
||||
cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, PACKAGE_COUNT,
|
||||
"I", null, numPackages)
|
||||
.visitEnd();
|
||||
|
||||
this.mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V",
|
||||
null, null);
|
||||
mv.visitCode();
|
||||
MethodVisitor clinit =
|
||||
cw.visitMethod(ACC_STATIC, "<clinit>", "()V",
|
||||
null, null);
|
||||
clinit.visitCode();
|
||||
|
||||
// create the MODULE_NAMES array
|
||||
pushInt(numModules);
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
|
||||
pushInt(clinit, numModules);
|
||||
clinit.visitTypeInsn(ANEWARRAY, "java/lang/String");
|
||||
|
||||
int index = 0;
|
||||
for (ModuleDescriptorBuilder builder : builders) {
|
||||
mv.visitInsn(DUP); // arrayref
|
||||
pushInt(index++);
|
||||
mv.visitLdcInsn(builder.md.name()); // value
|
||||
mv.visitInsn(AASTORE);
|
||||
for (ModuleInfo minfo : moduleInfos) {
|
||||
clinit.visitInsn(DUP); // arrayref
|
||||
pushInt(clinit, index++);
|
||||
clinit.visitLdcInsn(minfo.moduleName()); // value
|
||||
clinit.visitInsn(AASTORE);
|
||||
}
|
||||
|
||||
mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULE_NAMES,
|
||||
clinit.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULE_NAMES,
|
||||
"[Ljava/lang/String;");
|
||||
|
||||
// create the MODULES_TO_HASH array
|
||||
pushInt(numModules);
|
||||
mv.visitTypeInsn(ANEWARRAY, "[B");
|
||||
|
||||
index = 0;
|
||||
for (ModuleDescriptorBuilder builder : builders) {
|
||||
String mn = builder.md.name();
|
||||
byte[] recordedHash = modulesToHash.get(mn);
|
||||
if (recordedHash != null) {
|
||||
mv.visitInsn(DUP); // arrayref
|
||||
pushInt(index);
|
||||
pushInt(recordedHash.length);
|
||||
mv.visitIntInsn(NEWARRAY, T_BYTE);
|
||||
for (int i = 0; i < recordedHash.length; i++) {
|
||||
mv.visitInsn(DUP); // arrayref
|
||||
pushInt(i);
|
||||
mv.visitIntInsn(BIPUSH, recordedHash[i]);
|
||||
mv.visitInsn(BASTORE);
|
||||
}
|
||||
mv.visitInsn(AASTORE);
|
||||
modulesToHashIndex.put(mn, index);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULES_TO_HASH, "[[B");
|
||||
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
|
||||
clinit.visitInsn(RETURN);
|
||||
clinit.visitMaxs(0, 0);
|
||||
clinit.visitEnd();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -360,9 +386,9 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
* prepares mapping from various Sets to SetBuilders to emit an
|
||||
* optimized number of sets during build.
|
||||
*/
|
||||
public void addModule(ModuleDescriptor md, Set<String> packages) {
|
||||
ModuleDescriptorBuilder builder = new ModuleDescriptorBuilder(md, packages);
|
||||
builders.add(builder);
|
||||
public void addModule(ModuleInfo moduleInfo) {
|
||||
ModuleDescriptor md = moduleInfo.descriptor;
|
||||
moduleInfos.add(moduleInfo);
|
||||
|
||||
// exports
|
||||
for (Exports e : md.exports()) {
|
||||
@ -383,45 +409,129 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
|
||||
// uses
|
||||
dedupSetBuilder.stringSet(md.uses());
|
||||
|
||||
// hashes
|
||||
JLMA.hashes(md).ifPresent(mh -> modulesToHash.putAll(mh.hashes()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate bytecode for SystemModules
|
||||
*/
|
||||
public ClassWriter getClassWriter() {
|
||||
int numModules = builders.size();
|
||||
int numModules = moduleInfos.size();
|
||||
int numPackages = 0;
|
||||
for (ModuleDescriptorBuilder builder : builders) {
|
||||
numPackages += builder.md.packages().size();
|
||||
for (ModuleInfo minfo : moduleInfos) {
|
||||
numPackages += minfo.packages.size();
|
||||
}
|
||||
|
||||
this.clinit(numModules, numPackages);
|
||||
this.mv = cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
|
||||
"modules", "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
|
||||
"()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE, null);
|
||||
clinit(numModules, numPackages);
|
||||
|
||||
// generate SystemModules::descriptors
|
||||
genDescriptorsMethod();
|
||||
// generate SystemModules::hashes
|
||||
genHashesMethod();
|
||||
// generate SystemModules::moduleResolutions
|
||||
genModuleResolutionsMethod();
|
||||
|
||||
return cw;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate bytecode for SystemModules::descriptors method
|
||||
*/
|
||||
private void genDescriptorsMethod() {
|
||||
this.mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
|
||||
"descriptors",
|
||||
"()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
|
||||
"()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
|
||||
null);
|
||||
mv.visitCode();
|
||||
pushInt(numModules);
|
||||
pushInt(mv, moduleInfos.size());
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor");
|
||||
mv.visitVarInsn(ASTORE, MD_VAR);
|
||||
|
||||
for (ModuleDescriptorBuilder builder : builders) {
|
||||
builder.build();
|
||||
for (int index = 0; index < moduleInfos.size(); index++) {
|
||||
ModuleInfo minfo = moduleInfos.get(index);
|
||||
new ModuleDescriptorBuilder(minfo.descriptor,
|
||||
minfo.packages,
|
||||
index).build();
|
||||
}
|
||||
mv.visitVarInsn(ALOAD, MD_VAR);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
return cw;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate bytecode for SystemModules::hashes method
|
||||
*/
|
||||
private void genHashesMethod() {
|
||||
MethodVisitor hmv =
|
||||
cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
|
||||
"hashes",
|
||||
"()" + MODULE_HASHES_ARRAY_SIGNATURE,
|
||||
"()" + MODULE_HASHES_ARRAY_SIGNATURE,
|
||||
null);
|
||||
hmv.visitCode();
|
||||
pushInt(hmv, moduleInfos.size());
|
||||
hmv.visitTypeInsn(ANEWARRAY, "jdk/internal/module/ModuleHashes");
|
||||
hmv.visitVarInsn(ASTORE, MH_VAR);
|
||||
|
||||
for (int index = 0; index < moduleInfos.size(); index++) {
|
||||
ModuleInfo minfo = moduleInfos.get(index);
|
||||
if (minfo.recordedHashes != null) {
|
||||
new ModuleHashesBuilder(minfo.recordedHashes,
|
||||
index,
|
||||
hmv).build();
|
||||
}
|
||||
}
|
||||
|
||||
hmv.visitVarInsn(ALOAD, MH_VAR);
|
||||
hmv.visitInsn(ARETURN);
|
||||
hmv.visitMaxs(0, 0);
|
||||
hmv.visitEnd();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate bytecode for SystemModules::methodResoultions method
|
||||
*/
|
||||
private void genModuleResolutionsMethod() {
|
||||
MethodVisitor mresmv =
|
||||
cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
|
||||
"moduleResolutions",
|
||||
"()" + MODULE_RESOLUTIONS_ARRAY_SIGNATURE,
|
||||
"()" + MODULE_RESOLUTIONS_ARRAY_SIGNATURE,
|
||||
null);
|
||||
mresmv.visitCode();
|
||||
pushInt(mresmv, moduleInfos.size());
|
||||
mresmv.visitTypeInsn(ANEWARRAY, MODULE_RESOLUTION_CLASSNAME);
|
||||
mresmv.visitVarInsn(ASTORE, 0);
|
||||
|
||||
for (int index=0; index < moduleInfos.size(); index++) {
|
||||
ModuleInfo minfo = moduleInfos.get(index);
|
||||
if (minfo.moduleResolution != null) {
|
||||
mresmv.visitVarInsn(ALOAD, 0);
|
||||
pushInt(mresmv, index);
|
||||
mresmv.visitTypeInsn(NEW, MODULE_RESOLUTION_CLASSNAME);
|
||||
mresmv.visitInsn(DUP);
|
||||
mresmv.visitLdcInsn(minfo.moduleResolution.value());
|
||||
mresmv.visitMethodInsn(INVOKESPECIAL,
|
||||
MODULE_RESOLUTION_CLASSNAME,
|
||||
"<init>",
|
||||
"(I)V", false);
|
||||
mresmv.visitInsn(AASTORE);
|
||||
}
|
||||
}
|
||||
mresmv.visitVarInsn(ALOAD, 0);
|
||||
mresmv.visitInsn(ARETURN);
|
||||
mresmv.visitMaxs(0, 0);
|
||||
mresmv.visitEnd();
|
||||
}
|
||||
|
||||
public boolean isOverriddenClass(String path) {
|
||||
return path.equals("/java.base/" + CLASSNAME + ".class");
|
||||
}
|
||||
|
||||
void pushInt(int num) {
|
||||
void pushInt(MethodVisitor mv, int num) {
|
||||
if (num <= 5) {
|
||||
mv.visitInsn(ICONST_0 + num);
|
||||
} else if (num < Byte.MAX_VALUE) {
|
||||
@ -460,6 +570,8 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
"(Ljava/lang/String;Ljava/util/List;)" + PROVIDES_TYPE;
|
||||
static final String REQUIRES_SET_STRING_SIG =
|
||||
"(Ljava/util/Set;Ljava/lang/String;)" + REQUIRES_TYPE;
|
||||
static final String REQUIRES_SET_STRING_STRING_SIG =
|
||||
"(Ljava/util/Set;Ljava/lang/String;Ljava/lang/String;)" + REQUIRES_TYPE;
|
||||
|
||||
// method signature for Builder instance methods that
|
||||
// return this Builder instance
|
||||
@ -473,20 +585,18 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
"([" + REQUIRES_TYPE + ")" + BUILDER_TYPE;
|
||||
static final String SET_SIG = "(Ljava/util/Set;)" + BUILDER_TYPE;
|
||||
static final String STRING_SIG = "(Ljava/lang/String;)" + BUILDER_TYPE;
|
||||
static final String STRING_BYTE_ARRAY_SIG =
|
||||
"(Ljava/lang/String;[B)" + BUILDER_TYPE;
|
||||
static final String BOOLEAN_SIG = "(Z)" + BUILDER_TYPE;
|
||||
|
||||
|
||||
final ModuleDescriptor md;
|
||||
final Set<String> packages;
|
||||
|
||||
ModuleDescriptorBuilder(ModuleDescriptor md, Set<String> packages) {
|
||||
final int index;
|
||||
ModuleDescriptorBuilder(ModuleDescriptor md, Set<String> packages, int index) {
|
||||
if (md.isAutomatic()) {
|
||||
throw new InternalError("linking automatic module is not supported");
|
||||
}
|
||||
this.md = md;
|
||||
this.packages = packages;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
void build() {
|
||||
@ -517,12 +627,6 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
// main class
|
||||
md.mainClass().ifPresent(this::mainClass);
|
||||
|
||||
// hashes
|
||||
JLMA.hashes(md).ifPresent(mh -> {
|
||||
algorithm(mh.algorithm());
|
||||
mh.names().forEach(mn -> moduleHash(mn, mh.hashFor(mn)));
|
||||
});
|
||||
|
||||
putModuleDescriptor();
|
||||
}
|
||||
|
||||
@ -554,7 +658,7 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
mv.visitInsn(ICONST_0);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
|
||||
methodName, BOOLEAN_SIG, false);
|
||||
methodName, BOOLEAN_SIG, false);
|
||||
mv.visitInsn(POP);
|
||||
}
|
||||
|
||||
@ -563,12 +667,12 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
*/
|
||||
void putModuleDescriptor() {
|
||||
mv.visitVarInsn(ALOAD, MD_VAR);
|
||||
pushInt(nextModulesIndex++);
|
||||
pushInt(mv, index);
|
||||
mv.visitVarInsn(ALOAD, BUILDER_VAR);
|
||||
mv.visitLdcInsn(md.hashCode());
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
|
||||
"build", "(I)Ljava/lang/module/ModuleDescriptor;",
|
||||
false);
|
||||
"build", "(I)Ljava/lang/module/ModuleDescriptor;",
|
||||
false);
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
|
||||
@ -580,31 +684,42 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
*/
|
||||
void requires(Set<Requires> requires) {
|
||||
mv.visitVarInsn(ALOAD, BUILDER_VAR);
|
||||
pushInt(requires.size());
|
||||
pushInt(mv, requires.size());
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Requires");
|
||||
int arrayIndex = 0;
|
||||
for (Requires require : requires) {
|
||||
mv.visitInsn(DUP); // arrayref
|
||||
pushInt(arrayIndex++);
|
||||
newRequires(require.modifiers(), require.name());
|
||||
String compiledVersion = null;
|
||||
if (require.compiledVersion().isPresent()) {
|
||||
compiledVersion = require.compiledVersion().get().toString();
|
||||
}
|
||||
|
||||
mv.visitInsn(DUP); // arrayref
|
||||
pushInt(mv, arrayIndex++);
|
||||
newRequires(require.modifiers(), require.name(), compiledVersion);
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
|
||||
"requires", REQUIRES_ARRAY_SIG, false);
|
||||
"requires", REQUIRES_ARRAY_SIG, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoke Builder.newRequires(Set<Modifier> mods, String mn)
|
||||
* Invoke Builder.newRequires(Set<Modifier> mods, String mn, String compiledVersion)
|
||||
*
|
||||
* Set<Modifier> mods = ...
|
||||
* Builder.newRequires(mods, mn);
|
||||
* Builder.newRequires(mods, mn, compiledVersion);
|
||||
*/
|
||||
void newRequires(Set<Requires.Modifier> mods, String name) {
|
||||
void newRequires(Set<Requires.Modifier> mods, String name, String compiledVersion) {
|
||||
int varIndex = dedupSetBuilder.indexOfRequiresModifiers(mods);
|
||||
mv.visitVarInsn(ALOAD, varIndex);
|
||||
mv.visitLdcInsn(name);
|
||||
mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
|
||||
"newRequires", REQUIRES_SET_STRING_SIG, false);
|
||||
if (compiledVersion != null) {
|
||||
mv.visitLdcInsn(compiledVersion);
|
||||
mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
|
||||
"newRequires", REQUIRES_SET_STRING_STRING_SIG, false);
|
||||
} else {
|
||||
mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
|
||||
"newRequires", REQUIRES_SET_STRING_SIG, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -615,17 +730,17 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
*/
|
||||
void exports(Set<Exports> exports) {
|
||||
mv.visitVarInsn(ALOAD, BUILDER_VAR);
|
||||
pushInt(exports.size());
|
||||
pushInt(mv, exports.size());
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Exports");
|
||||
int arrayIndex = 0;
|
||||
for (Exports export : exports) {
|
||||
mv.visitInsn(DUP); // arrayref
|
||||
pushInt(arrayIndex++);
|
||||
pushInt(mv, arrayIndex++);
|
||||
newExports(export.modifiers(), export.source(), export.targets());
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
|
||||
"exports", EXPORTS_ARRAY_SIG, false);
|
||||
"exports", EXPORTS_ARRAY_SIG, false);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -664,22 +779,21 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
/**
|
||||
* Call Builder::newOpens to create Opens instances and
|
||||
* then pass it to the builder by calling:
|
||||
* Builder.opens(Opens[])
|
||||
*
|
||||
* Builder.opens(Opens[])
|
||||
*/
|
||||
void opens(Set<Opens> opens) {
|
||||
mv.visitVarInsn(ALOAD, BUILDER_VAR);
|
||||
pushInt(opens.size());
|
||||
pushInt(mv, opens.size());
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Opens");
|
||||
int arrayIndex = 0;
|
||||
for (Opens open : opens) {
|
||||
mv.visitInsn(DUP); // arrayref
|
||||
pushInt(arrayIndex++);
|
||||
pushInt(mv, arrayIndex++);
|
||||
newOpens(open.modifiers(), open.source(), open.targets());
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
|
||||
"opens", OPENS_ARRAY_SIG, false);
|
||||
"opens", OPENS_ARRAY_SIG, false);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -705,12 +819,12 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
mv.visitLdcInsn(pn);
|
||||
mv.visitVarInsn(ALOAD, stringSetIndex);
|
||||
mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
|
||||
"newOpens", OPENS_MODIFIER_SET_STRING_SET_SIG, false);
|
||||
"newOpens", OPENS_MODIFIER_SET_STRING_SET_SIG, false);
|
||||
} else {
|
||||
mv.visitVarInsn(ALOAD, modifiersSetIndex);
|
||||
mv.visitLdcInsn(pn);
|
||||
mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
|
||||
"newOpens", OPENS_MODIFIER_SET_STRING_SIG, false);
|
||||
"newOpens", OPENS_MODIFIER_SET_STRING_SIG, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -722,7 +836,7 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
mv.visitVarInsn(ALOAD, BUILDER_VAR);
|
||||
mv.visitVarInsn(ALOAD, varIndex);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
|
||||
"uses", SET_SIG, false);
|
||||
"uses", SET_SIG, false);
|
||||
mv.visitInsn(POP);
|
||||
}
|
||||
|
||||
@ -734,17 +848,17 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
*/
|
||||
void provides(Collection<Provides> provides) {
|
||||
mv.visitVarInsn(ALOAD, BUILDER_VAR);
|
||||
pushInt(provides.size());
|
||||
pushInt(mv, provides.size());
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Provides");
|
||||
int arrayIndex = 0;
|
||||
for (Provides provide : provides) {
|
||||
mv.visitInsn(DUP); // arrayref
|
||||
pushInt(arrayIndex++);
|
||||
pushInt(mv, arrayIndex++);
|
||||
newProvides(provide.service(), provide.providers());
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
|
||||
"provides", PROVIDES_ARRAY_SIG, false);
|
||||
"provides", PROVIDES_ARRAY_SIG, false);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -758,19 +872,19 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
*/
|
||||
void newProvides(String service, List<String> providers) {
|
||||
mv.visitLdcInsn(service);
|
||||
pushInt(providers.size());
|
||||
pushInt(mv, providers.size());
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
|
||||
int arrayIndex = 0;
|
||||
for (String provider : providers) {
|
||||
mv.visitInsn(DUP); // arrayref
|
||||
pushInt(arrayIndex++);
|
||||
pushInt(mv, arrayIndex++);
|
||||
mv.visitLdcInsn(provider);
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/util/List",
|
||||
"of", "([Ljava/lang/Object;)Ljava/util/List;", true);
|
||||
"of", "([Ljava/lang/Object;)Ljava/util/List;", true);
|
||||
mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
|
||||
"newProvides", PROVIDES_STRING_LIST_SIG, false);
|
||||
"newProvides", PROVIDES_STRING_LIST_SIG, false);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -781,7 +895,7 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
mv.visitVarInsn(ALOAD, BUILDER_VAR);
|
||||
mv.visitVarInsn(ALOAD, varIndex);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
|
||||
"packages", SET_SIG, false);
|
||||
"packages", SET_SIG, false);
|
||||
mv.visitInsn(POP);
|
||||
}
|
||||
|
||||
@ -792,7 +906,7 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
mv.visitVarInsn(ALOAD, BUILDER_VAR);
|
||||
mv.visitLdcInsn(cn);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
|
||||
"mainClass", STRING_SIG, false);
|
||||
"mainClass", STRING_SIG, false);
|
||||
mv.visitInsn(POP);
|
||||
}
|
||||
|
||||
@ -803,48 +917,96 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
mv.visitVarInsn(ALOAD, BUILDER_VAR);
|
||||
mv.visitLdcInsn(v.toString());
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
|
||||
"version", STRING_SIG, false);
|
||||
"version", STRING_SIG, false);
|
||||
mv.visitInsn(POP);
|
||||
}
|
||||
}
|
||||
|
||||
class ModuleHashesBuilder {
|
||||
private static final String MODULE_HASHES_BUILDER =
|
||||
"jdk/internal/module/ModuleHashes$Builder";
|
||||
private static final String MODULE_HASHES_BUILDER_TYPE =
|
||||
"L" + MODULE_HASHES_BUILDER + ";";
|
||||
static final String STRING_BYTE_ARRAY_SIG =
|
||||
"(Ljava/lang/String;[B)" + MODULE_HASHES_BUILDER_TYPE;
|
||||
|
||||
final ModuleHashes recordedHashes;
|
||||
final MethodVisitor hmv;
|
||||
final int index;
|
||||
|
||||
ModuleHashesBuilder(ModuleHashes hashes, int index, MethodVisitor hmv) {
|
||||
this.recordedHashes = hashes;
|
||||
this.hmv = hmv;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build ModuleHashes
|
||||
*/
|
||||
void build() {
|
||||
if (recordedHashes == null)
|
||||
return;
|
||||
|
||||
// new jdk.internal.module.ModuleHashes.Builder
|
||||
newModuleHashesBuilder();
|
||||
|
||||
// Invoke ModuleHashes.Builder::hashForModule
|
||||
recordedHashes
|
||||
.names()
|
||||
.forEach(mn -> hashForModule(mn, recordedHashes.hashFor(mn)));
|
||||
|
||||
// Put ModuleHashes into the hashes array
|
||||
pushModuleHashes();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create ModuleHashes.Builder instance
|
||||
*/
|
||||
void newModuleHashesBuilder() {
|
||||
hmv.visitTypeInsn(NEW, MODULE_HASHES_BUILDER);
|
||||
hmv.visitInsn(DUP);
|
||||
hmv.visitLdcInsn(recordedHashes.algorithm());
|
||||
hmv.visitMethodInsn(INVOKESPECIAL, MODULE_HASHES_BUILDER,
|
||||
"<init>", "(Ljava/lang/String;)V", false);
|
||||
hmv.visitVarInsn(ASTORE, BUILDER_VAR);
|
||||
hmv.visitVarInsn(ALOAD, BUILDER_VAR);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Invoke ModuleHashes.Builder::build and put the returned
|
||||
* ModuleHashes to the hashes array
|
||||
*/
|
||||
void pushModuleHashes() {
|
||||
hmv.visitVarInsn(ALOAD, MH_VAR);
|
||||
pushInt(hmv, index);
|
||||
hmv.visitVarInsn(ALOAD, BUILDER_VAR);
|
||||
hmv.visitMethodInsn(INVOKEVIRTUAL, MODULE_HASHES_BUILDER,
|
||||
"build", "()Ljdk/internal/module/ModuleHashes;",
|
||||
false);
|
||||
hmv.visitInsn(AASTORE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoke Builder.algorithm(String a);
|
||||
* Invoke ModuleHashes.Builder.hashForModule(String name, byte[] hash);
|
||||
*/
|
||||
void algorithm(String alg) {
|
||||
mv.visitVarInsn(ALOAD, BUILDER_VAR);
|
||||
mv.visitLdcInsn(alg);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
|
||||
"algorithm", STRING_SIG, false);
|
||||
mv.visitInsn(POP);
|
||||
}
|
||||
void hashForModule(String name, byte[] hash) {
|
||||
hmv.visitVarInsn(ALOAD, BUILDER_VAR);
|
||||
hmv.visitLdcInsn(name);
|
||||
|
||||
/*
|
||||
* Invoke Builder.moduleHash(String name, byte[] hash);
|
||||
*/
|
||||
void moduleHash(String name, byte[] hash) {
|
||||
mv.visitVarInsn(ALOAD, BUILDER_VAR);
|
||||
mv.visitLdcInsn(name);
|
||||
|
||||
// must exist
|
||||
Integer index = modulesToHashIndex.get(name);
|
||||
if (index != null) {
|
||||
mv.visitFieldInsn(GETSTATIC, CLASSNAME, MODULES_TO_HASH, "[[B");
|
||||
pushInt(index);
|
||||
mv.visitInsn(AALOAD);
|
||||
assert(Objects.equals(hash, modulesToHash.get(name)));
|
||||
} else {
|
||||
pushInt(hash.length);
|
||||
mv.visitIntInsn(NEWARRAY, T_BYTE);
|
||||
for (int i = 0; i < hash.length; i++) {
|
||||
mv.visitInsn(DUP); // arrayref
|
||||
pushInt(i);
|
||||
mv.visitIntInsn(BIPUSH, hash[i]);
|
||||
mv.visitInsn(BASTORE);
|
||||
}
|
||||
pushInt(hmv, hash.length);
|
||||
hmv.visitIntInsn(NEWARRAY, T_BYTE);
|
||||
for (int i = 0; i < hash.length; i++) {
|
||||
hmv.visitInsn(DUP); // arrayref
|
||||
pushInt(hmv, i);
|
||||
hmv.visitIntInsn(BIPUSH, hash[i]);
|
||||
hmv.visitInsn(BASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
|
||||
"moduleHash", STRING_BYTE_ARRAY_SIG, false);
|
||||
mv.visitInsn(POP);
|
||||
|
||||
hmv.visitMethodInsn(INVOKEVIRTUAL, MODULE_HASHES_BUILDER,
|
||||
"hashForModule", STRING_BYTE_ARRAY_SIG, false);
|
||||
hmv.visitInsn(POP);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1039,12 +1201,12 @@ public final class SystemModuleDescriptorPlugin implements Plugin {
|
||||
"of", sb.toString(), true);
|
||||
} else {
|
||||
// call Set.of(E... elements)
|
||||
pushInt(elements.size());
|
||||
pushInt(mv, elements.size());
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
|
||||
int arrayIndex = 0;
|
||||
for (T t : elements) {
|
||||
mv.visitInsn(DUP); // arrayref
|
||||
pushInt(arrayIndex);
|
||||
pushInt(mv, arrayIndex);
|
||||
visitElement(t, mv); // value
|
||||
mv.visitInsn(AASTORE);
|
||||
arrayIndex++;
|
@ -66,6 +66,7 @@ import java.util.Comparator;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@ -98,10 +99,11 @@ import jdk.internal.joptsimple.OptionSet;
|
||||
import jdk.internal.joptsimple.OptionSpec;
|
||||
import jdk.internal.joptsimple.ValueConverter;
|
||||
import jdk.internal.loader.ResourceHelper;
|
||||
import jdk.internal.misc.JavaLangModuleAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.module.ModuleHashes;
|
||||
import jdk.internal.module.ModuleInfo;
|
||||
import jdk.internal.module.ModuleInfoExtender;
|
||||
import jdk.internal.module.ModulePath;
|
||||
import jdk.internal.module.ModuleResolution;
|
||||
import jdk.tools.jlink.internal.Utils;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
@ -163,6 +165,7 @@ public class JmodTask {
|
||||
Mode mode;
|
||||
Path jmodFile;
|
||||
boolean help;
|
||||
boolean helpExtra;
|
||||
boolean version;
|
||||
List<Path> classpath;
|
||||
List<Path> cmds;
|
||||
@ -178,6 +181,7 @@ public class JmodTask {
|
||||
String osArch;
|
||||
String osVersion;
|
||||
Pattern modulesToHash;
|
||||
ModuleResolution moduleResolution;
|
||||
boolean dryrun;
|
||||
List<PathMatcher> excludes;
|
||||
Path extractDir;
|
||||
@ -191,7 +195,7 @@ public class JmodTask {
|
||||
showUsageSummary();
|
||||
return EXIT_CMDERR;
|
||||
}
|
||||
if (options.help) {
|
||||
if (options.help || options.helpExtra) {
|
||||
showHelp();
|
||||
return EXIT_OK;
|
||||
}
|
||||
@ -287,8 +291,8 @@ public class JmodTask {
|
||||
private boolean describe() throws IOException {
|
||||
try (JmodFile jf = new JmodFile(options.jmodFile)) {
|
||||
try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
|
||||
ModuleDescriptor md = ModuleDescriptor.read(in);
|
||||
printModuleDescriptor(md);
|
||||
ModuleInfo.Attributes attrs = ModuleInfo.read(in, null);
|
||||
printModuleDescriptor(attrs.descriptor(), attrs.recordedHashes());
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
throw new CommandException("err.module.descriptor.not.found");
|
||||
@ -302,9 +306,7 @@ public class JmodTask {
|
||||
.collect(joining(" "));
|
||||
}
|
||||
|
||||
private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
|
||||
|
||||
private void printModuleDescriptor(ModuleDescriptor md)
|
||||
private void printModuleDescriptor(ModuleDescriptor md, ModuleHashes hashes)
|
||||
throws IOException
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@ -350,15 +352,24 @@ public class JmodTask {
|
||||
|
||||
md.osVersion().ifPresent(v -> sb.append("\n operating-system-version " + v));
|
||||
|
||||
JLMA.hashes(md).ifPresent(
|
||||
hashes -> hashes.names().stream().sorted().forEach(
|
||||
mod -> sb.append("\n hashes ").append(mod).append(" ")
|
||||
.append(hashes.algorithm()).append(" ")
|
||||
.append(hashes.hashFor(mod))));
|
||||
if (hashes != null) {
|
||||
hashes.names().stream().sorted().forEach(
|
||||
mod -> sb.append("\n hashes ").append(mod).append(" ")
|
||||
.append(hashes.algorithm()).append(" ")
|
||||
.append(toHex(hashes.hashFor(mod))));
|
||||
}
|
||||
|
||||
out.println(sb.toString());
|
||||
}
|
||||
|
||||
private String toHex(byte[] ba) {
|
||||
StringBuilder sb = new StringBuilder(ba.length);
|
||||
for (byte b: ba) {
|
||||
sb.append(String.format("%02x", b & 0xff));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private boolean create() throws IOException {
|
||||
JmodFileWriter jmod = new JmodFileWriter();
|
||||
|
||||
@ -400,6 +411,7 @@ public class JmodTask {
|
||||
final String osVersion = options.osVersion;
|
||||
final List<PathMatcher> excludes = options.excludes;
|
||||
final Hasher hasher = hasher();
|
||||
final ModuleResolution moduleResolution = options.moduleResolution;
|
||||
|
||||
JmodFileWriter() { }
|
||||
|
||||
@ -509,6 +521,10 @@ public class JmodTask {
|
||||
}
|
||||
}
|
||||
|
||||
if (moduleResolution != null && moduleResolution.value() != 0) {
|
||||
extender.moduleResolution(moduleResolution);
|
||||
}
|
||||
|
||||
// write the (possibly extended or modified) module-info.class
|
||||
out.writeEntry(extender.toByteArray(), Section.CLASSES, MODULE_INFO);
|
||||
}
|
||||
@ -537,12 +553,12 @@ public class JmodTask {
|
||||
}
|
||||
|
||||
URI uri = options.jmodFile.toUri();
|
||||
ModuleReference mref = new ModuleReference(descriptor, uri, new Supplier<>() {
|
||||
ModuleReference mref = new ModuleReference(descriptor, uri) {
|
||||
@Override
|
||||
public ModuleReader get() {
|
||||
public ModuleReader open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// compose a module finder with the module path and also
|
||||
// a module finder that can find the jmod file being created
|
||||
@ -1139,6 +1155,28 @@ public class JmodTask {
|
||||
@Override public String valuePattern() { return "module-version"; }
|
||||
}
|
||||
|
||||
static class WarnIfResolvedReasonConverter
|
||||
implements ValueConverter<ModuleResolution>
|
||||
{
|
||||
@Override
|
||||
public ModuleResolution convert(String value) {
|
||||
if (value.equals("deprecated"))
|
||||
return ModuleResolution.empty().withDeprecated();
|
||||
else if (value.equals("deprecated-for-removal"))
|
||||
return ModuleResolution.empty().withDeprecatedForRemoval();
|
||||
else if (value.equals("incubating"))
|
||||
return ModuleResolution.empty().withIncubating();
|
||||
else
|
||||
throw new CommandException("err.bad.WarnIfResolvedReason", value);
|
||||
}
|
||||
|
||||
@Override public Class<ModuleResolution> valueType() {
|
||||
return ModuleResolution.class;
|
||||
}
|
||||
|
||||
@Override public String valuePattern() { return "reason"; }
|
||||
}
|
||||
|
||||
static class PatternConverter implements ValueConverter<Pattern> {
|
||||
@Override
|
||||
public Pattern convert(String value) {
|
||||
@ -1182,12 +1220,24 @@ public class JmodTask {
|
||||
*/
|
||||
private static final class JmodHelpFormatter extends BuiltinHelpFormatter {
|
||||
|
||||
private JmodHelpFormatter() { super(80, 2); }
|
||||
private final Options opts;
|
||||
|
||||
private JmodHelpFormatter(Options opts) {
|
||||
super(80, 2);
|
||||
this.opts = opts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(Map<String, ? extends OptionDescriptor> options) {
|
||||
Map<String, OptionDescriptor> all = new HashMap<>();
|
||||
Map<String, OptionDescriptor> all = new LinkedHashMap<>();
|
||||
all.putAll(options);
|
||||
|
||||
// extra options
|
||||
if (!opts.helpExtra) {
|
||||
all.remove("do-not-resolve-by-default");
|
||||
all.remove("warn-if-resolved");
|
||||
}
|
||||
|
||||
all.put(CMD_FILENAME, new OptionDescriptor() {
|
||||
@Override
|
||||
public Collection<String> options() {
|
||||
@ -1243,7 +1293,8 @@ public class JmodTask {
|
||||
private final OptionParser parser = new OptionParser("hp");
|
||||
|
||||
private void handleOptions(String[] args) {
|
||||
parser.formatHelpWith(new JmodHelpFormatter());
|
||||
options = new Options();
|
||||
parser.formatHelpWith(new JmodHelpFormatter(options));
|
||||
|
||||
OptionSpec<Path> classPath
|
||||
= parser.accepts("class-path", getMessage("main.opt.class-path"))
|
||||
@ -1285,6 +1336,9 @@ public class JmodTask {
|
||||
= parser.acceptsAll(Set.of("h", "help"), getMessage("main.opt.help"))
|
||||
.forHelp();
|
||||
|
||||
OptionSpec<Void> helpExtra
|
||||
= parser.accepts("help-extra", getMessage("main.opt.help-extra"));
|
||||
|
||||
OptionSpec<Path> headerFiles
|
||||
= parser.accepts("header-files", getMessage("main.opt.header-files"))
|
||||
.withRequiredArg()
|
||||
@ -1342,6 +1396,15 @@ public class JmodTask {
|
||||
.withRequiredArg()
|
||||
.describedAs(getMessage("main.opt.os-version.arg"));
|
||||
|
||||
OptionSpec<Void> doNotResolveByDefault
|
||||
= parser.accepts("do-not-resolve-by-default",
|
||||
getMessage("main.opt.do-not-resolve-by-default"));
|
||||
|
||||
OptionSpec<ModuleResolution> warnIfResolved
|
||||
= parser.accepts("warn-if-resolved", getMessage("main.opt.warn-if-resolved"))
|
||||
.withRequiredArg()
|
||||
.withValuesConvertedBy(new WarnIfResolvedReasonConverter());
|
||||
|
||||
OptionSpec<Void> version
|
||||
= parser.accepts("version", getMessage("main.opt.version"));
|
||||
|
||||
@ -1351,9 +1414,9 @@ public class JmodTask {
|
||||
try {
|
||||
OptionSet opts = parser.parse(args);
|
||||
|
||||
if (opts.has(help) || opts.has(version)) {
|
||||
options = new Options();
|
||||
if (opts.has(help) || opts.has(helpExtra) || opts.has(version)) {
|
||||
options.help = opts.has(help);
|
||||
options.helpExtra = opts.has(helpExtra);
|
||||
options.version = opts.has(version);
|
||||
return; // informational message will be shown
|
||||
}
|
||||
@ -1362,7 +1425,6 @@ public class JmodTask {
|
||||
if (words.isEmpty())
|
||||
throw new CommandException("err.missing.mode").showUsage(true);
|
||||
String verb = words.get(0);
|
||||
options = new Options();
|
||||
try {
|
||||
options.mode = Enum.valueOf(Mode.class, verb.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
@ -1391,7 +1453,7 @@ public class JmodTask {
|
||||
options.legalNotices = opts.valuesOf(legalNotices);
|
||||
if (opts.has(modulePath)) {
|
||||
Path[] dirs = opts.valuesOf(modulePath).toArray(new Path[0]);
|
||||
options.moduleFinder = JLMA.newModulePath(Runtime.version(), true, dirs);
|
||||
options.moduleFinder = new ModulePath(Runtime.version(), true, dirs);
|
||||
}
|
||||
if (opts.has(moduleVersion))
|
||||
options.moduleVersion = opts.valueOf(moduleVersion);
|
||||
@ -1403,6 +1465,13 @@ public class JmodTask {
|
||||
options.osArch = opts.valueOf(osArch);
|
||||
if (opts.has(osVersion))
|
||||
options.osVersion = opts.valueOf(osVersion);
|
||||
if (opts.has(warnIfResolved))
|
||||
options.moduleResolution = opts.valueOf(warnIfResolved);
|
||||
if (opts.has(doNotResolveByDefault)) {
|
||||
if (options.moduleResolution == null)
|
||||
options.moduleResolution = ModuleResolution.empty();
|
||||
options.moduleResolution = options.moduleResolution.withDoNotResolveByDefault();
|
||||
}
|
||||
if (opts.has(hashModules)) {
|
||||
options.modulesToHash = opts.valueOf(hashModules);
|
||||
// if storing hashes then the module path is required
|
||||
|
@ -47,6 +47,7 @@ main.opt.mode.hash=\
|
||||
\hash - Records hashes of tied modules.
|
||||
|
||||
main.opt.help=Print this usage message
|
||||
main.opt.help-extra=Print help on extra options
|
||||
main.opt.version=Version information
|
||||
main.opt.class-path=Application jar files|dir containing classes
|
||||
main.opt.libs=Location of native libraries
|
||||
@ -74,6 +75,9 @@ main.opt.hash-modules=Compute and record hashes to tie a packaged module\
|
||||
\ with modules matching the given <regex-pattern> and depending upon it directly\
|
||||
\ or indirectly. The hashes are recorded in the JMOD file being created, or\
|
||||
\ a JMOD file or modular JAR on the module path specified the jmod hash command.
|
||||
main.opt.do-not-resolve-by-default=Exclude from the default root set of modules
|
||||
main.opt.warn-if-resolved=Hint for a tool to issue a warning if the module \
|
||||
is resolved. One of deprecated, deprecated-for-removal, or incubating
|
||||
|
||||
main.opt.cmdfile=Read options from the specified file
|
||||
|
||||
@ -96,6 +100,8 @@ err.invalid.class.path.entry=invalid class path entry: {0}
|
||||
err.file.already.exists=file already exists: {0}
|
||||
err.jmod.not.found=no jmod file found: {0}
|
||||
err.bad.pattern=bad pattern {0}
|
||||
err.bad.WarnIfResolvedReason=bad reason: {0}, must be one of deprecated,\
|
||||
\ deprecated-for-removal, or incubating
|
||||
err.unknown.option=unknown option(s): {0}
|
||||
err.missing.arg=no value given for {0}
|
||||
err.internal.error=internal error: {0} {1} {2}
|
||||
|
@ -41,7 +41,7 @@ module jdk.jlink {
|
||||
jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin,
|
||||
jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin,
|
||||
jdk.tools.jlink.internal.plugins.LegalNoticeFilePlugin,
|
||||
jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin,
|
||||
jdk.tools.jlink.internal.plugins.SystemModulesPlugin,
|
||||
jdk.tools.jlink.internal.plugins.StripNativeCommandsPlugin,
|
||||
jdk.tools.jlink.internal.plugins.OrderResourcesPlugin,
|
||||
jdk.tools.jlink.internal.plugins.DefaultCompressPlugin,
|
||||
|
152
jdk/test/java/lang/invoke/DropLookupModeTest.java
Normal file
152
jdk/test/java/lang/invoke/DropLookupModeTest.java
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @run testng DropLookupModeTest
|
||||
* @summary Basic unit tests Lookup::dropLookupMode
|
||||
*/
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import static java.lang.invoke.MethodHandles.Lookup.*;
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
@Test
|
||||
public class DropLookupModeTest {
|
||||
|
||||
/**
|
||||
* Basic test of dropLookupMode
|
||||
*/
|
||||
public void testBasic() {
|
||||
final Lookup fullPowerLookup = MethodHandles.lookup();
|
||||
final Class<?> lc = fullPowerLookup.lookupClass();
|
||||
assertTrue(fullPowerLookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PROTECTED|PRIVATE));
|
||||
|
||||
Lookup lookup = fullPowerLookup.dropLookupMode(PRIVATE);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE));
|
||||
|
||||
lookup = fullPowerLookup.dropLookupMode(PROTECTED);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE));
|
||||
|
||||
lookup = fullPowerLookup.dropLookupMode(PACKAGE);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == (PUBLIC|MODULE));
|
||||
|
||||
lookup = fullPowerLookup.dropLookupMode(MODULE);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == (PUBLIC));
|
||||
|
||||
lookup = fullPowerLookup.dropLookupMode(PUBLIC);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starting with a full power Lookup, use dropLookupMode to create new Lookups
|
||||
* with reduced access.
|
||||
*/
|
||||
public void testReducingAccess() {
|
||||
Lookup lookup = MethodHandles.lookup();
|
||||
final Class<?> lc = lookup.lookupClass();
|
||||
assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PROTECTED|PRIVATE));
|
||||
|
||||
lookup = lookup.dropLookupMode(PROTECTED);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE));
|
||||
|
||||
lookup = lookup.dropLookupMode(PRIVATE);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE));
|
||||
|
||||
lookup = lookup.dropLookupMode(PACKAGE);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == (PUBLIC|MODULE));
|
||||
|
||||
lookup = lookup.dropLookupMode(MODULE);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC);
|
||||
|
||||
lookup = lookup.dropLookupMode(PUBLIC);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == 0);
|
||||
|
||||
// repeat with lookup has no access
|
||||
lookup = lookup.dropLookupMode(PUBLIC);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test dropLookupMode on the public Lookup.
|
||||
*/
|
||||
public void testPublicLookup() {
|
||||
final Lookup publicLookup = MethodHandles.publicLookup();
|
||||
final Class<?> lc = publicLookup.lookupClass();
|
||||
assertTrue(publicLookup.lookupModes() == PUBLIC);
|
||||
|
||||
Lookup lookup = publicLookup.dropLookupMode(PRIVATE);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC);
|
||||
|
||||
lookup = publicLookup.dropLookupMode(PROTECTED);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC);
|
||||
|
||||
lookup = publicLookup.dropLookupMode(PACKAGE);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC);
|
||||
|
||||
lookup = publicLookup.dropLookupMode(MODULE);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC);
|
||||
|
||||
lookup = publicLookup.dropLookupMode(PUBLIC);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == 0);
|
||||
}
|
||||
|
||||
@DataProvider(name = "badInput")
|
||||
public Object[][] badInput() {
|
||||
return new Object[][] {
|
||||
{ 0, null },
|
||||
{ (PACKAGE|PRIVATE), null }, // two modes
|
||||
{ Integer.MAX_VALUE, null },
|
||||
{ Integer.MIN_VALUE, null },
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that IllegalArgumentException is thrown for bad input
|
||||
*/
|
||||
@Test(dataProvider = "badInput", expectedExceptions = {IllegalArgumentException.class})
|
||||
public void testBadInput(Integer modeToDrop, Object ignore) {
|
||||
MethodHandles.lookup().dropLookupMode(modeToDrop);
|
||||
}
|
||||
|
||||
}
|
@ -84,8 +84,7 @@ public class PrivateLookupInTests {
|
||||
|
||||
// Invoke MethodHandles.privateLookupIn with a reduced-power caller
|
||||
public void testReducedAccessCallerSameModule() throws Throwable {
|
||||
// drop access
|
||||
Lookup caller = MethodHandles.lookup().in(publicType);
|
||||
Lookup caller = MethodHandles.lookup().dropLookupMode(PACKAGE);
|
||||
assertTrue((caller.lookupModes() & PRIVATE) == 0);
|
||||
assertTrue((caller.lookupModes() & PACKAGE) == 0);
|
||||
assertTrue((caller.lookupModes() & MODULE) != 0);
|
||||
|
@ -23,8 +23,7 @@
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @modules java.base/java.lang.module:open
|
||||
* java.base/jdk.internal.module
|
||||
* @modules java.base/jdk.internal.module
|
||||
* @run testng ModuleDescriptorTest
|
||||
* @summary Basic test for java.lang.module.ModuleDescriptor and its builder
|
||||
*/
|
||||
@ -41,16 +40,13 @@ import java.lang.module.ModuleDescriptor.Requires;
|
||||
import java.lang.module.ModuleDescriptor.Provides;
|
||||
import java.lang.module.ModuleDescriptor.Requires.Modifier;
|
||||
import java.lang.module.ModuleDescriptor.Version;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Module;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
|
||||
|
||||
@ -66,10 +62,20 @@ public class ModuleDescriptorTest {
|
||||
public Object[][] invalidJavaIdentifiers() {
|
||||
return new Object[][]{
|
||||
|
||||
{ null, null },
|
||||
{ ".foo", null },
|
||||
{ "foo.", null },
|
||||
{ "[foo]", null },
|
||||
{ null, null },
|
||||
{ "1", null },
|
||||
{ "1foo", null },
|
||||
{ ".foo", null },
|
||||
{ "foo.", null },
|
||||
{ "[foo]", null },
|
||||
{ "foo.1", null },
|
||||
{ "1foo.bar", null },
|
||||
{ "foo.1bar", null },
|
||||
{ "foo.[bar]", null },
|
||||
{ "foo..bar", null },
|
||||
{ "foo.bar.1", null },
|
||||
{ "foo.bar.1gus", null },
|
||||
{ "foo.bar.[gus]", null },
|
||||
|
||||
};
|
||||
}
|
||||
@ -86,6 +92,15 @@ public class ModuleDescriptorTest {
|
||||
.next();
|
||||
}
|
||||
|
||||
private Requires requires(Set<Modifier> mods, String mn, Version v) {
|
||||
return ModuleDescriptor.module("m")
|
||||
.requires(mods, mn, v)
|
||||
.build()
|
||||
.requires()
|
||||
.iterator()
|
||||
.next();
|
||||
}
|
||||
|
||||
private Requires requires(String mn) {
|
||||
return requires(Collections.emptySet(), mn);
|
||||
}
|
||||
@ -103,6 +118,7 @@ public class ModuleDescriptorTest {
|
||||
assertTrue(r.compareTo(r) == 0);
|
||||
assertTrue(r.modifiers().isEmpty());
|
||||
assertEquals(r.name(), "foo");
|
||||
assertFalse(r.compiledVersion().isPresent());
|
||||
}
|
||||
|
||||
public void testRequiresWithOneModifier() {
|
||||
@ -111,6 +127,7 @@ public class ModuleDescriptorTest {
|
||||
assertTrue(r.compareTo(r) == 0);
|
||||
assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE));
|
||||
assertEquals(r.name(), "foo");
|
||||
assertFalse(r.compiledVersion().isPresent());
|
||||
}
|
||||
|
||||
public void testRequiresWithTwoModifiers() {
|
||||
@ -119,6 +136,7 @@ public class ModuleDescriptorTest {
|
||||
assertTrue(r.compareTo(r) == 0);
|
||||
assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, SYNTHETIC));
|
||||
assertEquals(r.name(), "foo");
|
||||
assertFalse(r.compiledVersion().isPresent());
|
||||
}
|
||||
|
||||
public void testRequiresWithAllModifiers() {
|
||||
@ -127,6 +145,18 @@ public class ModuleDescriptorTest {
|
||||
assertTrue(r.compareTo(r) == 0);
|
||||
assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, STATIC, SYNTHETIC, MANDATED));
|
||||
assertEquals(r.name(), "foo");
|
||||
assertFalse(r.compiledVersion().isPresent());
|
||||
}
|
||||
|
||||
public void testRequiresWithCompiledVersion() {
|
||||
Version v = Version.parse("1.0");
|
||||
Requires r = requires(Set.of(), "foo", v);
|
||||
assertEquals(r, r);
|
||||
assertTrue(r.compareTo(r) == 0);
|
||||
assertEquals(r.modifiers(), Set.of());
|
||||
assertEquals(r.name(), "foo");
|
||||
assertTrue(r.compiledVersion().isPresent());
|
||||
assertEquals(r.compiledVersion().get().toString(), "1.0");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
@ -167,6 +197,16 @@ public class ModuleDescriptorTest {
|
||||
ModuleDescriptor.module("m").requires((Requires) null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testRequiresWithNullModifiers() {
|
||||
ModuleDescriptor.module("m").requires(null, "foo");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testRequiresWithNullVersion() {
|
||||
ModuleDescriptor.module("m").requires(Set.of(), "foo", null);
|
||||
}
|
||||
|
||||
public void testRequiresCompare() {
|
||||
Requires r1 = requires(EnumSet.noneOf(Modifier.class), "foo");
|
||||
Requires r2 = requires(EnumSet.noneOf(Modifier.class), "bar");
|
||||
@ -190,6 +230,20 @@ public class ModuleDescriptorTest {
|
||||
assertTrue(r2.compareTo(r1) == 0);
|
||||
}
|
||||
|
||||
public void testRequiresCompareWithSameCompiledVersion() {
|
||||
Requires r1 = requires(Set.of(), "foo", Version.parse("2.0"));
|
||||
Requires r2 = requires(Set.of(), "foo", Version.parse("2.0"));
|
||||
assertTrue(r1.compareTo(r2) == 0);
|
||||
assertTrue(r2.compareTo(r1) == 0);
|
||||
}
|
||||
|
||||
public void testRequiresCompareWithDifferentCompiledVersion() {
|
||||
Requires r1 = requires(Set.of(), "foo", Version.parse("1.0"));
|
||||
Requires r2 = requires(Set.of(), "foo", Version.parse("2.0"));
|
||||
assertTrue(r1.compareTo(r2) < 0);
|
||||
assertTrue(r2.compareTo(r1) > 0);
|
||||
}
|
||||
|
||||
public void testRequiresEqualsAndHashCode() {
|
||||
Requires r1 = requires("foo");
|
||||
Requires r2 = requires("foo");
|
||||
@ -208,6 +262,17 @@ public class ModuleDescriptorTest {
|
||||
r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo");
|
||||
r2 = requires(Set.of(), "foo");
|
||||
assertNotEquals(r1, r2);
|
||||
|
||||
Version v1 = Version.parse("1.0");
|
||||
r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1);
|
||||
r2 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1);
|
||||
assertEquals(r1, r2);
|
||||
assertTrue(r1.hashCode() == r2.hashCode());
|
||||
|
||||
Version v2 = Version.parse("2.0");
|
||||
r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1);
|
||||
r2 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v2);
|
||||
assertNotEquals(r1, r2);
|
||||
}
|
||||
|
||||
public void testRequiresToString() {
|
||||
@ -938,7 +1003,7 @@ public class ModuleDescriptorTest {
|
||||
};
|
||||
|
||||
// basic test reading module-info.class
|
||||
public void testRead1() throws Exception {
|
||||
public void testRead() throws Exception {
|
||||
Module base = Object.class.getModule();
|
||||
|
||||
try (InputStream in = base.getResourceAsStream("module-info.class")) {
|
||||
@ -954,45 +1019,6 @@ public class ModuleDescriptorTest {
|
||||
assertEquals(descriptor.name(), "java.base");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test reading a module-info.class that has a module name, requires,
|
||||
* and qualified exports with module names that are not supported in the
|
||||
* Java Language.
|
||||
*/
|
||||
public void testRead2() throws Exception {
|
||||
// use non-public constructor to create a Builder that is not strict
|
||||
Constructor<?> ctor = Builder.class.getDeclaredConstructor(String.class, boolean.class);
|
||||
ctor.setAccessible(true);
|
||||
|
||||
Builder builder = (ModuleDescriptor.Builder) ctor.newInstance("m?1", false);
|
||||
ModuleDescriptor descriptor = builder
|
||||
.requires("java.base")
|
||||
.requires("-m1")
|
||||
.exports("p", Set.of("m2-"))
|
||||
.build();
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ModuleInfoWriter.write(descriptor, baos);
|
||||
ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
|
||||
|
||||
descriptor = ModuleDescriptor.read(bb);
|
||||
assertEquals(descriptor.name(), "m?1");
|
||||
|
||||
Set<String> requires = descriptor.requires()
|
||||
.stream()
|
||||
.map(Requires::name)
|
||||
.collect(Collectors.toSet());
|
||||
assertTrue(requires.size() == 2);
|
||||
assertTrue(requires.contains("java.base"));
|
||||
assertTrue(requires.contains("-m1"));
|
||||
|
||||
assertTrue(descriptor.exports().size() == 1);
|
||||
Exports e = descriptor.exports().iterator().next();
|
||||
assertTrue(e.targets().size() == 1);
|
||||
assertTrue(e.targets().contains("m2-"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ModuleDescriptor with a packager finder
|
||||
*/
|
||||
|
261
jdk/test/java/lang/module/ModuleNamesTest.java
Normal file
261
jdk/test/java/lang/module/ModuleNamesTest.java
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.base/jdk.internal.module
|
||||
* @run testng ModuleNamesTest
|
||||
* @summary Basic test of reading a module-info.class with module names that
|
||||
* are legal in class files but not legal in the Java Language
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.lang.module.InvalidModuleDescriptorException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleDescriptor.Builder;
|
||||
import java.lang.module.ModuleDescriptor.Exports;
|
||||
import java.lang.module.ModuleDescriptor.Opens;
|
||||
import java.lang.module.ModuleDescriptor.Requires;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.module.ModuleInfoWriter;
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
@Test
|
||||
public class ModuleNamesTest {
|
||||
|
||||
@DataProvider(name = "legalModuleNames")
|
||||
public Object[][] legalModuleNames() {
|
||||
return new Object[][] {
|
||||
|
||||
{ ".", "." },
|
||||
{ ".foo", ".foo" },
|
||||
{ "foo.", "foo." },
|
||||
{ "foo.bar", "foo.bar" },
|
||||
|
||||
{ "..", ".." },
|
||||
{ "..foo", "..foo" },
|
||||
{ "foo..", "foo.." },
|
||||
{ "foo..bar", "foo..bar" },
|
||||
|
||||
{ "[", "[" },
|
||||
{ "[foo", "[foo" },
|
||||
{ "foo[", "foo[" },
|
||||
{ "foo[bar", "foo[bar" },
|
||||
|
||||
{ ";", ";" },
|
||||
{ ";foo", ";foo" },
|
||||
{ "foo;", "foo;" },
|
||||
{ "foo;bar", "foo;bar" },
|
||||
|
||||
{ "\\\\", "\\" },
|
||||
{ "\\\\foo", "\\foo" },
|
||||
{ "foo\\\\", "foo\\" },
|
||||
{ "foo\\\\bar", "foo\\bar" },
|
||||
|
||||
{ "\\\\\\\\", "\\\\" },
|
||||
{ "\\\\\\\\foo", "\\\\foo" },
|
||||
{ "foo\\\\\\\\", "foo\\\\" },
|
||||
{ "foo\\\\\\\\bar", "foo\\\\bar" },
|
||||
|
||||
{ "\\:", ":" },
|
||||
{ "\\:foo", ":foo" },
|
||||
{ "foo\\:", "foo:" },
|
||||
{ "foo\\:bar", "foo:bar" },
|
||||
|
||||
{ "\\:\\:", "::" },
|
||||
{ "\\:\\:foo", "::foo" },
|
||||
{ "foo\\:\\:", "foo::" },
|
||||
{ "foo\\:\\:bar", "foo::bar" },
|
||||
|
||||
{ "\\@", "@" },
|
||||
{ "\\@foo", "@foo" },
|
||||
{ "foo\\@", "foo@" },
|
||||
{ "foo\\@bar", "foo@bar" },
|
||||
|
||||
{ "\\@\\@", "@@" },
|
||||
{ "\\@\\@foo", "@@foo" },
|
||||
{ "foo\\@\\@", "foo@@" },
|
||||
{ "foo\\@\\@bar", "foo@@bar" },
|
||||
|
||||
{ makeString("", 0x20, ""), " " },
|
||||
{ makeString("foo", 0x20, ""), "foo " },
|
||||
{ makeString("", 0x20, "foo"), " foo" },
|
||||
{ makeString("foo", 0x20, "bar"), "foo bar" },
|
||||
};
|
||||
}
|
||||
|
||||
@DataProvider(name = "illegalModuleNames")
|
||||
public Object[][] illegalModuleNames() {
|
||||
return new Object[][] {
|
||||
|
||||
{ "", null },
|
||||
|
||||
{ ":", null },
|
||||
{ ":foo", null },
|
||||
{ "foo:", null },
|
||||
{ "foo:bar", null },
|
||||
|
||||
{ "@", null },
|
||||
{ "@foo", null },
|
||||
{ "foo@", null },
|
||||
{ "foo@bar", null },
|
||||
|
||||
{ "\\", null },
|
||||
{ "\\foo", null },
|
||||
{ "foo\\", null },
|
||||
{ "foo\\bar", null },
|
||||
|
||||
{ makeString("", 0x00, ""), null },
|
||||
{ makeString("", 0x00, "foo"), null },
|
||||
{ makeString("foo", 0x00, ""), null },
|
||||
{ makeString("foo", 0x00, "bar"), null },
|
||||
|
||||
{ makeString("", 0x1f, ""), null },
|
||||
{ makeString("", 0x1f, "foo"), null },
|
||||
{ makeString("foo", 0x1f, ""), null },
|
||||
{ makeString("foo", 0x1f, "bar"), null },
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "legalModuleNames")
|
||||
public void testLegalModuleName(String mn, String expected) throws Exception {
|
||||
ModuleDescriptor md = newBuilder(mn).requires("java.base").build();
|
||||
ByteBuffer bb = toBuffer(md);
|
||||
String name = ModuleDescriptor.read(bb).name();
|
||||
assertEquals(name, expected);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "illegalModuleNames",
|
||||
expectedExceptions = InvalidModuleDescriptorException.class)
|
||||
public void testIllegalModuleName(String mn, String ignore) throws Exception {
|
||||
ModuleDescriptor md = newBuilder(mn).requires("java.base").build();
|
||||
ByteBuffer bb = toBuffer(md);
|
||||
ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException
|
||||
}
|
||||
|
||||
@Test(dataProvider = "legalModuleNames")
|
||||
public void testLegalRequires(String mn, String expected) throws Exception {
|
||||
ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build();
|
||||
ByteBuffer bb = toBuffer(md);
|
||||
ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
|
||||
Optional<Requires> requires = descriptor.requires().stream()
|
||||
.filter(r -> !r.name().equals("java.base"))
|
||||
.findAny();
|
||||
assertTrue(requires.isPresent());
|
||||
assertEquals(requires.get().name(), expected);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "illegalModuleNames",
|
||||
expectedExceptions = InvalidModuleDescriptorException.class)
|
||||
public void testIllegalRequires(String mn, String ignore) throws Exception {
|
||||
ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build();
|
||||
ByteBuffer bb = toBuffer(md);
|
||||
ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException
|
||||
}
|
||||
|
||||
@Test(dataProvider = "legalModuleNames")
|
||||
public void testLegalExports(String mn, String expected) throws Exception {
|
||||
ModuleDescriptor md = newBuilder("m")
|
||||
.requires("java.base")
|
||||
.exports("p", Set.of(mn))
|
||||
.build();
|
||||
ByteBuffer bb = toBuffer(md);
|
||||
ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
|
||||
Optional<Exports> export = descriptor.exports().stream().findAny();
|
||||
assertTrue(export.isPresent());
|
||||
assertTrue(export.get().targets().contains(expected));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "illegalModuleNames",
|
||||
expectedExceptions = InvalidModuleDescriptorException.class)
|
||||
public void testIllegalExports(String mn, String ignore) throws Exception {
|
||||
ModuleDescriptor md = newBuilder("m")
|
||||
.requires("java.base")
|
||||
.exports("p", Set.of(mn))
|
||||
.build();
|
||||
ByteBuffer bb = toBuffer(md);
|
||||
ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException
|
||||
}
|
||||
|
||||
@Test(dataProvider = "legalModuleNames")
|
||||
public void testLegalOpens(String mn, String expected) throws Exception {
|
||||
ModuleDescriptor md = newBuilder("m")
|
||||
.requires("java.base")
|
||||
.opens("p", Set.of(mn))
|
||||
.build();
|
||||
ByteBuffer bb = toBuffer(md);
|
||||
ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
|
||||
Optional<Opens> opens = descriptor.opens().stream().findAny();
|
||||
assertTrue(opens.isPresent());
|
||||
assertTrue(opens.get().targets().contains(expected));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "illegalModuleNames",
|
||||
expectedExceptions = InvalidModuleDescriptorException.class)
|
||||
public void testIllegalOpens(String mn, String ignore) throws Exception {
|
||||
ModuleDescriptor md = newBuilder("m")
|
||||
.requires("java.base")
|
||||
.opens("p", Set.of(mn))
|
||||
.build();
|
||||
ByteBuffer bb = toBuffer(md);
|
||||
ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Builder that does not validate module names.
|
||||
*/
|
||||
private Builder newBuilder(String mn) {
|
||||
return SharedSecrets.getJavaLangModuleAccess()
|
||||
.newModuleBuilder(mn, false, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code ByteBuffer} containing the given module descriptor
|
||||
* in module-info.class format.
|
||||
*/
|
||||
private ByteBuffer toBuffer(ModuleDescriptor descriptor) throws Exception {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ModuleInfoWriter.write(descriptor, baos);
|
||||
return ByteBuffer.wrap(baos.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string containing a given code point.
|
||||
*/
|
||||
private String makeString(String prefix, int codePoint, String suffix) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(prefix);
|
||||
sb.appendCodePoint(codePoint);
|
||||
sb.append(suffix);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@
|
||||
/**
|
||||
* @test
|
||||
* @library /lib/testlibrary
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @modules java.base/jdk.internal.module
|
||||
* jdk.compiler
|
||||
* @build ModuleReaderTest CompilerUtils JarUtils
|
||||
* @run testng ModuleReaderTest
|
||||
@ -53,7 +53,7 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.spi.ToolProvider;
|
||||
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.module.ModulePath;
|
||||
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
@ -216,9 +216,7 @@ public class ModuleReaderTest {
|
||||
*/
|
||||
void test(Path mp) throws IOException {
|
||||
|
||||
ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
|
||||
.newModulePath(Runtime.version(), true, mp);
|
||||
|
||||
ModuleFinder finder = new ModulePath(Runtime.version(), true, mp);
|
||||
ModuleReference mref = finder.find(TEST_MODULE).get();
|
||||
ModuleReader reader = mref.open();
|
||||
|
||||
|
@ -31,7 +31,6 @@ import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleReader;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.net.URI;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
@ -39,8 +38,13 @@ import static org.testng.Assert.*;
|
||||
@Test
|
||||
public class ModuleReferenceTest {
|
||||
|
||||
private Supplier<ModuleReader> makeSupplier() {
|
||||
return () -> { throw new UnsupportedOperationException(); };
|
||||
private ModuleReference newModuleReference(ModuleDescriptor descriptor, URI uri) {
|
||||
return new ModuleReference(descriptor, uri) {
|
||||
@Override
|
||||
public ModuleReader open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void testBasic() throws Exception {
|
||||
@ -53,25 +57,16 @@ public class ModuleReferenceTest {
|
||||
|
||||
URI uri = URI.create("module:/m");
|
||||
|
||||
Supplier<ModuleReader> supplier = makeSupplier();
|
||||
|
||||
ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
|
||||
ModuleReference mref = newModuleReference(descriptor, uri);
|
||||
|
||||
assertTrue(mref.descriptor().equals(descriptor));
|
||||
assertTrue(mref.location().get().equals(uri));
|
||||
|
||||
// check that the supplier is called
|
||||
try {
|
||||
mref.open();
|
||||
assertTrue(false);
|
||||
} catch (UnsupportedOperationException expected) { }
|
||||
}
|
||||
|
||||
|
||||
@Test(expectedExceptions = { NullPointerException.class })
|
||||
public void testNullDescriptor() throws Exception {
|
||||
URI location = URI.create("module:/m");
|
||||
new ModuleReference(null, location, makeSupplier());
|
||||
newModuleReference(null, location);
|
||||
}
|
||||
|
||||
public void testNullLocation() {
|
||||
@ -79,55 +74,8 @@ public class ModuleReferenceTest {
|
||||
= ModuleDescriptor.module("m")
|
||||
.exports("p")
|
||||
.build();
|
||||
Supplier<ModuleReader> supplier = makeSupplier();
|
||||
ModuleReference mref = new ModuleReference(descriptor, null, supplier);
|
||||
ModuleReference mref = newModuleReference(descriptor, null);
|
||||
assertTrue(!mref.location().isPresent());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = { NullPointerException.class })
|
||||
public void testNullSupplier() throws Exception {
|
||||
ModuleDescriptor descriptor = ModuleDescriptor.module("m").build();
|
||||
URI location = URI.create("module:/m");
|
||||
new ModuleReference(descriptor, location, null);
|
||||
}
|
||||
|
||||
|
||||
public void testEqualsAndHashCode() {
|
||||
ModuleDescriptor descriptor1
|
||||
= ModuleDescriptor.module("m1")
|
||||
.exports("p")
|
||||
.build();
|
||||
ModuleDescriptor descriptor2
|
||||
= ModuleDescriptor.module("m1")
|
||||
.exports("p")
|
||||
.build();
|
||||
|
||||
URI uri = URI.create("module:/m1");
|
||||
Supplier<ModuleReader> supplier = makeSupplier();
|
||||
|
||||
ModuleReference mref1 = new ModuleReference(descriptor1, uri, supplier);
|
||||
ModuleReference mref2 = new ModuleReference(descriptor2, uri, supplier);
|
||||
ModuleReference mref3 = new ModuleReference(descriptor1, null, supplier);
|
||||
|
||||
assertTrue(mref1.equals(mref1));
|
||||
assertTrue(mref1.equals(mref2));
|
||||
assertTrue(mref2.equals(mref1));
|
||||
assertTrue(mref1.hashCode() == mref2.hashCode());
|
||||
|
||||
assertTrue(mref3.equals(mref3));
|
||||
assertFalse(mref3.equals(mref1));
|
||||
assertFalse(mref1.equals(mref3));
|
||||
}
|
||||
|
||||
|
||||
public void testToString() {
|
||||
ModuleDescriptor descriptor = ModuleDescriptor.module("m1").build();
|
||||
URI uri = URI.create("module:/m1");
|
||||
Supplier<ModuleReader> supplier = makeSupplier();
|
||||
ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
|
||||
String s = mref.toString();
|
||||
assertTrue(s.contains("m1"));
|
||||
assertTrue(s.contains(uri.toString()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -119,7 +119,6 @@ public class AnnotationsTest {
|
||||
List<Attribute> attrs = new ArrayList<>();
|
||||
attrs.add(new ClassFileAttributes.ModuleAttribute());
|
||||
attrs.add(new ClassFileAttributes.ModulePackagesAttribute());
|
||||
attrs.add(new ClassFileAttributes.ModuleVersionAttribute());
|
||||
attrs.add(new ClassFileAttributes.ModuleTargetAttribute());
|
||||
cr.accept(cv, attrs.toArray(new Attribute[0]), 0);
|
||||
|
||||
|
158
jdk/test/jdk/modules/incubator/DefaultImage.java
Normal file
158
jdk/test/jdk/modules/incubator/DefaultImage.java
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8170859
|
||||
* @summary Ensure no incubator modules are resolved by default in the image
|
||||
* @library /lib/testlibrary
|
||||
* @modules jdk.compiler
|
||||
* @build CompilerUtils
|
||||
* @run testng DefaultImage
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static jdk.testlibrary.ProcessTools.executeCommand;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class DefaultImage {
|
||||
private static final String JAVA_HOME = System.getProperty("java.home");
|
||||
private static final Path TEST_SRC = Paths.get(System.getProperty("test.src"));
|
||||
private static final Path CP_DIR = Paths.get("cp");
|
||||
|
||||
@BeforeTest
|
||||
private void setup() throws Throwable {
|
||||
Path src = TEST_SRC.resolve("src").resolve("cp").resolve("listmods");
|
||||
assertTrue(CompilerUtils.compile(src, CP_DIR));
|
||||
}
|
||||
|
||||
public void test() throws Throwable {
|
||||
if (isExplodedBuild()) {
|
||||
System.out.println("Test cannot run on exploded build");
|
||||
return;
|
||||
}
|
||||
|
||||
java("-cp", CP_DIR.toString(),
|
||||
"listmods.ListModules")
|
||||
.assertSuccess()
|
||||
.resultChecker(r -> r.assertOutputContains("java.base"))
|
||||
.resultChecker(r -> r.assertOutputDoesNotContain("jdk.incubator"));
|
||||
}
|
||||
|
||||
@DataProvider(name = "tokens")
|
||||
public Object[][] singleModuleValues() throws IOException {
|
||||
return new Object[][]{ { "ALL-DEFAULT" }, { "ALL-SYSTEM"} };
|
||||
}
|
||||
|
||||
@Test(dataProvider = "tokens")
|
||||
public void testAddMods(String addModsToken) throws Throwable {
|
||||
if (isExplodedBuild()) {
|
||||
System.out.println("Test cannot run on exploded build");
|
||||
return;
|
||||
}
|
||||
|
||||
java("--add-modules", addModsToken,
|
||||
"-cp", CP_DIR.toString(),
|
||||
"listmods.ListModules")
|
||||
.assertSuccess()
|
||||
.resultChecker(r -> r.assertOutputContains("java.base"))
|
||||
.resultChecker(r -> r.assertOutputDoesNotContain("jdk.incubator"));
|
||||
}
|
||||
|
||||
static ToolResult java(String... opts) throws Throwable {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
PrintStream ps = new PrintStream(baos);
|
||||
String[] options = Stream.concat(Stream.of(getJava()), Stream.of(opts))
|
||||
.toArray(String[]::new);
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(options);
|
||||
int exitValue = executeCommand(pb).outputTo(ps)
|
||||
.errorTo(ps)
|
||||
.getExitValue();
|
||||
|
||||
return new ToolResult(exitValue, new String(baos.toByteArray(), UTF_8));
|
||||
}
|
||||
|
||||
static class ToolResult {
|
||||
final int exitCode;
|
||||
final String output;
|
||||
|
||||
ToolResult(int exitValue, String output) {
|
||||
this.exitCode = exitValue;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
ToolResult assertSuccess() {
|
||||
assertEquals(exitCode, 0,
|
||||
"Expected exit code 0, got " + exitCode
|
||||
+ ", with output[" + output + "]");
|
||||
return this;
|
||||
}
|
||||
|
||||
ToolResult resultChecker(Consumer<ToolResult> r) {
|
||||
r.accept(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
ToolResult assertOutputContains(String subString) {
|
||||
assertTrue(output.contains(subString),
|
||||
"Expected to find [" + subString + "], in output ["
|
||||
+ output + "]" + "\n");
|
||||
return this;
|
||||
}
|
||||
|
||||
ToolResult assertOutputDoesNotContain(String subString) {
|
||||
assertFalse(output.contains(subString),
|
||||
"Expected to NOT find [" + subString + "], in output ["
|
||||
+ output + "]" + "\n");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
static String getJava() {
|
||||
Path image = Paths.get(JAVA_HOME);
|
||||
boolean isWindows = System.getProperty("os.name").startsWith("Windows");
|
||||
Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java");
|
||||
if (Files.notExists(java))
|
||||
throw new RuntimeException(java + " not found");
|
||||
return java.toAbsolutePath().toString();
|
||||
}
|
||||
|
||||
static boolean isExplodedBuild() {
|
||||
Path modulesPath = Paths.get(JAVA_HOME).resolve("lib").resolve("modules");
|
||||
return Files.notExists(modulesPath);
|
||||
}
|
||||
}
|
382
jdk/test/jdk/modules/incubator/ImageModules.java
Normal file
382
jdk/test/jdk/modules/incubator/ImageModules.java
Normal file
@ -0,0 +1,382 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8170859
|
||||
* @summary Basic test for incubator modules in jmods and images
|
||||
* @library /lib/testlibrary
|
||||
* @modules jdk.compiler jdk.jartool jdk.jlink
|
||||
* @build CompilerUtils
|
||||
* @run testng/othervm ImageModules
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.spi.ToolProvider;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.testlibrary.FileUtils;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static jdk.testlibrary.ProcessTools.executeCommand;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class ImageModules {
|
||||
private static final String JAVA_HOME = System.getProperty("java.home");
|
||||
private static final Path JDK_JMODS = Paths.get(JAVA_HOME, "jmods");
|
||||
|
||||
private static final Path TEST_SRC = Paths.get(System.getProperty("test.src"));
|
||||
private static final Path MODS_DIR = Paths.get("mods");
|
||||
private static final Path CP_DIR = Paths.get("cp");
|
||||
private static final Path JARS_DIR = Paths.get("jars");
|
||||
private static final Path JMODS_DIR = Paths.get("jmods");
|
||||
private static final Path IMAGE = Paths.get("image");
|
||||
|
||||
private static final String JAVA_BASE = "java.base";
|
||||
private final String[] modules = new String[] { "message.writer",
|
||||
"message.converter" };
|
||||
|
||||
@BeforeTest
|
||||
private void setup() throws Throwable {
|
||||
Path src = TEST_SRC.resolve("src");
|
||||
for (String name : modules) {
|
||||
assertTrue(CompilerUtils.compile(src.resolve(name),
|
||||
MODS_DIR,
|
||||
"--module-source-path", src.toString()));
|
||||
}
|
||||
|
||||
assertTrue(CompilerUtils.compile(src.resolve("cp"),
|
||||
CP_DIR,
|
||||
"--module-path", MODS_DIR.toString(),
|
||||
"--add-modules", "message.writer"));
|
||||
}
|
||||
|
||||
@DataProvider(name = "singleModule")
|
||||
public Object[][] singleModuleValues() throws IOException {
|
||||
Object[][] values = new Object[][]{
|
||||
// { Extra args to the build the message.converter jmod
|
||||
// Tokens to pass to the run time --add-modules option
|
||||
// SUCCESS or FAILURE expected
|
||||
// Messages expected in the run time output
|
||||
// Messages that must not appear in the run time output },
|
||||
{ "",
|
||||
List.of("ALL-DEFAULT", "ALL-SYSTEM"),
|
||||
ToolResult.ASSERT_SUCCESS,
|
||||
List.of("hello world", "message.converter", "java.base"),
|
||||
List.of("WARNING") },
|
||||
{ "--do-not-resolve-by-default",
|
||||
List.of("ALL-DEFAULT", "ALL-SYSTEM"),
|
||||
ToolResult.ASSERT_FAILURE,
|
||||
List.of("java.base", "java.lang.ClassNotFoundException: converter.MessageConverter"),
|
||||
List.of("WARNING", "message.converter") },
|
||||
{ "--warn-if-resolved=incubating",
|
||||
List.of("ALL-DEFAULT", "ALL-SYSTEM"),
|
||||
ToolResult.ASSERT_SUCCESS,
|
||||
List.of("hello world", "message.converter", "java.base",
|
||||
"WARNING: Using incubator modules: message.converter"),
|
||||
List.of() },
|
||||
{ "--do-not-resolve-by-default --warn-if-resolved=incubating",
|
||||
List.of("ALL-DEFAULT", "ALL-SYSTEM"),
|
||||
ToolResult.ASSERT_FAILURE,
|
||||
List.of("java.base", "java.lang.ClassNotFoundException: converter.MessageConverter"),
|
||||
List.of("WARNING", "message.converter") },
|
||||
{ "--do-not-resolve-by-default --warn-if-resolved=incubating",
|
||||
List.of("message.converter"),
|
||||
ToolResult.ASSERT_SUCCESS,
|
||||
List.of("hello world", "message.converter", "java.base", "WARNING"),
|
||||
List.of() }
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
@Test(dataProvider = "singleModule")
|
||||
public void singleModule(String extraJmodArg,
|
||||
List<String> addModsTokens,
|
||||
Consumer<ToolResult> assertExitCode,
|
||||
List<String> expectedOutput,
|
||||
List<String> unexpectedOutput)
|
||||
throws Throwable
|
||||
{
|
||||
if (Files.notExists(JDK_JMODS)) {
|
||||
System.out.println("JDK jmods not found test cannot run.");
|
||||
return;
|
||||
}
|
||||
|
||||
FileUtils.deleteFileTreeUnchecked(JMODS_DIR);
|
||||
FileUtils.deleteFileTreeUnchecked(IMAGE);
|
||||
Files.createDirectories(JMODS_DIR);
|
||||
Path converterJmod = JMODS_DIR.resolve("converter.jmod");
|
||||
|
||||
jmod("create",
|
||||
"--class-path", MODS_DIR.resolve("message.converter").toString(),
|
||||
extraJmodArg,
|
||||
converterJmod.toString())
|
||||
.assertSuccess();
|
||||
|
||||
String mpath = JDK_JMODS.toString() + File.pathSeparator + JMODS_DIR.toString();
|
||||
jlink("--module-path", mpath,
|
||||
"--add-modules", JAVA_BASE + ",message.converter",
|
||||
"--output", IMAGE.toString())
|
||||
.assertSuccess();
|
||||
|
||||
for (String addModsToken : addModsTokens) {
|
||||
String[] props = new String[] {"", "-Djdk.system.module.finder.disabledFastPath"};
|
||||
for (String systemProp : props)
|
||||
java(IMAGE,
|
||||
systemProp,
|
||||
"--add-modules", addModsToken,
|
||||
"-cp", CP_DIR.toString(),
|
||||
"test.ConvertToLowerCase", "HEllo WoRlD")
|
||||
.resultChecker(assertExitCode)
|
||||
.resultChecker(r -> {
|
||||
expectedOutput.forEach(e -> r.assertContains(e));
|
||||
unexpectedOutput.forEach(e -> r.assertDoesNotContains(e));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleModularJar() throws Throwable {
|
||||
FileUtils.deleteFileTreeUnchecked(JARS_DIR);
|
||||
Files.createDirectories(JARS_DIR);
|
||||
Path converterJar = JARS_DIR.resolve("converter.jar");
|
||||
|
||||
jar("--create",
|
||||
"--file", converterJar.toString(),
|
||||
"--warn-if-resolved=incubating",
|
||||
"-C", MODS_DIR.resolve("message.converter").toString() , ".")
|
||||
.assertSuccess();
|
||||
|
||||
|
||||
java(Paths.get(JAVA_HOME),
|
||||
"--module-path", JARS_DIR.toString(),
|
||||
"--add-modules", "message.converter",
|
||||
"-cp", CP_DIR.toString(),
|
||||
"test.ConvertToLowerCase", "HEllo WoRlD")
|
||||
.assertSuccess()
|
||||
.resultChecker(r -> {
|
||||
r.assertContains("WARNING: Using incubator modules: message.converter");
|
||||
});
|
||||
}
|
||||
|
||||
@DataProvider(name = "twoModules")
|
||||
public Object[][] twoModulesValues() throws IOException {
|
||||
Object[][] values = new Object[][]{
|
||||
// { Extra args to the build the message.writer jmod
|
||||
// Extra args to the build the message.converter jmod
|
||||
// Tokens to pass to the run time --add-modules option
|
||||
// SUCCESS or FAILURE expected
|
||||
// Messages expected in the run time output
|
||||
// Messages that must not appear in the run time output },
|
||||
{ "",
|
||||
"",
|
||||
List.of("ALL-DEFAULT", "ALL-SYSTEM"),
|
||||
ToolResult.ASSERT_SUCCESS,
|
||||
List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base"),
|
||||
List.of() },
|
||||
{ "",
|
||||
"--do-not-resolve-by-default",
|
||||
List.of("ALL-DEFAULT", "ALL-SYSTEM"),
|
||||
ToolResult.ASSERT_SUCCESS,
|
||||
List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base"),
|
||||
List.of() },
|
||||
{ "--do-not-resolve-by-default",
|
||||
"",
|
||||
List.of("ALL-DEFAULT", "ALL-SYSTEM"),
|
||||
ToolResult.ASSERT_FAILURE,
|
||||
List.of("java.lang.ClassNotFoundException: writer.MessageWriter", "java.base"),
|
||||
List.of("message.writer") },
|
||||
{ "--do-not-resolve-by-default",
|
||||
"--do-not-resolve-by-default",
|
||||
List.of("ALL-DEFAULT", "ALL-SYSTEM"),
|
||||
ToolResult.ASSERT_FAILURE,
|
||||
List.of("java.lang.ClassNotFoundException: writer.MessageWriter", "java.base"),
|
||||
List.of("message.converter", "message.writer") },
|
||||
// now add in warnings
|
||||
{ "--do-not-resolve-by-default --warn-if-resolved=incubating",
|
||||
"",
|
||||
List.of("message.writer"),
|
||||
ToolResult.ASSERT_SUCCESS,
|
||||
List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base",
|
||||
"WARNING: Using incubator modules: message.writer"),
|
||||
List.of() },
|
||||
{ "",
|
||||
"--do-not-resolve-by-default --warn-if-resolved=incubating",
|
||||
List.of("message.writer"),
|
||||
ToolResult.ASSERT_SUCCESS,
|
||||
List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base",
|
||||
"WARNING: Using incubator modules: message.converter"),
|
||||
List.of() } };
|
||||
return values;
|
||||
}
|
||||
|
||||
@Test(dataProvider = "twoModules")
|
||||
public void doNotResolveByDefaultTwoModules(String extraFirstJmodArg,
|
||||
String extraSecondJmodArg,
|
||||
List<String> addModsTokens,
|
||||
Consumer<ToolResult> assertExitCode,
|
||||
List<String> expectedOutput,
|
||||
List<String> unexpectedOutput)
|
||||
throws Throwable
|
||||
{
|
||||
if (Files.notExists(JDK_JMODS)) {
|
||||
System.out.println("JDK jmods not found test cannot run.");
|
||||
return;
|
||||
}
|
||||
|
||||
FileUtils.deleteFileTreeUnchecked(JMODS_DIR);
|
||||
FileUtils.deleteFileTreeUnchecked(IMAGE);
|
||||
Files.createDirectories(JMODS_DIR);
|
||||
Path writerJmod = JMODS_DIR.resolve("writer.jmod");
|
||||
Path converterJmod = JMODS_DIR.resolve("converter.jmod");
|
||||
|
||||
jmod("create",
|
||||
extraFirstJmodArg,
|
||||
"--class-path", MODS_DIR.resolve("message.writer").toString(),
|
||||
writerJmod.toString());
|
||||
|
||||
jmod("create",
|
||||
"--class-path", MODS_DIR.resolve("message.converter").toString(),
|
||||
extraSecondJmodArg,
|
||||
converterJmod.toString())
|
||||
.assertSuccess();
|
||||
|
||||
String mpath = JDK_JMODS.toString() + File.pathSeparator + JMODS_DIR.toString();
|
||||
jlink("--module-path", mpath,
|
||||
"--add-modules", JAVA_BASE + ",message.writer,message.converter",
|
||||
"--output", IMAGE.toString())
|
||||
.assertSuccess();
|
||||
|
||||
for (String addModsToken : addModsTokens) {
|
||||
String[] props = new String[] {"", "-Djdk.system.module.finder.disabledFastPath"};
|
||||
for (String systemProp : props)
|
||||
java(IMAGE,
|
||||
systemProp,
|
||||
"--add-modules", addModsToken,
|
||||
"-cp", CP_DIR.toString(),
|
||||
"test.WriteUpperCase", "hello chegar !!!")
|
||||
.resultChecker(assertExitCode)
|
||||
.resultChecker(r -> {
|
||||
expectedOutput.forEach(e -> r.assertContains(e));
|
||||
unexpectedOutput.forEach(e -> r.assertDoesNotContains(e));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod")
|
||||
.orElseThrow(() -> new RuntimeException("jmod tool not found"));
|
||||
static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
|
||||
.orElseThrow(() -> new RuntimeException("jar tool not found"));
|
||||
static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
|
||||
.orElseThrow(() -> new RuntimeException("jlink tool not found"));
|
||||
|
||||
static ToolResult jmod(String... args) { return execTool(JMOD_TOOL, args); }
|
||||
|
||||
static ToolResult jar(String... args) { return execTool(JAR_TOOL, args); }
|
||||
|
||||
static ToolResult jlink(String... args) { return execTool(JLINK_TOOL, args); }
|
||||
|
||||
static ToolResult java(Path image, String... opts) throws Throwable {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
PrintStream ps = new PrintStream(baos);
|
||||
String[] options = Stream.concat(Stream.of(getJava(image)),
|
||||
Stream.of(opts).filter(s -> !s.equals("")))
|
||||
.toArray(String[]::new);
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(options);
|
||||
int exitValue = executeCommand(pb).outputTo(ps)
|
||||
.errorTo(ps)
|
||||
.getExitValue();
|
||||
|
||||
return new ToolResult(exitValue, new String(baos.toByteArray(), UTF_8));
|
||||
}
|
||||
|
||||
static ToolResult execTool(ToolProvider tool, String... args) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
PrintStream ps = new PrintStream(baos);
|
||||
List<String> filteredArgs = Stream.of(args)
|
||||
.map(s -> s.split(" ")).flatMap(Stream::of)
|
||||
.filter(s -> !s.equals(""))
|
||||
.collect(Collectors.toList());
|
||||
System.out.println(tool + " " + filteredArgs);
|
||||
int ec = tool.run(ps, ps, filteredArgs.toArray(new String[] {}));
|
||||
return new ToolResult(ec, new String(baos.toByteArray(), UTF_8));
|
||||
}
|
||||
|
||||
static class ToolResult {
|
||||
final int exitCode;
|
||||
final String output;
|
||||
|
||||
ToolResult(int exitValue, String output) {
|
||||
this.exitCode = exitValue;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
static Consumer<ToolResult> ASSERT_SUCCESS = r ->
|
||||
assertEquals(r.exitCode, 0,
|
||||
"Expected exit code 0, got " + r.exitCode
|
||||
+ ", with output[" + r.output + "]");
|
||||
static Consumer<ToolResult> ASSERT_FAILURE = r ->
|
||||
assertNotEquals(r.exitCode, 0,
|
||||
"Expected exit code != 0, got " + r.exitCode
|
||||
+ ", with output[" + r.output + "]");
|
||||
|
||||
ToolResult assertSuccess() { ASSERT_SUCCESS.accept(this); return this; }
|
||||
ToolResult assertFailure() { ASSERT_FAILURE.accept(this); return this; }
|
||||
ToolResult resultChecker(Consumer<ToolResult> r) { r.accept(this); return this; }
|
||||
|
||||
ToolResult assertContains(String subString) {
|
||||
assertTrue(output.contains(subString),
|
||||
"Expected to find [" + subString + "], in output ["
|
||||
+ output + "]" + "\n");
|
||||
return this;
|
||||
}
|
||||
ToolResult assertDoesNotContains(String subString) {
|
||||
assertFalse(output.contains(subString),
|
||||
"Expected to NOT find [" + subString + "], in output ["
|
||||
+ output + "]" + "\n");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
static String getJava(Path image) {
|
||||
boolean isWindows = System.getProperty("os.name").startsWith("Windows");
|
||||
Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java");
|
||||
if (Files.notExists(java))
|
||||
throw new RuntimeException(java + " not found");
|
||||
return java.toAbsolutePath().toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package listmods;
|
||||
|
||||
import java.lang.reflect.Layer;
|
||||
import java.lang.reflect.Module;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
public class ListModules {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println(Layer.boot()
|
||||
.modules()
|
||||
.stream()
|
||||
.map(Module::getName)
|
||||
.sorted()
|
||||
.collect(joining("\n")));
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.reflect.Layer;
|
||||
import java.lang.reflect.Module;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
public class ConvertToLowerCase {
|
||||
public static void main(String[] args) {
|
||||
System.out.println(Layer.boot()
|
||||
.modules()
|
||||
.stream()
|
||||
.map(Module::getName)
|
||||
.sorted()
|
||||
.collect(joining("\n")));
|
||||
System.out.println(converter.MessageConverter.toLowerCase(args[0]));
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.reflect.Layer;
|
||||
import java.lang.reflect.Module;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
public class WriteUpperCase {
|
||||
public static void main(String[] args) {
|
||||
System.out.println(Layer.boot()
|
||||
.modules()
|
||||
.stream()
|
||||
.map(Module::getName)
|
||||
.sorted()
|
||||
.collect(joining("\n")));
|
||||
writer.MessageWriter.writeOn(args[0], System.out);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package converter;
|
||||
|
||||
public class MessageConverter {
|
||||
public static String toUpperCase(String message) {
|
||||
return message.toUpperCase(java.util.Locale.ROOT);
|
||||
}
|
||||
|
||||
public static String toLowerCase(String message) {
|
||||
return message.toLowerCase(java.util.Locale.ROOT);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
module message.converter {
|
||||
exports converter;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
module message.writer {
|
||||
requires message.converter;
|
||||
exports writer;
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package writer;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.Locale;
|
||||
|
||||
public class MessageWriter {
|
||||
public static void writeOn(String message, PrintStream out) {
|
||||
String newMesssage = converter.MessageConverter.toUpperCase(message);
|
||||
if (!newMesssage.equals(message.toUpperCase(Locale.ROOT)))
|
||||
throw new RuntimeException("Expected " + message.toUpperCase(Locale.ROOT)
|
||||
+ ", got " + newMesssage );
|
||||
|
||||
out.println(newMesssage);
|
||||
}
|
||||
}
|
@ -32,7 +32,6 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
||||
/**
|
||||
@ -58,12 +57,13 @@ public final class ModuleUtils {
|
||||
|
||||
URI uri = URI.create("module:/" + name);
|
||||
|
||||
Supplier<ModuleReader> supplier = () -> {
|
||||
throw new UnsupportedOperationException();
|
||||
ModuleReference mref = new ModuleReference(descriptor, uri) {
|
||||
@Override
|
||||
public ModuleReader open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
|
||||
|
||||
namesToReference.put(name, mref);
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,7 @@ import org.testng.annotations.Test;
|
||||
import static java.lang.String.format;
|
||||
import static java.lang.System.out;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
/*
|
||||
@ -428,10 +429,12 @@ public class CLICompatibility {
|
||||
|
||||
jar("--help")
|
||||
.assertSuccess()
|
||||
.resultChecker(r ->
|
||||
.resultChecker(r -> {
|
||||
assertTrue(r.output.startsWith("Usage: jar [OPTION...] [ [--release VERSION] [-C dir] files]"),
|
||||
"Failed, got [" + r.output + "]")
|
||||
);
|
||||
"Failed, got [" + r.output + "]");
|
||||
assertFalse(r.output.contains("--do-not-resolve-by-default"));
|
||||
assertFalse(r.output.contains("--warn-if-resolved"));
|
||||
});
|
||||
|
||||
jar("--help:compat")
|
||||
.assertSuccess()
|
||||
@ -439,6 +442,15 @@ public class CLICompatibility {
|
||||
assertTrue(r.output.startsWith("Compatibility Interface:"),
|
||||
"Failed, got [" + r.output + "]")
|
||||
);
|
||||
|
||||
jar("--help-extra")
|
||||
.assertSuccess()
|
||||
.resultChecker(r -> {
|
||||
assertTrue(r.output.startsWith("Usage: jar [OPTION...] [ [--release VERSION] [-C dir] files]"),
|
||||
"Failed, got [" + r.output + "]");
|
||||
assertTrue(r.output.contains("--do-not-resolve-by-default"));
|
||||
assertTrue(r.output.contains("--warn-if-resolved"));
|
||||
});
|
||||
}
|
||||
|
||||
// -- Infrastructure
|
||||
|
@ -25,16 +25,18 @@ package jdk.test.bar;
|
||||
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleDescriptor.Exports;
|
||||
import java.lang.module.ModuleDescriptor.Requires;
|
||||
import java.lang.module.ModuleDescriptor.Provides;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.lang.module.ResolvedModule;
|
||||
import java.lang.reflect.Module;
|
||||
import java.util.Optional;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.misc.JavaLangModuleAccess;
|
||||
import jdk.internal.module.ModuleHashes;
|
||||
import jdk.internal.module.ModuleReferenceImpl;
|
||||
import jdk.test.bar.internal.Message;
|
||||
|
||||
public class Bar {
|
||||
@ -71,9 +73,14 @@ public class Bar {
|
||||
if (!sj.toString().equals(""))
|
||||
System.out.println("contains:" + sj.toString());
|
||||
|
||||
ModuleDescriptor foo = jdk.test.foo.Foo.class.getModule().getDescriptor();
|
||||
JavaLangModuleAccess jlma = SharedSecrets.getJavaLangModuleAccess();
|
||||
Optional<ModuleHashes> oHashes = jlma.hashes(foo);
|
||||
System.out.println("hashes:" + oHashes.get().hashFor("bar"));
|
||||
|
||||
Module foo = jdk.test.foo.Foo.class.getModule();
|
||||
Optional<ResolvedModule> om = foo.getLayer().configuration().findModule(foo.getName());
|
||||
assert om.isPresent();
|
||||
ModuleReference mref = om.get().reference();
|
||||
assert mref instanceof ModuleReferenceImpl;
|
||||
ModuleHashes hashes = ((ModuleReferenceImpl) mref).recordedHashes();
|
||||
assert hashes != null;
|
||||
System.out.println("hashes:" + hashes.hashFor("bar"));
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ import jdk.internal.jimage.ImageLocation;
|
||||
* @test
|
||||
* @summary Verify jimage
|
||||
* @modules java.base/jdk.internal.jimage
|
||||
* @run main/othervm --add-modules=ALL-SYSTEM VerifyJimage
|
||||
* @run main/othervm --add-modules=ALL-SYSTEM,jdk.incubator.httpclient VerifyJimage
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.testlibrary.FileUtils;
|
||||
import static jdk.testlibrary.ProcessTools.*;
|
||||
|
||||
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @library /lib/testlibrary
|
||||
* @modules jdk.compiler jdk.jlink
|
||||
* @build CompiledVersionTest CompilerUtils jdk.testlibrary.FileUtils jdk.testlibrary.ProcessTools
|
||||
* @run testng CompiledVersionTest
|
||||
*/
|
||||
|
||||
public class CompiledVersionTest {
|
||||
private static final String JAVA_HOME = System.getProperty("java.home");
|
||||
private static final String TEST_SRC = System.getProperty("test.src");
|
||||
|
||||
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
|
||||
private static final Path MODS_DIR = Paths.get("mods");
|
||||
private static final Path IMAGE = Paths.get("image");
|
||||
private static final Path JMODS = Paths.get(JAVA_HOME, "jmods");
|
||||
private static final String MAIN_MID = "test/jdk.test.Main";
|
||||
|
||||
// the names of the modules in this test
|
||||
private static String[] modules = new String[] { "m1", "m2", "test"};
|
||||
private static String[] versions = new String[] { "1.0", "2-ea", "3-internal"};
|
||||
|
||||
|
||||
private static boolean hasJmods() {
|
||||
if (!Files.exists(JMODS)) {
|
||||
System.err.println("Test skipped. NO jmods directory");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compiles all modules used by the test
|
||||
*/
|
||||
@BeforeTest
|
||||
public void compileAll() throws Throwable {
|
||||
if (!hasJmods()) return;
|
||||
|
||||
for (int i=0; i < modules.length; i++) {
|
||||
String mn = modules[i];
|
||||
String version = versions[i];
|
||||
Path msrc = SRC_DIR.resolve(mn);
|
||||
if (version.equals("0")) {
|
||||
assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
|
||||
"--module-source-path", SRC_DIR.toString()));
|
||||
} else {
|
||||
assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
|
||||
"--module-source-path", SRC_DIR.toString(),
|
||||
"--module-version", version));
|
||||
}
|
||||
}
|
||||
|
||||
if (Files.exists(IMAGE)) {
|
||||
FileUtils.deleteFileTreeUnchecked(IMAGE);
|
||||
}
|
||||
|
||||
createImage(IMAGE, modules);
|
||||
}
|
||||
|
||||
private void createImage(Path outputDir, String... modules) throws Throwable {
|
||||
Path jlink = Paths.get(JAVA_HOME, "bin", "jlink");
|
||||
String mp = JMODS.toString() + File.pathSeparator + MODS_DIR.toString();
|
||||
assertTrue(executeProcess(jlink.toString(), "--output", outputDir.toString(),
|
||||
"--add-modules", Arrays.stream(modules).collect(Collectors.joining(",")),
|
||||
"--module-path", mp)
|
||||
.outputTo(System.out)
|
||||
.errorTo(System.out)
|
||||
.getExitValue() == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the image created when linking with a module with
|
||||
* no Packages attribute
|
||||
*/
|
||||
@Test
|
||||
public void testCompiledVersions() throws Throwable {
|
||||
if (!hasJmods()) return;
|
||||
|
||||
Path java = IMAGE.resolve("bin").resolve("java");
|
||||
Stream<String> options = Stream.concat(
|
||||
Stream.of(java.toString(), "-m", MAIN_MID, String.valueOf(modules.length)),
|
||||
Stream.concat(Arrays.stream(modules), Arrays.stream(versions))
|
||||
);
|
||||
|
||||
assertTrue(executeProcess(options.toArray(String[]::new))
|
||||
.outputTo(System.out)
|
||||
.errorTo(System.out)
|
||||
.getExitValue() == 0);
|
||||
}
|
||||
}
|
@ -59,7 +59,7 @@ public class SystemModulesTest {
|
||||
private void testModuleDescriptor(ModuleDescriptor md) {
|
||||
assertUnmodifiable(md.packages(), "package");
|
||||
assertUnmodifiable(md.requires(),
|
||||
jlma.newRequires(Set.of(Requires.Modifier.TRANSITIVE), "require"));
|
||||
jlma.newRequires(Set.of(Requires.Modifier.TRANSITIVE), "require", null));
|
||||
for (Requires req : md.requires()) {
|
||||
assertUnmodifiable(req.modifiers(), Requires.Modifier.TRANSITIVE);
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ import static org.testng.Assert.*;
|
||||
/**
|
||||
* @test
|
||||
* @library /lib/testlibrary
|
||||
* @modules jdk.compiler
|
||||
* @modules jdk.compiler jdk.jlink
|
||||
* @build UserModuleTest CompilerUtils jdk.testlibrary.FileUtils jdk.testlibrary.ProcessTools
|
||||
* @run testng UserModuleTest
|
||||
*/
|
||||
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.test;
|
||||
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.reflect.Layer;
|
||||
import java.lang.reflect.Module;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
/*
|
||||
* Main class to verify if ModuleDescriptor carries the correct version
|
||||
*/
|
||||
public class Main {
|
||||
static final Map<String, String> nameToVersion = new HashMap<>();
|
||||
|
||||
// jdk.test.Main $count $module-name... $version...
|
||||
public static void main(String... args) throws Exception {
|
||||
int count = args.length > 0 ? Integer.valueOf(args[0]) : 0;
|
||||
if (count < 1 || args.length != count*2+1) {
|
||||
throw new IllegalArgumentException(Arrays.toString(args));
|
||||
}
|
||||
|
||||
List<String> modules = List.of(Arrays.copyOfRange(args, 1, 1+count));
|
||||
List<String> versions = List.of(Arrays.copyOfRange(args, 1+count, args.length));
|
||||
for (int i=0; i < modules.size(); i++) {
|
||||
System.out.format("module %s expects %s version%n",
|
||||
modules.get(i), versions.get(i));
|
||||
nameToVersion.put(modules.get(i), versions.get(i));
|
||||
}
|
||||
|
||||
FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"),
|
||||
Collections.emptyMap());
|
||||
// check the module descriptor of a system module
|
||||
for (int i=0; i < modules.size(); i++) {
|
||||
String mn = modules.get(i);
|
||||
Module module = Layer.boot().findModule(mn).orElseThrow(
|
||||
() -> new RuntimeException(mn + " not found")
|
||||
);
|
||||
|
||||
// check ModuleDescriptor from the run-time
|
||||
validate(module.getDescriptor());
|
||||
|
||||
// check module-info.class in the image
|
||||
Path path = fs.getPath("/", "modules", modules.get(i), "module-info.class");
|
||||
validate(ModuleDescriptor.read(Files.newInputStream(path)));
|
||||
}
|
||||
}
|
||||
|
||||
static void validate(ModuleDescriptor descriptor) {
|
||||
checkVersion(descriptor.name(), descriptor.version());
|
||||
descriptor.requires()
|
||||
.stream()
|
||||
.filter(r -> !r.name().equals("java.base"))
|
||||
.forEach(r -> checkVersion(r.name(), r.compiledVersion()));
|
||||
}
|
||||
|
||||
static void checkVersion(String mn, Optional<ModuleDescriptor.Version> version) {
|
||||
boolean matched;
|
||||
String v = nameToVersion.get(mn);
|
||||
if (version.isPresent()) {
|
||||
matched = version.get().toString().equals(v);
|
||||
} else {
|
||||
// 0 indicate no version
|
||||
matched = v.equals("0");
|
||||
}
|
||||
|
||||
if (!matched) {
|
||||
throw new RuntimeException(mn + " mismatched version " + version
|
||||
+ " expected: " + v);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
module test {
|
||||
requires m1;
|
||||
requires m2;
|
||||
exports jdk.test;
|
||||
}
|
@ -470,9 +470,22 @@ public class JmodTest {
|
||||
public void testHelp() {
|
||||
jmod("--help")
|
||||
.assertSuccess()
|
||||
.resultChecker(r ->
|
||||
assertTrue(r.output.startsWith("Usage: jmod"), "Help not printed")
|
||||
);
|
||||
.resultChecker(r -> {
|
||||
assertTrue(r.output.startsWith("Usage: jmod"), "Help not printed");
|
||||
assertFalse(r.output.contains("--do-not-resolve-by-default"));
|
||||
assertFalse(r.output.contains("--warn-if-resolved"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelpExtra() {
|
||||
jmod("--help-extra")
|
||||
.assertSuccess()
|
||||
.resultChecker(r -> {
|
||||
assertTrue(r.output.startsWith("Usage: jmod"), "Extra help not printed");
|
||||
assertContains(r.output, "--do-not-resolve-by-default");
|
||||
assertContains(r.output, "--warn-if-resolved");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -50,14 +50,13 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.spi.ToolProvider;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.misc.JavaLangModuleAccess;
|
||||
import jdk.internal.module.ModuleInfo;
|
||||
import jdk.internal.module.ModuleHashes;
|
||||
import jdk.internal.module.ModulePath;
|
||||
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
@ -103,54 +102,53 @@ public class HashesTest {
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
for (String mn : modules) {
|
||||
assertFalse(hashes(mn).isPresent());
|
||||
assertTrue(hashes(mn) == null);
|
||||
}
|
||||
|
||||
// hash m1 in m2
|
||||
jmod("m2", "--module-path", jmods.toString(), "--hash-modules", "m1");
|
||||
checkHashes(hashes("m2").get(), "m1");
|
||||
checkHashes(hashes("m2"), "m1");
|
||||
|
||||
// hash m1 in m2
|
||||
jmod("m2", "--module-path", jmods.toString(), "--hash-modules", ".*");
|
||||
checkHashes(hashes("m2").get(), "m1");
|
||||
checkHashes(hashes("m2"), "m1");
|
||||
|
||||
// create m2.jmod with no hash
|
||||
jmod("m2");
|
||||
// run jmod hash command to hash m1 in m2 and m3
|
||||
runJmod(Arrays.asList("hash", "--module-path", jmods.toString(),
|
||||
"--hash-modules", ".*"));
|
||||
checkHashes(hashes("m2").get(), "m1");
|
||||
checkHashes(hashes("m3").get(), "m1");
|
||||
checkHashes(hashes("m2"), "m1");
|
||||
checkHashes(hashes("m3"), "m1");
|
||||
|
||||
jmod("org.bar");
|
||||
jmod("org.foo");
|
||||
|
||||
jmod("org.bar", "--module-path", jmods.toString(), "--hash-modules", "org.*");
|
||||
checkHashes(hashes("org.bar").get(), "org.foo");
|
||||
checkHashes(hashes("org.bar"), "org.foo");
|
||||
|
||||
jmod("m3", "--module-path", jmods.toString(), "--hash-modules", ".*");
|
||||
checkHashes(hashes("m3").get(), "org.foo", "org.bar", "m1");
|
||||
checkHashes(hashes("m3"), "org.foo", "org.bar", "m1");
|
||||
}
|
||||
|
||||
private void checkHashes(ModuleHashes hashes, String... hashModules) {
|
||||
assertTrue(hashes.names().equals(Set.of(hashModules)));
|
||||
}
|
||||
|
||||
private Optional<ModuleHashes> hashes(String name) throws Exception {
|
||||
ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
|
||||
.newModulePath(Runtime.version(), true, jmods.resolve(name + ".jmod"));
|
||||
private ModuleHashes hashes(String name) throws Exception {
|
||||
ModuleFinder finder = new ModulePath(Runtime.version(),
|
||||
true,
|
||||
jmods.resolve(name + ".jmod"));
|
||||
ModuleReference mref = finder.find(name).orElseThrow(RuntimeException::new);
|
||||
ModuleReader reader = mref.open();
|
||||
try (InputStream in = reader.open("module-info.class").get()) {
|
||||
ModuleDescriptor md = ModuleDescriptor.read(in);
|
||||
JavaLangModuleAccess jmla = SharedSecrets.getJavaLangModuleAccess();
|
||||
Optional<ModuleHashes> hashes = jmla.hashes(md);
|
||||
ModuleHashes hashes = ModuleInfo.read(in, null).recordedHashes();
|
||||
System.out.format("hashes in module %s %s%n", name,
|
||||
hashes.isPresent() ? "present" : "absent");
|
||||
if (hashes.isPresent()) {
|
||||
hashes.get().names().stream()
|
||||
(hashes != null) ? "present" : "absent");
|
||||
if (hashes != null) {
|
||||
hashes.names().stream()
|
||||
.sorted()
|
||||
.forEach(n -> System.out.format(" %s %s%n", n, hashes.get().hashFor(n)));
|
||||
.forEach(n -> System.out.format(" %s %s%n", n, hashes.hashFor(n)));
|
||||
}
|
||||
return hashes;
|
||||
} finally {
|
||||
|
@ -41,6 +41,8 @@ import com.sun.tools.classfile.Code_attribute;
|
||||
import com.sun.tools.classfile.CompilationID_attribute;
|
||||
import com.sun.tools.classfile.ConstantPool;
|
||||
import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
|
||||
import com.sun.tools.classfile.ConstantPool.CONSTANT_Module_info;
|
||||
import com.sun.tools.classfile.ConstantPool.CONSTANT_Package_info;
|
||||
import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info;
|
||||
import com.sun.tools.classfile.ConstantPool.CONSTANT_Fieldref_info;
|
||||
import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info;
|
||||
@ -80,9 +82,9 @@ import com.sun.tools.classfile.Module_attribute.RequiresEntry;
|
||||
import com.sun.tools.classfile.ModuleHashes_attribute;
|
||||
import com.sun.tools.classfile.ModuleHashes_attribute.Entry;
|
||||
import com.sun.tools.classfile.ModuleMainClass_attribute;
|
||||
import com.sun.tools.classfile.ModuleResolution_attribute;
|
||||
import com.sun.tools.classfile.ModuleTarget_attribute;
|
||||
import com.sun.tools.classfile.ModulePackages_attribute;
|
||||
import com.sun.tools.classfile.ModuleVersion_attribute;
|
||||
import com.sun.tools.classfile.Opcode;
|
||||
import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
|
||||
import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
|
||||
@ -669,6 +671,40 @@ class ConstantPoolVisitor implements ConstantPool.Visitor<String, Integer> {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitModule(CONSTANT_Module_info info, Integer p) {
|
||||
String value = slist.get(p);
|
||||
if (value == null) {
|
||||
try {
|
||||
value = visit(cfpool.get(info.name_index), info.name_index);
|
||||
slist.set(p, value);
|
||||
xpool.add(new Element("CONSTANT_Module",
|
||||
new String[]{"id", p.toString()},
|
||||
value));
|
||||
} catch (ConstantPoolException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitPackage(CONSTANT_Package_info info, Integer p) {
|
||||
String value = slist.get(p);
|
||||
if (value == null) {
|
||||
try {
|
||||
value = visit(cfpool.get(info.name_index), info.name_index);
|
||||
slist.set(p, value);
|
||||
xpool.add(new Element("CONSTANT_Package",
|
||||
new String[]{"id", p.toString()},
|
||||
value));
|
||||
} catch (ConstantPoolException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitDouble(CONSTANT_Double_info c, Integer p) {
|
||||
String value = slist.get(p);
|
||||
@ -1495,20 +1531,20 @@ class AttributeVisitor implements Attribute.Visitor<Element, Element> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element visitModuleTarget(ModuleTarget_attribute attr, Element p) {
|
||||
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));
|
||||
public Element visitModuleResolution(ModuleResolution_attribute attr, Element p) {
|
||||
Element e = new Element("ModuleResolution");
|
||||
e.setAttr("flags", Integer.toString(attr.resolution_flags));
|
||||
e.trimToSize();
|
||||
p.add(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element visitModuleVersion(ModuleVersion_attribute attr, Element p) {
|
||||
public Element visitModuleTarget(ModuleTarget_attribute attr, Element p) {
|
||||
Element e = new Element(x.getCpString(attr.attribute_name_index));
|
||||
e.add(x.getCpString(attr.version_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;
|
||||
|
Loading…
Reference in New Issue
Block a user