1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.reflexiveframework.proxy;
25
26 import java.lang.reflect.Method;
27 import java.util.HashMap;
28 import java.util.LinkedList;
29 import java.util.List;
30
31
32
33 import net.sf.cglib.proxy.Enhancer;
34 import net.sf.cglib.proxy.MethodInterceptor;
35 import net.sf.cglib.proxy.MethodProxy;
36
37 /***
38 * Reflexive provides a clean way to handle string literals,
39 * by dynamically resolving properties.
40 *
41 * Create a control object by invoking <code>create</code>.
42 * Only use with control objects. Usage with normal objects is unsupported.
43 *
44 * @author Andries Inze
45 *
46 */
47 public class Reflexive implements MethodInterceptor {
48
49 /***
50 * The instance of the singleton.
51 * Making this an on-access loading, since double checked locking is broken.
52 */
53 private static Reflexive instance = new Reflexive();
54
55 /*** Handles the mapping between method and the proxy object. */
56 private HashMap methodToObject;
57
58 /***
59 * The method name that was invoke.
60 */
61 private List previousMethods;
62
63 /***
64 * The cglib enchancer
65 */
66 private Enhancer e;
67
68 private Reflexive() {
69 previousMethods = new LinkedList();
70 e = new Enhancer();
71 methodToObject = new HashMap();
72 }
73
74 private Object newInstance(Class clazz) {
75 try {
76 e.setSuperclass(clazz);
77 e.setCallback(this);
78 Object bean = Enhancer.create(clazz, getInstance());
79 return bean;
80 } catch (Throwable e) {
81 throw new Error(e.getMessage());
82 }
83 }
84
85 /***
86 * Creates a new control object.
87 *
88 * @param clazz
89 * @return
90 */
91 public static Object create(final Class clazz) {
92 return getInstance().newInstance(clazz);
93 }
94
95 /***
96 * @return the instance of the singleton
97 */
98 private final static Reflexive getInstance() {
99 return instance;
100 }
101
102 /***
103 * Resolves the property from the method that was invoked. Usage:
104 * <code>Reflexive.resolvePropertyName(myObject.getMyProperty())</code>
105 * This would return <code>myProperty</code>
106 *
107 * Only get- and is-methods are supported.
108 *
109 * @param object
110 * The returned object after invoking the created reflexive
111 * object
112 * @return the resolved propertyName
113 */
114 public static String resolvePropertyName(final Object object) {
115 List previousMethods = getInstance().previousMethods;
116
117 String propertyName =
118 ReflexiveUtils.convertMethodNameToPropertyName(
119 ((Method)previousMethods.get(previousMethods.size()-1))
120 .getName());
121
122 previousMethods.clear();
123
124 return ReflexiveUtils.makeNestedPath(propertyName);
125 }
126
127 /***
128 * @param number the number to process
129 * @see resolvePropertyName(Object)
130 * @return the resolved propertyName
131 */
132 public static String resolvePropertyName(final long number) {
133 return resolvePropertyName(null);
134 }
135
136 /***
137 * @param number the number to process
138 * @see resolvePropertyName(Object)
139 * @return the resolved propertyName
140 */
141 public static String resolvePropertyName(final double number) {
142 return resolvePropertyName(null);
143 }
144
145 /***
146 * @param number the number to process
147 * @see resolvePropertyName(Object)
148 * @return the resolved propertyName
149 */
150 public static String resolvePropertyName(final boolean number) {
151 return resolvePropertyName(null);
152 }
153
154 /***
155 * Resolves the property from the method that was invoked. Usage:
156 * <code>Reflexive.resolveNestedPropertyName(myObject.getMyProperty().myNestedProperty())</code>
157 * This would return <code>myProperty.myNestedProperty</code>
158 *
159 * Only get- and is-methods are supported.
160 *
161 * @param object
162 * The returned object after invoking the created reflexive
163 * object
164 * @return the resolved propertyName
165 */
166 public static String resolveNestedPropertyName(final Object object) {
167
168 List previousMethods = getInstance().previousMethods;
169
170 String[] propertyNames = new String[previousMethods.size()];
171
172 for (int i = 0; i < previousMethods.size(); i++) {
173 propertyNames[i] = ReflexiveUtils
174 .convertMethodNameToPropertyName(
175 ((Method) previousMethods.get(i)).getName());
176 }
177
178 previousMethods.clear();
179
180 return ReflexiveUtils.makeNestedPath(propertyNames);
181
182 }
183
184 /***
185 * @see resolveNestedPropertyName(Object)
186 * @param value the returned value after the invocation
187 * @return the nested propertyPath
188 */
189 public static String resolveNestedPropertyName(final long value) {
190 return resolveNestedPropertyName(null);
191 }
192
193 /***
194 * @see resolveNestedPropertyName(Object)
195 * @param value the returned value after the invocation
196 * @return the nested propertyPath
197 */
198 public static String resolveNestedPropertyName(final double value) {
199 return resolveNestedPropertyName(null);
200 }
201
202 /***
203 * @see resolveNestedPropertyName(Object)
204 * @param value the returned value after the invocation
205 * @return the nested propertyPath
206 */
207 public static String resolveNestedPropertyName(final boolean value) {
208 return resolveNestedPropertyName(null);
209 }
210
211 /***
212 * @see net.sf.cglib.proxy.MethodInterceptor #intercept(java.lang.Object,
213 * java.lang.reflect.Method, java.lang.Object[],
214 * net.sf.cglib.proxy.MethodProxy)
215 */
216 public Object intercept(final Object object, final Method method,
217 final Object[] args, final MethodProxy methodProxy)
218 throws Throwable {
219
220 if (method.getName().equals("hashCode")) {
221 return Integer.valueOf(method.getReturnType().hashCode());
222 } else if(method.getName().equals("equals")) {
223 return Boolean.FALSE;
224 }
225
226 if (!method.getName().startsWith("get")
227 && !method.getName().startsWith("is")) {
228 throw new RuntimeException("Only getters (or issers) are supported");
229 }
230
231 if (method.getReturnType().equals(Void.TYPE)) {
232 throw new RuntimeException("Can't use proxy in void return types");
233 }
234
235 previousMethods.add(method);
236
237 if (method.getReturnType().equals(int.class)
238 || method.getReturnType().equals(boolean.class)
239 || method.getReturnType().equals(short.class)
240 || method.getReturnType().equals(double.class)
241 || method.getReturnType().equals(char.class)
242 || method.getReturnType().equals(long.class)
243 || method.getReturnType().equals(float.class)
244 || method.getReturnType().equals(byte.class)) {
245
246 return null;
247 } else {
248
249 if (!methodToObject.containsKey(method)) {
250 methodToObject.put(method, buildMethodReturnProxy(method));
251 }
252 return methodToObject.get(method);
253 }
254 }
255
256 private Object buildMethodReturnProxy(final Method method) {
257 Object proxy = null;
258
259 if (method.getReturnType().equals(String.class)) {
260 proxy = ReflexiveUtils.createRandomString();
261 } else if (method.getReturnType().equals(Boolean.class)) {
262 proxy = new Boolean(true);
263 } else if (method.getReturnType().equals(Integer.class)) {
264 proxy = new Integer(1000);
265 } else if (method.getReturnType().equals(Double.class)) {
266 proxy = new Double(1000.0);
267 } else if (method.getReturnType().equals(Long.class)) {
268 proxy = new Long(1000L);
269 } else if (method.getReturnType().equals(Float.class)) {
270 proxy = new Float(1000L);
271 } else if (method.getReturnType().equals(Character.class)) {
272 proxy = new Character('x');
273 } else if (method.getReturnType().equals(Short.class)) {
274 proxy = new Short((short) 1);
275 } else if (method.getReturnType().equals(Byte.class)) {
276 proxy = new Byte((byte) 1);
277 } else {
278
279
280 e.setSuperclass(method.getReturnType());
281 e.setCallback(this);
282 Object bean = Enhancer
283 .create(method.getReturnType(), getInstance());
284 return bean;
285 }
286 return proxy;
287 }
288 }