1 package com.atlassian.plugins.rest.module.util;
2
3 import com.atlassian.plugins.rest.module.ChainingClassLoader;
4 import com.google.common.base.Function;
5 import com.google.common.collect.MapMaker;
6 import net.sf.cglib.proxy.Callback;
7 import net.sf.cglib.proxy.Enhancer;
8 import net.sf.cglib.proxy.Factory;
9
10 import java.lang.reflect.Constructor;
11 import java.lang.reflect.InvocationHandler;
12 import java.lang.reflect.Method;
13 import java.lang.reflect.Modifier;
14 import java.lang.reflect.Proxy;
15 import java.util.Map;
16
17
18
19
20 public class ProxyUtils
21 {
22 private static Map<Class<?>, ConstructorAndArgs> generatorCache = new MapMaker().weakKeys().makeComputingMap(new Function<Class<?>, ConstructorAndArgs>()
23 {
24 public ConstructorAndArgs apply(Class<?> from)
25 {
26 return new ConstructorAndArgs(from);
27 }
28 });
29
30 public static <T> T create(Class<T> clazz, Callback callback)
31 {
32 return (T) generatorCache.get(clazz).create(callback);
33 }
34 }
35
36
37
38
39
40 class ConstructorAndArgs
41 {
42 private Class<?> clazz;
43 private Object prototype;
44 private Object[] args;
45 private Constructor<?> constructor;
46
47 ConstructorAndArgs(Class<?> clazz)
48 {
49 this.clazz = clazz;
50 initialise();
51 }
52
53 private void initialise()
54 {
55 Enhancer enhancer = new Enhancer();
56 enhancer.setSuperclass(clazz);
57 enhancer.setCallback(new UnsupportedOperationInvocationHandler());
58 enhancer.setClassLoader(new ChainingClassLoader(ProxyUtils.class.getClassLoader(), clazz.getClassLoader()));
59
60 Constructor<?>[] constructors = clazz.getConstructors();
61
62 for (Constructor constructor : constructors)
63 {
64 if ((constructor.getModifiers() & Modifier.PUBLIC) != 0)
65 {
66 this.constructor = constructor;
67
68 int size = constructor.getParameterTypes().length;
69 args = new Object[size];
70
71 for (int i = 0; i < args.length; i++)
72 args[i] = createEmptyValue(constructor.getParameterTypes()[i]);
73
74 prototype = clazz.cast(enhancer.create(constructor.getParameterTypes(), args));
75 return;
76 }
77 }
78
79 throw new IllegalArgumentException("Class has no accessible constructor");
80 }
81
82
83 private static Object createEmptyValue(Class aClass)
84 {
85
86 if (aClass.isInterface())
87 return stubInterface(aClass);
88 else if (aClass == Long.TYPE)
89 return 0L;
90 else
91 return null;
92 }
93
94 private static Object stubInterface(Class _interface)
95 {
96 return Proxy.newProxyInstance(_interface.getClassLoader(), new Class[]{_interface}, UnsupportedOperationInvocationHandler.INSTANCE);
97 }
98
99 public Object create(Callback... callback)
100 {
101 return clazz.cast(((Factory) prototype).newInstance(constructor.getParameterTypes(), args, callback));
102 }
103 }
104
105 class UnsupportedOperationInvocationHandler implements InvocationHandler, net.sf.cglib.proxy.InvocationHandler
106 {
107 public static UnsupportedOperationInvocationHandler INSTANCE = new UnsupportedOperationInvocationHandler();
108
109 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
110 {
111 throw new UnsupportedOperationException();
112 }
113 }