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:
Adam Sotona 2023-03-15 07:09:55 +00:00
parent 065d3e0d58
commit 714b5f036f
8 changed files with 185 additions and 234 deletions

View File

@ -250,44 +250,20 @@ public class Classfile {
* @return the classfile bytes * @return the classfile bytes
*/ */
public static byte[] buildModule(ModuleAttribute moduleAttribute) { public static byte[] buildModule(ModuleAttribute moduleAttribute) {
return buildModule(moduleAttribute, List.of(), clb -> {}); return buildModule(moduleAttribute, clb -> {});
} }
/** /**
* Build a module descriptor into a byte array. * Build a module descriptor into a byte array.
* @param moduleAttribute the {@code Module} attribute * @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} * @param handler a handler that receives a {@link ClassBuilder}
* @return the classfile bytes * @return the classfile bytes
*/ */
public static byte[] buildModule(ModuleAttribute moduleAttribute, public static byte[] buildModule(ModuleAttribute moduleAttribute,
List<PackageDesc> packages,
Consumer<? super ClassBuilder> handler) { Consumer<? super ClassBuilder> handler) {
return build(ClassDesc.of("module-info"), clb -> { return build(ClassDesc.of("module-info"), clb -> {
clb.withFlags(AccessFlag.MODULE); clb.withFlags(AccessFlag.MODULE);
clb.with(moduleAttribute); 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); handler.accept(clb);
}); });
} }
@ -299,33 +275,19 @@ public class Classfile {
*/ */
public static void buildModuleTo(Path path, public static void buildModuleTo(Path path,
ModuleAttribute moduleAttribute) throws IOException { ModuleAttribute moduleAttribute) throws IOException {
buildModuleTo(path, moduleAttribute, List.of(), clb -> {}); buildModuleTo(path, moduleAttribute, clb -> {});
} }
/** /**
* Build a module descriptor into a file. * Build a module descriptor into a file.
* @param path the file to write * @param path the file to write
* @param moduleAttribute the {@code Module} attribute * @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} * @param handler a handler that receives a {@link ClassBuilder}
*/ */
public static void buildModuleTo(Path path, public static void buildModuleTo(Path path,
ModuleAttribute moduleAttribute, ModuleAttribute moduleAttribute,
List<PackageDesc> packages,
Consumer<? super ClassBuilder> handler) throws IOException { 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; public static final int MAGIC_NUMBER = 0xCAFEBABE;

View File

@ -142,6 +142,19 @@ public sealed interface ModuleAttribute
return mb.build(); 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 public sealed interface ModuleAttributeBuilder
permits ModuleAttributeBuilderImpl { permits ModuleAttributeBuilderImpl {

View File

@ -49,11 +49,15 @@ public final class ModuleAttributeBuilderImpl
private final Set<ClassEntry> uses = new LinkedHashSet<>(); private final Set<ClassEntry> uses = new LinkedHashSet<>();
private final Set<ModuleProvideInfo> provides = new LinkedHashSet<>(); private final Set<ModuleProvideInfo> provides = new LinkedHashSet<>();
public ModuleAttributeBuilderImpl(ModuleDesc moduleName) { public ModuleAttributeBuilderImpl(ModuleEntry moduleName) {
this.moduleEntry = TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(moduleName.moduleName())); this.moduleEntry = moduleName;
this.moduleFlags = 0; this.moduleFlags = 0;
} }
public ModuleAttributeBuilderImpl(ModuleDesc moduleName) {
this(TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(moduleName.moduleName())));
}
@Override @Override
public ModuleAttribute build() { public ModuleAttribute build() {
return new UnboundAttribute.UnboundModuleAttribute(moduleEntry, moduleFlags, moduleVersion, return new UnboundAttribute.UnboundModuleAttribute(moduleEntry, moduleFlags, moduleVersion,

View File

@ -28,21 +28,23 @@ package jdk.internal.module;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.constant.ClassDesc;
import java.lang.module.ModuleDescriptor.Version; import java.lang.module.ModuleDescriptor.Version;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; 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. * Utility class to extend a module-info.class with additional attributes.
@ -148,90 +150,53 @@ public final class ModuleInfoExtender {
* be discarded. * be discarded.
*/ */
public byte[] toByteArray() throws IOException { public byte[] toByteArray() throws IOException {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS var cm = Classfile.parse(in.readAllBytes());
+ ClassWriter.COMPUTE_FRAMES); Version v = ModuleInfoExtender.this.version;
return cm.transform(ClassTransform.endHandler(clb -> {
ClassReader cr = new ClassReader(in); // ModuleMainClass attribute
if (mainClass != null) {
ClassVisitor cv = new ClassVisitor(Opcodes.ASM7, cw) { clb.with(ModuleMainClassAttribute.of(ClassDesc.of(mainClass)));
@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);
}
}
};
} }
@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<>(); // ModuleTarget, ModuleResolution and ModuleHashes attributes
attrs.add(new ModuleTargetAttribute()); if (targetPlatform != null) {
attrs.add(new ModuleResolutionAttribute()); clb.with(ModuleTargetAttribute.of(targetPlatform));
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));
} }
cw.visitAttribute(new ModuleHashesAttribute(algorithm, names, values)); if (moduleResolution != null) {
} clb.with(ModuleResolutionAttribute.of(moduleResolution.value()));
}
return cw.toByteArray(); 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);
}
}));
} }
/** /**

View File

@ -26,17 +26,22 @@ package jdk.internal.module;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.constant.ClassDesc;
import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor;
import java.lang.reflect.AccessFlag;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Map; import java.util.Map;
import java.util.stream.Stream; import jdk.internal.classfile.Classfile;
import jdk.internal.classfile.java.lang.constant.PackageDesc;
import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.classfile.attribute.ModuleAttribute;
import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.classfile.attribute.ModuleExportInfo;
import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.classfile.attribute.ModuleMainClassAttribute;
import jdk.internal.org.objectweb.asm.commons.ModuleResolutionAttribute; import jdk.internal.classfile.attribute.ModuleOpenInfo;
import jdk.internal.org.objectweb.asm.commons.ModuleTargetAttribute; import jdk.internal.classfile.attribute.ModulePackagesAttribute;
import static jdk.internal.org.objectweb.asm.Opcodes.*; 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. * 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> private static final Map<ModuleDescriptor.Modifier, Integer>
MODULE_MODS_TO_FLAGS = Map.of( MODULE_MODS_TO_FLAGS = Map.of(
ModuleDescriptor.Modifier.OPEN, ACC_OPEN, ModuleDescriptor.Modifier.OPEN, Classfile.ACC_OPEN,
ModuleDescriptor.Modifier.SYNTHETIC, ACC_SYNTHETIC, ModuleDescriptor.Modifier.SYNTHETIC, Classfile.ACC_SYNTHETIC,
ModuleDescriptor.Modifier.MANDATED, ACC_MANDATED ModuleDescriptor.Modifier.MANDATED, Classfile.ACC_MANDATED
); );
private static final Map<ModuleDescriptor.Requires.Modifier, Integer> private static final Map<ModuleDescriptor.Requires.Modifier, Integer>
REQUIRES_MODS_TO_FLAGS = Map.of( REQUIRES_MODS_TO_FLAGS = Map.of(
ModuleDescriptor.Requires.Modifier.TRANSITIVE, ACC_TRANSITIVE, ModuleDescriptor.Requires.Modifier.TRANSITIVE, Classfile.ACC_TRANSITIVE,
ModuleDescriptor.Requires.Modifier.STATIC, ACC_STATIC_PHASE, ModuleDescriptor.Requires.Modifier.STATIC, Classfile.ACC_STATIC_PHASE,
ModuleDescriptor.Requires.Modifier.SYNTHETIC, ACC_SYNTHETIC, ModuleDescriptor.Requires.Modifier.SYNTHETIC, Classfile.ACC_SYNTHETIC,
ModuleDescriptor.Requires.Modifier.MANDATED, ACC_MANDATED ModuleDescriptor.Requires.Modifier.MANDATED, Classfile.ACC_MANDATED
); );
private static final Map<ModuleDescriptor.Exports.Modifier, Integer> private static final Map<ModuleDescriptor.Exports.Modifier, Integer>
EXPORTS_MODS_TO_FLAGS = Map.of( EXPORTS_MODS_TO_FLAGS = Map.of(
ModuleDescriptor.Exports.Modifier.SYNTHETIC, ACC_SYNTHETIC, ModuleDescriptor.Exports.Modifier.SYNTHETIC, Classfile.ACC_SYNTHETIC,
ModuleDescriptor.Exports.Modifier.MANDATED, ACC_MANDATED ModuleDescriptor.Exports.Modifier.MANDATED, Classfile.ACC_MANDATED
); );
private static final Map<ModuleDescriptor.Opens.Modifier, Integer> private static final Map<ModuleDescriptor.Opens.Modifier, Integer>
OPENS_MODS_TO_FLAGS = Map.of( OPENS_MODS_TO_FLAGS = Map.of(
ModuleDescriptor.Opens.Modifier.SYNTHETIC, ACC_SYNTHETIC, ModuleDescriptor.Opens.Modifier.SYNTHETIC, Classfile.ACC_SYNTHETIC,
ModuleDescriptor.Opens.Modifier.MANDATED, ACC_MANDATED ModuleDescriptor.Opens.Modifier.MANDATED, Classfile.ACC_MANDATED
); );
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private ModuleInfoWriter() { } private ModuleInfoWriter() { }
/** /**
@ -82,86 +85,86 @@ public final class ModuleInfoWriter {
private static byte[] toModuleInfo(ModuleDescriptor md, private static byte[] toModuleInfo(ModuleDescriptor md,
ModuleResolution mres, ModuleResolution mres,
ModuleTarget target) { ModuleTarget target) {
ClassWriter cw = new ClassWriter(0); //using low-level module building to avoid validation in ModuleDesc and allow invalid names
cw.visit(Opcodes.V10, ACC_MODULE, "module-info", null, null, null); 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() md.rawVersion().ifPresent(vs -> mb.moduleVersion(vs));
.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);
// requires // requires
for (ModuleDescriptor.Requires r : md.requires()) { for (ModuleDescriptor.Requires r : md.requires()) {
int flags = r.modifiers().stream() int flags = r.modifiers().stream()
.map(REQUIRES_MODS_TO_FLAGS::get) .mapToInt(REQUIRES_MODS_TO_FLAGS::get)
.reduce(0, (x, y) -> (x | y)); .reduce(0, (x, y) -> (x | y));
vs = r.rawCompiledVersion().orElse(null); mb.requires(ModuleRequireInfo.of(
mv.visitRequire(r.name(), flags, vs); cp.moduleEntry(cp.utf8Entry(r.name())),
} flags,
r.rawCompiledVersion().map(cp::utf8Entry).orElse(null)));
}
// exports // exports
for (ModuleDescriptor.Exports e : md.exports()) { for (ModuleDescriptor.Exports e : md.exports()) {
int flags = e.modifiers().stream() int flags = e.modifiers().stream()
.map(EXPORTS_MODS_TO_FLAGS::get) .mapToInt(EXPORTS_MODS_TO_FLAGS::get)
.reduce(0, (x, y) -> (x | y)); .reduce(0, (x, y) -> (x | y));
String[] targets = e.targets().toArray(EMPTY_STRING_ARRAY); var targets = e.targets().stream().map(mn -> cp.moduleEntry(cp.utf8Entry(mn)))
mv.visitExport(e.source().replace('.', '/'), flags, targets); .toArray(ModuleEntry[]::new);
} mb.exports(ModuleExportInfo.of(
cp.packageEntry(cp.utf8Entry(e.source())),
flags,
targets));
}
// opens // opens
for (ModuleDescriptor.Opens opens : md.opens()) { for (ModuleDescriptor.Opens opens : md.opens()) {
int flags = opens.modifiers().stream() int flags = opens.modifiers().stream()
.map(OPENS_MODS_TO_FLAGS::get) .mapToInt(OPENS_MODS_TO_FLAGS::get)
.reduce(0, (x, y) -> (x | y)); .reduce(0, (x, y) -> (x | y));
String[] targets = opens.targets().toArray(EMPTY_STRING_ARRAY); var targets = opens.targets().stream().map(mn -> cp.moduleEntry(cp.utf8Entry(mn)))
mv.visitOpen(opens.source().replace('.', '/'), flags, targets); .toArray(ModuleEntry[]::new);
} mb.opens(ModuleOpenInfo.of(
cp.packageEntry(cp.utf8Entry(opens.source())),
flags,
targets));
}
// uses // uses
md.uses().stream().map(sn -> sn.replace('.', '/')).forEach(mv::visitUse); md.uses().stream().map(ClassDesc::of).forEach(mb::uses);
// provides // provides
for (ModuleDescriptor.Provides p : md.provides()) { for (ModuleDescriptor.Provides p : md.provides()) {
mv.visitProvide(p.service().replace('.', '/'), mb.provides(ClassDesc.of(p.service()),
p.providers() p.providers().stream()
.stream() .map(ClassDesc::of)
.map(pn -> pn.replace('.', '/')) .toArray(ClassDesc[]::new));
.toArray(String[]::new)); }
} }));
// add the ModulePackages attribute when there are packages that aren't // packages
// exported or open var packages = md.packages().stream().sorted().map(PackageDesc::of).toList();
Stream<String> exported = md.exports().stream() if (!packages.isEmpty()) {
.map(ModuleDescriptor.Exports::source); clb.with(ModulePackagesAttribute.ofNames(packages));
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);
}
// ModuleMainClass attribute // ModuleMainClass attribute
md.mainClass() md.mainClass().ifPresent(mc ->
.map(mc -> mc.replace('.', '/')) clb.with(ModuleMainClassAttribute.of(ClassDesc.of(mc))));
.ifPresent(mv::visitMainClass);
mv.visitEnd(); // write ModuleResolution attribute if specified
if (mres != null) {
clb.with(ModuleResolutionAttribute.of(mres.value()));
}
// write ModuleResolution attribute if specified // write ModuleTarget attribute if there is a target platform
if (mres != null) { if (target != null && !target.targetPlatform().isEmpty()) {
cw.visitAttribute(new ModuleResolutionAttribute(mres.value())); clb.with(ModuleTargetAttribute.of(target.targetPlatform()));
} }
});
// 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();
} }
/** /**

View File

@ -26,6 +26,9 @@
* @bug 8142968 8158456 8298875 * @bug 8142968 8158456 8298875
* @modules java.base/jdk.internal.access * @modules java.base/jdk.internal.access
* java.base/jdk.internal.module * 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 * @run testng ModuleDescriptorTest
* @summary Basic test for java.lang.module.ModuleDescriptor and its builder * @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.JavaLangModuleAccess;
import jdk.internal.access.SharedSecrets; 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 jdk.internal.module.ModuleInfoWriter;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -1362,14 +1369,11 @@ public class ModuleDescriptorTest {
* complete set of packages. * complete set of packages.
*/ */
public void testReadsWithBadPackageFinder() throws Exception { public void testReadsWithBadPackageFinder() throws Exception {
ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo") ByteBuffer bb = ByteBuffer.wrap(Classfile.buildModule(
.requires("java.base") ModuleAttribute.of(
.exports("p") ModuleDesc.of("foo"),
.build(); mb -> mb.requires(ModuleDesc.of("java.base"), 0, null)
.exports(PackageDesc.of("p"), 0))));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ModuleInfoWriter.write(descriptor, baos);
ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
// package finder returns a set that doesn't include p // package finder returns a set that doesn't include p
assertThrows(InvalidModuleDescriptorException.class, assertThrows(InvalidModuleDescriptorException.class,

View File

@ -85,8 +85,8 @@ class ModuleBuilderTest {
.uses(ClassDesc.of("another.Service")) .uses(ClassDesc.of("another.Service"))
.provides(ClassDesc.of("some.nice.Feature"), ClassDesc.of("impl"), ClassDesc.of("another.impl"))), .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"))) 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")))); .with(ModuleMainClassAttribute.of(ClassDesc.of("overwritten.main.Class"))));
moduleModel = Classfile.parse(modInfo); moduleModel = Classfile.parse(modInfo);
attr = ((ModuleAttribute) moduleModel.attributes().stream() attr = ((ModuleAttribute) moduleModel.attributes().stream()
@ -182,7 +182,7 @@ class ModuleBuilderTest {
@Test @Test
void verifyPackages() { void verifyPackages() {
ModulePackagesAttribute a = moduleModel.findAttribute(Attributes.MODULE_PACKAGES).orElseThrow(); 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 @Test

View File

@ -78,7 +78,7 @@ public class ModuleExamples {
}); });
// Build it // 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 // Add an annotation to the module
clb.with(RuntimeVisibleAnnotationsAttribute.of(Annotation.of(ClassDesc.ofDescriptor("Ljava/lang/Deprecated;"), clb.with(RuntimeVisibleAnnotationsAttribute.of(Annotation.of(ClassDesc.ofDescriptor("Ljava/lang/Deprecated;"),