11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package jdk.internal.module;
26
27 import java.io.IOException;
28 import java.io.OutputStream;
29 import java.lang.module.ModuleDescriptor;
30 import java.nio.ByteBuffer;
31 import java.util.stream.Stream;
32
33 import jdk.internal.org.objectweb.asm.ClassWriter;
34 import jdk.internal.org.objectweb.asm.Opcodes;
35
36 import static jdk.internal.module.ClassFileAttributes.*;
37 import static jdk.internal.module.ClassFileConstants.ACC_MODULE;
38
39 /**
40 * Utility class to write a ModuleDescriptor as a module-info.class.
41 */
42
43 public final class ModuleInfoWriter {
44
45 private ModuleInfoWriter() { }
46
47 /**
48 * Writes the given module descriptor to a module-info.class file,
49 * returning it in a byte array.
50 */
51 private static byte[] toModuleInfo(ModuleDescriptor md, ModuleTarget target) {
52 ClassWriter cw = new ClassWriter(0);
53 cw.visit(Opcodes.V1_9, ACC_MODULE, "module-info", null, null, null);
54 cw.visitAttribute(new ModuleAttribute(md));
55
56 // for tests: write the ModulePackages attribute when there are packages
57 // that aren't exported or open
58 Stream<String> exported = md.exports().stream()
59 .map(ModuleDescriptor.Exports::source);
60 Stream<String> open = md.opens().stream()
61 .map(ModuleDescriptor.Opens::source);
62 long exportedOrOpen = Stream.concat(exported, open).distinct().count();
63 if (md.packages().size() > exportedOrOpen)
64 cw.visitAttribute(new ModulePackagesAttribute(md.packages()));
65
66 // write ModuleMainClass if the module has a main class
67 md.mainClass().ifPresent(mc -> cw.visitAttribute(new ModuleMainClassAttribute(mc)));
68
69 // write ModuleTarget if there is a target platform
70 if (target != null) {
71 cw.visitAttribute(new ModuleTargetAttribute(target.targetPlatform()));
72 }
73
74 cw.visitEnd();
75 return cw.toByteArray();
76 }
77
78 /**
79 * Writes a module descriptor to the given output stream as a
80 * module-info.class.
81 */
82 public static void write(ModuleDescriptor descriptor,
83 ModuleTarget target,
84 OutputStream out)
85 throws IOException
86 {
87 byte[] bytes = toModuleInfo(descriptor, target);
88 out.write(bytes);
89 }
90
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package jdk.internal.module;
26
27 import java.io.IOException;
28 import java.io.OutputStream;
29 import java.lang.module.ModuleDescriptor;
30 import java.nio.ByteBuffer;
31 import java.util.Map;
32 import java.util.stream.Stream;
33
34 import jdk.internal.org.objectweb.asm.ClassWriter;
35 import jdk.internal.org.objectweb.asm.ModuleVisitor;
36 import jdk.internal.org.objectweb.asm.Opcodes;
37 import jdk.internal.org.objectweb.asm.commons.ModuleTargetAttribute;
38 import static jdk.internal.org.objectweb.asm.Opcodes.*;
39
40 /**
41 * Utility class to write a ModuleDescriptor as a module-info.class.
42 */
43
44 public final class ModuleInfoWriter {
45
46 private static final Map<ModuleDescriptor.Modifier, Integer>
47 MODULE_MODS_TO_FLAGS = Map.of(
48 ModuleDescriptor.Modifier.OPEN, ACC_OPEN,
49 ModuleDescriptor.Modifier.SYNTHETIC, ACC_SYNTHETIC,
50 ModuleDescriptor.Modifier.MANDATED, ACC_MANDATED
51 );
52
53 private static final Map<ModuleDescriptor.Requires.Modifier, Integer>
54 REQUIRES_MODS_TO_FLAGS = Map.of(
55 ModuleDescriptor.Requires.Modifier.TRANSITIVE, ACC_TRANSITIVE,
56 ModuleDescriptor.Requires.Modifier.STATIC, ACC_STATIC_PHASE,
57 ModuleDescriptor.Requires.Modifier.SYNTHETIC, ACC_SYNTHETIC,
58 ModuleDescriptor.Requires.Modifier.MANDATED, ACC_MANDATED
59 );
60
61 private static final Map<ModuleDescriptor.Exports.Modifier, Integer>
62 EXPORTS_MODS_TO_FLAGS = Map.of(
63 ModuleDescriptor.Exports.Modifier.SYNTHETIC, ACC_SYNTHETIC,
64 ModuleDescriptor.Exports.Modifier.MANDATED, ACC_MANDATED
65 );
66
67 private static final Map<ModuleDescriptor.Opens.Modifier, Integer>
68 OPENS_MODS_TO_FLAGS = Map.of(
69 ModuleDescriptor.Opens.Modifier.SYNTHETIC, ACC_SYNTHETIC,
70 ModuleDescriptor.Opens.Modifier.MANDATED, ACC_MANDATED
71 );
72
73 private static final String[] EMPTY_STRING_ARRAY = new String[0];
74
75 private ModuleInfoWriter() { }
76
77 /**
78 * Writes the given module descriptor to a module-info.class file,
79 * returning it in a byte array.
80 */
81 private static byte[] toModuleInfo(ModuleDescriptor md, ModuleTarget target) {
82 ClassWriter cw = new ClassWriter(0);
83 cw.visit(Opcodes.V9, ACC_MODULE, "module-info", null, null, null);
84
85 int moduleFlags = md.modifiers().stream()
86 .map(MODULE_MODS_TO_FLAGS::get)
87 .reduce(0, (x, y) -> (x | y));
88 String vs = md.rawVersion().orElse(null);
89 ModuleVisitor mv = cw.visitModule(md.name(), moduleFlags, vs);
90
91 // requires
92 for (ModuleDescriptor.Requires r : md.requires()) {
93 int flags = r.modifiers().stream()
94 .map(REQUIRES_MODS_TO_FLAGS::get)
95 .reduce(0, (x, y) -> (x | y));
96 vs = r.rawCompiledVersion().orElse(null);
97 mv.visitRequire(r.name(), flags, vs);
98 }
99
100 // exports
101 for (ModuleDescriptor.Exports e : md.exports()) {
102 int flags = e.modifiers().stream()
103 .map(EXPORTS_MODS_TO_FLAGS::get)
104 .reduce(0, (x, y) -> (x | y));
105 String[] targets = e.targets().toArray(EMPTY_STRING_ARRAY);
106 mv.visitExport(e.source().replace('.', '/'), flags, targets);
107 }
108
109 // opens
110 for (ModuleDescriptor.Opens opens : md.opens()) {
111 int flags = opens.modifiers().stream()
112 .map(OPENS_MODS_TO_FLAGS::get)
113 .reduce(0, (x, y) -> (x | y));
114 String[] targets = opens.targets().toArray(EMPTY_STRING_ARRAY);
115 mv.visitOpen(opens.source().replace('.', '/'), flags, targets);
116 }
117
118 // uses
119 md.uses().stream().map(sn -> sn.replace('.', '/')).forEach(mv::visitUse);
120
121 // provides
122 for (ModuleDescriptor.Provides p : md.provides()) {
123 mv.visitProvide(p.service().replace('.', '/'),
124 p.providers()
125 .stream()
126 .map(pn -> pn.replace('.', '/'))
127 .toArray(String[]::new));
128 }
129
130 // add the ModulePackages attribute when there are packages that aren't
131 // exported or open
132 Stream<String> exported = md.exports().stream()
133 .map(ModuleDescriptor.Exports::source);
134 Stream<String> open = md.opens().stream()
135 .map(ModuleDescriptor.Opens::source);
136 long exportedOrOpen = Stream.concat(exported, open).distinct().count();
137 if (md.packages().size() > exportedOrOpen) {
138 md.packages().stream()
139 .map(pn -> pn.replace('.', '/'))
140 .forEach(mv::visitPackage);
141 }
142
143 // ModuleMainClass attribute
144 md.mainClass()
145 .map(mc -> mc.replace('.', '/'))
146 .ifPresent(mv::visitMainClass);
147
148 mv.visitEnd();
149
150 // write ModuleTarget attribute if there is a target platform
151 if (target != null && target.targetPlatform().length() > 0) {
152 cw.visitAttribute(new ModuleTargetAttribute(target.targetPlatform()));
153 }
154
155 cw.visitEnd();
156 return cw.toByteArray();
157 }
158
159 /**
160 * Writes a module descriptor to the given output stream as a
161 * module-info.class.
162 */
163 public static void write(ModuleDescriptor descriptor,
164 ModuleTarget target,
165 OutputStream out)
166 throws IOException
167 {
168 byte[] bytes = toModuleInfo(descriptor, target);
169 out.write(bytes);
170 }
171
|