lucee.transformer.bytecode.util.MethodCleaner.java Source code

Java tutorial

Introduction

Here is the source code for lucee.transformer.bytecode.util.MethodCleaner.java

Source

/**
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either 
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public 
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 * 
 **/
package lucee.transformer.bytecode.util;

import java.io.IOException;

import lucee.commons.io.IOUtil;
import lucee.commons.io.res.Resource;
import lucee.commons.io.res.util.ResourceUtil;
import lucee.commons.lang.ClassUtil;
import lucee.commons.lang.StringUtil;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.exp.ExpressionException;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

public class MethodCleaner extends ClassVisitor implements Opcodes {

    private final String methodName;
    //private Class[] arguments;
    private String strArgs;
    private Class rtn;
    private String msg;

    MethodCleaner(ClassVisitor cv, String methodName, Class[] args, Class rtn, String msg) {
        super(ASM4, cv);
        this.methodName = methodName;
        //this.arguments = arguments;

        StringBuilder sb = new StringBuilder("(");
        for (int i = 0; i < args.length; i++) {
            sb.append(Type.getDescriptor(args[i]));
        }
        sb.append(")");
        sb.append(Type.getDescriptor(rtn));
        strArgs = sb.toString();
        this.rtn = rtn;
        this.msg = StringUtil.isEmpty(msg) ? null : msg;
    }

    public void visit(int version, int access, String name, String signature, String superName,
            String[] interfaces) {
        cv.visit(version, access, name, signature, superName, interfaces);
    }

    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        if (name.equals(methodName) && desc.equals(strArgs)) {

            MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
            mv.visitCode();

            if (msg == null)
                empty(mv);
            else
                exception(mv);

            mv.visitEnd();
            return mv;
        }
        return super.visitMethod(access, name, desc, signature, exceptions);

    }

    private void exception(MethodVisitor mv) {
        mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
        mv.visitInsn(DUP);
        mv.visitLdcInsn(msg);
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V");
        mv.visitInsn(ATHROW);
        mv.visitMaxs(3, 1);
    }

    private void empty(MethodVisitor mv) {
        // void
        if (rtn == void.class) {
            mv.visitInsn(RETURN);
        }
        // int,boolean,short,char,byte
        else if (rtn == int.class) {
            mv.visitInsn(ICONST_0);
            mv.visitInsn(IRETURN);
            mv.visitMaxs(1, 1);
        }
        // double
        else if (rtn == double.class) {
            mv.visitInsn(DCONST_0);
            mv.visitInsn(DRETURN);
            mv.visitMaxs(2, 1);
        }
        // float
        else if (rtn == float.class) {
            mv.visitInsn(FCONST_0);
            mv.visitInsn(FRETURN);
            mv.visitMaxs(1, 1);
        }
        // long
        else if (rtn == long.class) {
            mv.visitInsn(LCONST_0);
            mv.visitInsn(LRETURN);
            mv.visitMaxs(2, 1);
        }
        // Object
        else {
            mv.visitInsn(ACONST_NULL);
            mv.visitInsn(ARETURN);
            mv.visitMaxs(1, 1);
        }
    }

    public static byte[] modifie(byte[] src, String methodName, Class[] args, Class rtn, String msg) {
        ClassReader cr = new ClassReader(src);
        ClassWriter cw = ASMUtil.getClassWriter();
        ClassVisitor ca = new MethodCleaner(cw, methodName, args, rtn, msg);
        cr.accept(ca, 0);
        return cw.toByteArray();
    }

    public static void modifie(String path, String methodName, String[] argNames, String rtnName, String msg)
            throws IOException, ExpressionException {
        Resource res = ResourceUtil.toResourceExisting(ThreadLocalPageContext.getConfig(), path);
        Class[] args = new Class[argNames.length];
        for (int i = 0; i < argNames.length; i++) {
            args[i] = ClassUtil.loadClass(argNames[i]);
        }
        Class rtn = ClassUtil.loadClass(rtnName);
        byte[] result = modifie(IOUtil.toBytes(res), methodName, args, rtn, msg);
        IOUtil.write(res, result);
    }
}