1/* 2 * Copyright (c) 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24package selectionresolution; 25 26import java.io.File; 27import java.io.FileOutputStream; 28import jdk.internal.org.objectweb.asm.ClassWriter; 29import jdk.internal.org.objectweb.asm.Opcodes; 30 31public abstract class ClassConstruct { 32 private final ClassWriter cw; 33 private final String name; 34 private final boolean isInterface; 35 private final int index; 36 37 /** 38 * Base constructor for building a Class or Interface 39 * @param name Name of Class/Interface, including package name 40 * @param extending Name of extending Class if any 41 * @param access Access for Class/Interface 42 * @param classFileVersion Class file version 43 * @param interfaces Interface implemented 44 */ 45 public ClassConstruct(String name, 46 String extending, 47 int access, 48 int classFileVersion, 49 int index, 50 String... interfaces) { 51 this.name = name; 52 isInterface = (access & Opcodes.ACC_INTERFACE) == Opcodes.ACC_INTERFACE; 53 cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 54 cw.visit(classFileVersion, access, name, null, extending, interfaces == null ? new String[] { } : interfaces); 55 this.index = index; 56 } 57 58 /** 59 * Get full Class/Interface name including package name, as it 60 * should appear in a classfile. 61 * 62 * @return The full Class/Interface name including package name 63 */ 64 public String getName() { 65 return name; 66 } 67 68 /** 69 * Get the name of the class, including package as it would appear 70 * in Java source. 71 * 72 * @return The name of the class as it would appear in Java source. 73 */ 74 public String getDottedName() { 75 return name.replace("/", "."); 76 } 77 78 public String getPackageName() { 79 final int idx = name.lastIndexOf('/'); 80 if (idx != -1) { 81 return name.substring(0, name.indexOf('/')); 82 } else { 83 return null; 84 } 85 } 86 87 public String getClassName() { 88 final int idx = name.lastIndexOf('/'); 89 if (idx != -1) { 90 return name.substring(name.indexOf('/')); 91 } else { 92 return name; 93 } 94 } 95 96 /** 97 * Add a method, no code associated with it yet 98 * @param name Name of method 99 * @param descriptor Descriptor for method 100 * @param access Access for the method 101 * @return Method object that can be used for constructing a method body 102 */ 103 public Method addMethod(String name, 104 String descriptor, 105 int access) { 106 return addMethod(name, descriptor, access, null); 107 } 108 109 /** 110 * Add a method, no code associated with it yet 111 * @param name Name of method 112 * @param descriptor Descriptor for method 113 * @param access Access for the method 114 * @param execMode The execution mode for the method. 115 * @return Method object that can be used for constructing a method body 116 */ 117 public Method addMethod(String name, 118 String descriptor, 119 int access, 120 ClassBuilder.ExecutionMode execMode) { 121 return new Method(this, cw, name, descriptor, access, execMode); 122 } 123 124 /** 125 * Adds a m()LTestObject; method which returns null unless the method is abstract 126 * @param access Access for the method 127 */ 128 public void addTestMethod(int access) { 129 Method m = new Method(this, cw, Method.defaultMethodName, Method.defaultMethodDescriptor, access, null); 130 if ((access & Opcodes.ACC_ABSTRACT) != Opcodes.ACC_ABSTRACT) { 131 m.makeDefaultMethod(); 132 } 133 } 134 135 /** 136 * Construct the class to a byte[] 137 * @return byte[] with class file 138 */ 139 public byte[] generateBytes() { 140 cw.visitEnd(); 141 return cw.toByteArray(); 142 } 143 144 /** 145 * Write out a class to a file in the specified directory. 146 * 147 * @param dir Directory to which to write out the file. 148 */ 149 public void writeClass(final File dir) throws Exception { 150 final String pkgname = getPackageName(); 151 final File pkgdir = pkgname != null ? new File(dir, getPackageName()) : dir; 152 pkgdir.mkdirs(); 153 final File out = new File(pkgdir, getClassName() + ".class"); 154 out.createNewFile(); 155 try (final FileOutputStream fos = new FileOutputStream(out)) { 156 fos.write(generateBytes()); 157 } 158 } 159 160 public boolean isInterface() { 161 return isInterface; 162 } 163 164 public Integer getIndex() { 165 return index; 166 } 167} 168