Skip to content

Commit cafd10c

Browse files
committed
Fix for http://code.google.com/p/mybatis/issues/detail?id=11 and http://code.google.com/p/mybatis/issues/detail?id=145 . Cglib proxies for beans with no default constructors. Cglib upgraded from 2.1.3 to 2.2.
1 parent 9a853f6 commit cafd10c

File tree

13 files changed

+407
-86
lines changed

13 files changed

+407
-86
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@
227227
<dependency>
228228
<groupId>cglib</groupId>
229229
<artifactId>cglib</artifactId>
230-
<version>2.1_3</version>
230+
<version>2.2</version>
231231
<optional>true</optional>
232232
</dependency>
233233
<!-- Test dependencies -->

src/main/java/org/apache/ibatis/executor/loader/DeserializedObjectProxy.java

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import java.io.ObjectStreamException;
44
import java.lang.reflect.Method;
5-
import java.util.HashSet;
5+
import java.util.List;
66
import java.util.Locale;
77
import java.util.Set;
88

@@ -13,8 +13,6 @@
1313
import net.sf.cglib.proxy.MethodProxy;
1414

1515
import org.apache.ibatis.executor.ExecutorException;
16-
import org.apache.ibatis.logging.Log;
17-
import org.apache.ibatis.logging.LogFactory;
1816
import org.apache.ibatis.reflection.ExceptionUtil;
1917
import org.apache.ibatis.reflection.factory.ObjectFactory;
2018
import org.apache.ibatis.reflection.property.PropertyCopier;
@@ -23,33 +21,37 @@
2321

2422
public class DeserializedObjectProxy {
2523

26-
private static final Log log = LogFactory.getLog(DeserializedObjectProxy.class);
27-
2824
private static final String FINALIZE_METHOD = "finalize";
2925
private static final String WRITE_REPLACE_METHOD = "writeReplace";
3026

31-
public static Object createProxy(Object target, String[] unloadedProperties, ObjectFactory objectFactory) {
32-
return DeserializationProxyImpl.createProxy(target, unloadedProperties, objectFactory);
27+
public static Object createProxy(Object target, Set<String> unloadedProperties, ObjectFactory objectFactory,
28+
List<Class> constructorArgTypes, List<Object> constructorArgs) {
29+
return DeserializationProxyImpl.createProxy(target, unloadedProperties, objectFactory, constructorArgTypes,
30+
constructorArgs);
3331
}
3432

3533
private static class DeserializationProxyImpl implements MethodInterceptor {
3634

3735
private Class type;
3836
private Set<String> unloadedProperties;
3937
private ObjectFactory objectFactory;
38+
private List<Class> constructorArgTypes;
39+
private List<Object> constructorArgs;
4040

41-
private DeserializationProxyImpl(Class type, String[] unloadedProperties, ObjectFactory objectFactory) {
41+
private DeserializationProxyImpl(Class type, Set<String> unloadedProperties, ObjectFactory objectFactory,
42+
List<Class> constructorArgTypes, List<Object> constructorArgs) {
4243
this.type = type;
43-
this.unloadedProperties = new HashSet<String>();
44-
for (String s : unloadedProperties) {
45-
this.unloadedProperties.add(s);
46-
}
44+
this.unloadedProperties = unloadedProperties;
4745
this.objectFactory = objectFactory;
46+
this.constructorArgTypes = constructorArgTypes;
47+
this.constructorArgs = constructorArgs;
4848
}
4949

50-
public static Object createProxy(Object target, String[] unloadedProperties, ObjectFactory objectFactory) {
50+
public static Object createProxy(Object target, Set<String> unloadedProperties, ObjectFactory objectFactory,
51+
List<Class> constructorArgTypes, List<Object> constructorArgs) {
5152
final Class type = target.getClass();
52-
DeserializationProxyImpl proxy = new DeserializationProxyImpl(type, unloadedProperties, objectFactory);
53+
DeserializationProxyImpl proxy = new DeserializationProxyImpl(type, unloadedProperties, objectFactory,
54+
constructorArgTypes, constructorArgs);
5355
Enhancer enhancer = new Enhancer();
5456
enhancer.setCallback(proxy);
5557
enhancer.setSuperclass(type);
@@ -66,28 +68,41 @@ public static Object createProxy(Object target, String[] unloadedProperties, Obj
6668
// nothing to do here
6769
}
6870

69-
final Object enhanced = enhancer.create();
71+
Object enhanced = null;
72+
if (constructorArgTypes.isEmpty()) {
73+
enhanced = enhancer.create();
74+
} else {
75+
Class[] typesArray = constructorArgTypes.toArray(new Class[constructorArgTypes.size()]);
76+
Object[] valuesArray = constructorArgs.toArray(new Object[constructorArgs.size()]);
77+
enhanced = enhancer.create(typesArray, valuesArray);
78+
}
7079
PropertyCopier.copyBeanProperties(type, target, enhanced);
7180
return enhanced;
7281
}
73-
82+
7483
public Object intercept(Object enhanced, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
7584
final String methodName = method.getName();
7685
try {
7786
if (WRITE_REPLACE_METHOD.equals(methodName)) {
78-
Object original = objectFactory.create(type);
87+
Object original = null;
88+
if (constructorArgTypes.isEmpty()) {
89+
original = objectFactory.create(type);
90+
} else {
91+
original = objectFactory.create(type, constructorArgTypes, constructorArgs);
92+
}
7993
PropertyCopier.copyBeanProperties(type, enhanced, original);
80-
return new SerialStatusHolder(original, unloadedProperties.toArray(new String[unloadedProperties.size()]), objectFactory);
94+
return new SerialStateHolder(original, unloadedProperties, objectFactory, constructorArgTypes,
95+
constructorArgs);
8196
} else {
8297
if (!FINALIZE_METHOD.equals(methodName) && PropertyNamer.isProperty(methodName)) {
8398
final String property = PropertyNamer.methodToProperty(methodName);
8499
if (unloadedProperties.contains(property.toUpperCase(Locale.ENGLISH))) {
85-
throw new ExecutorException("An attempt has been made to read a not loaded lazy property '"
86-
+ property + "' of a disconnected object");
100+
throw new ExecutorException("An attempt has been made to read a not loaded lazy property '" + property
101+
+ "' of a disconnected object");
87102
}
88103
}
89104
return methodProxy.invokeSuper(enhanced, args);
90-
}
105+
}
91106
} catch (Throwable t) {
92107
throw ExceptionUtil.unwrapThrowable(t);
93108
}

src/main/java/org/apache/ibatis/executor/loader/ResultObjectProxy.java

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.lang.reflect.Method;
55
import java.util.Arrays;
66
import java.util.HashSet;
7+
import java.util.List;
78
import java.util.Set;
89

910
import net.sf.cglib.core.Signature;
@@ -25,13 +26,15 @@ public class ResultObjectProxy {
2526

2627
private static final Log log = LogFactory.getLog(ResultObjectProxy.class);
2728

28-
private static final Set<String> objectMethods = new HashSet<String>(Arrays.asList(new String[]{"equals","clone","hashCode","toString"}));
29+
private static final Set<String> objectMethods = new HashSet<String>(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));
2930
private static final TypeHandlerRegistry registry = new TypeHandlerRegistry();
3031
private static final String FINALIZE_METHOD = "finalize";
3132
private static final String WRITE_REPLACE_METHOD = "writeReplace";
3233

33-
public static Object createProxy(Object target, ResultLoaderMap lazyLoader, boolean aggressive, ObjectFactory objectFactory) {
34-
return EnhancedResultObjectProxyImpl.createProxy(target, lazyLoader, aggressive, objectFactory);
34+
public static Object createProxy(Object target, ResultLoaderMap lazyLoader, boolean aggressive,
35+
ObjectFactory objectFactory, List<Class> constructorArgTypes, List<Object> constructorArgs) {
36+
return EnhancedResultObjectProxyImpl.createProxy(target, lazyLoader, aggressive, objectFactory,
37+
constructorArgTypes, constructorArgs);
3538
}
3639

3740
private static class EnhancedResultObjectProxyImpl implements MethodInterceptor {
@@ -40,20 +43,27 @@ private static class EnhancedResultObjectProxyImpl implements MethodInterceptor
4043
private ResultLoaderMap lazyLoader;
4144
private boolean aggressive;
4245
private ObjectFactory objectFactory;
46+
private List<Class> constructorArgTypes;
47+
private List<Object> constructorArgs;
4348

44-
private EnhancedResultObjectProxyImpl(Class type, ResultLoaderMap lazyLoader, boolean aggressive, ObjectFactory objectFactory) {
49+
private EnhancedResultObjectProxyImpl(Class type, ResultLoaderMap lazyLoader, boolean aggressive,
50+
ObjectFactory objectFactory, List<Class> constructorArgTypes, List<Object> constructorArgs) {
4551
this.type = type;
4652
this.lazyLoader = lazyLoader;
4753
this.aggressive = aggressive;
4854
this.objectFactory = objectFactory;
55+
this.constructorArgTypes = constructorArgTypes;
56+
this.constructorArgs = constructorArgs;
4957
}
5058

51-
public static Object createProxy(Object target, ResultLoaderMap lazyLoader, boolean aggressive, ObjectFactory objectFactory) {
59+
public static Object createProxy(Object target, ResultLoaderMap lazyLoader, boolean aggressive,
60+
ObjectFactory objectFactory, List<Class> constructorArgTypes, List<Object> constructorArgs) {
5261
final Class type = target.getClass();
5362
if (registry.hasTypeHandler(type)) {
5463
return target;
5564
} else {
56-
EnhancedResultObjectProxyImpl proxy = new EnhancedResultObjectProxyImpl(type, lazyLoader, aggressive, objectFactory);
65+
EnhancedResultObjectProxyImpl proxy = new EnhancedResultObjectProxyImpl(type, lazyLoader, aggressive,
66+
objectFactory, constructorArgTypes, constructorArgs);
5767
Enhancer enhancer = new Enhancer();
5868
enhancer.setCallback(proxy);
5969
enhancer.setSuperclass(type);
@@ -71,24 +81,34 @@ public static Object createProxy(Object target, ResultLoaderMap lazyLoader, bool
7181
// nothing to do here
7282
}
7383

74-
final Object enhanced = enhancer.create();
84+
Object enhanced = null;
85+
if (constructorArgTypes.isEmpty()) {
86+
enhanced = enhancer.create();
87+
} else {
88+
Class[] typesArray = constructorArgTypes.toArray(new Class[constructorArgTypes.size()]);
89+
Object[] valuesArray = constructorArgs.toArray(new Object[constructorArgs.size()]);
90+
enhanced = enhancer.create(typesArray, valuesArray);
91+
}
7592
PropertyCopier.copyBeanProperties(type, target, enhanced);
7693
return enhanced;
7794
}
7895
}
79-
96+
8097
public Object intercept(Object enhanced, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
8198
final String methodName = method.getName();
8299
try {
83100
synchronized (lazyLoader) {
84101
if (WRITE_REPLACE_METHOD.equals(methodName)) {
85-
Object original = objectFactory.create(type);
102+
Object original = null;
103+
if (constructorArgTypes.isEmpty()) {
104+
original = objectFactory.create(type);
105+
} else {
106+
original = objectFactory.create(type, constructorArgTypes, constructorArgs);
107+
}
86108
PropertyCopier.copyBeanProperties(type, enhanced, original);
87109
if (lazyLoader.size() > 0) {
88-
Set<String> unloadedProperties = lazyLoader.getPropertyNames();
89-
return new SerialStatusHolder(original,
90-
unloadedProperties.toArray(new String[unloadedProperties.size()]),
91-
objectFactory);
110+
return new SerialStateHolder(original, lazyLoader.getPropertyNames(), objectFactory,
111+
constructorArgTypes, constructorArgs);
92112
} else {
93113
return original;
94114
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.apache.ibatis.executor.loader;
2+
3+
import java.io.ObjectStreamException;
4+
import java.io.Serializable;
5+
import java.util.Arrays;
6+
import java.util.HashSet;
7+
import java.util.List;
8+
import java.util.Set;
9+
10+
import org.apache.ibatis.reflection.factory.ObjectFactory;
11+
12+
class SerialStateHolder implements Serializable {
13+
14+
private static final long serialVersionUID = 9018585337519878124L;
15+
private Object userBean;
16+
private String[] unloadedProperties;
17+
private ObjectFactory objectFactory;
18+
private Class[] constructorArgTypes;
19+
private Object[] constructorArgs;
20+
21+
public SerialStateHolder(final Object userBean, final Set<String> unloadedProperties,
22+
final ObjectFactory objectFactory, List<Class> constructorArgTypes, List<Object> constructorArgs) {
23+
this.userBean = userBean;
24+
this.unloadedProperties = unloadedProperties.toArray(new String[unloadedProperties.size()]);
25+
this.objectFactory = objectFactory;
26+
this.constructorArgTypes = constructorArgTypes.toArray(new Class[constructorArgTypes.size()]);
27+
this.constructorArgs = constructorArgs.toArray(new Object[constructorArgs.size()]);
28+
}
29+
30+
protected Object readResolve() throws ObjectStreamException {
31+
Set<String> arrayProps = new HashSet<String>(Arrays.asList(this.unloadedProperties));
32+
List<Class> arrayTypes = Arrays.asList(this.constructorArgTypes);
33+
List<Object> arrayValues = Arrays.asList(this.constructorArgs);
34+
return DeserializedObjectProxy.createProxy(userBean, arrayProps, objectFactory, arrayTypes, arrayValues);
35+
}
36+
37+
}

src/main/java/org/apache/ibatis/executor/loader/SerialStatusHolder.java

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/main/java/org/apache/ibatis/executor/resultset/FastResultSetHandler.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -283,39 +283,41 @@ protected void loadMappedAndUnmappedColumnNames(ResultSet rs, ResultMap resultMa
283283
//
284284

285285
protected Object createResultObject(ResultSet rs, ResultMap resultMap, ResultLoaderMap lazyLoader) throws SQLException {
286-
final Object resultObject = createResultObject(rs, resultMap);
286+
final List<Class> constructorArgTypes = new ArrayList<Class>();
287+
final List<Object> constructorArgs = new ArrayList<Object>();
288+
final Object resultObject = createResultObject(rs, resultMap, constructorArgTypes, constructorArgs);
287289
if (resultObject != null && configuration.isLazyLoadingEnabled()) {
288-
return ResultObjectProxy.createProxy(resultObject, lazyLoader, configuration.isAggressiveLazyLoading(), objectFactory);
290+
return ResultObjectProxy.createProxy(resultObject, lazyLoader, configuration.isAggressiveLazyLoading(), objectFactory, constructorArgTypes, constructorArgs);
289291
}
290292
return resultObject;
291293
}
292294

293-
protected Object createResultObject(ResultSet rs, ResultMap resultMap) throws SQLException {
295+
protected Object createResultObject(ResultSet rs, ResultMap resultMap, List<Class> constructorArgTypes, List<Object> constructorArgs)
296+
throws SQLException {
294297
final Class resultType = resultMap.getType();
295298
final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
296299
if (typeHandlerRegistry.hasTypeHandler(resultType)) {
297300
return createPrimitiveResultObject(rs, resultMap);
298301
} else if (constructorMappings.size() > 0) {
299-
return createParameterizedResultObject(rs, resultType, constructorMappings);
302+
return createParameterizedResultObject(rs, resultType, constructorMappings, constructorArgTypes, constructorArgs);
300303
} else {
301304
return objectFactory.create(resultType);
302305
}
303306
}
304307

305-
protected Object createParameterizedResultObject(ResultSet rs, Class resultType, List<ResultMapping> constructorMappings) throws SQLException {
308+
protected Object createParameterizedResultObject(ResultSet rs, Class resultType,
309+
List<ResultMapping> constructorMappings, List<Class> constructorArgTypes, List<Object> constructorArgs) throws SQLException {
306310
boolean foundValues = false;
307-
final List<Class> parameterTypes = new ArrayList<Class>();
308-
final List<Object> parameterValues = new ArrayList<Object>();
309311
for (ResultMapping constructorMapping : constructorMappings) {
310312
final Class parameterType = constructorMapping.getJavaType();
311313
final TypeHandler typeHandler = constructorMapping.getTypeHandler();
312314
final String column = constructorMapping.getColumn();
313315
final Object value = typeHandler.getResult(rs, column);
314-
parameterTypes.add(parameterType);
315-
parameterValues.add(value);
316+
constructorArgTypes.add(parameterType);
317+
constructorArgs.add(value);
316318
foundValues = value != null || foundValues;
317319
}
318-
return foundValues ? objectFactory.create(resultType, parameterTypes, parameterValues) : null;
320+
return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
319321
}
320322

321323
protected Object createPrimitiveResultObject(ResultSet rs, ResultMap resultMap) throws SQLException {

0 commit comments

Comments
 (0)