1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package it.openutils.spring.rmibernate.server.aspects;
18
19 import it.openutils.spring.rmibernate.server.aspects.util.EntitySerializer;
20 import it.openutils.spring.rmibernate.shared.LazyReference;
21 import it.openutils.spring.rmibernate.shared.managers.HibernateLazyService;
22
23 import java.lang.reflect.Field;
24 import java.lang.reflect.Method;
25 import java.lang.reflect.Modifier;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.HashSet;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34
35 import net.sf.cglib.proxy.Callback;
36 import net.sf.cglib.proxy.CallbackFilter;
37 import net.sf.cglib.proxy.Enhancer;
38 import net.sf.cglib.proxy.Factory;
39 import net.sf.cglib.proxy.MethodInterceptor;
40 import net.sf.cglib.proxy.MethodProxy;
41 import net.sf.cglib.proxy.NoOp;
42
43 import org.apache.commons.collections.CollectionUtils;
44 import org.apache.commons.collections.ListUtils;
45 import org.apache.commons.collections.MapUtils;
46 import org.apache.commons.collections.SetUtils;
47 import org.apache.commons.collections.Transformer;
48 import org.apache.commons.lang.builder.HashCodeBuilder;
49 import org.hibernate.EntityMode;
50 import org.hibernate.SessionFactory;
51 import org.hibernate.collection.PersistentCollection;
52 import org.hibernate.proxy.HibernateProxy;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55 import org.springframework.util.ReflectionUtils;
56
57
58
59
60
61
62
63 public class SerializationInterceptor implements MethodInterceptor
64 {
65
66 private static ThreadLocal<List<Object>> processed = new ThreadLocal<List<Object>>();
67
68 private static ThreadLocal<HibernateLazyService> hibernateLazyService = new ThreadLocal<HibernateLazyService>();
69
70 @SuppressWarnings("unchecked")
71 private static Map<Class, Object> proxies = Collections.synchronizedMap(new HashMap<Class, Object>());
72
73
74
75
76 private static Logger log = LoggerFactory.getLogger(SerializationInterceptor.class);
77
78
79
80
81 private Object original;
82
83
84
85
86 private SessionFactory sessionFactory;
87
88
89
90
91
92
93 private SerializationInterceptor(Object o, SessionFactory sessionFactory)
94 {
95 this.original = o;
96 this.sessionFactory = sessionFactory;
97 }
98
99
100
101
102 public static void clean()
103 {
104 processed.set(null);
105 }
106
107
108
109
110
111
112
113 public static Object getEnhancedObject(Object o, SessionFactory sessionFactory)
114 {
115 return getEnhancedObject(o, sessionFactory, null);
116 }
117
118
119
120
121
122
123
124
125 @SuppressWarnings("unchecked")
126 public static Object getEnhancedObject(Object o, SessionFactory sessionFactory, LazyReference lazyRef)
127 {
128 if (o == null)
129 {
130 return null;
131 }
132
133 if (!(o instanceof HibernateProxy)
134 && !(o instanceof PersistentCollection)
135 && processed.get() != null
136 && processed.get().contains(o))
137 {
138 return o;
139 }
140
141 if (o.getClass().getName().startsWith("java.") && !((o instanceof Collection) || (o instanceof Map)))
142 {
143 return o;
144 }
145
146
147 try
148 {
149 o.getClass().getConstructor(new Class[]{});
150 }
151 catch (NoSuchMethodException ex)
152 {
153 return o;
154 }
155
156
157 if (Modifier.isFinal(o.getClass().getModifiers()))
158 {
159 return o;
160 }
161
162 try
163 {
164
165 Class clazz = o.getClass();
166
167
168 if (o instanceof HibernateProxy)
169 {
170 clazz = o.getClass().getSuperclass();
171 if (clazz == null)
172 {
173 clazz = o.getClass().getInterfaces()[0];
174 }
175 }
176
177 Callback callback = null;
178
179
180 if (lazyRef != null)
181 {
182 LazyReferenceAspect lra = new LazyReferenceAspect();
183 lra.setLazyReference(lazyRef);
184 callback = lra;
185 }
186 else
187 {
188
189 callback = new SerializationInterceptor(o, sessionFactory);
190 }
191
192 synchronized (proxies)
193 {
194 if (proxies.containsKey(clazz))
195 {
196 Factory proxy = (Factory) proxies.get(clazz);
197 return proxy.newInstance(new Callback[]{callback, NoOp.INSTANCE });
198 }
199 }
200
201 Object proxy = Enhancer.create(clazz, new Class[]{EntitySerializer.class }, new CallbackFilter()
202 {
203
204 public int accept(Method method)
205 {
206 if (method.getName().equals("writeReplace"))
207 {
208 return 0;
209 }
210 if (method.getName().equals("hashCode"))
211 {
212 return 0;
213 }
214 else
215 {
216 return 1;
217 }
218 }
219
220 }, new Callback[]{callback, NoOp.INSTANCE });
221
222
223 proxies.put(clazz, ((Factory) proxy).newInstance(new Callback[]{
224 EmptyMethodInterceptor.INSTANCE,
225 NoOp.INSTANCE }));
226 return proxy;
227 }
228 catch (Throwable t)
229 {
230 log.warn(t.getMessage(), t);
231 return o;
232 }
233 }
234
235
236
237
238 @SuppressWarnings("unchecked")
239 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable
240 {
241 if (method.getName().equals("hashCode"))
242 {
243 return hashCode();
244 }
245 try
246 {
247 if (original == null)
248 {
249 return null;
250 }
251
252 if (original.getClass().getName().startsWith("java.")
253 && !((original instanceof Collection) || (original instanceof Map)))
254 {
255 return original;
256 }
257
258 if (processed.get() == null)
259 {
260 processed.set(new ArrayList<Object>());
261 }
262
263
264 processed.get().add(original);
265
266 if (original.getClass().isPrimitive())
267 {
268 log.debug("Non enhancing primitive type: {}", original.getClass().getName());
269 return original;
270 }
271 else if (original.getClass().isArray())
272 {
273
274 Object[] array = (Object[]) original;
275 for (int i = 0; i < array.length; i++)
276 {
277 array[i] = SerializationInterceptor.getEnhancedObject(array[i], sessionFactory);
278 }
279 return array;
280 }
281 else if (original instanceof Set)
282 {
283
284 Set set = (Set) original;
285 Set transformed = SetUtils.transformedSet(new HashSet(), transformer(sessionFactory));
286 transformed.addAll(set);
287 Set result = new HashSet();
288 result.addAll(transformed);
289 return result;
290 }
291 else if (original instanceof List)
292 {
293 List list = (List) original;
294 List transformed = ListUtils.transformedList(new ArrayList(), transformer(sessionFactory));
295 transformed.addAll(list);
296 List result = new ArrayList();
297 result.addAll(transformed);
298 return result;
299 }
300 else if (original instanceof Collection)
301 {
302
303 Collection collection = (Collection) original;
304 CollectionUtils.transform(collection, transformer(sessionFactory));
305 return collection;
306 }
307 else if (original instanceof Map)
308 {
309
310 Map map = (Map) original;
311 Map transformed = MapUtils.transformedMap(
312 new HashMap(),
313 transformer(sessionFactory),
314 transformer(sessionFactory));
315
316
317
318 if (map.size() > 0)
319 {
320 transformed.putAll(map);
321 }
322 Map result = new HashMap();
323 result.putAll(transformed);
324 return result;
325 }
326 else
327 {
328
329 ReflectionUtils.doWithFields(original.getClass(), new ReflectionUtils.FieldCallback()
330 {
331
332
333
334
335 public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException
336 {
337
338 field.setAccessible(true);
339
340
341 Object oldValue = field.get(original);
342
343
344 Object newValue = null;
345
346 if (oldValue instanceof HibernateProxy || oldValue instanceof PersistentCollection)
347 {
348
349 LazyReference lazyRef = new LazyReference();
350 lazyRef.setFieldClassName(field.getType().getName());
351 lazyRef.setClassName(original.getClass().getName());
352 lazyRef.setFieldName(field.getName());
353
354 lazyRef.setId(sessionFactory.getClassMetadata(original.getClass()).getIdentifier(
355 original,
356 EntityMode.POJO));
357
358
359 newValue = SerializationInterceptor.getEnhancedObject(oldValue, sessionFactory, lazyRef);
360 }
361 else
362 {
363
364 newValue = SerializationInterceptor.getEnhancedObject(oldValue, sessionFactory);
365 }
366
367
368 if (newValue != oldValue)
369 {
370 field.set(original, newValue);
371 }
372 }
373
374 });
375 }
376
377 return original;
378
379 }
380 catch (Throwable t)
381 {
382 log.error(t.getMessage(), t);
383 return original;
384 }
385 }
386
387
388
389
390
391
392 private Transformer transformer(SessionFactory factory)
393 {
394 return new Transformer()
395 {
396
397 public Object transform(Object input)
398 {
399 return SerializationInterceptor.getEnhancedObject(input, sessionFactory);
400 }
401
402 };
403 }
404
405
406
407
408
409 public static void setHibernateLazyService(HibernateLazyService hibernateLazyService)
410 {
411 SerializationInterceptor.hibernateLazyService.set(hibernateLazyService);
412 }
413
414
415
416
417
418 public static HibernateLazyService getHibernateLazyService()
419 {
420 return hibernateLazyService.get();
421 }
422
423
424
425
426 @Override
427 public int hashCode()
428 {
429 return new HashCodeBuilder(-469032761, 855711273)
430 .appendSuper(super.hashCode())
431 .append(this.original)
432 .toHashCode();
433 }
434
435 }