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
|
* @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;
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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;"),
|
||||||
|
Loading…
Reference in New Issue
Block a user