All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mockito.asm.util.ASMifierClassVisitor Maven / Gradle / Ivy

There is a newer version: 2.0.2-beta
Show newest version
/***
 * ASM: a very small and fast Java bytecode manipulation framework
 * Copyright (c) 2000-2007 INRIA, France Telecom
 * 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. Neither the name of the copyright holders nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS 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 COPYRIGHT OWNER OR 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.
 */
package org.mockito.asm.util;

import java.io.FileInputStream;
import java.io.PrintWriter;

import org.mockito.asm.AnnotationVisitor;
import org.mockito.asm.ClassReader;
import org.mockito.asm.ClassVisitor;
import org.mockito.asm.FieldVisitor;
import org.mockito.asm.MethodVisitor;
import org.mockito.asm.Opcodes;

/**
 * A {@link ClassVisitor} that prints the ASM code that generates the classes it
 * visits. This class visitor can be used to quickly write ASM code to generate
 * some given bytecode: 
  • write the Java source code equivalent to the * bytecode you want to generate;
  • compile it with javac;
  • *
  • make a {@link ASMifierClassVisitor} visit this compiled class (see the * {@link #main main} method);
  • edit the generated source code, if * necessary.
The source code printed when visiting the * Hello class is the following:

* *
 * import org.mockito.asm.*;
 *
 * public class HelloDump implements Opcodes {
 *
 *     public static byte[] dump() throws Exception {
 *
 *         ClassWriter cw = new ClassWriter(0);
 *         FieldVisitor fv;
 *         MethodVisitor mv;
 *         AnnotationVisitor av0;
 *
 *         cw.visit(49,
 *                 ACC_PUBLIC + ACC_SUPER,
 *                 "Hello",
 *                 null,
 *                 "java/lang/Object",
 *                 null);
 *
 *         cw.visitSource("Hello.java", null);
 *
 *         {
 *             mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
 *             mv.visitVarInsn(ALOAD, 0);
 *             mv.visitMethodInsn(INVOKESPECIAL,
 *                     "java/lang/Object",
 *                     "<init>",
 *                     "()V");
 *             mv.visitInsn(RETURN);
 *             mv.visitMaxs(1, 1);
 *             mv.visitEnd();
 *         }
 *         {
 *             mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
 *                     "main",
 *                     "([Ljava/lang/String;)V",
 *                     null,
 *                     null);
 *             mv.visitFieldInsn(GETSTATIC,
 *                     "java/lang/System",
 *                     "out",
 *                     "Ljava/io/PrintStream;");
 *             mv.visitLdcInsn("hello");
 *             mv.visitMethodInsn(INVOKEVIRTUAL,
 *                     "java/io/PrintStream",
 *                     "println",
 *                     "(Ljava/lang/String;)V");
 *             mv.visitInsn(RETURN);
 *             mv.visitMaxs(2, 1);
 *             mv.visitEnd();
 *         }
 *         cw.visitEnd();
 *
 *         return cw.toByteArray();
 *     }
 * }
 *
 * 
* *
where Hello is defined by:

* *
 * public class Hello {
 *
 *     public static void main(String[] args) {
 *         System.out.println("hello");
 *     }
 * }
 * 
* *
* * @author Eric Bruneton * @author Eugene Kuleshov */ public class ASMifierClassVisitor extends ASMifierAbstractVisitor implements ClassVisitor { /** * Pseudo access flag used to distinguish class access flags. */ private static final int ACCESS_CLASS = 262144; /** * Pseudo access flag used to distinguish field access flags. */ private static final int ACCESS_FIELD = 524288; /** * Pseudo access flag used to distinguish inner class flags. */ private static final int ACCESS_INNER = 1048576; /** * The print writer to be used to print the class. */ protected final PrintWriter pw; /** * Prints the ASM source code to generate the given class to the standard * output.

Usage: ASMifierClassVisitor [-debug] <fully qualified * class name or class file name> * * @param args the command line arguments. * * @throws Exception if the class cannot be found, or if an IO exception * occurs. */ public static void main(final String[] args) throws Exception { int i = 0; int flags = ClassReader.SKIP_DEBUG; boolean ok = true; if (args.length < 1 || args.length > 2) { ok = false; } if (ok && "-debug".equals(args[0])) { i = 1; flags = 0; if (args.length != 2) { ok = false; } } if (!ok) { System.err.println("Prints the ASM code to generate the given class."); System.err.println("Usage: ASMifierClassVisitor [-debug] " + ""); return; } ClassReader cr; if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 || args[i].indexOf('/') > -1) { cr = new ClassReader(new FileInputStream(args[i])); } else { cr = new ClassReader(args[i]); } cr.accept(new ASMifierClassVisitor(new PrintWriter(System.out)), getDefaultAttributes(), flags); } /** * Constructs a new {@link ASMifierClassVisitor} object. * * @param pw the print writer to be used to print the class. */ public ASMifierClassVisitor(final PrintWriter pw) { super("cw"); this.pw = pw; } // ------------------------------------------------------------------------ // Implementation of the ClassVisitor interface // ------------------------------------------------------------------------ public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { String simpleName; int n = name.lastIndexOf('/'); if (n == -1) { simpleName = name; } else { text.add("package asm." + name.substring(0, n).replace('/', '.') + ";\n"); simpleName = name.substring(n + 1); } text.add("import java.util.*;\n"); text.add("import org.mockito.asm.*;\n"); text.add("import org.mockito.asm.attrs.*;\n"); text.add("public class " + simpleName + "Dump implements Opcodes {\n\n"); text.add("public static byte[] dump () throws Exception {\n\n"); text.add("ClassWriter cw = new ClassWriter(0);\n"); text.add("FieldVisitor fv;\n"); text.add("MethodVisitor mv;\n"); text.add("AnnotationVisitor av0;\n\n"); buf.setLength(0); buf.append("cw.visit("); switch (version) { case Opcodes.V1_1: buf.append("V1_1"); break; case Opcodes.V1_2: buf.append("V1_2"); break; case Opcodes.V1_3: buf.append("V1_3"); break; case Opcodes.V1_4: buf.append("V1_4"); break; case Opcodes.V1_5: buf.append("V1_5"); break; case Opcodes.V1_6: buf.append("V1_6"); break; default: buf.append(version); break; } buf.append(", "); appendAccess(access | ACCESS_CLASS); buf.append(", "); appendConstant(name); buf.append(", "); appendConstant(signature); buf.append(", "); appendConstant(superName); buf.append(", "); if (interfaces != null && interfaces.length > 0) { buf.append("new String[] {"); for (int i = 0; i < interfaces.length; ++i) { buf.append(i == 0 ? " " : ", "); appendConstant(interfaces[i]); } buf.append(" }"); } else { buf.append("null"); } buf.append(");\n\n"); text.add(buf.toString()); } public void visitSource(final String file, final String debug) { buf.setLength(0); buf.append("cw.visitSource("); appendConstant(file); buf.append(", "); appendConstant(debug); buf.append(");\n\n"); text.add(buf.toString()); } public void visitOuterClass( final String owner, final String name, final String desc) { buf.setLength(0); buf.append("cw.visitOuterClass("); appendConstant(owner); buf.append(", "); appendConstant(name); buf.append(", "); appendConstant(desc); buf.append(");\n\n"); text.add(buf.toString()); } public void visitInnerClass( final String name, final String outerName, final String innerName, final int access) { buf.setLength(0); buf.append("cw.visitInnerClass("); appendConstant(name); buf.append(", "); appendConstant(outerName); buf.append(", "); appendConstant(innerName); buf.append(", "); appendAccess(access | ACCESS_INNER); buf.append(");\n\n"); text.add(buf.toString()); } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { buf.setLength(0); buf.append("{\n"); buf.append("fv = cw.visitField("); appendAccess(access | ACCESS_FIELD); buf.append(", "); appendConstant(name); buf.append(", "); appendConstant(desc); buf.append(", "); appendConstant(signature); buf.append(", "); appendConstant(value); buf.append(");\n"); text.add(buf.toString()); ASMifierFieldVisitor aav = new ASMifierFieldVisitor(); text.add(aav.getText()); text.add("}\n"); return aav; } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { buf.setLength(0); buf.append("{\n"); buf.append("mv = cw.visitMethod("); appendAccess(access); buf.append(", "); appendConstant(name); buf.append(", "); appendConstant(desc); buf.append(", "); appendConstant(signature); buf.append(", "); if (exceptions != null && exceptions.length > 0) { buf.append("new String[] {"); for (int i = 0; i < exceptions.length; ++i) { buf.append(i == 0 ? " " : ", "); appendConstant(exceptions[i]); } buf.append(" }"); } else { buf.append("null"); } buf.append(");\n"); text.add(buf.toString()); ASMifierMethodVisitor acv = createASMifierMethodVisitor(); text.add(acv.getText()); text.add("}\n"); return acv; } protected ASMifierMethodVisitor createASMifierMethodVisitor() { return new ASMifierMethodVisitor(); } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { buf.setLength(0); buf.append("{\n"); buf.append("av0 = cw.visitAnnotation("); appendConstant(desc); buf.append(", "); buf.append(visible); buf.append(");\n"); text.add(buf.toString()); ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0); text.add(av.getText()); text.add("}\n"); return av; } public void visitEnd() { text.add("cw.visitEnd();\n\n"); text.add("return cw.toByteArray();\n"); text.add("}\n"); text.add("}\n"); printList(pw, text); pw.flush(); } // ------------------------------------------------------------------------ // Utility methods // ------------------------------------------------------------------------ /** * Appends a string representation of the given access modifiers to {@link * #buf buf}. * * @param access some access modifiers. */ void appendAccess(final int access) { boolean first = true; if ((access & Opcodes.ACC_PUBLIC) != 0) { buf.append("ACC_PUBLIC"); first = false; } if ((access & Opcodes.ACC_PRIVATE) != 0) { buf.append("ACC_PRIVATE"); first = false; } if ((access & Opcodes.ACC_PROTECTED) != 0) { buf.append("ACC_PROTECTED"); first = false; } if ((access & Opcodes.ACC_FINAL) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_FINAL"); first = false; } if ((access & Opcodes.ACC_STATIC) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_STATIC"); first = false; } if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { if (!first) { buf.append(" + "); } if ((access & ACCESS_CLASS) == 0) { buf.append("ACC_SYNCHRONIZED"); } else { buf.append("ACC_SUPER"); } first = false; } if ((access & Opcodes.ACC_VOLATILE) != 0 && (access & ACCESS_FIELD) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_VOLATILE"); first = false; } if ((access & Opcodes.ACC_BRIDGE) != 0 && (access & ACCESS_CLASS) == 0 && (access & ACCESS_FIELD) == 0) { if (!first) { buf.append(" + "); } buf.append("ACC_BRIDGE"); first = false; } if ((access & Opcodes.ACC_VARARGS) != 0 && (access & ACCESS_CLASS) == 0 && (access & ACCESS_FIELD) == 0) { if (!first) { buf.append(" + "); } buf.append("ACC_VARARGS"); first = false; } if ((access & Opcodes.ACC_TRANSIENT) != 0 && (access & ACCESS_FIELD) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_TRANSIENT"); first = false; } if ((access & Opcodes.ACC_NATIVE) != 0 && (access & ACCESS_CLASS) == 0 && (access & ACCESS_FIELD) == 0) { if (!first) { buf.append(" + "); } buf.append("ACC_NATIVE"); first = false; } if ((access & Opcodes.ACC_ENUM) != 0 && ((access & ACCESS_CLASS) != 0 || (access & ACCESS_FIELD) != 0 || (access & ACCESS_INNER) != 0)) { if (!first) { buf.append(" + "); } buf.append("ACC_ENUM"); first = false; } if ((access & Opcodes.ACC_ANNOTATION) != 0 && (access & ACCESS_CLASS) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_ANNOTATION"); first = false; } if ((access & Opcodes.ACC_ABSTRACT) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_ABSTRACT"); first = false; } if ((access & Opcodes.ACC_INTERFACE) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_INTERFACE"); first = false; } if ((access & Opcodes.ACC_STRICT) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_STRICT"); first = false; } if ((access & Opcodes.ACC_SYNTHETIC) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_SYNTHETIC"); first = false; } if ((access & Opcodes.ACC_DEPRECATED) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_DEPRECATED"); first = false; } if (first) { buf.append('0'); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy