Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (C) 2011 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 org.snapscript.dx.stock;
import static java.lang.reflect.Modifier.FINAL;
import static java.lang.reflect.Modifier.PUBLIC;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.MessageDigest;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.snapscript.dx.Code;
import org.snapscript.dx.DexMaker;
import org.snapscript.dx.Local;
import org.snapscript.dx.MethodId;
import org.snapscript.dx.TypeId;
/**
* This class is not thread safe.
*/
public final class ProxyAdapterBuilder {
// Version of ProxyBuilder. It should be updated if the implementation
// of the generated proxy class changes.
public static final int VERSION = 1;
/**
* A cache of all proxy classes ever generated. At the time of writing, Android's runtime doesn't
* support class unloading so there's little value in using weak references.
*/
private static final Map, Class>> generatedAccessorClasses = Collections.synchronizedMap(new HashMap, Class>>());
private final Class baseClass;
private ClassLoader parentClassLoader = ProxyBuilder.class.getClassLoader();
private File dexCache;
private ProxyAdapterBuilder(Class clazz) {
baseClass = clazz;
}
public static ProxyAdapterBuilder forClass(Class clazz) {
return new ProxyAdapterBuilder(clazz);
}
/**
* Specifies the parent ClassLoader to use when creating the proxy.
*
*
* If null, {@code ProxyBuilder.class.getClassLoader()} will be used.
*/
public ProxyAdapterBuilder parentClassLoader(ClassLoader parent) {
parentClassLoader = parent;
return this;
}
/**
* Sets the directory where executable code is stored. See {@link DexMaker#generateAndLoad DexMaker.generateAndLoad()}
* for guidance on choosing a secure location for the dex cache.
*/
public ProxyAdapterBuilder dexCache(File dexCacheParent) {
dexCache = new File(dexCacheParent, "v" + Integer.toString(VERSION));
dexCache.mkdir();
return this;
}
// TODO: test coverage for this
public Class buildAccessor(Method method) throws Exception {
Method accessibleMethod = getAccessibleMethod(method);
if(accessibleMethod != null) {
Class accessorClass = generatedAccessorClasses.get(accessibleMethod);
if (accessorClass == null) {
DexMaker dexMaker = new DexMaker();
// the cache missed; generate the class
String generatedName = getNameForAccessorOf(accessibleMethod);
TypeId extends T> generatedType = TypeId.get("L" + generatedName + ";");
TypeId interfaceType = TypeId.get(ProxyAdapter.class);
generateConstructorsForAccessor(dexMaker, generatedType, TypeId.OBJECT); // generate default no arg
generateCodeForAccessor(dexMaker, generatedType, accessibleMethod);
dexMaker.declare(generatedType, generatedName + ".generated", PUBLIC | FINAL, TypeId.OBJECT, interfaceType);
ClassLoader classLoader = dexMaker.generateAndLoad(parentClassLoader, dexCache, generatedName);
try {
accessorClass = loadClass(classLoader, generatedName);
} catch (IllegalAccessError e) {
// Thrown when the base class is not accessible.
throw new UnsupportedOperationException("cannot proxy inaccessible class " + baseClass, e);
} catch (ClassNotFoundException e) {
// Should not be thrown, we're sure to have generated this class.
throw new AssertionError(e);
}
}
return accessorClass;
}
return null;
}
public Class buildAccessor(Constructor constructor) throws Exception {
Constructor accessibleConstructor = getAccessibleConstructor(constructor);
if(accessibleConstructor != null) {
Class accessorClass = generatedAccessorClasses.get(accessibleConstructor);
if (accessorClass == null) {
DexMaker dexMaker = new DexMaker();
// the cache missed; generate the class
String generatedName = getNameForAccessorOf(accessibleConstructor);
TypeId extends T> generatedType = TypeId.get("L" + generatedName + ";");
TypeId interfaceType = TypeId.get(ProxyAdapter.class);
generateConstructorsForAccessor(dexMaker, generatedType, TypeId.OBJECT); // generate default no arg
generateCodeForAccessor(dexMaker, generatedType, accessibleConstructor);
dexMaker.declare(generatedType, generatedName + ".generated", PUBLIC | FINAL, TypeId.OBJECT, interfaceType);
ClassLoader classLoader = dexMaker.generateAndLoad(parentClassLoader, dexCache, generatedName);
try {
accessorClass = loadClass(classLoader, generatedName);
} catch (IllegalAccessError e) {
// Thrown when the base class is not accessible.
throw new UnsupportedOperationException("cannot proxy inaccessible class " + baseClass, e);
} catch (ClassNotFoundException e) {
// Should not be thrown, we're sure to have generated this class.
throw new AssertionError(e);
}
}
return accessorClass;
}
return null;
}
// The type cast is safe: the generated type will extend the base class type.
@SuppressWarnings("unchecked")
private Class extends T> loadClass(ClassLoader classLoader, String generatedName) throws ClassNotFoundException {
return (Class extends T>) classLoader.loadClass(generatedName);
}
private static void generateCodeForAccessor(DexMaker dexMaker, TypeId generatedType, Method accessorMethod) {
int modifiers = accessorMethod.getModifiers();
String name = accessorMethod.getName();
Class declaringClass = accessorMethod.getDeclaringClass();
Class>[] argClasses = accessorMethod.getParameterTypes();
Class> returnClass = accessorMethod.getReturnType();
TypeId