Inject anonymous inner classes of injected classes [DO NOT MERGE]

When injecting classes in LayoutLib (eg. CreateInfo), so that LayoutLib
can refer back to the changes, also inject the anonymous inner classes.
Without this, the injected classes are not loadable. Although, LayoutLib
itself doesn't load these classes, but some tests do.

Change-Id: Ib5f6b779ef4d79dec8d614d3dbb26eeac88a1064
(cherry picked from commit bfc9c3bcbe)
This commit is contained in:
Deepanshu Gupta
2015-05-20 14:51:37 -07:00
parent d7e89906a4
commit cc5e69e4fe
4 changed files with 32 additions and 11 deletions

View File

@ -24,9 +24,11 @@ import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@ -86,7 +88,23 @@ public class AsmGenerator {
public AsmGenerator(Log log, String osDestJar, ICreateInfo createInfo) {
mLog = log;
mOsDestJar = osDestJar;
mInjectClasses = createInfo.getInjectedClasses();
ArrayList<Class<?>> injectedClasses =
new ArrayList<Class<?>>(Arrays.asList(createInfo.getInjectedClasses()));
// Search for and add anonymous inner classes also.
ListIterator<Class<?>> iter = injectedClasses.listIterator();
while (iter.hasNext()) {
Class<?> clazz = iter.next();
try {
int i = 1;
while(i < 100) {
iter.add(Class.forName(clazz.getName() + "$" + i));
i++;
}
} catch (ClassNotFoundException ignored) {
// Expected.
}
}
mInjectClasses = injectedClasses.toArray(new Class<?>[0]);
mStubMethods = new HashSet<String>(Arrays.asList(createInfo.getOverriddenMethods()));
// Create the map/set of methods to change to delegates
@ -290,13 +308,7 @@ public class AsmGenerator {
* e.g. it returns something like "com/foo/OuterClass$InnerClass1$InnerClass2.class"
*/
private String classToEntryPath(Class<?> clazz) {
String name = "";
Class<?> parent;
while ((parent = clazz.getEnclosingClass()) != null) {
name = "$" + clazz.getSimpleName() + name;
clazz = parent;
}
return classNameToEntryPath(clazz.getCanonicalName() + name);
return classNameToEntryPath(clazz.getName());
}
/**

View File

@ -136,6 +136,8 @@ public final class CreateInfo implements ICreateInfo {
ICreateInfo.class,
CreateInfo.class,
LayoutlibDelegate.class,
InjectMethodRunnable.class,
InjectMethodRunnables.class,
/* Java package classes */
AutoCloseable.class,
Objects.class,
@ -304,4 +306,3 @@ public final class CreateInfo implements ICreateInfo {
InjectMethodRunnables.CONTEXT_GET_FRAMEWORK_CLASS_LOADER);
}};
}

View File

@ -85,6 +85,12 @@ public interface ICreateInfo {
Map<String, InjectMethodRunnable> getInjectedMethodsMap();
abstract class InjectMethodRunnable {
public abstract void generateMethods(ClassVisitor cv);
/**
* @param cv Must be {@link ClassVisitor}. However, the param type is object so that when
* loading the class, ClassVisitor is not loaded. This is because when injecting
* CreateInfo in LayoutLib (see {@link #getInjectedClasses()}, we don't want to inject
* asm classes also, but still keep CreateInfo loadable.
*/
public abstract void generateMethods(Object cv);
}
}

View File

@ -30,7 +30,9 @@ public class InjectMethodRunnables {
public static final ICreateInfo.InjectMethodRunnable CONTEXT_GET_FRAMEWORK_CLASS_LOADER
= new InjectMethodRunnable() {
@Override
public void generateMethods(ClassVisitor cv) {
public void generateMethods(Object classVisitor) {
assert classVisitor instanceof ClassVisitor;
ClassVisitor cv = (ClassVisitor) classVisitor;
// generated by compiling the class:
// class foo { public ClassLoader getFrameworkClassLoader() { return getClass().getClassLoader(); } }
// and then running ASMifier on it: