1 /* 2 * Copyright (c) 2015, 2016, 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) { 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 attribute if have any of OS name/arch/version 70 String osName = md.osName().orElse(null); 71 String osArch = md.osArch().orElse(null); 72 String osVersion = md.osVersion().orElse(null); 73 if (osName != null || osArch != null || osVersion != null) { 74 cw.visitAttribute(new ModuleTargetAttribute(osName, osArch, osVersion)); 75 } 76 77 cw.visitEnd(); 78 return cw.toByteArray(); 79 } 80 81 /** 82 * Writes a module descriptor to the given output stream as a 83 * module-info.class. 84 */ 85 public static void write(ModuleDescriptor descriptor, OutputStream out) 86 throws IOException 87 { 88 byte[] bytes = toModuleInfo(descriptor); 89 out.write(bytes); 90 } 91 92 /** 93 * Returns a {@code ByteBuffer} containing the given module descriptor 94 * in module-info.class format. 95 */ 96 public static ByteBuffer toByteBuffer(ModuleDescriptor descriptor) { 97 byte[] bytes = toModuleInfo(descriptor); 98 return ByteBuffer.wrap(bytes); 99 } 100 101 }