1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.bcel.internal.util; 23 24 import java.io.IOException; 25 import java.io.OutputStream; 26 import java.io.PrintWriter; 27 import java.util.Locale; 28 29 import com.sun.org.apache.bcel.internal.Const; 30 import com.sun.org.apache.bcel.internal.Repository; 31 import com.sun.org.apache.bcel.internal.classfile.ClassParser; 32 import com.sun.org.apache.bcel.internal.classfile.ConstantValue; 33 import com.sun.org.apache.bcel.internal.classfile.Field; 34 import com.sun.org.apache.bcel.internal.classfile.JavaClass; 35 import com.sun.org.apache.bcel.internal.classfile.Method; 36 import com.sun.org.apache.bcel.internal.classfile.Utility; 37 import com.sun.org.apache.bcel.internal.generic.ArrayType; 38 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 39 import com.sun.org.apache.bcel.internal.generic.MethodGen; 40 import com.sun.org.apache.bcel.internal.generic.Type; 41 42 /** 43 * This class takes a given JavaClass object and converts it to a 44 * Java program that creates that very class using BCEL. This 45 * gives new users of BCEL a useful example showing how things 46 * are done with BCEL. It does not cover all features of BCEL, 47 * but tries to mimic hand-written code as close as possible. 48 * 49 * @version $Id$ 50 */ 51 public class BCELifier extends com.sun.org.apache.bcel.internal.classfile.EmptyVisitor { 52 53 /** 54 * Enum corresponding to flag source. 55 */ 56 public enum FLAGS { 57 UNKNOWN, 58 CLASS, 59 METHOD, 60 } 61 62 // The base package name for imports; assumes Const is at the top level 63 // N.B we use the class so renames will be detected by the compiler/IDE 64 private static final String BASE_PACKAGE = Const.class.getPackage().getName(); 65 private static final String CONSTANT_PREFIX = Const.class.getSimpleName()+"."; 66 67 private final JavaClass _clazz; 68 private final PrintWriter _out; 69 private final ConstantPoolGen _cp; 70 71 /** @param clazz Java class to "decompile" 72 * @param out where to output Java program 73 */ 74 public BCELifier(final JavaClass clazz, final OutputStream out) { 75 _clazz = clazz; 76 _out = new PrintWriter(out); 77 _cp = new ConstantPoolGen(_clazz.getConstantPool()); 78 } 79 80 81 /** Start Java code generation 82 */ 83 public void start() { 84 visitJavaClass(_clazz); 85 _out.flush(); 86 } 87 88 89 @Override 90 public void visitJavaClass( final JavaClass clazz ) { 91 String class_name = clazz.getClassName(); 92 final String super_name = clazz.getSuperclassName(); 93 final String package_name = clazz.getPackageName(); 94 final String inter = Utility.printArray(clazz.getInterfaceNames(), false, true); 95 if (!"".equals(package_name)) { 96 class_name = class_name.substring(package_name.length() + 1); 97 _out.println("package " + package_name + ";"); 98 _out.println(); 99 } 100 _out.println("import " + BASE_PACKAGE + ".generic.*;"); 101 _out.println("import " + BASE_PACKAGE + ".classfile.*;"); 102 _out.println("import " + BASE_PACKAGE + ".*;"); 103 _out.println("import java.io.*;"); 104 _out.println(); 105 _out.println("public class " + class_name + "Creator {"); 106 _out.println(" private InstructionFactory _factory;"); 107 _out.println(" private ConstantPoolGen _cp;"); 108 _out.println(" private ClassGen _cg;"); 109 _out.println(); 110 _out.println(" public " + class_name + "Creator() {"); 111 _out.println(" _cg = new ClassGen(\"" 112 + (("".equals(package_name)) ? class_name : package_name + "." + class_name) 113 + "\", \"" + super_name + "\", " + "\"" + clazz.getSourceFileName() + "\", " 114 + printFlags(clazz.getAccessFlags(), FLAGS.CLASS) + ", " 115 + "new String[] { " + inter + " });"); 116 _out.println(); 117 _out.println(" _cp = _cg.getConstantPool();"); 118 _out.println(" _factory = new InstructionFactory(_cg, _cp);"); 119 _out.println(" }"); 120 _out.println(); 121 printCreate(); 122 final Field[] fields = clazz.getFields(); 123 if (fields.length > 0) { 124 _out.println(" private void createFields() {"); 125 _out.println(" FieldGen field;"); 126 for (final Field field : fields) { 127 field.accept(this); 128 } 129 _out.println(" }"); 130 _out.println(); 131 } 132 final Method[] methods = clazz.getMethods(); 133 for (int i = 0; i < methods.length; i++) { 134 _out.println(" private void createMethod_" + i + "() {"); 135 methods[i].accept(this); 136 _out.println(" }"); 137 _out.println(); 138 } 139 printMain(); 140 _out.println("}"); 141 } 142 143 144 private void printCreate() { 145 _out.println(" public void create(OutputStream out) throws IOException {"); 146 final Field[] fields = _clazz.getFields(); 147 if (fields.length > 0) { 148 _out.println(" createFields();"); 149 } 150 final Method[] methods = _clazz.getMethods(); 151 for (int i = 0; i < methods.length; i++) { 152 _out.println(" createMethod_" + i + "();"); 153 } 154 _out.println(" _cg.getJavaClass().dump(out);"); 155 _out.println(" }"); 156 _out.println(); 157 } 158 159 160 private void printMain() { 161 final String class_name = _clazz.getClassName(); 162 _out.println(" public static void main(String[] args) throws Exception {"); 163 _out.println(" " + class_name + "Creator creator = new " + class_name + "Creator();"); 164 _out.println(" creator.create(new FileOutputStream(\"" + class_name + ".class\"));"); 165 _out.println(" }"); 166 } 167 168 169 @Override 170 public void visitField( final Field field ) { 171 _out.println(); 172 _out.println(" field = new FieldGen(" + printFlags(field.getAccessFlags()) + ", " 173 + printType(field.getSignature()) + ", \"" + field.getName() + "\", _cp);"); 174 final ConstantValue cv = field.getConstantValue(); 175 if (cv != null) { 176 final String value = cv.toString(); 177 _out.println(" field.setInitValue(" + value + ")"); 178 } 179 _out.println(" _cg.addField(field.getField());"); 180 } 181 182 183 @Override 184 public void visitMethod( final Method method ) { 185 final MethodGen mg = new MethodGen(method, _clazz.getClassName(), _cp); 186 _out.println(" InstructionList il = new InstructionList();"); 187 _out.println(" MethodGen method = new MethodGen(" 188 + printFlags(method.getAccessFlags(), FLAGS.METHOD) + ", " 189 + printType(mg.getReturnType()) + ", " 190 + printArgumentTypes(mg.getArgumentTypes()) + ", " 191 + "new String[] { " + Utility.printArray(mg.getArgumentNames(), false, true) 192 + " }, \"" + method.getName() + "\", \"" + _clazz.getClassName() + "\", il, _cp);"); 193 _out.println(); 194 final BCELFactory factory = new BCELFactory(mg, _out); 195 factory.start(); 196 _out.println(" method.setMaxStack();"); 197 _out.println(" method.setMaxLocals();"); 198 _out.println(" _cg.addMethod(method.getMethod());"); 199 _out.println(" il.dispose();"); 200 } 201 202 203 static String printFlags( final int flags ) { 204 return printFlags(flags, FLAGS.UNKNOWN); 205 } 206 207 /** 208 * Return a string with the flag settings 209 * @param flags the flags field to interpret 210 * @param location the item type 211 * @return the formatted string 212 * @since 6.0 made public 213 */ 214 public static String printFlags( final int flags, final FLAGS location ) { 215 if (flags == 0) { 216 return "0"; 217 } 218 final StringBuilder buf = new StringBuilder(); 219 for (int i = 0, pow = 1; pow <= Const.MAX_ACC_FLAG; i++) { 220 if ((flags & pow) != 0) { 221 if ((pow == Const.ACC_SYNCHRONIZED) && (location == FLAGS.CLASS)) { 222 buf.append(CONSTANT_PREFIX+"ACC_SUPER | "); 223 } else if ((pow == Const.ACC_VOLATILE) && (location == FLAGS.METHOD)) { 224 buf.append(CONSTANT_PREFIX+"ACC_BRIDGE | "); 225 } else if ((pow == Const.ACC_TRANSIENT) && (location == FLAGS.METHOD)) { 226 buf.append(CONSTANT_PREFIX+"ACC_VARARGS | "); 227 } else { 228 if (i < Const.ACCESS_NAMES_LENGTH) { 229 buf.append(CONSTANT_PREFIX+"ACC_") 230 .append(Const.getAccessName(i).toUpperCase(Locale.ENGLISH)) 231 .append( " | "); 232 } else { 233 buf.append(String.format (CONSTANT_PREFIX+"ACC_BIT %x | ", pow)); 234 } 235 } 236 } 237 pow <<= 1; 238 } 239 final String str = buf.toString(); 240 return str.substring(0, str.length() - 3); 241 } 242 243 244 static String printArgumentTypes( final Type[] arg_types ) { 245 if (arg_types.length == 0) { 246 return "Type.NO_ARGS"; 247 } 248 final StringBuilder args = new StringBuilder(); 249 for (int i = 0; i < arg_types.length; i++) { 250 args.append(printType(arg_types[i])); 251 if (i < arg_types.length - 1) { 252 args.append(", "); 253 } 254 } 255 return "new Type[] { " + args.toString() + " }"; 256 } 257 258 259 static String printType( final Type type ) { 260 return printType(type.getSignature()); 261 } 262 263 264 static String printType( final String signature ) { 265 final Type type = Type.getType(signature); 266 final byte t = type.getType(); 267 if (t <= Const.T_VOID) { 268 return "Type." + Const.getTypeName(t).toUpperCase(Locale.ENGLISH); 269 } else if (type.toString().equals("java.lang.String")) { 270 return "Type.STRING"; 271 } else if (type.toString().equals("java.lang.Object")) { 272 return "Type.OBJECT"; 273 } else if (type.toString().equals("java.lang.StringBuffer")) { 274 return "Type.STRINGBUFFER"; 275 } else if (type instanceof ArrayType) { 276 final ArrayType at = (ArrayType) type; 277 return "new ArrayType(" + printType(at.getBasicType()) + ", " + at.getDimensions() 278 + ")"; 279 } else { 280 return "new ObjectType(\"" + Utility.signatureToString(signature, false) + "\")"; 281 } 282 } 283 284 285 /** Default main method 286 */ 287 public static void main( final String[] argv ) throws Exception { 288 if (argv.length != 1) { 289 System.out.println("Usage: BCELifier classname"); 290 System.out.println("\tThe class must exist on the classpath"); 291 return; 292 } 293 final JavaClass java_class = getJavaClass(argv[0]); 294 final BCELifier bcelifier = new BCELifier(java_class, System.out); 295 bcelifier.start(); 296 } 297 298 299 // Needs to be accessible from unit test code 300 static JavaClass getJavaClass(final String name) throws ClassNotFoundException, IOException { 301 JavaClass java_class; 302 if ((java_class = Repository.lookupClass(name)) == null) { 303 java_class = new ClassParser(name).parse(); // May throw IOException 304 } 305 return java_class; 306 } 307 }