Created
February 22, 2011 16:47
-
-
Save vvakame/838957 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.vvakame.delegatefactory.sample.hide; | |
/* @hide */ | |
public class Bridge { | |
public Bridge() { | |
} | |
/* @hide */ | |
static Data2 combine(Data1 data) { | |
return Data2.getInstance(data.getData()); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2011 [email protected] | |
* | |
* 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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.vvakame.delegatefactory.sample.delegate; | |
public interface IData1 { | |
void setData(String data); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.vvakame.delegatefactory.sample.delegate; | |
public interface IData2 { | |
String getData(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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