1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.executor.loader;
17
18 import java.lang.reflect.Method;
19 import java.util.List;
20 import java.util.Locale;
21 import java.util.Map;
22 import java.util.concurrent.locks.ReentrantLock;
23
24 import org.apache.ibatis.executor.ExecutorException;
25 import org.apache.ibatis.reflection.ExceptionUtil;
26 import org.apache.ibatis.reflection.factory.ObjectFactory;
27 import org.apache.ibatis.reflection.property.PropertyCopier;
28 import org.apache.ibatis.reflection.property.PropertyNamer;
29
30
31
32
33 public abstract class AbstractEnhancedDeserializationProxy {
34
35 protected static final String FINALIZE_METHOD = "finalize";
36 protected static final String WRITE_REPLACE_METHOD = "writeReplace";
37 private final Class<?> type;
38 private final Map<String, ResultLoaderMap.LoadPair> unloadedProperties;
39 private final ObjectFactory objectFactory;
40 private final List<Class<?>> constructorArgTypes;
41 private final List<Object> constructorArgs;
42 private final ReentrantLock lock = new ReentrantLock();
43 private boolean reloadingProperty;
44
45 protected AbstractEnhancedDeserializationProxy(Class<?> type,
46 Map<String, ResultLoaderMap.LoadPair> unloadedProperties, ObjectFactory objectFactory,
47 List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
48 this.type = type;
49 this.unloadedProperties = unloadedProperties;
50 this.objectFactory = objectFactory;
51 this.constructorArgTypes = constructorArgTypes;
52 this.constructorArgs = constructorArgs;
53 this.reloadingProperty = false;
54 }
55
56 public final Object invoke(Object enhanced, Method method, Object[] args) throws Throwable {
57 final String methodName = method.getName();
58 try {
59 if (WRITE_REPLACE_METHOD.equals(methodName)) {
60 final Object original;
61 if (constructorArgTypes.isEmpty()) {
62 original = objectFactory.create(type);
63 } else {
64 original = objectFactory.create(type, constructorArgTypes, constructorArgs);
65 }
66
67 PropertyCopier.copyBeanProperties(type, enhanced, original);
68 return this.newSerialStateHolder(original, unloadedProperties, objectFactory, constructorArgTypes,
69 constructorArgs);
70 }
71 lock.lock();
72 try {
73 if (!FINALIZE_METHOD.equals(methodName) && PropertyNamer.isProperty(methodName) && !reloadingProperty) {
74 final String property = PropertyNamer.methodToProperty(methodName);
75 final String propertyKey = property.toUpperCase(Locale.ENGLISH);
76 if (unloadedProperties.containsKey(propertyKey)) {
77 final ResultLoaderMap.LoadPair loadPair = unloadedProperties.remove(propertyKey);
78 if (loadPair != null) {
79 try {
80 reloadingProperty = true;
81 loadPair.load(enhanced);
82 } finally {
83 reloadingProperty = false;
84 }
85 } else {
86
87
88
89
90 throw new ExecutorException("An attempt has been made to read a not loaded lazy property '" + property
91 + "' of a disconnected object");
92 }
93 }
94 }
95
96 return enhanced;
97 } finally {
98 lock.unlock();
99 }
100 } catch (Throwable t) {
101 throw ExceptionUtil.unwrapThrowable(t);
102 }
103 }
104
105 protected abstract AbstractSerialStateHolder newSerialStateHolder(Object userBean,
106 Map<String, ResultLoaderMap.LoadPair> unloadedProperties, ObjectFactory objectFactory,
107 List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
108
109 }