1
1
package org .apache .ibatis .executor .loader ;
2
2
3
+ import java .io .NotSerializableException ;
4
+ import java .io .ObjectStreamException ;
5
+ import java .io .Serializable ;
6
+ import java .lang .reflect .Field ;
7
+ import java .lang .reflect .Method ;
8
+ import java .util .Arrays ;
9
+ import java .util .HashSet ;
10
+ import java .util .Set ;
11
+
12
+ import net .sf .cglib .core .Signature ;
3
13
import net .sf .cglib .proxy .Enhancer ;
14
+ import net .sf .cglib .proxy .InterfaceMaker ;
4
15
import net .sf .cglib .proxy .MethodInterceptor ;
5
16
import net .sf .cglib .proxy .MethodProxy ;
17
+
18
+ import org .apache .ibatis .logging .Log ;
19
+ import org .apache .ibatis .logging .LogFactory ;
6
20
import org .apache .ibatis .reflection .ExceptionUtil ;
21
+ import org .apache .ibatis .reflection .factory .ObjectFactory ;
7
22
import org .apache .ibatis .reflection .property .PropertyNamer ;
8
23
import org .apache .ibatis .type .TypeHandlerRegistry ;
9
-
10
- import java .io .Serializable ;
11
- import java .lang .reflect .Method ;
12
- import java .lang .reflect .Field ;
13
- import java .util .*;
24
+ import org .objectweb .asm .Type ;
14
25
15
26
public class ResultObjectProxy {
16
27
28
+ private static final Log log = LogFactory .getLog (ResultObjectProxy .class );
29
+
17
30
private static final Set <String > objectMethods = new HashSet <String >(Arrays .asList (new String []{"equals" ,"clone" ,"hashCode" ,"toString" }));
18
31
private static final TypeHandlerRegistry registry = new TypeHandlerRegistry ();
19
32
private static final String FINALIZE_METHOD = "finalize" ;
33
+ private static final String WRITE_REPLACE_METHOD = "writeReplace" ;
20
34
21
- public static Object createProxy (Object target , ResultLoaderMap lazyLoader , boolean aggressive ) {
22
- return EnhancedResultObjectProxyImpl .createProxy (target , lazyLoader , aggressive );
35
+ public static Object createProxy (Object target , ResultLoaderMap lazyLoader , boolean aggressive , ObjectFactory objectFactory ) {
36
+ return EnhancedResultObjectProxyImpl .createProxy (target , lazyLoader , aggressive , objectFactory );
23
37
}
24
38
25
39
private static class EnhancedResultObjectProxyImpl implements MethodInterceptor , Serializable {
26
40
41
+ private static final long serialVersionUID = 3943261828110652464L ;
42
+ private Class type ;
27
43
private ResultLoaderMap lazyLoader ;
28
44
private boolean aggressive ;
45
+ private ObjectFactory objectFactory ;
29
46
30
- private EnhancedResultObjectProxyImpl (ResultLoaderMap lazyLoader , boolean aggressive ) {
47
+ private EnhancedResultObjectProxyImpl (Class type , ResultLoaderMap lazyLoader , boolean aggressive , ObjectFactory objectFactory ) {
48
+ this .type = type ;
31
49
this .lazyLoader = lazyLoader ;
32
50
this .aggressive = aggressive ;
51
+ this .objectFactory = objectFactory ;
33
52
}
34
53
35
- public static Object createProxy (Object target , ResultLoaderMap lazyLoader , boolean aggressive ) {
54
+ public static Object createProxy (Object target , ResultLoaderMap lazyLoader , boolean aggressive , ObjectFactory objectFactory ) {
36
55
final Class type = target .getClass ();
37
56
if (registry .hasTypeHandler (type )) {
38
57
return target ;
39
58
} else {
40
- final Object enhanced = Enhancer .create (type , new EnhancedResultObjectProxyImpl (lazyLoader , aggressive ));
41
- copyInitialState (type , target , enhanced );
59
+ EnhancedResultObjectProxyImpl proxy = new EnhancedResultObjectProxyImpl (type , lazyLoader , aggressive , objectFactory );
60
+ Enhancer enhancer = new Enhancer ();
61
+ enhancer .setCallback (proxy );
62
+ enhancer .setSuperclass (type );
63
+
64
+ try {
65
+ type .getDeclaredMethod (WRITE_REPLACE_METHOD );
66
+ // ObjectOutputStream will call writeReplace of objects returned by writeReplace
67
+ log .warn (WRITE_REPLACE_METHOD + " method was found on bean " + type + ", make sure it returns this" );
68
+ } catch (NoSuchMethodException e ) {
69
+ // using asm (org.objectweb.asm.Type), this will not work with cglib-nodep
70
+ InterfaceMaker writeReplaceInterface = new InterfaceMaker ();
71
+ Signature signature = new Signature (WRITE_REPLACE_METHOD , Type .getType (Object .class ), new Type [] {});
72
+ writeReplaceInterface .add (signature , new Type [] { Type .getType (ObjectStreamException .class ) });
73
+ enhancer .setInterfaces (new Class [] { writeReplaceInterface .create () });
74
+ } catch (SecurityException e ) {
75
+ // nothing to do here
76
+ }
77
+
78
+ final Object enhanced = enhancer .create ();
79
+ copyBeanProperties (type , target , enhanced );
42
80
return enhanced ;
43
81
}
44
82
}
45
-
83
+
46
84
public Object intercept (Object o , Method method , Object [] args , MethodProxy methodProxy ) throws Throwable {
85
+ final String methodName = method .getName ();
47
86
try {
48
- final String methodName = method .getName ();
49
87
synchronized (lazyLoader ) {
50
- if (lazyLoader .size () > 0 ) {
51
- if (!FINALIZE_METHOD .equals (methodName )) {
88
+ if (WRITE_REPLACE_METHOD .equals (methodName )) {
89
+ if (lazyLoader .size () > 0 ) {
90
+ throw new NotSerializableException ("Not all lazy properties have been loaded yet" );
91
+ }
92
+ Object original = objectFactory .create (type );
93
+ copyBeanProperties (type , o , original );
94
+ return original ;
95
+ } else if (!FINALIZE_METHOD .equals (methodName )) {
96
+ if (lazyLoader .size () > 0 ) {
52
97
if (aggressive || objectMethods .contains (methodName )) {
53
98
lazyLoader .loadAll ();
54
99
} else if (PropertyNamer .isProperty (methodName )) {
@@ -66,22 +111,22 @@ public Object intercept(Object o, Method method, Object[] args, MethodProxy meth
66
111
}
67
112
}
68
113
69
- private static void copyInitialState (Class type , Object target , Object enhanced ) {
114
+ private static void copyBeanProperties (Class type , Object sourceBean , Object destinationBean ) {
70
115
Class parent = type ;
71
116
while (parent != null ) {
72
117
final Field [] fields = parent .getDeclaredFields ();
73
118
for (Field field : fields ) {
74
119
try {
75
120
field .setAccessible (true );
76
- field .set (enhanced ,field .get (target ));
121
+ Object val = field .get (sourceBean );
122
+ field .set (destinationBean , val );
77
123
} catch (Exception e ) {
78
124
// Nothing useful to do, will only fail on final fields, which will be ignored.
79
125
}
80
126
}
81
127
parent = parent .getSuperclass ();
82
128
}
83
129
}
84
-
85
130
}
86
131
87
132
}
0 commit comments