org.yx.asm.AsmUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.yx.asm.AsmUtils.java

Source

/**
 * Copyright (C) 2016 - 2017 youtongluan.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.yx.asm;

import static org.objectweb.asm.Opcodes.ACC_PUBLIC;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.yx.common.MethodInfo;
import org.yx.rpc.server.intf.ActionContext;

public final class AsmUtils {

    private static String[] blanks = new String[] { "getClass", "wait", "equals", "notify", "notifyAll", "toString",
            "hashCode" };

    private static Map<String, Class<?>> clzMap;
    private static Map<Class<?>, Method> loaderDefinds = new HashMap<>();

    public static String proxyCalssName(Class<?> clz) {
        String name = clz.getName();
        int index = name.lastIndexOf(".");
        return name.substring(0, index) + ".sumkbox" + name.substring(index);
    }

    private static ClassLoader loader() {
        ClassLoader load = Thread.currentThread().getContextClassLoader();
        if (load != null) {
            return load;
        }
        return AsmUtils.class.getClassLoader();
    }

    public static InputStream openStreamForClass(String name) {
        String internalName = name.replace('.', '/') + ".class";
        return loader().getResourceAsStream(internalName);
    }

    /**
     * 
     * @param method
     * @return true
     */
    public static boolean isFilted(String method) {
        for (String m : blanks) {
            if (m.equals(method)) {
                return true;
            }
        }
        return false;
    }

    /**
     * typesclazzes?
     * 
     * @param types
     * @param clazzes
     * @return
     */
    public static boolean sameType(Type[] types, Class<?>[] clazzes) {

        if (types.length != clazzes.length) {
            return false;
        }

        for (int i = 0; i < types.length; i++) {
            if (!Type.getType(clazzes[i]).equals(types[i])) {
                return false;
            }
        }
        return true;
    }

    /**
     * ???null
     * 
     * @param clzName
     * @param methodName
     * @param p
     * @return
     * @throws Exception
     */
    public static Class<?> CreateArgPojo(String clzName, MethodInfo p) throws Exception {
        String fullName = clzName + "_" + p.getMethod().getName();
        if (p.getArgNames() == null || p.getArgNames().length == 0) {
            return null;
        }

        ClassWriter cw = new ClassWriter(0);
        cw.visit(Vars.JVM_VERSION, ACC_PUBLIC, fullName.replace('.', '/'), null, "java/lang/Object", null);
        Class<?>[] argTypes = p.getMethod().getParameterTypes();
        int argCount = 0;
        for (int i = 0; i < p.getArgNames().length; i++) {
            if (ActionContext.class.isInstance(argTypes[i])) {
                continue;
            }
            argCount++;
            String arg = p.getArgNames()[i];
            String desc = p.getDescs()[i];
            cw.visitField(ACC_PUBLIC, arg, desc, p.getSignatures()[i], null).visitEnd();
        }
        cw.visitEnd();
        if (argCount == 0) {
            return null;
        }
        byte[] b = cw.toByteArray();

        return loadClass(fullName, b);

    }

    public static MethodInfo createMethodInfo(String classFullName, Method m) throws IOException {
        ClassReader cr = new ClassReader(openStreamForClass(classFullName));
        MethodInfoClassVisitor cv = new MethodInfoClassVisitor(m);
        cr.accept(cv, 0);
        return new MethodInfo(m, cv.argNames.toArray(new String[0]), cv.descriptor,
                cv.signatures.toArray(new String[0]));
    }

    public static Method getMethod(Class<?> clz, String methodName, Class<?>[] paramTypes) {
        while (clz != Object.class) {
            Method[] ms = clz.getDeclaredMethods();
            for (Method m : ms) {
                if (!m.getName().equals(methodName)) {
                    continue;
                }
                Class<?>[] paramTypes2 = m.getParameterTypes();
                if (!Arrays.equals(paramTypes2, paramTypes)) {
                    continue;
                }
                return m;
            }
            clz = clz.getSuperclass();
        }
        return null;
    }

    public static Class<?> loadClass(String fullName, byte[] b) throws Exception {
        if (clzMap == null) {
            clzMap = new ConcurrentHashMap<>();
        }
        Class<?> clz = clzMap.get(fullName);
        if (clz != null) {
            return clz;
        }
        synchronized (AsmUtils.class) {
            clz = clzMap.get(fullName);
            if (clz != null) {
                return clz;
            }
            Class<?> loaderClz = loader().getClass();
            Method defineClass = loaderDefinds.get(loaderClz);
            if (defineClass == null) {
                defineClass = getMethod(loaderClz, "defineClass",
                        new Class<?>[] { String.class, byte[].class, int.class, int.class });
                defineClass.setAccessible(true);
                loaderDefinds.put(loaderClz, defineClass);
            }
            clz = (Class<?>) defineClass.invoke(loader(), fullName, b, 0, b.length);
            if (clz == null) {
                throw new Exception("cannot load class " + fullName);
            }
            clzMap.put(fullName, clz);
            return clz;
        }
    }

    public static final int BADMODIFIERS = Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | Modifier.PRIVATE;

    /**
     * true?public<br>
     * ??final?public
     * 
     * @param modifiers
     * @return
     */
    public static boolean notPublicOnly(int modifiers) {
        return (modifiers & Modifier.PUBLIC) == 0 || (modifiers & BADMODIFIERS) != 0;
    }

    public static boolean canProxy(int modifiers) {
        return (modifiers & BADMODIFIERS) == 0;
    }

    public static List<Object> getImplicitFrame(String desc) {
        List<Object> locals = new ArrayList<>();
        if (desc.isEmpty()) {
            return locals;
        }
        int i = 0;
        while (desc.length() > i) {
            int j = i;
            switch (desc.charAt(i++)) {
            case 'Z':
            case 'C':
            case 'B':
            case 'S':
            case 'I':
                locals.add(Opcodes.INTEGER);
                break;
            case 'F':
                locals.add(Opcodes.FLOAT);
                break;
            case 'J':
                locals.add(Opcodes.LONG);
                break;
            case 'D':
                locals.add(Opcodes.DOUBLE);
                break;
            case '[':
                while (desc.charAt(i) == '[') {
                    ++i;
                }
                if (desc.charAt(i) == 'L') {
                    ++i;
                    while (desc.charAt(i) != ';') {
                        ++i;
                    }
                }
                locals.add(desc.substring(j, ++i));
                break;
            case 'L':
                while (desc.charAt(i) != ';') {
                    ++i;
                }
                locals.add(desc.substring(j + 1, i++));
                break;
            default:
                break;
            }
        }

        return locals;
    }

    /**
     * ??
     * 
     * @param method
     *            
     * @param proxyedClass
     *            ??
     * @return
     */
    public static Method proxyMethod(Method method, Class<?> proxyedClass) {
        Class<?> clz = method.getDeclaringClass();
        if (clz == proxyedClass) {
            return method;
        }
        String methodName = method.getName();
        Class<?>[] argTypes = method.getParameterTypes();
        Method[] proxyedMethods = proxyedClass.getDeclaredMethods();
        for (Method proxyedMethod : proxyedMethods) {
            if (proxyedMethod.getName().equals(methodName)
                    && Arrays.equals(argTypes, proxyedMethod.getParameterTypes())) {
                return proxyedMethod;
            }
        }
        return method;
    }

}