Author: cbegin
Date: Sat Sep 5 22:46:17 2009
New Revision: 811723
URL: http://svn.apache.org/viewvc?rev=811723&view=rev
Log:
Broke up defaultresulthandler into multiple classes that are more meaningful,
to prepare for a larger refactoring that will resolve a few outstanding issues.
Added:
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/DiscriminatorHandler.java
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NestedResultSetHandler.java
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NestedSelectHandler.java
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NoValue.java
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/Reference.java
Modified:
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/test/java/org/apache/ibatis/builder/BlogMapper.xml
Modified:
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java
URL:
http://svn.apache.org/viewvc/ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java?rev=811723&r1=811722&r2=811723&view=diff
==============================================================================
---
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java
(original)
+++
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java
Sat Sep 5 22:46:17 2009
@@ -1,6 +1,6 @@
package org.apache.ibatis.executor.resultset;
-import org.apache.ibatis.cache.CacheKey;
+import static org.apache.ibatis.executor.resultset.NoValue.*;
import org.apache.ibatis.executor.*;
import org.apache.ibatis.executor.loader.*;
import org.apache.ibatis.executor.parameter.ParameterHandler;
@@ -15,10 +15,7 @@
public class DefaultResultSetHandler implements ResultSetHandler {
- private static final Object NO_VALUE = new Object();
-
- private Configuration configuration;
- private final Executor executor;
+ private final Configuration configuration;
private final ObjectFactory objectFactory;
private final TypeHandlerRegistry typeHandlerRegistry;
private final MappedStatement mappedStatement;
@@ -26,25 +23,26 @@
private final int rowLimit;
private final Object parameterObject;
- private final Map nestedResultObjects;
-
private final ResultHandler resultHandler;
private final BoundSql boundSql;
-
- private CacheKey currentNestedKey;
+ private final NestedSelectHandler nestedSelectHandler;
+ private final NestedResultSetHandler nestedResultSetHandler;
+ private final DiscriminatorHandler discriminatorHandler;
public DefaultResultSetHandler(Configuration configuration, Executor
executor, MappedStatement mappedStatement, ParameterHandler parameterHandler,
int rowOffset, int rowLimit, ResultHandler resultHandler, BoundSql boundSql) {
this.configuration = configuration;
- this.executor = executor;
this.objectFactory = mappedStatement.getConfiguration().getObjectFactory();
this.typeHandlerRegistry =
mappedStatement.getConfiguration().getTypeHandlerRegistry();
this.mappedStatement = mappedStatement;
this.rowOffset = rowOffset;
this.rowLimit = rowLimit;
this.parameterObject = parameterHandler.getParameterObject();
- this.nestedResultObjects = new HashMap();
this.resultHandler = resultHandler;
this.boundSql = boundSql;
+
+ this.nestedResultSetHandler = new
NestedResultSetHandler(configuration,mappedStatement,this);
+ this.nestedSelectHandler = new
NestedSelectHandler(executor,configuration,mappedStatement);
+ this.discriminatorHandler = new DiscriminatorHandler(mappedStatement);
}
public List handleResultSets(Statement statement) throws SQLException {
@@ -53,6 +51,7 @@
if (rs != null) {
try {
for (int i = 0, n = mappedStatement.getResultMaps().size(); i < n;
i++) {
+
ResultMap resultMap = mappedStatement.getResultMaps().get(i);
ErrorContext.instance().activity("handling result
set").object(resultMap.getId());
if (resultHandler == null) {
@@ -63,8 +62,8 @@
handleResults(rs, resultMap, resultHandler, rowOffset, rowLimit);
}
if (moveToNextResultsSafely(statement)) {
+ nestedResultSetHandler.reset();
rs = statement.getResultSet();
- nestedResultObjects.clear();
} else {
break;
}
@@ -88,8 +87,6 @@
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() == ParameterMode.OUT ||
parameterMapping.getMode() == ParameterMode.INOUT) {
if
("java.sql.ResultSet".equalsIgnoreCase(parameterMapping.getJavaType().getName()))
{
- // TODO: We need an easy way to unit test this without installing
Oracle.
- // Mocks are obvious, but will they be effective enough? DBunit?
ResultSet rs = (ResultSet) callableStatement.getObject(i + 1);
String resultMapId = parameterMapping.getResultMapId();
if (resultMapId != null) {
@@ -114,8 +111,7 @@
ResultContext context = new ResultContext();
while ((maxResults == Executor.NO_ROW_LIMIT || context.getResultCount()
< maxResults)
&& !context.isStopped() && rs.next()) {
- currentNestedKey = null;
- ResultMap rm = resolveSubMap(rs, resultMap);
+ ResultMap rm = discriminatorHandler.resolveSubMap(rs, resultMap);
Object resultObject = loadResultObject(rs, rm, new Reference(false));
if (resultObject != NO_VALUE) {
if (resultObject instanceof PlatformTypeHolder) {
@@ -128,28 +124,34 @@
}
}
- private Object loadResultObject(ResultSet rs, ResultMap rm,
Reference<Boolean> foundValues) throws SQLException {
+ public Object loadResultObject(ResultSet rs, ResultMap rm,
Reference<Boolean> foundValues) throws SQLException {
if (rm.getType() == null) {
throw new ExecutorException("The result class was null when trying to
get results for ResultMap " + rm.getId());
}
-
Object resultObject = createResultObject(rs, rm);
ResultLoaderRegistry lazyLoader = null;
if (this.mappedStatement.getConfiguration().isEnhancementEnabled()) {
lazyLoader = new ResultLoaderRegistry();
resultObject = ResultObjectProxy.createProxy(rm.getType(), resultObject,
lazyLoader);
}
-
List<ResultMapping> appliedResultMappings = new ArrayList<ResultMapping>();
resultObject = mapResults(rs, rm, lazyLoader, resultObject,
appliedResultMappings, foundValues);
- resultObject = processNestedJoinResults(rs, appliedResultMappings,
resultObject);
+ resultObject = nestedResultSetHandler.processNestedJoinResults(rs,
appliedResultMappings, resultObject);
return resultObject;
}
private Object mapResults(ResultSet rs, ResultMap rm, ResultLoaderRegistry
lazyLoader, Object resultObject, List<ResultMapping> appliedResultMappings,
Reference<Boolean> foundValues) throws SQLException {
- MetaObject metaResultObject = MetaObject.forObject(resultObject);
- Set<String> propSet = new HashSet<String>();
Set<String> colSet = new HashSet<String>();
+ Map<String, ResultMapping> autoMappings =
createResultMappingsForColumnsThatMatchPropertyNames(rs, resultObject, colSet);
+ // Map results/ignore missing
+ resultObject = mapSpecifiedResultsIgnoringMissingColumns(rs, rm,
lazyLoader, resultObject, appliedResultMappings, foundValues, colSet,
autoMappings);
+ // Automap remaining results
+ resultObject = automaticallyMapRemainingColumnsThatMatchPropertyNames(rs,
rm, lazyLoader, resultObject, appliedResultMappings, foundValues, autoMappings);
+ return resultObject;
+ }
+
+ private Map<String, ResultMapping>
createResultMappingsForColumnsThatMatchPropertyNames(ResultSet rs, Object
resultObject, Set<String> colSet) throws SQLException {
+ MetaObject metaResultObject = MetaObject.forObject(resultObject);
Map<String, ResultMapping> autoMappings = new HashMap<String,
ResultMapping>();
ResultSetMetaData rsmd = rs.getMetaData();
for (int i = 1, n = rsmd.getColumnCount(); i <= n; i++) {
@@ -159,7 +161,6 @@
String propName = metaResultObject.findProperty(columnLabel);
colSet.add(columnLabel);
if (propName != null && metaResultObject.hasSetter(propName)) {
- propSet.add(propName);
Class javaType = metaResultObject.getSetterType(propName);
TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(javaType);
ResultMapping resultMapping = new ResultMapping.Builder(configuration,
propName, columnLabel, typeHandler)
@@ -167,7 +168,21 @@
autoMappings.put(propName, resultMapping);
}
}
- // Map results/ignore missing
+ return autoMappings;
+ }
+
+ private Object
automaticallyMapRemainingColumnsThatMatchPropertyNames(ResultSet rs, ResultMap
rm, ResultLoaderRegistry lazyLoader, Object resultObject, List<ResultMapping>
appliedResultMappings, Reference<Boolean> foundValues, Map<String,
ResultMapping> autoMappings) throws SQLException {
+ for (String key : autoMappings.keySet()) {
+ ResultMapping autoMapping = autoMappings.get(key);
+ if (autoMapping.getTypeHandler() != null) {
+ resultObject = processResult(rs, rm, autoMapping, lazyLoader,
resultObject, foundValues);
+ appliedResultMappings.add(autoMapping);
+ }
+ }
+ return resultObject;
+ }
+
+ private Object mapSpecifiedResultsIgnoringMissingColumns(ResultSet rs,
ResultMap rm, ResultLoaderRegistry lazyLoader, Object resultObject,
List<ResultMapping> appliedResultMappings, Reference<Boolean> foundValues,
Set<String> colSet, Map<String, ResultMapping> autoMappings) throws
SQLException {
for (ResultMapping resultMapping : rm.getPropertyResultMappings()) {
String propName = resultMapping.getProperty();
String colName = resultMapping.getColumn();
@@ -178,14 +193,6 @@
appliedResultMappings.add(resultMapping);
}
}
- // Automap remaining results
- for (String key : autoMappings.keySet()) {
- ResultMapping autoMapping = autoMappings.get(key);
- if (autoMapping.getTypeHandler() != null) {
- resultObject = processResult(rs, rm, autoMapping, lazyLoader,
resultObject, foundValues);
- appliedResultMappings.add(autoMapping);
- }
- }
return resultObject;
}
@@ -210,41 +217,9 @@
return resultObject;
}
- private Object processNestedSelectResult(MappedStatement nestedQuery,
ResultMap rm, ResultMapping resultMapping, ResultLoaderRegistry lazyLoader,
Object parameterObject, Object resultObject) {
- MetaObject metaResultObject = MetaObject.forObject(resultObject);
- Object value = null;
- try {
- if (parameterObject != null) {
- CacheKey key = executor.createCacheKey(nestedQuery, parameterObject,
Executor.NO_ROW_OFFSET, Executor.NO_ROW_LIMIT);
- if (executor.isCached(nestedQuery, key)) {
- executor.deferLoad(nestedQuery, metaResultObject,
resultMapping.getProperty(), key);
- } else {
- ResultLoader resultLoader = new ResultLoader(configuration,
executor, nestedQuery, parameterObject, resultMapping.getJavaType());
- if (lazyLoader == null) {
- value = resultLoader.loadResult();
- } else {
- lazyLoader.registerLoader(resultMapping.getProperty(),
metaResultObject, resultLoader);
- }
- }
- }
- } catch (Exception e) {
- throw new ExecutorException("Error setting nested bean property. Cause:
" + e, e);
- }
- if (typeHandlerRegistry.hasTypeHandler(rm.getType())) {
- resultObject = value;
- } else if (value != null) {
- metaResultObject.setValue(resultMapping.getProperty(), value);
- }
- return resultObject;
- }
-
private Object processResult(ResultSet rs, ResultMap rm, ResultMapping
resultMapping, ResultLoaderRegistry lazyLoader, Object resultObject,
Reference<Boolean> foundValues) throws SQLException {
if (resultMapping.getNestedQueryId() != null) {
- Configuration configuration = mappedStatement.getConfiguration();
- MappedStatement nestedQuery =
configuration.getMappedStatement(resultMapping.getNestedQueryId());
- Class parameterType = nestedQuery.getParameterMap().getType();
- Object parameterObject = prepareNestedParameterObject(rs, resultMapping,
parameterType);
- resultObject = processNestedSelectResult(nestedQuery, rm, resultMapping,
lazyLoader, parameterObject, resultObject);
+ resultObject = nestedSelectHandler.processNestedSelect(rs, rm,
resultMapping, lazyLoader, resultObject);
} else if (resultMapping.getNestedResultMapId() == null) {
resultObject = processSimpleResult(rs, rm, resultMapping, resultObject,
foundValues);
}
@@ -264,130 +239,11 @@
return resultObject;
}
- private Object processNestedJoinResults(ResultSet rs, List<ResultMapping>
resultMappings, Object resultObject) {
- CacheKey previousKey = currentNestedKey;
- try {
- currentNestedKey = createUniqueResultKey(resultMappings, resultObject,
currentNestedKey);
- if (nestedResultObjects.containsKey(currentNestedKey)) {
- // Unique key is already known, so get the existing result object and
process additional results.
- resultObject = NO_VALUE;
- } else if (currentNestedKey != null) {
- // Unique key is NOT known, so create a new result object and then
process additional results.
- nestedResultObjects.put(currentNestedKey, resultObject);
- }
- Object knownResultObject = nestedResultObjects.get(currentNestedKey);
- if (knownResultObject != null && knownResultObject != NO_VALUE) {
- for (ResultMapping resultMapping : resultMappings) {
- Configuration configuration = mappedStatement.getConfiguration();
- String nestedResultMapId = resultMapping.getNestedResultMapId();
- if (nestedResultMapId != null) {
- ResultMap nestedResultMap =
configuration.getResultMap(nestedResultMapId);
- try {
-
- // get the discriminated submap if it exists
- nestedResultMap = resolveSubMap(rs, nestedResultMap);
-
- Class type = resultMapping.getJavaType();
- String propertyName = resultMapping.getProperty();
-
- MetaObject metaObject = MetaObject.forObject(knownResultObject);
- Object propertyValue = metaObject.getValue(propertyName);
- if (propertyValue == null) {
- if (type == null) {
- type = metaObject.getSetterType(propertyName);
- }
-
- try {
- // create the object if is it a Collection. If not a
Collection
- // then we will just set the property to the object created
- // in processing the nested result map
- if (Collection.class.isAssignableFrom(type)) {
- propertyValue = objectFactory.create(type);
- metaObject.setValue(propertyName, propertyValue);
- }
- } catch (Exception e) {
- throw new ExecutorException("Error instantiating collection
property for result '" + resultMapping.getProperty() + "'. Cause: " + e, e);
- }
- }
-
- Reference<Boolean> foundValues = new Reference(false);
- Object nestedResultObject = loadResultObject(rs,
nestedResultMap, foundValues);
- if (nestedResultObject != null && nestedResultObject !=
NO_VALUE) {
- if (propertyValue != null && propertyValue instanceof
Collection) {
- if (foundValues.get()) {
- ((Collection) propertyValue).add(nestedResultObject);
- }
- } else {
- metaObject.setValue(propertyName, nestedResultObject);
- }
- }
- } catch (Exception e) {
- throw new ExecutorException("Error getting nested result map
values for '" + resultMapping.getProperty() + "'. Cause: " + e, e);
- }
- }
- }
- }
- } finally {
- currentNestedKey = previousKey;
- }
- return resultObject;
- }
-
- private Object prepareNestedParameterObject(ResultSet rs, ResultMapping
resultMapping, Class parameterType) throws SQLException {
- Object parameterObject;
- if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
- TypeHandler th = typeHandlerRegistry.getTypeHandler(parameterType);
- parameterObject = th.getResult(rs, resultMapping.getColumn());
- } else {
- if (parameterType == null) {
- parameterObject = new HashMap();
- } else {
- parameterObject = objectFactory.create(parameterType);
- }
- if (resultMapping.isCompositeResult()) {
- MetaObject metaObject = MetaObject.forObject(parameterObject);
- for (ResultMapping innerResultMapping : resultMapping.getComposites())
{
- Class propType =
metaObject.getSetterType(innerResultMapping.getProperty());
- TypeHandler typeHandler =
typeHandlerRegistry.getTypeHandler(propType);
- Object propValue = typeHandler.getResult(rs,
innerResultMapping.getColumn());
- metaObject.setValue(innerResultMapping.getProperty(), propValue);
- }
- } else {
- String columnName = resultMapping.getColumn();
- TypeHandler typeHandler =
typeHandlerRegistry.getTypeHandler(parameterType);
- if (typeHandler == null) {
- typeHandler = typeHandlerRegistry.getUnkownTypeHandler();
- }
- parameterObject = typeHandler.getResult(rs, columnName);
- }
- }
- return parameterObject;
- }
//////////////////////////////////////////
// UTILITY METHODS
//////////////////////////////////////////
- private ResultMap resolveSubMap(ResultSet rs, ResultMap rm) throws
SQLException {
- ResultMap subMap = rm;
- Discriminator discriminator = rm.getDiscriminator();
- if (discriminator != null) {
- ResultMapping resultMapping = discriminator.getResultMapping();
- Object value = getPrimitiveResultMappingValue(rs, resultMapping);
- String subMapId = discriminator.getMapIdFor(String.valueOf(value));
-
- try {
- subMap = mappedStatement.getConfiguration().getResultMap(subMapId);
- } catch (Exception e) {
- subMap = rm;
- }
-
- if (subMap != rm) {
- subMap = resolveSubMap(rs, subMap);
- }
- }
- return subMap;
- }
private Object getPrimitiveResultMappingValue(ResultSet rs, ResultMapping
resultMapping) throws SQLException {
Object value;
@@ -400,31 +256,6 @@
return value;
}
- private CacheKey createUniqueResultKey(List<ResultMapping> resultMappings,
Object resultObject, CacheKey parentCacheKey) {
- if (resultObject == null) {
- return null;
- } else {
- MetaObject metaResultObject = MetaObject.forObject(resultObject);
- CacheKey cacheKey = new CacheKey();
- cacheKey.update(parentCacheKey);
- boolean updated = false;
- if (typeHandlerRegistry.hasTypeHandler(resultObject.getClass())) {
- cacheKey.update(resultObject);
- } else {
- for (ResultMapping resultMapping : resultMappings) {
- if (resultMapping.getNestedQueryId() == null) {
- String propName = resultMapping.getProperty();
- if (propName != null) {
- cacheKey.update(metaResultObject.getValue(propName));
- updated = true;
- }
- }
- }
- }
- return updated ? cacheKey : null;
- }
- }
-
private ResultSet getFirstResultSet(Statement statement) throws SQLException
{
ResultSet rs = null;
boolean hasMoreResults = true;
@@ -468,20 +299,5 @@
}
}
- private static class Reference<T> {
- private T value;
-
- private Reference(T value) {
- this.value = value;
- }
-
- public T get() {
- return value;
- }
-
- public void set(T value) {
- this.value = value;
- }
- }
}
Added:
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/DiscriminatorHandler.java
URL:
http://svn.apache.org/viewvc/ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/DiscriminatorHandler.java?rev=811723&view=auto
==============================================================================
---
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/DiscriminatorHandler.java
(added)
+++
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/DiscriminatorHandler.java
Sat Sep 5 22:46:17 2009
@@ -0,0 +1,53 @@
+package org.apache.ibatis.executor.resultset;
+
+import org.apache.ibatis.mapping.ResultMap;
+import org.apache.ibatis.mapping.Discriminator;
+import org.apache.ibatis.mapping.ResultMapping;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.type.TypeHandler;
+import org.apache.ibatis.executor.ExecutorException;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class DiscriminatorHandler {
+
+ private final MappedStatement mappedStatement;
+
+ public DiscriminatorHandler(MappedStatement mappedStatement) {
+ this.mappedStatement = mappedStatement;
+ }
+
+ public ResultMap resolveSubMap(ResultSet rs, ResultMap rm) throws
SQLException {
+ ResultMap subMap = rm;
+ Discriminator discriminator = rm.getDiscriminator();
+ if (discriminator != null) {
+ ResultMapping resultMapping = discriminator.getResultMapping();
+ Object value = getPrimitiveResultMappingValue(rs, resultMapping);
+ String subMapId = discriminator.getMapIdFor(String.valueOf(value));
+
+ try {
+ subMap = mappedStatement.getConfiguration().getResultMap(subMapId);
+ } catch (Exception e) {
+ subMap = rm;
+ }
+
+ if (subMap != rm) {
+ subMap = resolveSubMap(rs, subMap);
+ }
+ }
+ return subMap;
+ }
+
+ private Object getPrimitiveResultMappingValue(ResultSet rs, ResultMapping
resultMapping) throws SQLException {
+ Object value;
+ TypeHandler typeHandler = resultMapping.getTypeHandler();
+ if (typeHandler != null) {
+ value = typeHandler.getResult(rs, resultMapping.getColumn());
+ } else {
+ throw new ExecutorException("No type handler could be found to map the
property '" + resultMapping.getProperty() + "' to the column '" +
resultMapping.getColumn() + "'. One or both of the types, or the combination
of types is not supported.");
+ }
+ return value;
+ }
+
+}
Added:
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NestedResultSetHandler.java
URL:
http://svn.apache.org/viewvc/ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NestedResultSetHandler.java?rev=811723&view=auto
==============================================================================
---
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NestedResultSetHandler.java
(added)
+++
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NestedResultSetHandler.java
Sat Sep 5 22:46:17 2009
@@ -0,0 +1,141 @@
+package org.apache.ibatis.executor.resultset;
+
+import static org.apache.ibatis.executor.resultset.NoValue.*;
+
+import org.apache.ibatis.mapping.ResultMapping;
+import org.apache.ibatis.mapping.Configuration;
+import org.apache.ibatis.mapping.ResultMap;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.cache.CacheKey;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.reflection.factory.ObjectFactory;
+import org.apache.ibatis.executor.ExecutorException;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.type.TypeHandlerRegistry;
+
+import java.sql.ResultSet;
+import java.util.List;
+import java.util.Collection;
+import java.util.Map;
+import java.util.HashMap;
+
+public class NestedResultSetHandler {
+
+ private final ObjectFactory objectFactory;
+ private final TypeHandlerRegistry typeHandlerRegistry;
+ private final MappedStatement mappedStatement;
+ private final Map nestedResultObjects;
+
+ private CacheKey currentNestedKey;
+ private final DiscriminatorHandler discriminatorHandler;
+ private DefaultResultSetHandler resultSetHandler;
+
+ public NestedResultSetHandler(Configuration configuration, MappedStatement
mappedStatement, DefaultResultSetHandler resultSetHandler) {
+ this.objectFactory = configuration.getObjectFactory();
+ this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
+ this.mappedStatement = mappedStatement;
+ this.nestedResultObjects = new HashMap();
+ this.discriminatorHandler = new DiscriminatorHandler(mappedStatement);
+ this.resultSetHandler = resultSetHandler;
+ }
+
+ public Object processNestedJoinResults(ResultSet rs, List<ResultMapping>
resultMappings, Object resultObject) {
+ CacheKey previousKey = currentNestedKey;
+ try {
+ currentNestedKey = createUniqueResultKey(resultMappings, resultObject,
currentNestedKey);
+ if (nestedResultObjects.containsKey(currentNestedKey)) {
+ // Unique key is already known, so get the existing result object and
process additional results.
+ resultObject = NO_VALUE;
+ } else if (currentNestedKey != null) {
+ // Unique key is NOT known, so create a new result object and then
process additional results.
+ nestedResultObjects.put(currentNestedKey, resultObject);
+ }
+ Object knownResultObject = nestedResultObjects.get(currentNestedKey);
+ if (knownResultObject != null && knownResultObject != NO_VALUE) {
+ for (ResultMapping resultMapping : resultMappings) {
+ Configuration configuration = mappedStatement.getConfiguration();
+ String nestedResultMapId = resultMapping.getNestedResultMapId();
+ if (nestedResultMapId != null) {
+ ResultMap nestedResultMap =
configuration.getResultMap(nestedResultMapId);
+ try {
+
+ // get the discriminated submap if it exists
+ nestedResultMap = discriminatorHandler.resolveSubMap(rs,
nestedResultMap);
+
+ Class type = resultMapping.getJavaType();
+ String propertyName = resultMapping.getProperty();
+
+ MetaObject metaObject = MetaObject.forObject(knownResultObject);
+ Object propertyValue = metaObject.getValue(propertyName);
+ if (propertyValue == null) {
+ if (type == null) {
+ type = metaObject.getSetterType(propertyName);
+ }
+
+ try {
+ // create the object if is it a Collection. If not a
Collection
+ // then we will just set the property to the object created
+ // in processing the nested result map
+ if (Collection.class.isAssignableFrom(type)) {
+ propertyValue = objectFactory.create(type);
+ metaObject.setValue(propertyName, propertyValue);
+ }
+ } catch (Exception e) {
+ throw new ExecutorException("Error instantiating collection
property for result '" + resultMapping.getProperty() + "'. Cause: " + e, e);
+ }
+ }
+
+ Reference<Boolean> foundValues = new Reference(false);
+ Object nestedResultObject =
resultSetHandler.loadResultObject(rs, nestedResultMap, foundValues);
+ if (nestedResultObject != null && nestedResultObject !=
NO_VALUE) {
+ if (propertyValue != null && propertyValue instanceof
Collection) {
+ if (foundValues.get()) {
+ ((Collection) propertyValue).add(nestedResultObject);
+ }
+ } else {
+ metaObject.setValue(propertyName, nestedResultObject);
+ }
+ }
+ } catch (Exception e) {
+ throw new ExecutorException("Error getting nested result map
values for '" + resultMapping.getProperty() + "'. Cause: " + e, e);
+ }
+ }
+ }
+ }
+ } finally {
+ currentNestedKey = previousKey;
+ }
+ return resultObject;
+ }
+
+ private CacheKey createUniqueResultKey(List<ResultMapping> resultMappings,
Object resultObject, CacheKey parentCacheKey) {
+ if (resultObject == null) {
+ return null;
+ } else {
+ MetaObject metaResultObject = MetaObject.forObject(resultObject);
+ CacheKey cacheKey = new CacheKey();
+ cacheKey.update(parentCacheKey);
+ boolean updated = false;
+ if (typeHandlerRegistry.hasTypeHandler(resultObject.getClass())) {
+ cacheKey.update(resultObject);
+ } else {
+ for (ResultMapping resultMapping : resultMappings) {
+ if (resultMapping.getNestedQueryId() == null) {
+ String propName = resultMapping.getProperty();
+ if (propName != null) {
+ cacheKey.update(metaResultObject.getValue(propName));
+ updated = true;
+ }
+ }
+ }
+ }
+ return updated ? cacheKey : null;
+ }
+ }
+
+
+ public void reset() {
+ nestedResultObjects.clear();
+ currentNestedKey = null;
+ }
+}
Added:
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NestedSelectHandler.java
URL:
http://svn.apache.org/viewvc/ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NestedSelectHandler.java?rev=811723&view=auto
==============================================================================
---
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NestedSelectHandler.java
(added)
+++
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NestedSelectHandler.java
Sat Sep 5 22:46:17 2009
@@ -0,0 +1,108 @@
+package org.apache.ibatis.executor.resultset;
+
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.ResultMap;
+import org.apache.ibatis.mapping.ResultMapping;
+import org.apache.ibatis.mapping.Configuration;
+import org.apache.ibatis.executor.loader.ResultLoaderRegistry;
+import org.apache.ibatis.executor.loader.ResultLoader;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.executor.ExecutorException;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.reflection.factory.ObjectFactory;
+import org.apache.ibatis.cache.CacheKey;
+import org.apache.ibatis.type.TypeHandler;
+import org.apache.ibatis.type.TypeHandlerRegistry;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+
+public class NestedSelectHandler {
+
+ private final Configuration configuration;
+ private final Executor executor;
+ private final ObjectFactory objectFactory;
+ private final TypeHandlerRegistry typeHandlerRegistry;
+ private final MappedStatement mappedStatement;
+
+ public NestedSelectHandler(Executor executor, Configuration configuration,
MappedStatement mappedStatement) {
+ this.executor = executor;
+ this.configuration = configuration;
+ this.mappedStatement = mappedStatement;
+ this.objectFactory = configuration.getObjectFactory();
+ this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
+ }
+
+ public Object processNestedSelect(ResultSet rs, ResultMap rm, ResultMapping
resultMapping, ResultLoaderRegistry lazyLoader, Object resultObject)
+ throws SQLException {
+ Configuration configuration = mappedStatement.getConfiguration();
+ MappedStatement nestedQuery =
configuration.getMappedStatement(resultMapping.getNestedQueryId());
+ Class parameterType = nestedQuery.getParameterMap().getType();
+ Object parameterObject = prepareNestedParameterObject(rs, resultMapping,
parameterType);
+ resultObject = processNestedSelectResult(nestedQuery, rm, resultMapping,
lazyLoader, parameterObject, resultObject);
+ return resultObject;
+ }
+
+ private Object processNestedSelectResult(MappedStatement nestedQuery,
ResultMap rm, ResultMapping resultMapping, ResultLoaderRegistry lazyLoader,
Object parameterObject, Object resultObject) {
+ MetaObject metaResultObject = MetaObject.forObject(resultObject);
+ Object value = null;
+ try {
+ if (parameterObject != null) {
+ CacheKey key = executor.createCacheKey(nestedQuery, parameterObject,
Executor.NO_ROW_OFFSET, Executor.NO_ROW_LIMIT);
+ if (executor.isCached(nestedQuery, key)) {
+ executor.deferLoad(nestedQuery, metaResultObject,
resultMapping.getProperty(), key);
+ } else {
+ ResultLoader resultLoader = new ResultLoader(configuration,
executor, nestedQuery, parameterObject, resultMapping.getJavaType());
+ if (lazyLoader == null) {
+ value = resultLoader.loadResult();
+ } else {
+ lazyLoader.registerLoader(resultMapping.getProperty(),
metaResultObject, resultLoader);
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new ExecutorException("Error setting nested bean property. Cause:
" + e, e);
+ }
+ if (typeHandlerRegistry.hasTypeHandler(rm.getType())) {
+ resultObject = value;
+ } else if (value != null) {
+ metaResultObject.setValue(resultMapping.getProperty(), value);
+ }
+ return resultObject;
+ }
+
+
+ private Object prepareNestedParameterObject(ResultSet rs, ResultMapping
resultMapping, Class parameterType) throws SQLException {
+ Object parameterObject;
+ if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
+ TypeHandler th = typeHandlerRegistry.getTypeHandler(parameterType);
+ parameterObject = th.getResult(rs, resultMapping.getColumn());
+ } else {
+ if (parameterType == null) {
+ parameterObject = new HashMap();
+ } else {
+ parameterObject = objectFactory.create(parameterType);
+ }
+ if (resultMapping.isCompositeResult()) {
+ MetaObject metaObject = MetaObject.forObject(parameterObject);
+ for (ResultMapping innerResultMapping : resultMapping.getComposites())
{
+ Class propType =
metaObject.getSetterType(innerResultMapping.getProperty());
+ TypeHandler typeHandler =
typeHandlerRegistry.getTypeHandler(propType);
+ Object propValue = typeHandler.getResult(rs,
innerResultMapping.getColumn());
+ metaObject.setValue(innerResultMapping.getProperty(), propValue);
+ }
+ } else {
+ String columnName = resultMapping.getColumn();
+ TypeHandler typeHandler =
typeHandlerRegistry.getTypeHandler(parameterType);
+ if (typeHandler == null) {
+ typeHandler = typeHandlerRegistry.getUnkownTypeHandler();
+ }
+ parameterObject = typeHandler.getResult(rs, columnName);
+ }
+ }
+ return parameterObject;
+ }
+
+
+}
Added:
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NoValue.java
URL:
http://svn.apache.org/viewvc/ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NoValue.java?rev=811723&view=auto
==============================================================================
---
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NoValue.java
(added)
+++
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/NoValue.java
Sat Sep 5 22:46:17 2009
@@ -0,0 +1,5 @@
+package org.apache.ibatis.executor.resultset;
+
+public enum NoValue {
+ NO_VALUE
+}
Added:
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/Reference.java
URL:
http://svn.apache.org/viewvc/ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/Reference.java?rev=811723&view=auto
==============================================================================
---
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/Reference.java
(added)
+++
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/Reference.java
Sat Sep 5 22:46:17 2009
@@ -0,0 +1,17 @@
+package org.apache.ibatis.executor.resultset;
+
+public class Reference<T> {
+ private T value;
+
+ public Reference(T value) {
+ this.value = value;
+ }
+
+ public T get() {
+ return value;
+ }
+
+ public void set(T value) {
+ this.value = value;
+ }
+}
\ No newline at end of file
Modified:
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/test/java/org/apache/ibatis/builder/BlogMapper.xml
URL:
http://svn.apache.org/viewvc/ibatis/java/ibatis-3/trunk/ibatis-3-core/src/test/java/org/apache/ibatis/builder/BlogMapper.xml?rev=811723&r1=811722&r2=811723&view=diff
==============================================================================
---
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/test/java/org/apache/ibatis/builder/BlogMapper.xml
(original)
+++
ibatis/java/ibatis-3/trunk/ibatis-3-core/src/test/java/org/apache/ibatis/builder/BlogMapper.xml
Sat Sep 5 22:46:17 2009
@@ -33,6 +33,7 @@
<resultMap id="joinedComment" type="domain.blog.Comment">
<id property="id" column="comment_id"/>
+ <!--<association property="post" column="post_id"
resultMap="joinedPost"/>-->
</resultMap>
<resultMap id="joinedTag" type="domain.blog.Tag">