Home | History | Annotate | Download | only in examples
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  */
     18 
     19 import org.apache.bcel.Constants;
     20 import org.apache.bcel.classfile.ClassParser;
     21 import org.apache.bcel.classfile.Code;
     22 import org.apache.bcel.classfile.ConstantClass;
     23 import org.apache.bcel.classfile.ConstantPool;
     24 import org.apache.bcel.classfile.ConstantUtf8;
     25 import org.apache.bcel.classfile.JavaClass;
     26 import org.apache.bcel.classfile.Method;
     27 import org.apache.bcel.classfile.Utility;
     28 import org.apache.bcel.generic.ConstantPoolGen;
     29 import org.apache.bcel.generic.GETSTATIC;
     30 import org.apache.bcel.generic.INVOKESPECIAL;
     31 import org.apache.bcel.generic.INVOKEVIRTUAL;
     32 import org.apache.bcel.generic.InstructionHandle;
     33 import org.apache.bcel.generic.InstructionList;
     34 import org.apache.bcel.generic.MethodGen;
     35 import org.apache.bcel.generic.PUSH;
     36 
     37 /**
     38  * Read class file(s) and patch all of its methods, so that they print
     39  * "hello" and their name and signature before doing anything else.
     40  *
     41  * @version $Id$
     42  */
     43 public final class helloify implements Constants {
     44 
     45     private static String class_name;
     46     private static ConstantPoolGen cp;
     47     private static int out;     // reference to System.out
     48     private static int println; // reference to PrintStream.println
     49 
     50     public static void main(String[] argv) throws Exception {
     51         for (String arg : argv) {
     52             if (arg.endsWith(".class")) {
     53                 JavaClass java_class = new ClassParser(arg).parse();
     54                 ConstantPool constants = java_class.getConstantPool();
     55                 String file_name = arg.substring(0, arg.length() - 6) + "_hello.class";
     56                 cp = new ConstantPoolGen(constants);
     57 
     58                 helloifyClassName(java_class);
     59 
     60                 out = cp.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;");
     61                 println = cp.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V");
     62                 // Patch all methods.
     63                 Method[] methods = java_class.getMethods();
     64 
     65                 for (int j = 0; j < methods.length; j++) {
     66                     methods[j] = helloifyMethod(methods[j]);
     67                 }
     68 
     69                 // Finally dump it back to a file.
     70                 java_class.setConstantPool(cp.getFinalConstantPool());
     71                 java_class.dump(file_name);
     72             }
     73         }
     74     }
     75 
     76     /**
     77      * Change class name to <old_name>_hello
     78      */
     79     private static void helloifyClassName(JavaClass java_class) {
     80         class_name = java_class.getClassName() + "_hello";
     81         int index = java_class.getClassNameIndex();
     82 
     83         index = ((ConstantClass) cp.getConstant(index)).getNameIndex();
     84         cp.setConstant(index, new ConstantUtf8(class_name.replace('.', '/')));
     85     }
     86 
     87     /**
     88      * Patch a method.
     89      */
     90     private static Method helloifyMethod(Method m) {
     91         Code code = m.getCode();
     92         int flags = m.getAccessFlags();
     93         String name = m.getName();
     94 
     95         // Sanity check
     96         if (m.isNative() || m.isAbstract() || (code == null)) {
     97             return m;
     98         }
     99 
    100         // Create instruction list to be inserted at method start.
    101         String mesg = "Hello from " + Utility.methodSignatureToString(m.getSignature(),
    102                 name,
    103                 Utility.accessToString(flags));
    104         InstructionList patch = new InstructionList();
    105         patch.append(new GETSTATIC(out));
    106         patch.append(new PUSH(cp, mesg));
    107         patch.append(new INVOKEVIRTUAL(println));
    108 
    109         MethodGen mg = new MethodGen(m, class_name, cp);
    110         InstructionList il = mg.getInstructionList();
    111         InstructionHandle[] ihs = il.getInstructionHandles();
    112 
    113         if (name.equals("<init>")) { // First let the super or other constructor be called
    114             for (int j = 1; j < ihs.length; j++) {
    115                 if (ihs[j].getInstruction() instanceof INVOKESPECIAL) {
    116                     il.append(ihs[j], patch); // Should check: method name == "<init>"
    117                     break;
    118                 }
    119             }
    120         } else {
    121             il.insert(ihs[0], patch);
    122         }
    123 
    124         // Stack size must be at least 2, since the println method takes 2 argument.
    125         if (code.getMaxStack() < 2) {
    126             mg.setMaxStack(2);
    127         }
    128 
    129         m = mg.getMethod();
    130 
    131         il.dispose(); // Reuse instruction handles
    132 
    133         return m;
    134     }
    135 }
    136