2008-05-29 01:52:53 +02:00
|
|
|
package org.aspectj.apache.bcel.verifier.util;
|
2004-11-18 15:48:11 +01:00
|
|
|
|
|
|
|
/* ====================================================================
|
|
|
|
* The Apache Software License, Version 1.1
|
|
|
|
*
|
|
|
|
* Copyright (c) 2002 The Apache Software Foundation. All rights
|
|
|
|
* reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
*
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
*
|
|
|
|
* 3. The end-user documentation included with the redistribution,
|
|
|
|
* if any, must include the following acknowledgment:
|
|
|
|
* "This product includes software developed by the
|
|
|
|
* Apache Software Foundation (http://www.apache.org/)."
|
|
|
|
* Alternately, this acknowledgment may appear in the software itself,
|
|
|
|
* if and wherever such third-party acknowledgments normally appear.
|
|
|
|
*
|
|
|
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
|
|
|
* "Apache BCEL" must not be used to endorse or promote products
|
|
|
|
* derived from this software without prior written permission. For
|
|
|
|
* written permission, please contact apache@apache.org.
|
|
|
|
*
|
|
|
|
* 5. Products derived from this software may not be called "Apache",
|
|
|
|
* "Apache BCEL", nor may "Apache" appear in their name, without
|
|
|
|
* prior written permission of the Apache Software Foundation.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
|
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
|
|
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
|
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
* ====================================================================
|
|
|
|
*
|
|
|
|
* This software consists of voluntary contributions made by many
|
|
|
|
* individuals on behalf of the Apache Software Foundation. For more
|
|
|
|
* information on the Apache Software Foundation, please see
|
|
|
|
* <http://www.apache.org/>.
|
|
|
|
*/
|
2004-11-22 09:31:23 +01:00
|
|
|
import java.io.OutputStream;
|
|
|
|
import java.io.PrintWriter;
|
|
|
|
|
|
|
|
import org.aspectj.apache.bcel.Constants;
|
|
|
|
import org.aspectj.apache.bcel.Repository;
|
2004-11-19 17:45:18 +01:00
|
|
|
import org.aspectj.apache.bcel.classfile.ClassParser;
|
|
|
|
import org.aspectj.apache.bcel.classfile.ConstantValue;
|
|
|
|
import org.aspectj.apache.bcel.classfile.Field;
|
|
|
|
import org.aspectj.apache.bcel.classfile.JavaClass;
|
|
|
|
import org.aspectj.apache.bcel.classfile.Method;
|
|
|
|
import org.aspectj.apache.bcel.classfile.Utility;
|
2004-11-22 09:31:23 +01:00
|
|
|
import org.aspectj.apache.bcel.generic.ArrayType;
|
2008-05-29 01:52:53 +02:00
|
|
|
import org.aspectj.apache.bcel.classfile.ConstantPool;
|
2004-11-22 09:31:23 +01:00
|
|
|
import org.aspectj.apache.bcel.generic.MethodGen;
|
|
|
|
import org.aspectj.apache.bcel.generic.Type;
|
2004-11-18 15:48:11 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This class takes a given JavaClass object and converts it to a
|
|
|
|
* Java program that creates that very class using BCEL. This
|
|
|
|
* gives new users of BCEL a useful example showing how things
|
|
|
|
* are done with BCEL. It does not cover all features of BCEL,
|
|
|
|
* but tries to mimic hand-written code as close as possible.
|
|
|
|
*
|
2008-05-29 01:52:53 +02:00
|
|
|
* @version $Id: BCELifier.java,v 1.2 2008/05/28 23:53:04 aclement Exp $
|
2004-11-18 15:48:11 +01:00
|
|
|
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
|
|
|
|
*/
|
2008-05-29 01:52:53 +02:00
|
|
|
public class BCELifier extends org.aspectj.apache.bcel.verifier.EmptyClassVisitor {
|
2004-11-18 15:48:11 +01:00
|
|
|
private JavaClass _clazz;
|
|
|
|
private PrintWriter _out;
|
2008-05-29 01:52:53 +02:00
|
|
|
private ConstantPool _cp;
|
2004-11-18 15:48:11 +01:00
|
|
|
|
|
|
|
/** @param clazz Java class to "decompile"
|
|
|
|
* @param out where to output Java program
|
|
|
|
*/
|
|
|
|
public BCELifier(JavaClass clazz, OutputStream out) {
|
|
|
|
_clazz = clazz;
|
|
|
|
_out = new PrintWriter(out);
|
2008-05-29 01:52:53 +02:00
|
|
|
_cp = new ConstantPool(_clazz.getConstantPool().getConstantPool());
|
2004-11-18 15:48:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Start Java code generation
|
|
|
|
*/
|
|
|
|
public void start() {
|
|
|
|
visitJavaClass(_clazz);
|
|
|
|
_out.flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void visitJavaClass(JavaClass clazz) {
|
|
|
|
String class_name = clazz.getClassName();
|
|
|
|
String super_name = clazz.getSuperclassName();
|
|
|
|
String package_name = clazz.getPackageName();
|
2008-05-29 01:52:53 +02:00
|
|
|
String inter = BCELifier.printArray(clazz.getInterfaceNames(),
|
2004-11-18 15:48:11 +01:00
|
|
|
false, true);
|
|
|
|
if(!"".equals(package_name)) {
|
|
|
|
class_name = class_name.substring(package_name.length() + 1);
|
|
|
|
_out.println("package " + package_name + ";\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
_out.println("import org.aspectj.apache.bcel.generic.*;");
|
|
|
|
_out.println("import org.aspectj.apache.bcel.classfile.*;");
|
|
|
|
_out.println("import org.aspectj.apache.bcel.*;");
|
|
|
|
_out.println("import java.io.*;\n");
|
|
|
|
|
|
|
|
_out.println("public class " + class_name + "Creator implements Constants {");
|
|
|
|
_out.println(" private InstructionFactory _factory;");
|
|
|
|
_out.println(" private ConstantPoolGen _cp;");
|
|
|
|
_out.println(" private ClassGen _cg;\n");
|
|
|
|
|
|
|
|
_out.println(" public " + class_name + "Creator() {");
|
|
|
|
_out.println(" _cg = new ClassGen(\"" +
|
|
|
|
(("".equals(package_name))? class_name :
|
|
|
|
package_name + "." + class_name) +
|
|
|
|
"\", \"" + super_name + "\", " +
|
|
|
|
"\"" + clazz.getSourceFileName() + "\", " +
|
2008-05-29 01:52:53 +02:00
|
|
|
printFlags(clazz.getModifiers(), true) + ", " +
|
2004-11-18 15:48:11 +01:00
|
|
|
"new String[] { " + inter + " });\n");
|
|
|
|
|
|
|
|
_out.println(" _cp = _cg.getConstantPool();");
|
|
|
|
_out.println(" _factory = new InstructionFactory(_cg, _cp);");
|
|
|
|
_out.println(" }\n");
|
|
|
|
|
|
|
|
printCreate();
|
|
|
|
|
|
|
|
Field[] fields = clazz.getFields();
|
|
|
|
|
|
|
|
if(fields.length > 0) {
|
|
|
|
_out.println(" private void createFields() {");
|
|
|
|
_out.println(" FieldGen field;");
|
|
|
|
|
|
|
|
for(int i=0; i < fields.length; i++) {
|
|
|
|
fields[i].accept(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
_out.println(" }\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
Method[] methods = clazz.getMethods();
|
|
|
|
|
|
|
|
for(int i=0; i < methods.length; i++) {
|
|
|
|
_out.println(" private void createMethod_" + i + "() {");
|
|
|
|
|
|
|
|
methods[i].accept(this);
|
|
|
|
_out.println(" }\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
printMain();
|
|
|
|
_out.println("}");
|
|
|
|
}
|
|
|
|
|
|
|
|
private void printCreate() {
|
|
|
|
_out.println(" public void create(OutputStream out) throws IOException {");
|
|
|
|
|
|
|
|
Field[] fields = _clazz.getFields();
|
|
|
|
if(fields.length > 0) {
|
|
|
|
_out.println(" createFields();");
|
|
|
|
}
|
|
|
|
|
|
|
|
Method[] methods = _clazz.getMethods();
|
|
|
|
for(int i=0; i < methods.length; i++) {
|
|
|
|
_out.println(" createMethod_" + i + "();");
|
|
|
|
}
|
|
|
|
|
|
|
|
_out.println(" _cg.getJavaClass().dump(out);");
|
|
|
|
|
|
|
|
_out.println(" }\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
private void printMain() {
|
|
|
|
String class_name = _clazz.getClassName();
|
|
|
|
|
|
|
|
_out.println(" public static void main(String[] args) throws Exception {");
|
|
|
|
_out.println(" " + class_name + "Creator creator = new " +
|
|
|
|
class_name + "Creator();");
|
|
|
|
_out.println(" creator.create(new FileOutputStream(\"" + class_name +
|
|
|
|
".class\"));");
|
|
|
|
_out.println(" }");
|
|
|
|
}
|
|
|
|
|
|
|
|
public void visitField(Field field) {
|
|
|
|
_out.println("\n field = new FieldGen(" +
|
2008-05-29 01:52:53 +02:00
|
|
|
printFlags(field.getModifiers()) +
|
2004-11-18 15:48:11 +01:00
|
|
|
", " + printType(field.getSignature()) + ", \"" +
|
|
|
|
field.getName() + "\", _cp);");
|
|
|
|
|
|
|
|
ConstantValue cv = field.getConstantValue();
|
|
|
|
|
|
|
|
if(cv != null) {
|
|
|
|
String value = cv.toString();
|
|
|
|
_out.println(" field.setInitValue(" + value + ")");
|
|
|
|
}
|
|
|
|
|
|
|
|
_out.println(" _cg.addField(field.getField());");
|
|
|
|
}
|
|
|
|
|
|
|
|
public void visitMethod(Method method) {
|
|
|
|
MethodGen mg = new MethodGen(method, _clazz.getClassName(), _cp);
|
|
|
|
|
|
|
|
Type result_type = mg.getReturnType();
|
|
|
|
Type[] arg_types = mg.getArgumentTypes();
|
|
|
|
|
|
|
|
_out.println(" InstructionList il = new InstructionList();");
|
|
|
|
_out.println(" MethodGen method = new MethodGen(" +
|
2008-05-29 01:52:53 +02:00
|
|
|
printFlags(method.getModifiers()) +
|
2004-11-18 15:48:11 +01:00
|
|
|
", " + printType(result_type) +
|
|
|
|
", " + printArgumentTypes(arg_types) + ", " +
|
|
|
|
"new String[] { " +
|
2008-05-29 01:52:53 +02:00
|
|
|
BCELifier.printArray(mg.getArgumentNames(), false, true) +
|
2004-11-18 15:48:11 +01:00
|
|
|
" }, \"" + method.getName() + "\", \"" +
|
|
|
|
_clazz.getClassName() + "\", il, _cp);\n");
|
|
|
|
|
|
|
|
BCELFactory factory = new BCELFactory(mg, _out);
|
|
|
|
factory.start();
|
|
|
|
|
|
|
|
_out.println(" method.setMaxStack();");
|
|
|
|
_out.println(" method.setMaxLocals();");
|
|
|
|
_out.println(" _cg.addMethod(method.getMethod());");
|
|
|
|
_out.println(" il.dispose();");
|
|
|
|
}
|
|
|
|
|
2008-05-29 01:52:53 +02:00
|
|
|
public static final String printArray(Object[] obj, boolean braces,
|
|
|
|
boolean quote) {
|
|
|
|
if(obj == null)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
StringBuffer buf = new StringBuffer();
|
|
|
|
if(braces)
|
|
|
|
buf.append('{');
|
|
|
|
|
|
|
|
for(int i=0; i < obj.length; i++) {
|
|
|
|
if(obj[i] != null) {
|
|
|
|
buf.append((quote? "\"" : "") + obj[i].toString() + (quote? "\"" : ""));
|
|
|
|
} else {
|
|
|
|
buf.append("null");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(i < obj.length - 1) {
|
|
|
|
buf.append(", ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(braces)
|
|
|
|
buf.append('}');
|
|
|
|
|
|
|
|
return buf.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
static String printFlags(int flags) {
|
2004-11-18 15:48:11 +01:00
|
|
|
return printFlags(flags, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static String printFlags(int flags, boolean for_class) {
|
|
|
|
if(flags == 0)
|
|
|
|
return "0";
|
|
|
|
|
|
|
|
StringBuffer buf = new StringBuffer();
|
|
|
|
for(int i=0, pow=1; i <= Constants.MAX_ACC_FLAG; i++) {
|
|
|
|
if((flags & pow) != 0) {
|
|
|
|
if((pow == Constants.ACC_SYNCHRONIZED) && for_class)
|
|
|
|
buf.append("ACC_SUPER | ");
|
|
|
|
else
|
|
|
|
buf.append("ACC_" + Constants.ACCESS_NAMES[i].toUpperCase() + " | ");
|
|
|
|
}
|
|
|
|
|
|
|
|
pow <<= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
String str = buf.toString();
|
|
|
|
return str.substring(0, str.length() - 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
static String printArgumentTypes(Type[] arg_types) {
|
|
|
|
if(arg_types.length == 0)
|
|
|
|
return "Type.NO_ARGS";
|
|
|
|
|
|
|
|
StringBuffer args = new StringBuffer();
|
|
|
|
|
|
|
|
for(int i=0; i < arg_types.length; i++) {
|
|
|
|
args.append(printType(arg_types[i]));
|
|
|
|
|
|
|
|
if(i < arg_types.length - 1)
|
|
|
|
args.append(", ");
|
|
|
|
}
|
|
|
|
|
|
|
|
return "new Type[] { " + args.toString() + " }";
|
|
|
|
}
|
|
|
|
|
|
|
|
static String printType(Type type) {
|
|
|
|
return printType(type.getSignature());
|
|
|
|
}
|
|
|
|
|
|
|
|
static String printType(String signature) {
|
|
|
|
Type type = Type.getType(signature);
|
|
|
|
byte t = type.getType();
|
|
|
|
|
|
|
|
if(t <= Constants.T_VOID) {
|
|
|
|
return "Type." + Constants.TYPE_NAMES[t].toUpperCase();
|
|
|
|
} else if(type.toString().equals("java.lang.String")) {
|
|
|
|
return "Type.STRING";
|
|
|
|
} else if(type.toString().equals("java.lang.Object")) {
|
|
|
|
return "Type.OBJECT";
|
|
|
|
} else if(type.toString().equals("java.lang.StringBuffer")) {
|
|
|
|
return "Type.STRINGBUFFER";
|
|
|
|
} else if(type instanceof ArrayType) {
|
|
|
|
ArrayType at = (ArrayType)type;
|
|
|
|
|
|
|
|
return "new ArrayType(" + printType(at.getBasicType()) +
|
|
|
|
", " + at.getDimensions() + ")";
|
|
|
|
} else {
|
|
|
|
return "new ObjectType(\"" + Utility.signatureToString(signature, false) +
|
|
|
|
"\")";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Default main method
|
|
|
|
*/
|
|
|
|
public static void main(String[] argv) throws Exception {
|
|
|
|
JavaClass java_class;
|
|
|
|
String name = argv[0];
|
|
|
|
|
|
|
|
if((java_class = Repository.lookupClass(name)) == null)
|
|
|
|
java_class = new ClassParser(name).parse(); // May throw IOException
|
|
|
|
|
|
|
|
BCELifier bcelifier = new BCELifier(java_class, System.out);
|
|
|
|
bcelifier.start();
|
|
|
|
}
|
|
|
|
}
|