use of java.lang.module.ModuleDescriptor.Builder in project Bytecoder by mirkosertic.
the class ModuleInfo method readModuleAttribute.
/**
* Reads the Module attribute, returning the ModuleDescriptor.Builder to
* build the corresponding ModuleDescriptor.
*/
private Builder readModuleAttribute(DataInput in, ConstantPool cpool) throws IOException {
// module_name
int module_name_index = in.readUnsignedShort();
String mn = cpool.getModuleName(module_name_index);
int module_flags = in.readUnsignedShort();
Set<ModuleDescriptor.Modifier> modifiers = new HashSet<>();
boolean open = ((module_flags & ACC_OPEN) != 0);
if (open)
modifiers.add(ModuleDescriptor.Modifier.OPEN);
if ((module_flags & ACC_SYNTHETIC) != 0)
modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC);
if ((module_flags & ACC_MANDATED) != 0)
modifiers.add(ModuleDescriptor.Modifier.MANDATED);
Builder builder = JLMA.newModuleBuilder(mn, false, modifiers);
int module_version_index = in.readUnsignedShort();
if (module_version_index != 0) {
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 requires_index = in.readUnsignedShort();
String dn = cpool.getModuleName(requires_index);
int requires_flags = in.readUnsignedShort();
Set<Requires.Modifier> mods;
if (requires_flags == 0) {
mods = Collections.emptySet();
} else {
mods = new HashSet<>();
if ((requires_flags & ACC_TRANSITIVE) != 0)
mods.add(Requires.Modifier.TRANSITIVE);
if ((requires_flags & ACC_STATIC_PHASE) != 0)
mods.add(Requires.Modifier.STATIC);
if ((requires_flags & ACC_SYNTHETIC) != 0)
mods.add(Requires.Modifier.SYNTHETIC);
if ((requires_flags & ACC_MANDATED) != 0)
mods.add(Requires.Modifier.MANDATED);
}
int requires_version_index = in.readUnsignedShort();
if (requires_version_index == 0) {
builder.requires(mods, dn);
} else {
String vs = cpool.getUtf8(requires_version_index);
JLMA.requires(builder, mods, dn, vs);
}
if (dn.equals("java.base"))
requiresJavaBase = true;
}
if (mn.equals("java.base")) {
if (requires_count > 0) {
throw invalidModuleDescriptor("The requires table for java.base" + " must be 0 length");
}
} else if (!requiresJavaBase) {
throw invalidModuleDescriptor("The requires table must have" + " an entry for java.base");
}
int exports_count = in.readUnsignedShort();
if (exports_count > 0) {
for (int i = 0; i < exports_count; i++) {
int exports_index = in.readUnsignedShort();
String pkg = cpool.getPackageName(exports_index);
Set<Exports.Modifier> mods;
int exports_flags = in.readUnsignedShort();
if (exports_flags == 0) {
mods = Collections.emptySet();
} else {
mods = new HashSet<>();
if ((exports_flags & ACC_SYNTHETIC) != 0)
mods.add(Exports.Modifier.SYNTHETIC);
if ((exports_flags & ACC_MANDATED) != 0)
mods.add(Exports.Modifier.MANDATED);
}
int exports_to_count = in.readUnsignedShort();
if (exports_to_count > 0) {
Set<String> targets = new HashSet<>(exports_to_count);
for (int j = 0; j < exports_to_count; j++) {
int exports_to_index = in.readUnsignedShort();
String target = cpool.getModuleName(exports_to_index);
if (!targets.add(target)) {
throw invalidModuleDescriptor(pkg + " exported to " + target + " more than once");
}
}
builder.exports(mods, pkg, targets);
} else {
builder.exports(mods, pkg);
}
}
}
int opens_count = in.readUnsignedShort();
if (opens_count > 0) {
if (open) {
throw invalidModuleDescriptor("The opens table for an open" + " module must be 0 length");
}
for (int i = 0; i < opens_count; i++) {
int opens_index = in.readUnsignedShort();
String pkg = cpool.getPackageName(opens_index);
Set<Opens.Modifier> mods;
int opens_flags = in.readUnsignedShort();
if (opens_flags == 0) {
mods = Collections.emptySet();
} else {
mods = new HashSet<>();
if ((opens_flags & ACC_SYNTHETIC) != 0)
mods.add(Opens.Modifier.SYNTHETIC);
if ((opens_flags & ACC_MANDATED) != 0)
mods.add(Opens.Modifier.MANDATED);
}
int open_to_count = in.readUnsignedShort();
if (open_to_count > 0) {
Set<String> targets = new HashSet<>(open_to_count);
for (int j = 0; j < open_to_count; j++) {
int opens_to_index = in.readUnsignedShort();
String target = cpool.getModuleName(opens_to_index);
if (!targets.add(target)) {
throw invalidModuleDescriptor(pkg + " opened to " + target + " more than once");
}
}
builder.opens(mods, pkg, targets);
} else {
builder.opens(mods, pkg);
}
}
}
int uses_count = in.readUnsignedShort();
if (uses_count > 0) {
for (int i = 0; i < uses_count; i++) {
int index = in.readUnsignedShort();
String sn = cpool.getClassName(index);
builder.uses(sn);
}
}
int provides_count = in.readUnsignedShort();
if (provides_count > 0) {
for (int i = 0; i < provides_count; i++) {
int index = in.readUnsignedShort();
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.getClassName(index);
if (!providers.add(pn)) {
throw invalidModuleDescriptor(sn + " provides " + pn + " more than once");
}
}
builder.provides(sn, providers);
}
}
return builder;
}
use of java.lang.module.ModuleDescriptor.Builder in project Bytecoder by mirkosertic.
the class ModuleInfo method doRead.
/**
* Reads the input as a module-info class file.
*
* @throws IOException
* @throws InvalidModuleDescriptorException
* @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder
* because an identifier is not a legal Java identifier, duplicate
* exports, and many other reasons
*/
private Attributes doRead(DataInput in) throws IOException {
int magic = in.readInt();
if (magic != 0xCAFEBABE)
throw invalidModuleDescriptor("Bad magic number");
int minor_version = in.readUnsignedShort();
int major_version = in.readUnsignedShort();
if (major_version < 53) {
throw invalidModuleDescriptor("Must be >= 53.0");
}
ConstantPool cpool = new ConstantPool(in);
int access_flags = in.readUnsignedShort();
if (access_flags != ACC_MODULE)
throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
int this_class = in.readUnsignedShort();
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)
throw invalidModuleDescriptor("bad #super_class");
int interfaces_count = in.readUnsignedShort();
if (interfaces_count > 0)
throw invalidModuleDescriptor("Bad #interfaces");
int fields_count = in.readUnsignedShort();
if (fields_count > 0)
throw invalidModuleDescriptor("Bad #fields");
int methods_count = in.readUnsignedShort();
if (methods_count > 0)
throw invalidModuleDescriptor("Bad #methods");
int attributes_count = in.readUnsignedShort();
// the names of the attributes found in the class file
Set<String> attributes = new HashSet<>();
Builder builder = null;
Set<String> allPackages = null;
String mainClass = null;
ModuleTarget moduleTarget = null;
ModuleHashes moduelHashes = null;
ModuleResolution moduleResolution = null;
for (int i = 0; i < attributes_count; i++) {
int name_index = in.readUnsignedShort();
String attribute_name = cpool.getUtf8(name_index);
int length = in.readInt();
boolean added = attributes.add(attribute_name);
if (!added && isAttributeAtMostOnce(attribute_name)) {
throw invalidModuleDescriptor("More than one " + attribute_name + " attribute");
}
switch(attribute_name) {
case MODULE:
builder = readModuleAttribute(in, cpool);
break;
case MODULE_PACKAGES:
allPackages = readModulePackagesAttribute(in, cpool);
break;
case MODULE_MAIN_CLASS:
mainClass = readModuleMainClassAttribute(in, cpool);
break;
case MODULE_TARGET:
moduleTarget = readModuleTargetAttribute(in, cpool);
break;
case MODULE_HASHES:
if (parseHashes) {
moduelHashes = readModuleHashesAttribute(in, cpool);
} else {
in.skipBytes(length);
}
break;
case MODULE_RESOLUTION:
moduleResolution = readModuleResolution(in, cpool);
break;
default:
if (isAttributeDisallowed(attribute_name)) {
throw invalidModuleDescriptor(attribute_name + " attribute not allowed");
} else {
in.skipBytes(length);
}
}
}
// the Module attribute is required
if (builder == null) {
throw invalidModuleDescriptor(MODULE + " attribute not found");
}
// ModuleMainClass attribute
if (mainClass != null) {
builder.mainClass(mainClass);
}
// If the ModulePackages attribute is not present then the packageFinder
// is used to find the set of packages
boolean usedPackageFinder = false;
if (allPackages == null && packageFinder != null) {
try {
allPackages = packageFinder.get();
} catch (UncheckedIOException x) {
throw x.getCause();
}
usedPackageFinder = true;
}
if (allPackages != null) {
Set<String> knownPackages = JLMA.packages(builder);
if (!allPackages.containsAll(knownPackages)) {
Set<String> missingPackages = new HashSet<>(knownPackages);
missingPackages.removeAll(allPackages);
assert !missingPackages.isEmpty();
String missingPackage = missingPackages.iterator().next();
String tail;
if (usedPackageFinder) {
tail = " not found in module";
} else {
tail = " missing from ModulePackages class file attribute";
}
throw invalidModuleDescriptor("Package " + missingPackage + tail);
}
builder.packages(allPackages);
}
ModuleDescriptor descriptor = builder.build();
return new Attributes(descriptor, moduleTarget, moduelHashes, moduleResolution);
}
use of java.lang.module.ModuleDescriptor.Builder in project Bytecoder by mirkosertic.
the class ModulePath method deriveModuleDescriptor.
/**
* Treat the given JAR file as a module as follows:
*
* 1. The value of the Automatic-Module-Name attribute is the module name
* 2. The version, and the module name when the Automatic-Module-Name
* attribute is not present, is derived from the file ame of the JAR file
* 3. All packages are derived from the .class files in the JAR file
* 4. The contents of any META-INF/services configuration files are mapped
* to "provides" declarations
* 5. The Main-Class attribute in the main attributes of the JAR manifest
* is mapped to the module descriptor mainClass if possible
*/
private ModuleDescriptor deriveModuleDescriptor(JarFile jf) throws IOException {
// Read Automatic-Module-Name attribute if present
Manifest man = jf.getManifest();
Attributes attrs = null;
String moduleName = null;
if (man != null) {
attrs = man.getMainAttributes();
if (attrs != null) {
moduleName = attrs.getValue(AUTOMATIC_MODULE_NAME);
}
}
// Derive the version, and the module name if needed, from JAR file name
String fn = jf.getName();
int i = fn.lastIndexOf(File.separator);
if (i != -1)
fn = fn.substring(i + 1);
// drop ".jar"
String name = fn.substring(0, fn.length() - 4);
String vs = null;
// find first occurrence of -${NUMBER}. or -${NUMBER}$
Matcher matcher = Patterns.DASH_VERSION.matcher(name);
if (matcher.find()) {
int start = matcher.start();
// attempt to parse the tail as a version string
try {
String tail = name.substring(start + 1);
ModuleDescriptor.Version.parse(tail);
vs = tail;
} catch (IllegalArgumentException ignore) {
}
name = name.substring(0, start);
}
// Create builder, using the name derived from file name when
// Automatic-Module-Name not present
Builder builder;
if (moduleName != null) {
try {
builder = ModuleDescriptor.newAutomaticModule(moduleName);
} catch (IllegalArgumentException e) {
throw new FindException(AUTOMATIC_MODULE_NAME + ": " + e.getMessage());
}
} else {
builder = ModuleDescriptor.newAutomaticModule(cleanModuleName(name));
}
// module version if present
if (vs != null)
builder.version(vs);
// scan the names of the entries in the JAR file
Map<Boolean, Set<String>> map = VersionedStream.stream(jf).filter(e -> !e.isDirectory()).map(JarEntry::getName).filter(e -> (e.endsWith(".class") ^ e.startsWith(SERVICES_PREFIX))).collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX), Collectors.toSet()));
Set<String> classFiles = map.get(Boolean.FALSE);
Set<String> configFiles = map.get(Boolean.TRUE);
// the packages containing class files
Set<String> packages = classFiles.stream().map(this::toPackageName).flatMap(Optional::stream).distinct().collect(Collectors.toSet());
// all packages are exported and open
builder.packages(packages);
// map names of service configuration files to service names
Set<String> serviceNames = configFiles.stream().map(this::toServiceName).flatMap(Optional::stream).collect(Collectors.toSet());
// parse each service configuration file
for (String sn : serviceNames) {
JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
List<String> providerClasses = new ArrayList<>();
try (InputStream in = jf.getInputStream(entry)) {
BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
String cn;
while ((cn = nextLine(reader)) != null) {
if (cn.length() > 0) {
String pn = packageName(cn);
if (!packages.contains(pn)) {
String msg = "Provider class " + cn + " not in module";
throw new InvalidModuleDescriptorException(msg);
}
providerClasses.add(cn);
}
}
}
if (!providerClasses.isEmpty())
builder.provides(sn, providerClasses);
}
// Main-Class attribute if it exists
if (attrs != null) {
String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
if (mainClass != null) {
mainClass = mainClass.replace("/", ".");
if (Checks.isClassName(mainClass)) {
String pn = packageName(mainClass);
if (packages.contains(pn)) {
builder.mainClass(mainClass);
}
}
}
}
return builder.build();
}
use of java.lang.module.ModuleDescriptor.Builder in project Bytecoder by mirkosertic.
the class ModulePatcher method patchIfNeeded.
/**
* Returns a module reference that interposes on the given module if
* needed. If there are no patches for the given module then the module
* reference is simply returned. Otherwise the patches for the module
* are scanned (to find any new packages) and a new module reference is
* returned.
*
* @throws UncheckedIOException if an I/O error is detected
*/
public ModuleReference patchIfNeeded(ModuleReference mref) {
// if there are no patches for the module then nothing to do
ModuleDescriptor descriptor = mref.descriptor();
String mn = descriptor.name();
List<Path> paths = map.get(mn);
if (paths == null)
return mref;
// Scan the JAR file or directory tree to get the set of packages.
// For automatic modules then packages that do not contain class files
// must be ignored.
Set<String> packages = new HashSet<>();
boolean isAutomatic = descriptor.isAutomatic();
try {
for (Path file : paths) {
if (Files.isRegularFile(file)) {
// is not supported by the boot class loader
try (JarFile jf = new JarFile(file.toString())) {
jf.stream().filter(e -> !e.isDirectory() && (!isAutomatic || e.getName().endsWith(".class"))).map(e -> toPackageName(file, e)).filter(Checks::isPackageName).forEach(packages::add);
}
} else if (Files.isDirectory(file)) {
// exploded directory without following sym links
Path top = file;
Files.find(top, Integer.MAX_VALUE, ((path, attrs) -> attrs.isRegularFile())).filter(path -> (!isAutomatic || path.toString().endsWith(".class")) && !isHidden(path)).map(path -> toPackageName(top, path)).filter(Checks::isPackageName).forEach(packages::add);
}
}
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
// if there are new packages then we need a new ModuleDescriptor
packages.removeAll(descriptor.packages());
if (!packages.isEmpty()) {
Builder builder = JLMA.newModuleBuilder(descriptor.name(), /*strict*/
false, descriptor.modifiers());
if (!descriptor.isAutomatic()) {
descriptor.requires().forEach(builder::requires);
descriptor.exports().forEach(builder::exports);
descriptor.opens().forEach(builder::opens);
descriptor.uses().forEach(builder::uses);
}
descriptor.provides().forEach(builder::provides);
descriptor.version().ifPresent(builder::version);
descriptor.mainClass().ifPresent(builder::mainClass);
// original + new packages
builder.packages(descriptor.packages());
builder.packages(packages);
descriptor = builder.build();
}
// return a module reference to the patched module
URI location = mref.location().orElse(null);
ModuleTarget target = null;
ModuleHashes recordedHashes = null;
ModuleHashes.HashSupplier hasher = null;
ModuleResolution mres = null;
if (mref instanceof ModuleReferenceImpl) {
ModuleReferenceImpl impl = (ModuleReferenceImpl) mref;
target = impl.moduleTarget();
recordedHashes = impl.recordedHashes();
hasher = impl.hasher();
mres = impl.moduleResolution();
}
return new ModuleReferenceImpl(descriptor, location, () -> new PatchedModuleReader(paths, mref), this, target, recordedHashes, hasher, mres);
}
Aggregations