public Builder(Configuration configuration, String property) {
   resultMapping.configuration = configuration;
   resultMapping.property = property;
   resultMapping.flags = new ArrayList<org.apache.ibatis.mapping.ResultFlag>();
   resultMapping.composites = new ArrayList<org.apache.ibatis.mapping.ResultMapping>();
   resultMapping.lazy = configuration.isLazyLoadingEnabled();
 }
 private boolean applyPropertyMappings(
     ResultSetWrapper rsw,
     ResultMap resultMap,
     MetaObject metaObject,
     ResultLoaderMap lazyLoader,
     String columnPrefix)
     throws SQLException {
   final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
   boolean foundValues = false;
   final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
   for (ResultMapping propertyMapping : propertyMappings) {
     final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
     if (propertyMapping.isCompositeResult()
         || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
         || propertyMapping.getResultSet() != null) {
       Object value =
           getPropertyMappingValue(
               rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
       final String property = propertyMapping.getProperty(); // issue #541 make property optional
       if (value != NO_VALUE
           && property != null
           && (value != null
               || configuration.isCallSettersOnNulls())) { // issue #377, call setter on nulls
         if (value != null || !metaObject.getSetterType(property).isPrimitive()) {
           metaObject.setValue(property, value);
         }
         foundValues = true;
       }
     }
   }
   return foundValues;
 }
 private Object instantiateCollectionPropertyIfAppropriate(
     ResultMapping resultMapping, MetaObject metaObject) {
   final String propertyName = resultMapping.getProperty();
   Object propertyValue = metaObject.getValue(propertyName);
   if (propertyValue == null) {
     Class<?> type = resultMapping.getJavaType();
     if (type == null) {
       type = metaObject.getSetterType(propertyName);
     }
     try {
       if (objectFactory.isCollection(type)) {
         propertyValue = objectFactory.create(type);
         metaObject.setValue(propertyName, propertyValue);
         return propertyValue;
       }
     } catch (Exception e) {
       throw new ExecutorException(
           "Error instantiating collection property for result '"
               + resultMapping.getProperty()
               + "'.  Cause: "
               + e,
           e);
     }
   } else if (objectFactory.isCollection(propertyValue.getClass())) {
     return propertyValue;
   }
   return null;
 }
 private Object createResultObject(
     ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix)
     throws SQLException {
   final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();
   final List<Object> constructorArgs = new ArrayList<Object>();
   final Object resultObject =
       createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
   if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
     final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
     for (ResultMapping propertyMapping : propertyMappings) {
       if (propertyMapping.getNestedQueryId() != null
           && propertyMapping.isLazy()) { // issue gcode #109 && issue #149
         return configuration
             .getProxyFactory()
             .createProxy(
                 resultObject,
                 lazyLoader,
                 configuration,
                 objectFactory,
                 constructorArgTypes,
                 constructorArgs);
       }
     }
   }
   return resultObject;
 }
 private Object getNestedQueryConstructorValue(
     ResultSet rs, ResultMapping constructorMapping, String columnPrefix) throws SQLException {
   final String nestedQueryId = constructorMapping.getNestedQueryId();
   final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
   final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
   final Object nestedQueryParameterObject =
       prepareParameterForNestedQuery(
           rs, constructorMapping, nestedQueryParameterType, columnPrefix);
   Object value = null;
   if (nestedQueryParameterObject != null) {
     final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
     final CacheKey key =
         executor.createCacheKey(
             nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
     final Class<?> targetType = constructorMapping.getJavaType();
     final ResultLoader resultLoader =
         new ResultLoader(
             configuration,
             executor,
             nestedQuery,
             nestedQueryParameterObject,
             targetType,
             key,
             nestedBoundSql);
     value = resultLoader.loadResult();
   }
   return value;
 }
  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    final List<Object> multipleResults = new ArrayList<Object>();

    int resultSetCount = 0;
    ResultSetWrapper rsw = getFirstResultSet(stmt);

    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    while (rsw != null && resultMapCount > resultSetCount) {
      ResultMap resultMap = resultMaps.get(resultSetCount);
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }

    String[] resultSets = mappedStatement.getResulSets();
    if (resultSets != null) {
      while (rsw != null && resultSetCount < resultSets.length) {
        ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
        if (parentMapping != null) {
          String nestedResultMapId = parentMapping.getNestedResultMapId();
          ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
          handleResultSet(rsw, resultMap, null, parentMapping);
        }
        rsw = getNextResultSet(stmt);
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
      }
    }

    return collapseSingleResultList(multipleResults);
  }
 public org.apache.ibatis.mapping.ResultMapping build() {
   // lock down collections
   resultMapping.flags = Collections.unmodifiableList(resultMapping.flags);
   resultMapping.composites = Collections.unmodifiableList(resultMapping.composites);
   resolveTypeHandler();
   validate();
   return resultMapping;
 }
 private String getColumnPrefix(String parentPrefix, ResultMapping resultMapping) {
   final StringBuilder columnPrefixBuilder = new StringBuilder();
   if (parentPrefix != null) columnPrefixBuilder.append(parentPrefix);
   if (resultMapping.getColumnPrefix() != null)
     columnPrefixBuilder.append(resultMapping.getColumnPrefix());
   final String columnPrefix =
       columnPrefixBuilder.length() == 0
           ? null
           : columnPrefixBuilder.toString().toUpperCase(Locale.ENGLISH);
   return columnPrefix;
 }
 private void createRowKeyForMappedProperties(
     ResultMap resultMap,
     ResultSetWrapper rsw,
     CacheKey cacheKey,
     List<ResultMapping> resultMappings,
     String columnPrefix)
     throws SQLException {
   for (ResultMapping resultMapping : resultMappings) {
     if (resultMapping.getNestedResultMapId() != null
         && resultMapping.getResultSet() == null) { // Issue #392
       final ResultMap nestedResultMap =
           configuration.getResultMap(resultMapping.getNestedResultMapId());
       createRowKeyForMappedProperties(
           nestedResultMap,
           rsw,
           cacheKey,
           nestedResultMap.getConstructorResultMappings(),
           prependPrefix(resultMapping.getColumnPrefix(), columnPrefix));
     } else if (resultMapping.getNestedQueryId() == null) {
       final String column = prependPrefix(resultMapping.getColumn(), columnPrefix);
       final TypeHandler<?> th = resultMapping.getTypeHandler();
       List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
       if (column != null
           && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) { // Issue #114
         final Object value = th.getResult(rsw.getResultSet(), column);
         if (value != null) {
           cacheKey.update(column);
           cacheKey.update(value);
         }
       }
     }
   }
 }
 private Object createPrimitiveResultObject(
     ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
   final Class<?> resultType = resultMap.getType();
   final String columnName;
   if (resultMap.getResultMappings().size() > 0) {
     final List<ResultMapping> resultMappingList = resultMap.getResultMappings();
     final ResultMapping mapping = resultMappingList.get(0);
     columnName = prependPrefix(mapping.getColumn(), columnPrefix);
   } else {
     columnName = rsw.getColumnNames().get(0);
   }
   final TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName);
   return typeHandler.getResult(rsw.getResultSet(), columnName);
 }
 private void resolveTypeHandler() {
   if (resultMapping.typeHandler == null && resultMapping.javaType != null) {
     Configuration configuration = resultMapping.configuration;
     TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
     resultMapping.typeHandler =
         typeHandlerRegistry.getTypeHandler(resultMapping.javaType, resultMapping.jdbcType);
   }
 }
 private Object createParameterizedResultObject(
     ResultSetWrapper rsw,
     Class<?> resultType,
     List<ResultMapping> constructorMappings,
     List<Class<?>> constructorArgTypes,
     List<Object> constructorArgs,
     String columnPrefix)
     throws SQLException {
   boolean foundValues = false;
   for (ResultMapping constructorMapping : constructorMappings) {
     final Class<?> parameterType = constructorMapping.getJavaType();
     final String column = constructorMapping.getColumn();
     final Object value;
     if (constructorMapping.getNestedQueryId() != null) {
       value =
           getNestedQueryConstructorValue(rsw.getResultSet(), constructorMapping, columnPrefix);
     } else if (constructorMapping.getNestedResultMapId() != null) {
       final ResultMap resultMap =
           configuration.getResultMap(constructorMapping.getNestedResultMapId());
       value = getRowValue(rsw, resultMap);
     } else {
       final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
       value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
     }
     constructorArgTypes.add(parameterType);
     constructorArgs.add(value);
     foundValues = value != null || foundValues;
   }
   return foundValues
       ? objectFactory.create(resultType, constructorArgTypes, constructorArgs)
       : null;
 }
 private Object prepareParameterForNestedQuery(
     ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix)
     throws SQLException {
   if (resultMapping.isCompositeResult()) {
     return prepareCompositeKeyParameter(rs, resultMapping, parameterType, columnPrefix);
   } else {
     return prepareSimpleKeyParameter(rs, resultMapping, parameterType, columnPrefix);
   }
 }
 private Object prepareCompositeKeyParameter(
     ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix)
     throws SQLException {
   final Object parameterObject = instantiateParameterObject(parameterType);
   final MetaObject metaObject = configuration.newMetaObject(parameterObject);
   boolean foundValues = false;
   for (ResultMapping innerResultMapping : resultMapping.getComposites()) {
     final Class<?> propType = metaObject.getSetterType(innerResultMapping.getProperty());
     final TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(propType);
     final Object propValue =
         typeHandler.getResult(rs, prependPrefix(innerResultMapping.getColumn(), columnPrefix));
     if (propValue != null) { // issue #353 & #560 do not execute nested query if key is null
       metaObject.setValue(innerResultMapping.getProperty(), propValue);
       foundValues = true;
     }
   }
   return foundValues ? parameterObject : null;
 }
 private void linkToParent(ResultSet rs, ResultMapping parentMapping, Object rowValue)
     throws SQLException {
   CacheKey parentKey =
       createKeyForMultipleResults(
           rs, parentMapping, parentMapping.getColumn(), parentMapping.getForeignColumn());
   PendingRelation parent = pendingRelations.get(parentKey);
   if (parent != null) {
     final Object collectionProperty =
         instantiateCollectionPropertyIfAppropriate(parent.propertyMapping, parent.metaObject);
     if (rowValue != null) {
       if (collectionProperty != null) {
         final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
         targetMetaObject.add(rowValue);
       } else {
         parent.metaObject.setValue(parent.propertyMapping.getProperty(), rowValue);
       }
     }
   }
 }
 private Object prepareSimpleKeyParameter(
     ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix)
     throws SQLException {
   final TypeHandler<?> typeHandler;
   if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
     typeHandler = typeHandlerRegistry.getTypeHandler(parameterType);
   } else {
     typeHandler = typeHandlerRegistry.getUnknownTypeHandler();
   }
   return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
 }
 private Object getNestedQueryMappingValue(
     ResultSet rs,
     MetaObject metaResultObject,
     ResultMapping propertyMapping,
     ResultLoaderMap lazyLoader,
     String columnPrefix)
     throws SQLException {
   final String nestedQueryId = propertyMapping.getNestedQueryId();
   final String property = propertyMapping.getProperty();
   final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
   final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
   final Object nestedQueryParameterObject =
       prepareParameterForNestedQuery(rs, propertyMapping, nestedQueryParameterType, columnPrefix);
   Object value = NO_VALUE;
   if (nestedQueryParameterObject != null) {
     final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
     final CacheKey key =
         executor.createCacheKey(
             nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
     final Class<?> targetType = propertyMapping.getJavaType();
     if (executor.isCached(nestedQuery, key)) {
       executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);
     } else {
       final ResultLoader resultLoader =
           new ResultLoader(
               configuration,
               executor,
               nestedQuery,
               nestedQueryParameterObject,
               targetType,
               key,
               nestedBoundSql);
       if (propertyMapping.isLazy()) {
         lazyLoader.addLoader(property, metaResultObject, resultLoader);
       } else {
         value = resultLoader.loadResult();
       }
     }
   }
   return value;
 }
 private Object getPropertyMappingValue(
     ResultSet rs,
     MetaObject metaResultObject,
     ResultMapping propertyMapping,
     ResultLoaderMap lazyLoader,
     String columnPrefix)
     throws SQLException {
   if (propertyMapping.getNestedQueryId() != null) {
     return getNestedQueryMappingValue(
         rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
   } else if (propertyMapping.getResultSet() != null) {
     addPendingChildRelation(rs, metaResultObject, propertyMapping);
     return NO_VALUE;
   } else if (propertyMapping.getNestedResultMapId() != null) {
     // the user added a column attribute to a nested result map, ignore it
     return NO_VALUE;
   } else {
     final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
     final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
     return typeHandler.getResult(rs, column);
   }
 }
 private boolean applyNestedResultMappings(
     ResultSetWrapper rsw,
     ResultMap resultMap,
     MetaObject metaObject,
     String parentPrefix,
     CacheKey parentRowKey,
     boolean newObject) {
   boolean foundValues = false;
   for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {
     final String nestedResultMapId = resultMapping.getNestedResultMapId();
     if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
       try {
         final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
         final ResultMap nestedResultMap =
             getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix);
         CacheKey rowKey = null;
         Object ancestorObject = null;
         if (ancestorColumnPrefix.containsKey(nestedResultMapId)) {
           rowKey =
               createRowKey(nestedResultMap, rsw, ancestorColumnPrefix.get(nestedResultMapId));
           ancestorObject = ancestorObjects.get(rowKey);
         }
         if (ancestorObject != null) {
           if (newObject) metaObject.setValue(resultMapping.getProperty(), ancestorObject);
         } else {
           rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
           final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
           Object rowValue = nestedResultObjects.get(combinedKey);
           boolean knownValue = (rowValue != null);
           final Object collectionProperty =
               instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
           if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw.getResultSet())) {
             rowValue =
                 getRowValue(rsw, nestedResultMap, combinedKey, rowKey, columnPrefix, rowValue);
             if (rowValue != null && !knownValue) {
               if (collectionProperty != null) {
                 final MetaObject targetMetaObject =
                     configuration.newMetaObject(collectionProperty);
                 targetMetaObject.add(rowValue);
               } else {
                 metaObject.setValue(resultMapping.getProperty(), rowValue);
               }
               foundValues = true;
             }
           }
         }
       } catch (SQLException e) {
         throw new ExecutorException(
             "Error getting nested result map values for '"
                 + resultMapping.getProperty()
                 + "'.  Cause: "
                 + e,
             e);
       }
     }
   }
   return foundValues;
 }
 private boolean anyNotNullColumnHasValue(
     ResultMapping resultMapping, String columnPrefix, ResultSet rs) throws SQLException {
   Set<String> notNullColumns = resultMapping.getNotNullColumns();
   boolean anyNotNullColumnHasValue = true;
   if (notNullColumns != null && !notNullColumns.isEmpty()) {
     anyNotNullColumnHasValue = false;
     for (String column : notNullColumns) {
       rs.getObject(prependPrefix(column, columnPrefix));
       if (!rs.wasNull()) {
         anyNotNullColumnHasValue = true;
         break;
       }
     }
   }
   return anyNotNullColumnHasValue;
 }
 private void validate() {
   // Issue #697: cannot define both nestedQueryId and nestedResultMapId
   if (resultMapping.nestedQueryId != null && resultMapping.nestedResultMapId != null) {
     throw new IllegalStateException(
         "Cannot define both nestedQueryId and nestedResultMapId in property "
             + resultMapping.property);
   }
   // Issue #5: there should be no mappings without typehandler
   if (resultMapping.nestedQueryId == null
       && resultMapping.nestedResultMapId == null
       && resultMapping.typeHandler == null) {
     throw new IllegalStateException(
         "No typehandler found for property " + resultMapping.property);
   }
   // Issue #4 and GH #39: column is optional only in nested resultmaps but not in the rest
   if (resultMapping.nestedResultMapId == null
       && resultMapping.column == null
       && resultMapping.composites.size() == 0) {
     throw new IllegalStateException(
         "Mapping is missing column attribute for property " + resultMapping.property);
   }
   if (resultMapping.getResultSet() != null) {
     int numColums = 0;
     if (resultMapping.column != null) {
       numColums = resultMapping.column.split(",").length;
     }
     int numForeignColumns = 0;
     if (resultMapping.foreignColumn != null) {
       numForeignColumns = resultMapping.foreignColumn.split(",").length;
     }
     if (numColums != numForeignColumns) {
       throw new IllegalStateException(
           "There should be the same number of columns and foreignColumns in property "
               + resultMapping.property);
     }
   }
 }
 private void addPendingChildRelation(
     ResultSet rs, MetaObject metaResultObject, ResultMapping parentMapping) throws SQLException {
   CacheKey cacheKey =
       createKeyForMultipleResults(
           rs, parentMapping, parentMapping.getColumn(), parentMapping.getColumn());
   PendingRelation deferLoad = new PendingRelation();
   deferLoad.metaObject = metaResultObject;
   deferLoad.propertyMapping = parentMapping;
   pendingRelations.put(cacheKey, deferLoad);
   ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet());
   if (previous == null) {
     nextResultMaps.put(parentMapping.getResultSet(), parentMapping);
   } else {
     if (!previous.equals(parentMapping)) {
       throw new ExecutorException("Two different properties are mapped to the same resultSet");
     }
   }
 }
 private Object getDiscriminatorValue(
     ResultSet rs, Discriminator discriminator, String columnPrefix) throws SQLException {
   final ResultMapping resultMapping = discriminator.getResultMapping();
   final TypeHandler<?> typeHandler = resultMapping.getTypeHandler();
   return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
 }
 public Builder foreignColumn(String foreignColumn) {
   resultMapping.foreignColumn = foreignColumn;
   return this;
 }
 public Builder jdbcType(JdbcType jdbcType) {
   resultMapping.jdbcType = jdbcType;
   return this;
 }
 public Builder javaType(Class<?> javaType) {
   resultMapping.javaType = javaType;
   return this;
 }
 public Builder(Configuration configuration, String property, String column, Class<?> javaType) {
   this(configuration, property);
   resultMapping.column = column;
   resultMapping.javaType = javaType;
 }
 public Builder resultSet(String resultSet) {
   resultMapping.resultSet = resultSet;
   return this;
 }
 public Builder(
     Configuration configuration, String property, String column, TypeHandler<?> typeHandler) {
   this(configuration, property);
   resultMapping.column = column;
   resultMapping.typeHandler = typeHandler;
 }
 public Builder nestedQueryId(String nestedQueryId) {
   resultMapping.nestedQueryId = nestedQueryId;
   return this;
 }