/* * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package selectionresolution; import java.io.File; import java.io.FileOutputStream; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.Opcodes; public abstract class ClassConstruct { private final ClassWriter cw; private final String name; private final boolean isInterface; private final int index; /** * Base constructor for building a Class or Interface * @param name Name of Class/Interface, including package name * @param extending Name of extending Class if any * @param access Access for Class/Interface * @param classFileVersion Class file version * @param interfaces Interface implemented */ public ClassConstruct(String name, String extending, int access, int classFileVersion, int index, String... interfaces) { this.name = name; isInterface = (access & Opcodes.ACC_INTERFACE) == Opcodes.ACC_INTERFACE; cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); cw.visit(classFileVersion, access, name, null, extending, interfaces == null ? new String[] { } : interfaces); this.index = index; } /** * Get full Class/Interface name including package name, as it * should appear in a classfile. * * @return The full Class/Interface name including package name */ public String getName() { return name; } /** * Get the name of the class, including package as it would appear * in Java source. * * @return The name of the class as it would appear in Java source. */ public String getDottedName() { return name.replace("/", "."); } public String getPackageName() { final int idx = name.lastIndexOf('/'); if (idx != -1) { return name.substring(0, name.indexOf('/')); } else { return null; } } public String getClassName() { final int idx = name.lastIndexOf('/'); if (idx != -1) { return name.substring(name.indexOf('/')); } else { return name; } } /** * Add a method, no code associated with it yet * @param name Name of method * @param descriptor Descriptor for method * @param access Access for the method * @return Method object that can be used for constructing a method body */ public Method addMethod(String name, String descriptor, int access) { return addMethod(name, descriptor, access, null); } /** * Add a method, no code associated with it yet * @param name Name of method * @param descriptor Descriptor for method * @param access Access for the method * @param execMode The execution mode for the method. * @return Method object that can be used for constructing a method body */ public Method addMethod(String name, String descriptor, int access, ClassBuilder.ExecutionMode execMode) { return new Method(this, cw, name, descriptor, access, execMode); } /** * Adds a m()LTestObject; method which returns null unless the method is abstract * @param access Access for the method */ public void addTestMethod(int access) { Method m = new Method(this, cw, Method.defaultMethodName, Method.defaultMethodDescriptor, access, null); if ((access & Opcodes.ACC_ABSTRACT) != Opcodes.ACC_ABSTRACT) { m.makeDefaultMethod(); } } /** * Construct the class to a byte[] * @return byte[] with class file */ public byte[] generateBytes() { cw.visitEnd(); return cw.toByteArray(); } /** * Write out a class to a file in the specified directory. * * @param dir Directory to which to write out the file. */ public void writeClass(final File dir) throws Exception { final String pkgname = getPackageName(); final File pkgdir = pkgname != null ? new File(dir, getPackageName()) : dir; pkgdir.mkdirs(); final File out = new File(pkgdir, getClassName() + ".class"); out.createNewFile(); try (final FileOutputStream fos = new FileOutputStream(out)) { fos.write(generateBytes()); } } public boolean isInterface() { return isInterface; } public Integer getIndex() { return index; } }