org.coldswap.asm.method.MethodCleaner.java Source code

Java tutorial

Introduction

Here is the source code for org.coldswap.asm.method.MethodCleaner.java

Source

package org.coldswap.asm.method;

/**
 * (C) Copyright 2013 Faur Ioan-Aurel.
 * <p/>
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 * <p/>
 * 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.
 * <p/>
 * Created with IntelliJ IDEA.
 * User: faur
 * Date: 6/8/13
 * Time: 7:30 PM
 */

import org.coldswap.asm.MemberReplacer;
import org.coldswap.util.ClassUtil;
import org.coldswap.util.MethodUtil;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;

import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

/**
 * The scope of this class is to remove any method that was not inserted in the helper
 * method so that redefinition will be successful. Please note that code might break during runtime
 * because calls to the removed method will not be fixed.
 */
public class MethodCleaner implements MemberReplacer {
    private static final Logger logger = Logger.getLogger(MethodCleaner.class.getName());
    private int counter = 0;
    private Class<?> aClass;
    private byte[] bytes;

    static {
        logger.setLevel(ClassUtil.logLevel);
    }

    public MethodCleaner(Class<?> aClass, byte[] bytes) {
        this.aClass = aClass;
        this.bytes = bytes;
    }

    @Override
    public byte[] replace() {
        final ClassNode cn = new ClassNode(Opcodes.ASM5);
        ClassReader cr = new ClassReader(bytes);
        ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
        cr.accept(cn, 0);
        // get a list of public/protected/package/private methods but exclude
        // inherited methods.
        Method[] methods = aClass.getDeclaredMethods();
        List asmMethods = cn.methods;
        Iterator iterator = asmMethods.iterator();
        while (iterator.hasNext()) {
            final MethodNode mNode = (MethodNode) iterator.next();
            // exclude <init>() and <clinit>()
            if (!"<clinit>".equals(mNode.name) && !"<init>".equals(mNode.name)) {
                boolean foundIt = false;
                int publicAccessor = Opcodes.ACC_PUBLIC;
                // search only for public methods
                if ((mNode.access == publicAccessor)) {
                    // check if this method exist in the old loaded class
                    // and if not proceed with the trick.
                    Type mRetType = MethodUtil.getReturnType(mNode);
                    Type[] mParamType = MethodUtil.getParamsType(mNode);
                    for (Method method : methods) {
                        if (mNode.name.equals(method.getName())) {
                            Type fRetType = Type.getType(method).getReturnType();
                            if (mRetType.equals(fRetType)) {
                                Type[] fParamType = MethodUtil.classToType(method.getParameterTypes());
                                boolean tmp = true;
                                if (mParamType.length == fParamType.length) {
                                    for (int i = 0; i < mParamType.length; i++) {
                                        if (!mParamType[i].equals(fParamType[i])) {
                                            tmp = false;
                                        }
                                    }
                                }
                                foundIt = tmp;
                            }
                        }
                    }
                    if (!foundIt) {
                        // remove
                        counter++;
                        iterator.remove();
                    }
                }
            }
        }
        // note user about removed methods.
        if (counter > 0) {
            logger.severe(
                    counter + " new methods found and removed. Please consider stopping the application because"
                            + " there might be calls to this methods that would break application state.");
        }
        cn.accept(cw);
        return cw.toByteArray();
    }
}