--- old/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java Fri Oct 27 09:23:29 2017 +++ new/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java Fri Oct 27 09:23:28 2017 @@ -28,14 +28,15 @@ import java.io.OutputStream; import java.lang.module.ModuleDescriptor; 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.ModuleTargetAttribute; +import static jdk.internal.org.objectweb.asm.Opcodes.*; -import static jdk.internal.module.ClassFileAttributes.*; -import static jdk.internal.module.ClassFileConstants.ACC_MODULE; - /** * Utility class to write a ModuleDescriptor as a module-info.class. */ @@ -42,6 +43,35 @@ public final class ModuleInfoWriter { + private static final Map + MODULE_MODS_TO_FLAGS = Map.of( + ModuleDescriptor.Modifier.OPEN, ACC_OPEN, + ModuleDescriptor.Modifier.SYNTHETIC, ACC_SYNTHETIC, + ModuleDescriptor.Modifier.MANDATED, ACC_MANDATED + ); + + private static final Map + 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 + ); + + private static final Map + EXPORTS_MODS_TO_FLAGS = Map.of( + ModuleDescriptor.Exports.Modifier.SYNTHETIC, ACC_SYNTHETIC, + ModuleDescriptor.Exports.Modifier.MANDATED, ACC_MANDATED + ); + + private static final Map + OPENS_MODS_TO_FLAGS = Map.of( + ModuleDescriptor.Opens.Modifier.SYNTHETIC, ACC_SYNTHETIC, + ModuleDescriptor.Opens.Modifier.MANDATED, ACC_MANDATED + ); + + private static final String[] EMPTY_STRING_ARRAY = new String[0]; + private ModuleInfoWriter() { } /** @@ -50,24 +80,75 @@ */ private static byte[] toModuleInfo(ModuleDescriptor md, ModuleTarget target) { ClassWriter cw = new ClassWriter(0); - cw.visit(Opcodes.V1_9, ACC_MODULE, "module-info", null, null, null); - cw.visitAttribute(new ModuleAttribute(md)); + cw.visit(Opcodes.V9, ACC_MODULE, "module-info", null, null, null); - // for tests: write the ModulePackages attribute when there are packages - // that aren't exported or open + 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); + + // 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); + } + + // 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); + } + + // 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); + } + + // uses + md.uses().stream().map(sn -> sn.replace('.', '/')).forEach(mv::visitUse); + + // provides + for (ModuleDescriptor.Provides p : md.provides()) { + mv.visitProvide(p.service().replace('.', '/'), + p.providers() + .stream() + .map(pn -> pn.replace('.', '/')) + .toArray(String[]::new)); + } + + // add the ModulePackages attribute when there are packages that aren't + // exported or open Stream exported = md.exports().stream() .map(ModuleDescriptor.Exports::source); Stream open = md.opens().stream() .map(ModuleDescriptor.Opens::source); long exportedOrOpen = Stream.concat(exported, open).distinct().count(); - if (md.packages().size() > exportedOrOpen) - cw.visitAttribute(new ModulePackagesAttribute(md.packages())); + if (md.packages().size() > exportedOrOpen) { + md.packages().stream() + .map(pn -> pn.replace('.', '/')) + .forEach(mv::visitPackage); + } - // write ModuleMainClass if the module has a main class - md.mainClass().ifPresent(mc -> cw.visitAttribute(new ModuleMainClassAttribute(mc))); + // ModuleMainClass attribute + md.mainClass() + .map(mc -> mc.replace('.', '/')) + .ifPresent(mv::visitMainClass); - // write ModuleTarget if there is a target platform - if (target != null) { + mv.visitEnd(); + + // write ModuleTarget attribute if there is a target platform + if (target != null && target.targetPlatform().length() > 0) { cw.visitAttribute(new ModuleTargetAttribute(target.targetPlatform())); }