pxb.android.dex2jar.v3.V3MethodAdapter.java Source code

Java tutorial

Introduction

Here is the source code for pxb.android.dex2jar.v3.V3MethodAdapter.java

Source

/*
 * Copyright (c) 2009-2010 Panxiaobo
 * 
 * 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 pxb.android.dex2jar.v3;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.MethodNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import pxb.android.dex2jar.Method;
import pxb.android.dex2jar.optimize.B;
import pxb.android.dex2jar.optimize.C;
import pxb.android.dex2jar.optimize.LdcOptimizeAdapter;
import pxb.android.dex2jar.optimize.MethodTransformer;
import pxb.android.dex2jar.v3.Ann.Item;
import pxb.android.dex2jar.visitors.DexAnnotationAble;
import pxb.android.dex2jar.visitors.DexCodeVisitor;
import pxb.android.dex2jar.visitors.DexMethodVisitor;

/**
 * @author Panxiaobo [pxb1988@126.com]
 * @version $Id$
 */
public class V3MethodAdapter implements DexMethodVisitor, Opcodes {
    final protected List<Ann> anns = new ArrayList<Ann>();
    final protected ClassVisitor cv;
    final protected Method method;
    final protected List<Ann>[] paramAnns;
    final protected MethodNode methodNode = new MethodNode();
    private static final Logger log = LoggerFactory.getLogger(V3MethodAdapter.class);

    static {
        log.debug("InsnList.check=false");
        // Optmize Tree Analyzer
        InsnList.check = false;
    }

    /**
     * @param cv
     * @param method
     */
    @SuppressWarnings("unchecked")
    public V3MethodAdapter(ClassVisitor cv, Method method) {
        super();
        this.cv = cv;
        this.method = method;
        List<Ann>[] paramAnns = new List[method.getType().getParameterTypes().length];
        for (int i = 0; i < paramAnns.length; i++) {
            paramAnns[i] = new ArrayList<Ann>();
        }
        this.paramAnns = paramAnns;
        methodNode.tryCatchBlocks = new ArrayList<Object>();
    }

    private void build() {
        List<String> exceptions = new ArrayList<String>();
        String signature = null;
        for (Iterator<Ann> it = anns.iterator(); it.hasNext();) {
            Ann ann = it.next();
            if ("Ldalvik/annotation/Throws;".equals(ann.type)) {
                it.remove();
                for (Item item : ann.items) {
                    if (item.name.equals("value")) {
                        Ann values = (Ann) item.value;
                        for (Item i : values.items) {
                            exceptions.add(i.value.toString());
                        }
                    }
                }
            } else if ("Ldalvik/annotation/Signature;".equals(ann.type)) {
                it.remove();
                for (Item item : ann.items) {
                    if (item.name.equals("value")) {
                        Ann values = (Ann) item.value;
                        StringBuilder sb = new StringBuilder();
                        for (Item i : values.items) {
                            sb.append(i.value.toString());
                        }
                        signature = sb.toString();
                    }
                }
            }
        }

        MethodNode methodNode = this.methodNode;
        methodNode.access = method.getAccessFlags();
        methodNode.name = method.getName();
        methodNode.desc = method.getType().getDesc();
        methodNode.signature = signature;
        methodNode.exceptions = exceptions;
        for (Ann ann : anns) {
            AnnotationVisitor av = methodNode.visitAnnotation(ann.type, ann.visible);
            V3AnnAdapter.accept(ann.items, av);
            av.visitEnd();
        }

        for (int i = 0; i < paramAnns.length; i++) {
            for (Ann ann : paramAnns[i]) {
                AnnotationVisitor av = methodNode.visitParameterAnnotation(i, ann.type, ann.visible);
                V3AnnAdapter.accept(ann.items, av);
                av.visitEnd();
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexMethodVisitor#visitAnnotation(java.lang .String, boolean)
     */
    public AnnotationVisitor visitAnnotation(String name, boolean visitable) {
        Ann ann = new Ann(name, visitable);
        anns.add(ann);
        return new V3AnnAdapter(ann);
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexMethodVisitor#visitCode()
     */
    public DexCodeVisitor visitCode() {
        return new V3CodeAdapter(methodNode);
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexMethodVisitor#visitEnd()
     */
    @SuppressWarnings("unchecked")
    public void visitEnd() {
        build();
        MethodNode methodNode = this.methodNode;

        try {
            if (methodNode.instructions.size() > 2) {
                List<? extends MethodTransformer> trs = Arrays.asList(new B(), new C(method));
                for (MethodTransformer tr : trs) {
                    // TraceMethodVisitor tmv = new TraceMethodVisitor();
                    // methodNode.instructions.accept(tmv);
                    // StringBuilder sb=new StringBuilder();
                    // int i=0;
                    // for(Object o:tmv.text){
                    // sb.append(i++).append(o);
                    // }
                    // System.out.println(sb);
                    tr.transform(methodNode);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("Error transform method:" + this.method, e);
        }

        MethodVisitor mv = cv.visitMethod(methodNode.access, methodNode.name, methodNode.desc, methodNode.signature,
                (String[]) methodNode.exceptions.toArray(new String[methodNode.exceptions.size()]));
        if (mv != null) {
            try {
                methodNode.accept(new LdcOptimizeAdapter(mv));
            } catch (Exception e) {
                throw new RuntimeException("Error visit method:" + this.method, e);
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexMethodVisitor#visitParamesterAnnotation (int)
     */
    public DexAnnotationAble visitParamesterAnnotation(int index) {
        final List<Ann> panns = paramAnns[index];
        return new DexAnnotationAble() {
            public AnnotationVisitor visitAnnotation(String name, boolean visitable) {
                Ann ann = new Ann(name, visitable);
                panns.add(ann);
                return new V3AnnAdapter(ann);
            }
        };
    }

}