Skip to content

Commit 942c2c7

Browse files
committed
#372 Removing static variables in Reflector
1 parent 7088e18 commit 942c2c7

19 files changed

+209
-122
lines changed

src/main/java/org/apache/ibatis/builder/MapperBuilderAssistant.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -271,11 +271,11 @@ public MappedStatement addMappedStatement(
271271
String databaseId,
272272
LanguageDriver lang,
273273
String resultSets) {
274-
274+
275275
if (unresolvedCacheRef) {
276276
throw new IncompleteElementException("Cache-ref not yet resolved");
277277
}
278-
278+
279279
id = applyCurrentNamespace(id, false);
280280
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
281281

@@ -392,7 +392,7 @@ public ResultMapping buildResultMapping(
392392
Class<? extends TypeHandler<?>> typeHandler,
393393
List<ResultFlag> flags,
394394
String resultSet,
395-
String foreignColumn,
395+
String foreignColumn,
396396
boolean lazy) {
397397
Class<?> javaTypeClass = resolveResultJavaType(resultType, property, javaType);
398398
TypeHandler<?> typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler);
@@ -448,7 +448,7 @@ private List<ResultMapping> parseCompositeColumnName(String columnName) {
448448
private Class<?> resolveResultJavaType(Class<?> resultType, String property, Class<?> javaType) {
449449
if (javaType == null && property != null) {
450450
try {
451-
MetaClass metaResultType = MetaClass.forClass(resultType);
451+
MetaClass metaResultType = MetaClass.forClass(resultType, configuration.getReflectorFactory());
452452
javaType = metaResultType.getSetterType(property);
453453
} catch (Exception e) {
454454
//ignore, following null check statement will deal with the situation
@@ -467,7 +467,7 @@ private Class<?> resolveParameterJavaType(Class<?> resultType, String property,
467467
} else if (Map.class.isAssignableFrom(resultType)) {
468468
javaType = Object.class;
469469
} else {
470-
MetaClass metaResultType = MetaClass.forClass(resultType);
470+
MetaClass metaResultType = MetaClass.forClass(resultType, configuration.getReflectorFactory());
471471
javaType = metaResultType.getGetterType(property);
472472
}
473473
}
@@ -491,9 +491,9 @@ public ResultMapping buildResultMapping(
491491
Class<? extends TypeHandler<?>> typeHandler,
492492
List<ResultFlag> flags) {
493493
return buildResultMapping(
494-
resultType, property, column, javaType, jdbcType, nestedSelect,
494+
resultType, property, column, javaType, jdbcType, nestedSelect,
495495
nestedResultMap, notNullColumn, columnPrefix, typeHandler, flags, null, null, configuration.isLazyLoadingEnabled());
496-
}
496+
}
497497

498498
public LanguageDriver getLanguageDriver(Class<?> langClass) {
499499
if (langClass != null) {
@@ -526,9 +526,9 @@ public MappedStatement addMappedStatement(
526526
String databaseId,
527527
LanguageDriver lang) {
528528
return addMappedStatement(
529-
id, sqlSource, statementType, sqlCommandType, fetchSize, timeout,
530-
parameterMap, parameterType, resultMap, resultType, resultSetType,
531-
flushCache, useCache, resultOrdered, keyGenerator, keyProperty,
529+
id, sqlSource, statementType, sqlCommandType, fetchSize, timeout,
530+
parameterMap, parameterType, resultMap, resultType, resultSetType,
531+
flushCache, useCache, resultOrdered, keyGenerator, keyProperty,
532532
keyColumn, databaseId, lang, null);
533533
}
534534

src/main/java/org/apache/ibatis/builder/SqlSourceBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ private ParameterMapping buildParameterMapping(String content) {
7979
} else if (JdbcType.CURSOR.name().equals(propertiesMap.get("jdbcType"))) {
8080
propertyType = java.sql.ResultSet.class;
8181
} else if (property != null) {
82-
MetaClass metaClass = MetaClass.forClass(parameterType);
82+
MetaClass metaClass = MetaClass.forClass(parameterType, configuration.getReflectorFactory());
8383
if (metaClass.hasGetter(property)) {
8484
propertyType = metaClass.getGetterType(property);
8585
} else {
@@ -133,5 +133,5 @@ private Map<String, String> parseParameterMapping(String content) {
133133
}
134134
}
135135
}
136-
136+
137137
}

src/main/java/org/apache/ibatis/builder/xml/XMLConfigBuilder.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@
3232
import org.apache.ibatis.parsing.XNode;
3333
import org.apache.ibatis.parsing.XPathParser;
3434
import org.apache.ibatis.plugin.Interceptor;
35+
import org.apache.ibatis.reflection.DefaultReflectorFactory;
3536
import org.apache.ibatis.reflection.MetaClass;
37+
import org.apache.ibatis.reflection.ReflectorFactory;
3638
import org.apache.ibatis.reflection.factory.ObjectFactory;
3739
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
3840
import org.apache.ibatis.session.AutoMappingBehavior;
@@ -50,6 +52,7 @@ public class XMLConfigBuilder extends BaseBuilder {
5052
private boolean parsed;
5153
private XPathParser parser;
5254
private String environment;
55+
private ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
5356

5457
public XMLConfigBuilder(Reader reader) {
5558
this(reader, null, null);
@@ -101,6 +104,7 @@ private void parseConfiguration(XNode root) {
101104
pluginElement(root.evalNode("plugins"));
102105
objectFactoryElement(root.evalNode("objectFactory"));
103106
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
107+
reflectionFactoryElement(root.evalNode("reflectionFactory"));
104108
settingsElement(root.evalNode("settings"));
105109
// read it after objectFactory and objectWrapperFactory issue #631
106110
environmentsElement(root.evalNode("environments"));
@@ -166,6 +170,14 @@ private void objectWrapperFactoryElement(XNode context) throws Exception {
166170
}
167171
}
168172

173+
private void reflectionFactoryElement(XNode context) throws Exception {
174+
if (context != null) {
175+
String type = context.getStringAttribute("type");
176+
ReflectorFactory factory = (ReflectorFactory) resolveClass(type).newInstance();
177+
configuration.setReflectorFactory(factory);
178+
}
179+
}
180+
169181
private void propertiesElement(XNode context) throws Exception {
170182
if (context != null) {
171183
Properties defaults = context.getChildrenAsProperties();
@@ -192,7 +204,7 @@ private void settingsElement(XNode context) throws Exception {
192204
if (context != null) {
193205
Properties props = context.getChildrenAsProperties();
194206
// Check that all settings are known to the configuration class
195-
MetaClass metaConfig = MetaClass.forClass(Configuration.class);
207+
MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
196208
for (Object key : props.keySet()) {
197209
if (!metaConfig.hasSetter(String.valueOf(key))) {
198210
throw new BuilderException("The setting " + key + " is not known. Make sure you spelled it correctly (case sensitive).");
@@ -222,7 +234,7 @@ private void settingsElement(XNode context) throws Exception {
222234
configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
223235
}
224236
}
225-
237+
226238
private void environmentsElement(XNode context) throws Exception {
227239
if (context != null) {
228240
if (environment == null) {

src/main/java/org/apache/ibatis/executor/result/DefaultMapResultHandler.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.util.Map;
1919

2020
import org.apache.ibatis.reflection.MetaObject;
21+
import org.apache.ibatis.reflection.ReflectorFactory;
2122
import org.apache.ibatis.reflection.factory.ObjectFactory;
2223
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
2324
import org.apache.ibatis.session.ResultContext;
@@ -32,19 +33,21 @@ public class DefaultMapResultHandler<K, V> implements ResultHandler<V> {
3233
private final String mapKey;
3334
private final ObjectFactory objectFactory;
3435
private final ObjectWrapperFactory objectWrapperFactory;
36+
private final ReflectorFactory reflectorFactory;
3537

3638
@SuppressWarnings("unchecked")
37-
public DefaultMapResultHandler(String mapKey, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) {
39+
public DefaultMapResultHandler(String mapKey, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
3840
this.objectFactory = objectFactory;
3941
this.objectWrapperFactory = objectWrapperFactory;
42+
this.reflectorFactory = reflectorFactory;
4043
this.mappedResults = objectFactory.create(Map.class);
4144
this.mapKey = mapKey;
4245
}
4346

4447
@Override
4548
public void handleResult(ResultContext<? extends V> context) {
4649
final V value = context.getResultObject();
47-
final MetaObject mo = MetaObject.forObject(value, objectFactory, objectWrapperFactory);
50+
final MetaObject mo = MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
4851
// TODO is that assignment always true?
4952
final K key = (K) mo.getValue(mapKey);
5053
mappedResults.put(key, value);

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

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.apache.ibatis.mapping.ResultMapping;
4747
import org.apache.ibatis.reflection.MetaClass;
4848
import org.apache.ibatis.reflection.MetaObject;
49+
import org.apache.ibatis.reflection.ReflectorFactory;
4950
import org.apache.ibatis.reflection.factory.ObjectFactory;
5051
import org.apache.ibatis.session.AutoMappingBehavior;
5152
import org.apache.ibatis.session.Configuration;
@@ -72,6 +73,7 @@ public class DefaultResultSetHandler implements ResultSetHandler {
7273
private final BoundSql boundSql;
7374
private final TypeHandlerRegistry typeHandlerRegistry;
7475
private final ObjectFactory objectFactory;
76+
private final ReflectorFactory reflectorFactory;
7577

7678
// nested resultmaps
7779
private final Map<CacheKey, Object> nestedResultObjects = new HashMap<CacheKey, Object>();
@@ -81,12 +83,12 @@ public class DefaultResultSetHandler implements ResultSetHandler {
8183
// multiple resultsets
8284
private final Map<String, ResultMapping> nextResultMaps = new HashMap<String, ResultMapping>();
8385
private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<CacheKey, List<PendingRelation>>();
84-
86+
8587
private static class PendingRelation {
8688
public MetaObject metaObject;
8789
public ResultMapping propertyMapping;
8890
}
89-
91+
9092
public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler, ResultHandler<?> resultHandler, BoundSql boundSql,
9193
RowBounds rowBounds) {
9294
this.executor = executor;
@@ -97,6 +99,7 @@ public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatemen
9799
this.boundSql = boundSql;
98100
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
99101
this.objectFactory = configuration.getObjectFactory();
102+
this.reflectorFactory = configuration.getReflectorFactory();
100103
this.resultHandler = resultHandler;
101104
}
102105

@@ -142,7 +145,7 @@ private void handleRefCursorOutputParameter(ResultSet rs, ParameterMapping param
142145
@Override
143146
public List<Object> handleResultSets(Statement stmt) throws SQLException {
144147
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
145-
148+
146149
final List<Object> multipleResults = new ArrayList<Object>();
147150

148151
int resultSetCount = 0;
@@ -268,7 +271,7 @@ private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHa
268271
} else {
269272
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
270273
}
271-
}
274+
}
272275

273276
private void ensureNoRowBounds() {
274277
if (configuration.isSafeRowBoundsEnabled() && rowBounds != null && (rowBounds.getLimit() < RowBounds.NO_ROW_LIMIT || rowBounds.getOffset() > RowBounds.NO_ROW_OFFSET)) {
@@ -280,10 +283,10 @@ private void ensureNoRowBounds() {
280283
protected void checkResultHandler() {
281284
if (resultHandler != null && configuration.isSafeResultHandlerEnabled() && !mappedStatement.isResultOrdered()) {
282285
throw new ExecutorException("Mapped Statements with nested result mappings cannot be safely used with a custom ResultHandler. "
283-
+ "Use safeResultHandlerEnabled=false setting to bypass this check "
286+
+ "Use safeResultHandlerEnabled=false setting to bypass this check "
284287
+ "or ensure your statement returns ordered data and set resultOrdered=true on it.");
285288
}
286-
}
289+
}
287290

288291
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
289292
throws SQLException {
@@ -336,7 +339,7 @@ private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQL
336339
if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
337340
final MetaObject metaObject = configuration.newMetaObject(resultObject);
338341
boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
339-
if (shouldApplyAutomaticMappings(resultMap, false)) {
342+
if (shouldApplyAutomaticMappings(resultMap, false)) {
340343
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
341344
}
342345
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
@@ -373,9 +376,9 @@ private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap,
373376
if (propertyMapping.getNestedResultMapId() != null) {
374377
// the user added a column attribute to a nested result map, ignore it
375378
column = null;
376-
}
377-
if (propertyMapping.isCompositeResult()
378-
|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
379+
}
380+
if (propertyMapping.isCompositeResult()
381+
|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
379382
|| propertyMapping.getResultSet() != null) {
380383
Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
381384
// issue #541 make property optional
@@ -548,7 +551,7 @@ private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, Res
548551
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
549552
throws SQLException {
550553
final Class<?> resultType = resultMap.getType();
551-
final MetaClass metaType = MetaClass.forClass(resultType);
554+
final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
552555
final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
553556
if (typeHandlerRegistry.hasTypeHandler(resultType)) {
554557
return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
@@ -785,7 +788,7 @@ private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap r
785788
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
786789
}
787790
}
788-
791+
789792
//
790793
// GET VALUE FROM ROW FOR NESTED RESULT MAP
791794
//
@@ -806,7 +809,7 @@ private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey c
806809
boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
807810
if (shouldApplyAutomaticMappings(resultMap, true)) {
808811
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
809-
}
812+
}
810813
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
811814
putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
812815
foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
@@ -846,16 +849,16 @@ private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap result
846849
rowKey = createRowKey(nestedResultMap, rsw, ancestorColumnPrefix.get(nestedResultMapId));
847850
ancestorObject = ancestorObjects.get(rowKey);
848851
}
849-
if (ancestorObject != null) {
852+
if (ancestorObject != null) {
850853
if (newObject) {
851854
metaObject.setValue(resultMapping.getProperty(), ancestorObject);
852855
}
853856
} else {
854857
rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
855-
final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
858+
final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
856859
Object rowValue = nestedResultObjects.get(combinedKey);
857860
boolean knownValue = (rowValue != null);
858-
final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
861+
final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
859862
if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw.getResultSet())) {
860863
rowValue = getRowValue(rsw, nestedResultMap, combinedKey, rowKey, columnPrefix, rowValue);
861864
if (rowValue != null && !knownValue) {
@@ -975,7 +978,7 @@ private void createRowKeyForMappedProperties(ResultMap resultMap, ResultSetWrapp
975978
}
976979

977980
private void createRowKeyForUnmappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, String columnPrefix) throws SQLException {
978-
final MetaClass metaType = MetaClass.forClass(resultMap.getType());
981+
final MetaClass metaType = MetaClass.forClass(resultMap.getType(), reflectorFactory);
979982
List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
980983
for (String column : unmappedColumnNames) {
981984
String property = column;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* Copyright 2009-2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.ibatis.reflection;
17+
18+
import java.util.concurrent.ConcurrentHashMap;
19+
import java.util.concurrent.ConcurrentMap;
20+
21+
public class DefaultReflectorFactory implements ReflectorFactory {
22+
private boolean classCacheEnabled = true;
23+
private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<Class<?>, Reflector>();
24+
25+
public DefaultReflectorFactory() {
26+
}
27+
28+
@Override
29+
public boolean isClassCacheEnabled() {
30+
return classCacheEnabled;
31+
}
32+
33+
@Override
34+
public void setClassCacheEnabled(boolean classCacheEnabled) {
35+
this.classCacheEnabled = classCacheEnabled;
36+
}
37+
38+
@Override
39+
public Reflector findForClass(Class<?> type) {
40+
if (classCacheEnabled) {
41+
// synchronized (type) removed see issue #461
42+
Reflector cached = reflectorMap.get(type);
43+
if (cached == null) {
44+
cached = new Reflector(type);
45+
reflectorMap.put(type, cached);
46+
}
47+
return cached;
48+
} else {
49+
return new Reflector(type);
50+
}
51+
}
52+
53+
}

0 commit comments

Comments
 (0)