Skip to content

Instantly share code, notes, and snippets.

@granoeste
Forked from vvakame/Bridge.java
Created March 19, 2012 17:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save granoeste/2119690 to your computer and use it in GitHub Desktop.
Save granoeste/2119690 to your computer and use it in GitHub Desktop.
package net.vvakame.delegatefactory.sample.hide;
/* @hide */
public class Bridge {
public Bridge() {
}
/* @hide */
static Data2 combine(Data1 data) {
return Data2.getInstance(data.getData());
}
}
package net.vvakame.delegatefactory.sample.hide;
/* @hide */
class Data1 {
private String data = "unknown";
/* @hide */
String getData() {
return data;
}
/* @hide */
void setData(String data) {
this.data = data;
}
}
package net.vvakame.delegatefactory.sample.hide;
/* @hide */
class Data2 {
private String data = null;
/* @hide */
static Data2 getInstance(String obj) {
Data2 data2 = new Data2();
data2.data = "i know " + obj + ".";
return data2;
}
/* @hide */
String getData() {
return data;
}
}
/*
* Copyright 2011 esmasui@gmail.com
*
* 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.undrdevelopment.android.util;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public abstract class DelegateFactory {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface DeclaredIn {
String value();
}
private static final class InvocationHandlerImpl implements InvocationHandler {
final Object mDelegate;
final Class<?> mClass;
final Map<Method, Method> mMethodCache;
final Map<Method, Object> mNegativeCache;
private final static Object UNRESOLVED = new Object();
InvocationHandlerImpl(Class<?> receiver, Class<?> delegateClass, Object delegateInstance) {
mDelegate = delegateInstance;
mClass = delegateClass;
mMethodCache = new ConcurrentHashMap<Method, Method>();
mNegativeCache = new ConcurrentHashMap<Method, Object>();
}
public final Object invoke(Object target, Method method, Object[] args) throws Throwable {
Method delegateMethod = getMethodFromCache(method);
if (!hasDelegateMethod(delegateMethod)) {
return unresolved(method.getReturnType());
}
Object receiver = null;
boolean staticMethod = isMethodStatic(delegateMethod);
if (!staticMethod) {
receiver = mDelegate;
}
boolean invoke = canInvoke(staticMethod, receiver);
if (!invoke) {
return null;
}
Object res = delegateMethod.invoke(receiver, args);
return res;
}
private Object unresolved(Class<?> returnType) {
if(!returnType.isPrimitive())
return null;
if(returnType.equals(Boolean.TYPE))
return false;
if(returnType.equals(Byte.TYPE))
return (byte)0;
if(returnType.equals(Short.TYPE))
return (short)0;
if(returnType.equals(Integer.TYPE))
return 0;
if(returnType.equals(Long.TYPE))
return 0L;
if(returnType.equals(Float.TYPE))
return 0F;
if(returnType.equals(Double.TYPE))
return 0D;
return null;
}
private Method getMethodFromCache(Method method) throws SecurityException {
Method delegate = mMethodCache.get(method);
if (delegate != null)
return delegate;
if (mNegativeCache.containsKey(method)) {
return null;
}
delegate = getDelegateMethod(method, mClass);
if (delegate == null) {
mNegativeCache.put(method, UNRESOLVED);
return null;
}
makeAccessible(delegate);
mMethodCache.put(method, delegate);
return delegate;
}
}
static final boolean canInvoke(boolean staticMethod, Object receiver) {
if (staticMethod) {
return true;
}
boolean b = receiver != null;
return b;
}
static final <T> T create(Class<T> type, Class<?> delegateClass, Object delegateInstance) {
if (type == null) {
throw new IllegalArgumentException("type must not be null");
}
if (delegateClass == null) {
throw new IllegalArgumentException("delegateClass must not be null");
}
InvocationHandler handler = new InvocationHandlerImpl(type, delegateClass, delegateInstance);
ClassLoader classLoader = type.getClassLoader();
Class<?>[] types = new Class[] { type };
Object proxy = Proxy.newProxyInstance(classLoader, types, handler);
T t = type.cast(proxy);
return t;
}
public static final <T> T create(Class<T> type, Object delegate) {
if (delegate == null) {
throw new IllegalArgumentException("delegate must not be null");
}
T t = create(type, delegate.getClass(), delegate);
return t;
}
public static final <T> T create(Class<T> type, String delegateClassName, Object delegate) throws ClassNotFoundException {
if (delegateClassName == null) {
throw new IllegalArgumentException("delegateClassName must not be null");
}
ClassLoader classLoader = type.getClassLoader();
Class<?> delegateClass = classLoader.loadClass(delegateClassName);
T t = create(type, delegateClass, delegate);
return t;
}
static final Method getDeclaredMethod(Class<?> type, String name, Class<?>[] params) {
for (Class<?> c = type; c != null; c = c.getSuperclass()) {
Method[] methods = c.getDeclaredMethods();
Method m = getMostMatchMethod(name, params, methods);
boolean b = m != null;
if (b) {
return m;
}
}
return null;
}
static final Method getDelegateMethod(Method method, Class<?> clazz) throws SecurityException {
String name = method.getName();
Class<?>[] params = method.getParameterTypes();
Method delegateMethod;
try {
delegateMethod = clazz.getMethod(name, params);
return delegateMethod;
} catch (NoSuchMethodException e) {
}
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
for (int i = 0, num = parameterAnnotations.length; i < num; ++i) {
Annotation[] annotations = parameterAnnotations[i];
if (annotations.length <= 0)
continue;
Annotation annon = annotations[i];
Class<?> annonType = annon.annotationType();
if (!DeclaredIn.class.equals(annonType))
continue;
DeclaredIn t = (DeclaredIn) annon;
try {
Class<?> type = DelegateFactory.class.getClassLoader().loadClass(t.value());
params[i] = type;
continue;
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
delegateMethod = getDeclaredMethod(clazz, name, params);
return delegateMethod;
}
static final Method getMostMatchMethod(String name, Class<?>[] params, Method[] methods) {
for (Method m : methods) {
boolean b = isSignatureMatches(m, name, params);
if (b) {
return m;
}
}
return null;
}
static final boolean hasDelegateMethod(Method m) {
return m != null;
}
static final boolean isMethodStatic(Method m) {
int modifiers = m.getModifiers();
boolean b = Modifier.isStatic(modifiers);
return b;
}
static final boolean isSignatureMatches(Method m, String name, Class<?>[] params) {
boolean b;
String n = m.getName();
b = n.equals(name);
if (!b) {
return false;
}
Class<?>[] delegateParams = m.getParameterTypes();
b = isParameterMatches(params, delegateParams);
return b;
}
static final boolean isParameterMatches(Class<?>[] params, Class<?>[] delegateParams) {
if (Arrays.equals(params, delegateParams))
return true;
return false;
}
static final void makeAccessible(Method m) {
if (m == null) {
return;
}
if (m.isAccessible()) {
return;
}
m.setAccessible(true);
}
}
package net.vvakame.delegatefactory.sample.delegate;
import com.undrdevelopment.android.util.DelegateFactory.DeclaredIn;
public interface IBridge {
Object combine(
@DeclaredIn("net.vvakame.delegatefactory.sample.hide.Data1") Object data);
}
package net.vvakame.delegatefactory.sample.delegate;
public interface IData1 {
void setData(String data);
}
package net.vvakame.delegatefactory.sample.delegate;
public interface IData2 {
String getData();
}
package net.vvakame.delegatefactory.sample.hide;
public class Main1 {
// sample
public static void main(String[] args) {
System.out.println("@hide");
Data1 data1 = new Data1();
data1.setData("android");
Data2 data2 = Bridge.combine(data1);
String result = data2.getData();
System.out.println(result);
}
}
package net.vvakame.delegatefactory.sample.delegate;
import net.vvakame.delegatefactory.sample.hide.Helper;
import com.undrdevelopment.android.util.DelegateFactory;
public class Main2 {
// sample
public static void main(String[] args) throws ClassNotFoundException {
System.out.println("hide destroyer");
Object data1 = Helper.getDataInstance();
IData1 iData1 = DelegateFactory.create(IData1.class, data1);
iData1.setData("android");
IBridge iBridge = DelegateFactory.create(IBridge.class,
"net.vvakame.delegatefactory.sample.hide.Bridge", null);
Object data2 = iBridge.combine(data1);
IData2 iData2 = DelegateFactory.create(IData2.class, data2);
String result = iData2.getData();
System.out.println(result);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment