1 /* 2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 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 91 /** 92 * Writes a module descriptor to the given output stream as a 93 * module-info.class. 94 */ 95 public static void write(ModuleDescriptor descriptor, OutputStream out) 96 throws IOException 97 { 98 write(descriptor, null, out); 99 } 100 101 /** 102 * Returns a {@code ByteBuffer} containing the given module descriptor 103 * in module-info.class format. 104 */ 105 public static ByteBuffer toByteBuffer(ModuleDescriptor descriptor) { 106 byte[] bytes = toModuleInfo(descriptor, null); 107 return ByteBuffer.wrap(bytes); 108 } 109 }