8294962: Convert java.base/jdk.internal.module package to use the Classfile API to modify and write module-info.class
Reviewed-by: alanb, mchung
This commit is contained in:
parent
065d3e0d58
commit
714b5f036f
@ -250,44 +250,20 @@ public class Classfile {
|
||||
* @return the classfile bytes
|
||||
*/
|
||||
public static byte[] buildModule(ModuleAttribute moduleAttribute) {
|
||||
return buildModule(moduleAttribute, List.of(), clb -> {});
|
||||
return buildModule(moduleAttribute, clb -> {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a module descriptor into a byte array.
|
||||
* @param moduleAttribute the {@code Module} attribute
|
||||
* @param packages additional module packages
|
||||
* @return the classfile bytes
|
||||
*/
|
||||
public static byte[] buildModule(ModuleAttribute moduleAttribute,
|
||||
List<PackageDesc> packages) {
|
||||
return buildModule(moduleAttribute, packages, clb -> {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a module descriptor into a byte array.
|
||||
* @param moduleAttribute the {@code Module} attribute
|
||||
* @param packages additional module packages
|
||||
* @param handler a handler that receives a {@link ClassBuilder}
|
||||
* @return the classfile bytes
|
||||
*/
|
||||
public static byte[] buildModule(ModuleAttribute moduleAttribute,
|
||||
List<PackageDesc> packages,
|
||||
Consumer<? super ClassBuilder> handler) {
|
||||
return build(ClassDesc.of("module-info"), clb -> {
|
||||
clb.withFlags(AccessFlag.MODULE);
|
||||
clb.with(moduleAttribute);
|
||||
if (!packages.isEmpty()) {
|
||||
var cp = clb.constantPool();
|
||||
var allPackages = new LinkedHashSet<PackageEntry>();
|
||||
for (var exp : moduleAttribute.exports()) allPackages.add(AbstractPoolEntry.maybeClone(cp, exp.exportedPackage()));
|
||||
for (var opn : moduleAttribute.opens()) allPackages.add(AbstractPoolEntry.maybeClone(cp, opn.openedPackage()));
|
||||
boolean emitMPA = false;
|
||||
for (var p : packages)
|
||||
emitMPA |= allPackages.add(cp.packageEntry(p));
|
||||
if(emitMPA)
|
||||
clb.with(new UnboundAttribute.UnboundModulePackagesAttribute(allPackages));
|
||||
}
|
||||
handler.accept(clb);
|
||||
});
|
||||
}
|
||||
@ -299,33 +275,19 @@ public class Classfile {
|
||||
*/
|
||||
public static void buildModuleTo(Path path,
|
||||
ModuleAttribute moduleAttribute) throws IOException {
|
||||
buildModuleTo(path, moduleAttribute, List.of(), clb -> {});
|
||||
buildModuleTo(path, moduleAttribute, clb -> {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a module descriptor into a file.
|
||||
* @param path the file to write
|
||||
* @param moduleAttribute the {@code Module} attribute
|
||||
* @param packages additional module packages
|
||||
*/
|
||||
public static void buildModuleTo(Path path,
|
||||
ModuleAttribute moduleAttribute,
|
||||
List<PackageDesc> packages) throws IOException {
|
||||
buildModuleTo(path, moduleAttribute, packages, clb -> {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a module descriptor into a file.
|
||||
* @param path the file to write
|
||||
* @param moduleAttribute the {@code Module} attribute
|
||||
* @param packages additional module packages
|
||||
* @param handler a handler that receives a {@link ClassBuilder}
|
||||
*/
|
||||
public static void buildModuleTo(Path path,
|
||||
ModuleAttribute moduleAttribute,
|
||||
List<PackageDesc> packages,
|
||||
Consumer<? super ClassBuilder> handler) throws IOException {
|
||||
Files.write(path, buildModule(moduleAttribute, packages, handler));
|
||||
Files.write(path, buildModule(moduleAttribute, handler));
|
||||
}
|
||||
|
||||
public static final int MAGIC_NUMBER = 0xCAFEBABE;
|
||||
|
@ -142,6 +142,19 @@ public sealed interface ModuleAttribute
|
||||
return mb.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a {@code Module} attribute}
|
||||
*
|
||||
* @param moduleName the module name
|
||||
* @param attrHandler a handler that receives a {@link ModuleAttributeBuilder}
|
||||
*/
|
||||
static ModuleAttribute of(ModuleEntry moduleName,
|
||||
Consumer<ModuleAttributeBuilder> attrHandler) {
|
||||
var mb = new ModuleAttributeBuilderImpl(moduleName);
|
||||
attrHandler.accept(mb);
|
||||
return mb.build();
|
||||
}
|
||||
|
||||
public sealed interface ModuleAttributeBuilder
|
||||
permits ModuleAttributeBuilderImpl {
|
||||
|
||||
|
@ -49,11 +49,15 @@ public final class ModuleAttributeBuilderImpl
|
||||
private final Set<ClassEntry> uses = new LinkedHashSet<>();
|
||||
private final Set<ModuleProvideInfo> provides = new LinkedHashSet<>();
|
||||
|
||||
public ModuleAttributeBuilderImpl(ModuleDesc moduleName) {
|
||||
this.moduleEntry = TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(moduleName.moduleName()));
|
||||
public ModuleAttributeBuilderImpl(ModuleEntry moduleName) {
|
||||
this.moduleEntry = moduleName;
|
||||
this.moduleFlags = 0;
|
||||
}
|
||||
|
||||
public ModuleAttributeBuilderImpl(ModuleDesc moduleName) {
|
||||
this(TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(moduleName.moduleName())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleAttribute build() {
|
||||
return new UnboundAttribute.UnboundModuleAttribute(moduleEntry, moduleFlags, moduleVersion,
|
||||
|
@ -28,21 +28,23 @@ package jdk.internal.module;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.module.ModuleDescriptor.Version;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import jdk.internal.classfile.Classfile;
|
||||
import jdk.internal.classfile.ClassTransform;
|
||||
import jdk.internal.classfile.attribute.ModuleAttribute;
|
||||
import jdk.internal.classfile.attribute.ModuleHashInfo;
|
||||
import jdk.internal.classfile.attribute.ModuleHashesAttribute;
|
||||
import jdk.internal.classfile.attribute.ModuleMainClassAttribute;
|
||||
import jdk.internal.classfile.attribute.ModulePackagesAttribute;
|
||||
import jdk.internal.classfile.attribute.ModuleResolutionAttribute;
|
||||
import jdk.internal.classfile.attribute.ModuleTargetAttribute;
|
||||
import jdk.internal.classfile.java.lang.constant.ModuleDesc;
|
||||
import jdk.internal.classfile.java.lang.constant.PackageDesc;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Attribute;
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.ClassVisitor;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.ModuleVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.commons.ModuleHashesAttribute;
|
||||
import jdk.internal.org.objectweb.asm.commons.ModuleResolutionAttribute;
|
||||
import jdk.internal.org.objectweb.asm.commons.ModuleTargetAttribute;
|
||||
|
||||
/**
|
||||
* Utility class to extend a module-info.class with additional attributes.
|
||||
@ -148,90 +150,53 @@ public final class ModuleInfoExtender {
|
||||
* be discarded.
|
||||
*/
|
||||
public byte[] toByteArray() throws IOException {
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
|
||||
+ ClassWriter.COMPUTE_FRAMES);
|
||||
|
||||
ClassReader cr = new ClassReader(in);
|
||||
|
||||
ClassVisitor cv = new ClassVisitor(Opcodes.ASM7, cw) {
|
||||
@Override
|
||||
public ModuleVisitor visitModule(String name, int flags, String version) {
|
||||
Version v = ModuleInfoExtender.this.version;
|
||||
String vs = (v != null) ? v.toString() : version;
|
||||
ModuleVisitor mv = super.visitModule(name, flags, vs);
|
||||
|
||||
// ModuleMainClass attribute
|
||||
if (mainClass != null) {
|
||||
mv.visitMainClass(mainClass.replace('.', '/'));
|
||||
}
|
||||
|
||||
// ModulePackages attribute
|
||||
if (packages != null) {
|
||||
packages.stream()
|
||||
.sorted()
|
||||
.forEach(pn -> mv.visitPackage(pn.replace('.', '/')));
|
||||
}
|
||||
|
||||
return new ModuleVisitor(Opcodes.ASM7, mv) {
|
||||
public void visitMainClass(String existingMainClass) {
|
||||
// skip main class if there is a new value
|
||||
if (mainClass == null) {
|
||||
super.visitMainClass(existingMainClass);
|
||||
}
|
||||
}
|
||||
public void visitPackage(String existingPackage) {
|
||||
// skip packages if there is a new set of packages
|
||||
if (packages == null) {
|
||||
super.visitPackage(existingPackage);
|
||||
}
|
||||
}
|
||||
};
|
||||
var cm = Classfile.parse(in.readAllBytes());
|
||||
Version v = ModuleInfoExtender.this.version;
|
||||
return cm.transform(ClassTransform.endHandler(clb -> {
|
||||
// ModuleMainClass attribute
|
||||
if (mainClass != null) {
|
||||
clb.with(ModuleMainClassAttribute.of(ClassDesc.of(mainClass)));
|
||||
}
|
||||
@Override
|
||||
public void visitAttribute(Attribute attr) {
|
||||
String name = attr.type;
|
||||
// drop existing attributes if there are replacements
|
||||
if (name.equals(ClassFileConstants.MODULE_TARGET)
|
||||
&& targetPlatform != null)
|
||||
return;
|
||||
if (name.equals(ClassFileConstants.MODULE_RESOLUTION)
|
||||
&& moduleResolution != null)
|
||||
return;
|
||||
if (name.equals(ClassFileConstants.MODULE_HASHES)
|
||||
&& hashes != null)
|
||||
return;
|
||||
|
||||
super.visitAttribute(attr);
|
||||
|
||||
// ModulePackages attribute
|
||||
if (packages != null) {
|
||||
List<PackageDesc> packageNames = packages.stream()
|
||||
.sorted()
|
||||
.map(PackageDesc::of)
|
||||
.toList();
|
||||
clb.with(ModulePackagesAttribute.ofNames(packageNames));
|
||||
}
|
||||
};
|
||||
|
||||
List<Attribute> attrs = new ArrayList<>();
|
||||
attrs.add(new ModuleTargetAttribute());
|
||||
attrs.add(new ModuleResolutionAttribute());
|
||||
attrs.add(new ModuleHashesAttribute());
|
||||
cr.accept(cv, attrs.toArray(new Attribute[0]), 0);
|
||||
|
||||
// add ModuleTarget, ModuleResolution and ModuleHashes attributes
|
||||
if (targetPlatform != null) {
|
||||
cw.visitAttribute(new ModuleTargetAttribute(targetPlatform));
|
||||
}
|
||||
if (moduleResolution != null) {
|
||||
int flags = moduleResolution.value();
|
||||
cw.visitAttribute(new ModuleResolutionAttribute(flags));
|
||||
}
|
||||
if (hashes != null) {
|
||||
String algorithm = hashes.algorithm();
|
||||
List<String> names = new ArrayList<>();
|
||||
List<byte[]> values = new ArrayList<>();
|
||||
for (String name : hashes.names()) {
|
||||
names.add(name);
|
||||
values.add(hashes.hashFor(name));
|
||||
// ModuleTarget, ModuleResolution and ModuleHashes attributes
|
||||
if (targetPlatform != null) {
|
||||
clb.with(ModuleTargetAttribute.of(targetPlatform));
|
||||
}
|
||||
cw.visitAttribute(new ModuleHashesAttribute(algorithm, names, values));
|
||||
}
|
||||
|
||||
return cw.toByteArray();
|
||||
if (moduleResolution != null) {
|
||||
clb.with(ModuleResolutionAttribute.of(moduleResolution.value()));
|
||||
}
|
||||
if (hashes != null) {
|
||||
clb.with(ModuleHashesAttribute.of(
|
||||
hashes.algorithm(),
|
||||
hashes.hashes().entrySet().stream().map(he ->
|
||||
ModuleHashInfo.of(ModuleDesc.of(
|
||||
he.getKey()),
|
||||
he.getValue())).toList()));
|
||||
}
|
||||
}).andThen((clb, cle) -> {
|
||||
if (v != null && cle instanceof ModuleAttribute ma) {
|
||||
clb.with(ModuleAttribute.of(
|
||||
ma.moduleName(),
|
||||
ma.moduleFlagsMask(),
|
||||
clb.constantPool().utf8Entry(v.toString()),
|
||||
ma.requires(),
|
||||
ma.exports(),
|
||||
ma.opens(),
|
||||
ma.uses(),
|
||||
ma.provides()));
|
||||
} else {
|
||||
clb.accept(cle);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,17 +26,22 @@ package jdk.internal.module;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.reflect.AccessFlag;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.ModuleVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.commons.ModuleResolutionAttribute;
|
||||
import jdk.internal.org.objectweb.asm.commons.ModuleTargetAttribute;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
import jdk.internal.classfile.Classfile;
|
||||
import jdk.internal.classfile.java.lang.constant.PackageDesc;
|
||||
import jdk.internal.classfile.attribute.ModuleAttribute;
|
||||
import jdk.internal.classfile.attribute.ModuleExportInfo;
|
||||
import jdk.internal.classfile.attribute.ModuleMainClassAttribute;
|
||||
import jdk.internal.classfile.attribute.ModuleOpenInfo;
|
||||
import jdk.internal.classfile.attribute.ModulePackagesAttribute;
|
||||
import jdk.internal.classfile.attribute.ModuleResolutionAttribute;
|
||||
import jdk.internal.classfile.attribute.ModuleRequireInfo;
|
||||
import jdk.internal.classfile.attribute.ModuleTargetAttribute;
|
||||
import jdk.internal.classfile.constantpool.ModuleEntry;
|
||||
|
||||
/**
|
||||
* Utility class to write a ModuleDescriptor as a module-info.class.
|
||||
@ -46,33 +51,31 @@ public final class ModuleInfoWriter {
|
||||
|
||||
private static final Map<ModuleDescriptor.Modifier, Integer>
|
||||
MODULE_MODS_TO_FLAGS = Map.of(
|
||||
ModuleDescriptor.Modifier.OPEN, ACC_OPEN,
|
||||
ModuleDescriptor.Modifier.SYNTHETIC, ACC_SYNTHETIC,
|
||||
ModuleDescriptor.Modifier.MANDATED, ACC_MANDATED
|
||||
ModuleDescriptor.Modifier.OPEN, Classfile.ACC_OPEN,
|
||||
ModuleDescriptor.Modifier.SYNTHETIC, Classfile.ACC_SYNTHETIC,
|
||||
ModuleDescriptor.Modifier.MANDATED, Classfile.ACC_MANDATED
|
||||
);
|
||||
|
||||
private static final Map<ModuleDescriptor.Requires.Modifier, Integer>
|
||||
REQUIRES_MODS_TO_FLAGS = Map.of(
|
||||
ModuleDescriptor.Requires.Modifier.TRANSITIVE, ACC_TRANSITIVE,
|
||||
ModuleDescriptor.Requires.Modifier.STATIC, ACC_STATIC_PHASE,
|
||||
ModuleDescriptor.Requires.Modifier.SYNTHETIC, ACC_SYNTHETIC,
|
||||
ModuleDescriptor.Requires.Modifier.MANDATED, ACC_MANDATED
|
||||
ModuleDescriptor.Requires.Modifier.TRANSITIVE, Classfile.ACC_TRANSITIVE,
|
||||
ModuleDescriptor.Requires.Modifier.STATIC, Classfile.ACC_STATIC_PHASE,
|
||||
ModuleDescriptor.Requires.Modifier.SYNTHETIC, Classfile.ACC_SYNTHETIC,
|
||||
ModuleDescriptor.Requires.Modifier.MANDATED, Classfile.ACC_MANDATED
|
||||
);
|
||||
|
||||
private static final Map<ModuleDescriptor.Exports.Modifier, Integer>
|
||||
EXPORTS_MODS_TO_FLAGS = Map.of(
|
||||
ModuleDescriptor.Exports.Modifier.SYNTHETIC, ACC_SYNTHETIC,
|
||||
ModuleDescriptor.Exports.Modifier.MANDATED, ACC_MANDATED
|
||||
ModuleDescriptor.Exports.Modifier.SYNTHETIC, Classfile.ACC_SYNTHETIC,
|
||||
ModuleDescriptor.Exports.Modifier.MANDATED, Classfile.ACC_MANDATED
|
||||
);
|
||||
|
||||
private static final Map<ModuleDescriptor.Opens.Modifier, Integer>
|
||||
OPENS_MODS_TO_FLAGS = Map.of(
|
||||
ModuleDescriptor.Opens.Modifier.SYNTHETIC, ACC_SYNTHETIC,
|
||||
ModuleDescriptor.Opens.Modifier.MANDATED, ACC_MANDATED
|
||||
ModuleDescriptor.Opens.Modifier.SYNTHETIC, Classfile.ACC_SYNTHETIC,
|
||||
ModuleDescriptor.Opens.Modifier.MANDATED, Classfile.ACC_MANDATED
|
||||
);
|
||||
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
|
||||
private ModuleInfoWriter() { }
|
||||
|
||||
/**
|
||||
@ -82,86 +85,86 @@ public final class ModuleInfoWriter {
|
||||
private static byte[] toModuleInfo(ModuleDescriptor md,
|
||||
ModuleResolution mres,
|
||||
ModuleTarget target) {
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
cw.visit(Opcodes.V10, ACC_MODULE, "module-info", null, null, null);
|
||||
//using low-level module building to avoid validation in ModuleDesc and allow invalid names
|
||||
return Classfile.build(ClassDesc.of("module-info"), clb -> {
|
||||
clb.withFlags(AccessFlag.MODULE);
|
||||
var cp = clb.constantPool();
|
||||
clb.with(ModuleAttribute.of(cp.moduleEntry(cp.utf8Entry(md.name())), mb -> {
|
||||
mb.moduleFlags(md.modifiers().stream()
|
||||
.mapToInt(mm -> MODULE_MODS_TO_FLAGS.getOrDefault(mm, 0))
|
||||
.reduce(0, (x, y) -> (x | y)));
|
||||
|
||||
int moduleFlags = md.modifiers().stream()
|
||||
.map(MODULE_MODS_TO_FLAGS::get)
|
||||
.reduce(0, (x, y) -> (x | y));
|
||||
String vs = md.rawVersion().orElse(null);
|
||||
ModuleVisitor mv = cw.visitModule(md.name(), moduleFlags, vs);
|
||||
md.rawVersion().ifPresent(vs -> mb.moduleVersion(vs));
|
||||
|
||||
// requires
|
||||
for (ModuleDescriptor.Requires r : md.requires()) {
|
||||
int flags = r.modifiers().stream()
|
||||
.map(REQUIRES_MODS_TO_FLAGS::get)
|
||||
.reduce(0, (x, y) -> (x | y));
|
||||
vs = r.rawCompiledVersion().orElse(null);
|
||||
mv.visitRequire(r.name(), flags, vs);
|
||||
}
|
||||
// requires
|
||||
for (ModuleDescriptor.Requires r : md.requires()) {
|
||||
int flags = r.modifiers().stream()
|
||||
.mapToInt(REQUIRES_MODS_TO_FLAGS::get)
|
||||
.reduce(0, (x, y) -> (x | y));
|
||||
mb.requires(ModuleRequireInfo.of(
|
||||
cp.moduleEntry(cp.utf8Entry(r.name())),
|
||||
flags,
|
||||
r.rawCompiledVersion().map(cp::utf8Entry).orElse(null)));
|
||||
}
|
||||
|
||||
// exports
|
||||
for (ModuleDescriptor.Exports e : md.exports()) {
|
||||
int flags = e.modifiers().stream()
|
||||
.map(EXPORTS_MODS_TO_FLAGS::get)
|
||||
.reduce(0, (x, y) -> (x | y));
|
||||
String[] targets = e.targets().toArray(EMPTY_STRING_ARRAY);
|
||||
mv.visitExport(e.source().replace('.', '/'), flags, targets);
|
||||
}
|
||||
// exports
|
||||
for (ModuleDescriptor.Exports e : md.exports()) {
|
||||
int flags = e.modifiers().stream()
|
||||
.mapToInt(EXPORTS_MODS_TO_FLAGS::get)
|
||||
.reduce(0, (x, y) -> (x | y));
|
||||
var targets = e.targets().stream().map(mn -> cp.moduleEntry(cp.utf8Entry(mn)))
|
||||
.toArray(ModuleEntry[]::new);
|
||||
mb.exports(ModuleExportInfo.of(
|
||||
cp.packageEntry(cp.utf8Entry(e.source())),
|
||||
flags,
|
||||
targets));
|
||||
}
|
||||
|
||||
// opens
|
||||
for (ModuleDescriptor.Opens opens : md.opens()) {
|
||||
int flags = opens.modifiers().stream()
|
||||
.map(OPENS_MODS_TO_FLAGS::get)
|
||||
.reduce(0, (x, y) -> (x | y));
|
||||
String[] targets = opens.targets().toArray(EMPTY_STRING_ARRAY);
|
||||
mv.visitOpen(opens.source().replace('.', '/'), flags, targets);
|
||||
}
|
||||
// opens
|
||||
for (ModuleDescriptor.Opens opens : md.opens()) {
|
||||
int flags = opens.modifiers().stream()
|
||||
.mapToInt(OPENS_MODS_TO_FLAGS::get)
|
||||
.reduce(0, (x, y) -> (x | y));
|
||||
var targets = opens.targets().stream().map(mn -> cp.moduleEntry(cp.utf8Entry(mn)))
|
||||
.toArray(ModuleEntry[]::new);
|
||||
mb.opens(ModuleOpenInfo.of(
|
||||
cp.packageEntry(cp.utf8Entry(opens.source())),
|
||||
flags,
|
||||
targets));
|
||||
}
|
||||
|
||||
// uses
|
||||
md.uses().stream().map(sn -> sn.replace('.', '/')).forEach(mv::visitUse);
|
||||
// uses
|
||||
md.uses().stream().map(ClassDesc::of).forEach(mb::uses);
|
||||
|
||||
// provides
|
||||
for (ModuleDescriptor.Provides p : md.provides()) {
|
||||
mv.visitProvide(p.service().replace('.', '/'),
|
||||
p.providers()
|
||||
.stream()
|
||||
.map(pn -> pn.replace('.', '/'))
|
||||
.toArray(String[]::new));
|
||||
}
|
||||
// provides
|
||||
for (ModuleDescriptor.Provides p : md.provides()) {
|
||||
mb.provides(ClassDesc.of(p.service()),
|
||||
p.providers().stream()
|
||||
.map(ClassDesc::of)
|
||||
.toArray(ClassDesc[]::new));
|
||||
}
|
||||
}));
|
||||
|
||||
// add 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()
|
||||
.map(ModuleDescriptor.Opens::source);
|
||||
long exportedOrOpen = Stream.concat(exported, open).distinct().count();
|
||||
if (md.packages().size() > exportedOrOpen) {
|
||||
md.packages().stream()
|
||||
.map(pn -> pn.replace('.', '/'))
|
||||
.forEach(mv::visitPackage);
|
||||
}
|
||||
// packages
|
||||
var packages = md.packages().stream().sorted().map(PackageDesc::of).toList();
|
||||
if (!packages.isEmpty()) {
|
||||
clb.with(ModulePackagesAttribute.ofNames(packages));
|
||||
}
|
||||
|
||||
// ModuleMainClass attribute
|
||||
md.mainClass()
|
||||
.map(mc -> mc.replace('.', '/'))
|
||||
.ifPresent(mv::visitMainClass);
|
||||
// ModuleMainClass attribute
|
||||
md.mainClass().ifPresent(mc ->
|
||||
clb.with(ModuleMainClassAttribute.of(ClassDesc.of(mc))));
|
||||
|
||||
mv.visitEnd();
|
||||
// write ModuleResolution attribute if specified
|
||||
if (mres != null) {
|
||||
clb.with(ModuleResolutionAttribute.of(mres.value()));
|
||||
}
|
||||
|
||||
// write ModuleResolution attribute if specified
|
||||
if (mres != null) {
|
||||
cw.visitAttribute(new ModuleResolutionAttribute(mres.value()));
|
||||
}
|
||||
|
||||
// write ModuleTarget attribute if there is a target platform
|
||||
if (target != null && target.targetPlatform().length() > 0) {
|
||||
cw.visitAttribute(new ModuleTargetAttribute(target.targetPlatform()));
|
||||
}
|
||||
|
||||
cw.visitEnd();
|
||||
return cw.toByteArray();
|
||||
// write ModuleTarget attribute if there is a target platform
|
||||
if (target != null && !target.targetPlatform().isEmpty()) {
|
||||
clb.with(ModuleTargetAttribute.of(target.targetPlatform()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,6 +26,9 @@
|
||||
* @bug 8142968 8158456 8298875
|
||||
* @modules java.base/jdk.internal.access
|
||||
* java.base/jdk.internal.module
|
||||
* java.base/jdk.internal.classfile
|
||||
* java.base/jdk.internal.classfile.attribute
|
||||
* java.base/jdk.internal.classfile.java.lang.constant
|
||||
* @run testng ModuleDescriptorTest
|
||||
* @summary Basic test for java.lang.module.ModuleDescriptor and its builder
|
||||
*/
|
||||
@ -57,6 +60,10 @@ import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
|
||||
|
||||
import jdk.internal.access.JavaLangModuleAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.classfile.Classfile;
|
||||
import jdk.internal.classfile.attribute.ModuleAttribute;
|
||||
import jdk.internal.classfile.java.lang.constant.PackageDesc;
|
||||
import jdk.internal.classfile.java.lang.constant.ModuleDesc;
|
||||
import jdk.internal.module.ModuleInfoWriter;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
@ -1362,14 +1369,11 @@ public class ModuleDescriptorTest {
|
||||
* complete set of packages.
|
||||
*/
|
||||
public void testReadsWithBadPackageFinder() throws Exception {
|
||||
ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo")
|
||||
.requires("java.base")
|
||||
.exports("p")
|
||||
.build();
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ModuleInfoWriter.write(descriptor, baos);
|
||||
ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
|
||||
ByteBuffer bb = ByteBuffer.wrap(Classfile.buildModule(
|
||||
ModuleAttribute.of(
|
||||
ModuleDesc.of("foo"),
|
||||
mb -> mb.requires(ModuleDesc.of("java.base"), 0, null)
|
||||
.exports(PackageDesc.of("p"), 0))));
|
||||
|
||||
// package finder returns a set that doesn't include p
|
||||
assertThrows(InvalidModuleDescriptorException.class,
|
||||
|
@ -85,8 +85,8 @@ class ModuleBuilderTest {
|
||||
.uses(ClassDesc.of("another.Service"))
|
||||
|
||||
.provides(ClassDesc.of("some.nice.Feature"), ClassDesc.of("impl"), ClassDesc.of("another.impl"))),
|
||||
List.of(PackageDesc.of("foo.bar.baz"), PackageDesc.of("quux"), PackageDesc.of("foo.bar.baz"), PackageDesc.of("quux")),
|
||||
clb -> clb.with(ModuleMainClassAttribute.of(ClassDesc.of("main.Class")))
|
||||
.with(ModulePackagesAttribute.ofNames(PackageDesc.of("foo.bar.baz"), PackageDesc.of("quux")))
|
||||
.with(ModuleMainClassAttribute.of(ClassDesc.of("overwritten.main.Class"))));
|
||||
moduleModel = Classfile.parse(modInfo);
|
||||
attr = ((ModuleAttribute) moduleModel.attributes().stream()
|
||||
@ -182,7 +182,7 @@ class ModuleBuilderTest {
|
||||
@Test
|
||||
void verifyPackages() {
|
||||
ModulePackagesAttribute a = moduleModel.findAttribute(Attributes.MODULE_PACKAGES).orElseThrow();
|
||||
assertEquals(a.packages().stream().map(pe -> pe.asSymbol().packageName()).toList(), List.of("0", "1", "2", "3", "4", "o0", "o1", "o2", "foo.bar.baz", "quux"));
|
||||
assertEquals(a.packages().stream().map(pe -> pe.asSymbol().packageName()).toList(), List.of("foo.bar.baz", "quux"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -78,7 +78,7 @@ public class ModuleExamples {
|
||||
});
|
||||
|
||||
// Build it
|
||||
byte[] moduleInfo = Classfile.buildModule(ModuleAttribute.of(moduleName, handler), List.of(), clb -> {
|
||||
byte[] moduleInfo = Classfile.buildModule(ModuleAttribute.of(moduleName, handler), clb -> {
|
||||
|
||||
// Add an annotation to the module
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(Annotation.of(ClassDesc.ofDescriptor("Ljava/lang/Deprecated;"),
|
||||
|
Loading…
Reference in New Issue
Block a user