blob: c23e5ddb55453ac8cb8d6b2d4e8308d17932e972 [file] [log] [blame]
/*
* 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;
}
}