alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Android example source code file (TransformClassAdapter.java)

This example Android source code file (TransformClassAdapter.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Android by Example" TM.

Java - Android tags/keywords

arrayindexoutofboundsexception, classvisitor, fieldvisitor, keep, log, methodvisitor, object, override, set, string, stubmethodadapter, transformclassadapter, type, util

The TransformClassAdapter.java Android example source code

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * 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 com.android.tools.layoutlib.create;

import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

import java.util.Set;

/**
 * Class adapter that can stub some or all of the methods of the class. 
 */
class TransformClassAdapter extends ClassAdapter {

    /** True if all methods should be stubbed, false if only native ones must be stubbed. */
    private final boolean mStubAll;
    /** True if the class is an interface. */
    private boolean mIsInterface;
    private final String mClassName;
    private final Log mLog;
    private final Set<String> mStubMethods;
    private Set<String> mDeleteReturns;

    /**
     * Creates a new class adapter that will stub some or all methods.
     * @param logger 
     * @param stubMethods 
     * @param deleteReturns list of types that trigger the deletion of methods returning them.
     * @param className The name of the class being modified
     * @param cv The parent class writer visitor
     * @param stubNativesOnly True if only native methods should be stubbed. False if all 
     *                        methods should be stubbed.
     * @param hasNative True if the method has natives, in which case its access should be
     *                  changed.
     */
    public TransformClassAdapter(Log logger, Set<String> stubMethods,
            Set<String> deleteReturns, String className, ClassVisitor cv,
            boolean stubNativesOnly, boolean hasNative) {
        super(cv);
        mLog = logger;
        mStubMethods = stubMethods;
        mClassName = className;
        mStubAll = !stubNativesOnly;
        mIsInterface = false;
        mDeleteReturns = deleteReturns;
    }

    /* Visits the class header. */
    @Override
    public void visit(int version, int access, String name,
            String signature, String superName, String[] interfaces) {
        
        // This class might be being renamed.
        name = mClassName;
        
        // remove protected or private and set as public
        access = access & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED);
        access |= Opcodes.ACC_PUBLIC;
        // remove final
        access = access & ~Opcodes.ACC_FINAL;
        // note: leave abstract classes as such
        // don't try to implement stub for interfaces

        mIsInterface = ((access & Opcodes.ACC_INTERFACE) != 0);
        super.visit(version, access, name, signature, superName, interfaces);
    }
    
    /* Visits the header of an inner class. */
    @Override
    public void visitInnerClass(String name, String outerName, String innerName, int access) {
        // remove protected or private and set as public
        access = access & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED);
        access |= Opcodes.ACC_PUBLIC;
        // remove final
        access = access & ~Opcodes.ACC_FINAL;
        // note: leave abstract classes as such
        // don't try to implement stub for interfaces

        super.visitInnerClass(name, outerName, innerName, access);
    }

    /* Visits a method. */
    @Override
    public MethodVisitor visitMethod(int access, String name, String desc,
            String signature, String[] exceptions) {
        
        if (mDeleteReturns != null) {
            Type t = Type.getReturnType(desc);
            if (t.getSort() == Type.OBJECT) {
                String returnType = t.getInternalName();
                if (returnType != null) {
                    if (mDeleteReturns.contains(returnType)) {
                        return null;
                    }
                }
            }
        }

        String methodSignature = mClassName.replace('/', '.') + "#" + name;

        // change access to public
        access &= ~(Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE);
        access |= Opcodes.ACC_PUBLIC;

        // remove final
        access = access & ~Opcodes.ACC_FINAL;

        // stub this method if they are all to be stubbed or if it is a native method
        // and don't try to stub interfaces nor abstract non-native methods.
        if (!mIsInterface &&
            ((access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE)) != Opcodes.ACC_ABSTRACT) &&
            (mStubAll ||
             (access & Opcodes.ACC_NATIVE) != 0) ||
             mStubMethods.contains(methodSignature)) {
            
            boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
            boolean isNative = (access & Opcodes.ACC_NATIVE) != 0;

            // remove abstract, final and native
            access = access & ~(Opcodes.ACC_ABSTRACT | Opcodes.ACC_FINAL | Opcodes.ACC_NATIVE);
            
            String invokeSignature = methodSignature + desc;
            mLog.debug("  Stub: %s (%s)", invokeSignature, isNative ? "native" : "");
            
            MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions);
            return new StubMethodAdapter(mw, name, returnType(desc), invokeSignature,
                    isStatic, isNative);

        } else {
            mLog.debug("  Keep: %s %s", name, desc);
            return super.visitMethod(access, name, desc, signature, exceptions);
        }
    }
    
    /* Visits a field. Makes it public. */
    @Override
    public FieldVisitor visitField(int access, String name, String desc, String signature,
            Object value) {
        // change access to public
        access &= ~(Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE);
        access |= Opcodes.ACC_PUBLIC;
        
        return super.visitField(access, name, desc, signature, value);
    }

    /**
     * Extracts the return {@link Type} of this descriptor.
     */
    Type returnType(String desc) {
        if (desc != null) {
            try {
                return Type.getReturnType(desc);
            } catch (ArrayIndexOutOfBoundsException e) {
                // ignore, not a valid type.
            }
        }
        return null;
    }
}

Other Android examples (source code examples)

Here is a short list of links related to this Android TransformClassAdapter.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.