FileDocCategorySizeDatePackage
ReplaceMethodCallsAdapter.javaAPI DocAndroid 5.1 API8645Thu Mar 12 22:22:44 GMT 2015com.android.tools.layoutlib.create

ReplaceMethodCallsAdapter

public class ReplaceMethodCallsAdapter extends org.objectweb.asm.ClassVisitor
Replaces calls to certain methods that do not exist in the Desktop VM. Useful for methods in the "java" package.

Fields Summary
private static Set
ARRAYCOPY_DESCRIPTORS
Descriptors for specialized versions {@link System#arraycopy} that are not present on the Desktop VM.
private static final List
METHOD_REPLACERS
private static final String
ANDROID_LOCALE_CLASS
private static final String
JAVA_LOCALE_CLASS
private static final org.objectweb.asm.Type
STRING
private static final String
JAVA_LANG_SYSTEM
Constructors Summary
public ReplaceMethodCallsAdapter(org.objectweb.asm.ClassVisitor cv)

        super(Opcodes.ASM4, cv);
    
Methods Summary
public static booleanisReplacementNeeded(java.lang.String owner, java.lang.String name, java.lang.String desc)


    // Static initialization block to initialize METHOD_REPLACERS.
     
        // Case 1: java.lang.System.arraycopy()
        METHOD_REPLACERS.add(new MethodReplacer() {
            @Override
            public boolean isNeeded(String owner, String name, String desc) {
                return JAVA_LANG_SYSTEM.equals(owner) && "arraycopy".equals(name) &&
                        ARRAYCOPY_DESCRIPTORS.contains(desc);
            }

            @Override
            public void replace(MethodInformation mi) {
                assert isNeeded(mi.owner, mi.name, mi.desc);
                mi.desc = "(Ljava/lang/Object;ILjava/lang/Object;II)V";
            }
        });

        // Case 2: java.util.Locale.toLanguageTag() and java.util.Locale.getScript()
        METHOD_REPLACERS.add(new MethodReplacer() {

            private final String LOCALE_TO_STRING =
                    Type.getMethodDescriptor(STRING, Type.getType(Locale.class));

            @Override
            public boolean isNeeded(String owner, String name, String desc) {
                return JAVA_LOCALE_CLASS.equals(owner) && "()Ljava/lang/String;".equals(desc) &&
                        ("toLanguageTag".equals(name) || "getScript".equals(name));
            }

            @Override
            public void replace(MethodInformation mi) {
                assert isNeeded(mi.owner, mi.name, mi.desc);
                mi.opcode = Opcodes.INVOKESTATIC;
                mi.owner = ANDROID_LOCALE_CLASS;
                mi.desc = LOCALE_TO_STRING;
            }
        });

        // Case 3: java.util.Locale.adjustLanguageCode() or java.util.Locale.forLanguageTag()
        METHOD_REPLACERS.add(new MethodReplacer() {

            private final String STRING_TO_STRING = Type.getMethodDescriptor(STRING, STRING);
            private final String STRING_TO_LOCALE = Type.getMethodDescriptor(
                    Type.getType(Locale.class), STRING);

            @Override
            public boolean isNeeded(String owner, String name, String desc) {
                return JAVA_LOCALE_CLASS.equals(owner) &&
                        ("adjustLanguageCode".equals(name) && desc.equals(STRING_TO_STRING) ||
                        "forLanguageTag".equals(name) && desc.equals(STRING_TO_LOCALE));
            }

            @Override
            public void replace(MethodInformation mi) {
                assert isNeeded(mi.owner, mi.name, mi.desc);
                mi.owner = ANDROID_LOCALE_CLASS;
            }
        });

        // Case 4: java.lang.System.log?()
        METHOD_REPLACERS.add(new MethodReplacer() {
            @Override
            public boolean isNeeded(String owner, String name, String desc) {
                return JAVA_LANG_SYSTEM.equals(owner) && name.length() == 4
                        && name.startsWith("log");
            }

            @Override
            public void replace(MethodInformation mi) {
                assert isNeeded(mi.owner, mi.name, mi.desc);
                assert mi.desc.equals("(Ljava/lang/String;Ljava/lang/Throwable;)V")
                        || mi.desc.equals("(Ljava/lang/String;)V");
                mi.name = "log";
                mi.owner = Type.getInternalName(System_Delegate.class);
            }
        });

        // Case 5: java.util.LinkedHashMap.eldest()
        METHOD_REPLACERS.add(new MethodReplacer() {

            private final String VOID_TO_MAP_ENTRY =
                    Type.getMethodDescriptor(Type.getType(Map.Entry.class));
            private final String LINKED_HASH_MAP = Type.getInternalName(LinkedHashMap.class);

            @Override
            public boolean isNeeded(String owner, String name, String desc) {
                return LINKED_HASH_MAP.equals(owner) &&
                        "eldest".equals(name) &&
                        VOID_TO_MAP_ENTRY.equals(desc);
            }

            @Override
            public void replace(MethodInformation mi) {
                assert isNeeded(mi.owner, mi.name, mi.desc);
                mi.opcode = Opcodes.INVOKESTATIC;
                mi.owner = Type.getInternalName(LinkedHashMap_Delegate.class);
                mi.desc = Type.getMethodDescriptor(
                        Type.getType(Map.Entry.class), Type.getType(LinkedHashMap.class));
            }
        });
    
        for (MethodReplacer replacer : METHOD_REPLACERS) {
            if (replacer.isNeeded(owner, name, desc)) {
                return true;
            }
        }
        return false;
    
public org.objectweb.asm.MethodVisitorvisitMethod(int access, java.lang.String name, java.lang.String desc, java.lang.String signature, java.lang.String[] exceptions)

        return new MyMethodVisitor(super.visitMethod(access, name, desc, signature, exceptions));