Initial commit from SVN.
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
package com.de22.javabytecode.generator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import com.common.io.*;
|
||||
import com.common.debug.*;
|
||||
import com.de22.javabytecode.*;
|
||||
import com.de22.javabytecode.code.*;
|
||||
|
||||
/**
|
||||
* Copyright Declarative Engineering LLC 1999<p>
|
||||
* Provides some assistance methods for generating a class.
|
||||
*/
|
||||
public abstract class ClassGenerator {
|
||||
public static final String INIT_METHOD_NAME = "<init>";
|
||||
//private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
|
||||
|
||||
protected StringBuffer sharedBuffer = new StringBuffer(500); //A shared string buffer that can be used by the class generator and subclasses to temporarily buffer data within the method. Warning: This is reused by many methods so make sure you don't store anything important before calling another method.//
|
||||
|
||||
private Type type = null;
|
||||
/**
|
||||
* ClassGenerator constructor.
|
||||
*/
|
||||
private ClassGenerator() {
|
||||
super();
|
||||
}//ClassGenerator()//
|
||||
/**
|
||||
* ClassGenerator constructor.
|
||||
*/
|
||||
public ClassGenerator(String qualifiedClassName) {
|
||||
super();
|
||||
|
||||
createClass(qualifiedClassName);
|
||||
}//ClassGenerator()//
|
||||
/**
|
||||
* Creates a new type. All subsequent operations are against this type.
|
||||
* <p>TODO: Provide more input to this method to allow different access flags and such.
|
||||
* @param qualifiedClassName The fully qualified class name of this new class. Must use '/' instead of '.' & do not use a '.class' or '.java' extention.
|
||||
*/
|
||||
protected void createClass(String qualifiedClassName) {
|
||||
try {
|
||||
Type type = new Type(qualifiedClassName);
|
||||
|
||||
type.setAccessFlags((short) (Type.ACC_PUBLIC | Type.ACC_SUPER));
|
||||
type.setMajorVersion((short) 45);
|
||||
type.setMinorVersion((short) 3);
|
||||
|
||||
setType(type);
|
||||
}//try//
|
||||
catch(Throwable e) {
|
||||
Debug.log(e);
|
||||
Debug.halt();
|
||||
}//catch//
|
||||
}//createClass()//
|
||||
/**
|
||||
* Creates the one and only init method which should at the very least call the super classes' init method.
|
||||
* <p>TODO: Stop ignoring the passed byte codes and instead add them in the mix.
|
||||
* @param superClass The class that this class will inherit from.
|
||||
* @param code This parameter is currently ignored.
|
||||
*/
|
||||
public void createInitMethod(Class superClass, byte[] code) {
|
||||
try {
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream(20, false);
|
||||
StandardOutputStream out = new StandardOutputStream(bout);
|
||||
short superInitIndex = getType().addConstantMethod(superClass, null, INIT_METHOD_NAME, new Class[0]);
|
||||
|
||||
out.writeByte((byte) 42); //aload_0
|
||||
out.writeByte((byte) 183); //invokespecial -> invoke super class' <init> method.
|
||||
out.writeShort((short) superInitIndex);
|
||||
out.writeByte((byte) 177); //return
|
||||
//Add the method to the type.//
|
||||
getType().addMethod(Modifier.PUBLIC, null, INIT_METHOD_NAME, new Class[0], bout.toByteArray(), 1, 1);
|
||||
}//try//
|
||||
catch(Throwable e) {
|
||||
Debug.log(e);
|
||||
Debug.halt();
|
||||
}//catch//
|
||||
}//createInitMethod()//
|
||||
/**
|
||||
* Formats a descriptor string using the parameters and return type of the method.
|
||||
* This is used to create method descriptors for a class file.
|
||||
* <p>Example: void methodName(double[] a, String b) -> ([DLjava/lang/String;)V;
|
||||
* @param returnType The descriptor's return type.
|
||||
* @param parameterTypes The descriptor's parameter types (in order of parameter).
|
||||
* @return The formatted type string.
|
||||
*/
|
||||
protected String formatDescriptor(Class returnType, Class[] parameterTypes) {
|
||||
sharedBuffer.setLength(0);
|
||||
FormatSupport.formatDescriptor(returnType, parameterTypes, sharedBuffer);
|
||||
|
||||
return sharedBuffer.toString();
|
||||
}//formatDescriptor()//
|
||||
/**
|
||||
* Formats a non-primitive class to a class file compatible string.
|
||||
* <p>NOTE: This method will not place an "L" at the beginning or a ";" at the end of the formatted string.
|
||||
* @param type The non-primitive class to convert to a string.
|
||||
* @return The string representation of the type.
|
||||
*/
|
||||
protected String formatNonPrimitiveType(String qualifiedTypeName) {
|
||||
sharedBuffer.setLength(0);
|
||||
FormatSupport.formatNonPrimitiveType(qualifiedTypeName, sharedBuffer);
|
||||
|
||||
return sharedBuffer.toString();
|
||||
}//formatNonPrimitiveType()//
|
||||
/**
|
||||
* Formats a class to a class file compatible string.
|
||||
* @param type The class to convert to a string.
|
||||
* @return The formatted type string.
|
||||
*/
|
||||
protected String formatType(Class type) {
|
||||
sharedBuffer.setLength(0);
|
||||
FormatSupport.formatType(type, sharedBuffer);
|
||||
|
||||
return sharedBuffer.toString();
|
||||
}//formatType()//
|
||||
/**
|
||||
* Generates a method signature string from the method.
|
||||
* @param method The method whose signature should be generated.
|
||||
*/
|
||||
protected static String generateMethodSignature(java.lang.reflect.Method method) {
|
||||
try {
|
||||
StringBuffer signature = new StringBuffer(100);
|
||||
Class[] parameterTypes = method.getParameterTypes();
|
||||
|
||||
for(int index = 0; index < parameterTypes.length; index++) {
|
||||
if(signature == null) {
|
||||
signature = new StringBuffer(100);
|
||||
}//if//
|
||||
else {
|
||||
signature.append(',');
|
||||
signature.append(' ');
|
||||
}//else//
|
||||
|
||||
signature.append(parameterTypes[index].getName());
|
||||
}//for//
|
||||
|
||||
signature.append('(');
|
||||
|
||||
if(signature != null) {
|
||||
signature.append(signature);
|
||||
}//if//
|
||||
|
||||
signature.append(')');
|
||||
|
||||
return signature.toString();
|
||||
}//try//
|
||||
catch(Throwable e) {
|
||||
Debug.log(e);
|
||||
Debug.halt();
|
||||
return "";
|
||||
}//catch//
|
||||
}//generateMethodSignature()//
|
||||
/**
|
||||
* Gets the classes' byte codes.
|
||||
* @return The array of byte codes for the class.
|
||||
*/
|
||||
public byte[] getClassByteCodes() throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(1000, false);
|
||||
|
||||
getType().writeExternal(new ObjectOutputStream(out, null));
|
||||
|
||||
return out.toByteArray();
|
||||
}//getClassByteCodes()//
|
||||
/**
|
||||
* Gets the classes' type object.
|
||||
* @return The type object describing the class byte codes.
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}//getType()//
|
||||
/**
|
||||
* Sets the classes' source file reference.
|
||||
* <p>TODO: Implement this properly by adding an addAttributeSourceFile method to the Type class.
|
||||
* @param path The path to the source file that created this class.
|
||||
*/
|
||||
public void setSourceFile(String path) {
|
||||
try {
|
||||
//Type type = getType();
|
||||
//SourceFile sourceFile = new SourceFile(type, path);
|
||||
|
||||
//Add the attribute to the class.//
|
||||
//type.addAttribute(sourceFile);
|
||||
}//try//
|
||||
catch(Throwable e) {
|
||||
Debug.log(e);
|
||||
Debug.halt();
|
||||
}//catch//
|
||||
}//setSuperClass()//
|
||||
/**
|
||||
* Sets the super class for this class.
|
||||
* @param qualifiedSuperClassName The qualified class name of the super class. This string will be reformatted for use in the class byte codes.
|
||||
*/
|
||||
public void setSuperClass(String qualifiedSuperClassName) {
|
||||
Type type = getType();
|
||||
|
||||
type.setSuperClass(formatNonPrimitiveType(qualifiedSuperClassName));
|
||||
}//setSuperClass()//
|
||||
/**
|
||||
* Sets the classes' type object.
|
||||
* @param type The type object describing the class byte codes.
|
||||
*/
|
||||
private void setType(Type type) {
|
||||
this.type = type;
|
||||
}//setType()//
|
||||
}//ClassGenerator//
|
||||
Reference in New Issue
Block a user