diff --git a/README.md b/README.md
index 6c3c1b2..ad6b791 100644
--- a/README.md
+++ b/README.md
@@ -5,4 +5,5 @@
[2.解析xml中静态sql的mapper](https://github.com/FuriousPws002/mini-mybatis/wiki/2.%E8%A7%A3%E6%9E%90xml%E4%B8%AD%E9%9D%99%E6%80%81sql%E7%9A%84mapper "Markdown")
[3.执行静态sql](https://github.com/FuriousPws002/mini-mybatis/wiki/3.%E6%89%A7%E8%A1%8C%E9%9D%99%E6%80%81sql "Markdown")
[4.参数绑定](https://github.com/FuriousPws002/mini-mybatis/wiki/4.%E5%8F%82%E6%95%B0%E7%BB%91%E5%AE%9A "Markdown")
-[5.resultType结果集处理](https://github.com/FuriousPws002/mini-mybatis/wiki/5.resultType%E7%BB%93%E6%9E%9C%E9%9B%86%E5%A4%84%E7%90%86 "Markdown")
\ No newline at end of file
+[5.resultType结果集处理](https://github.com/FuriousPws002/mini-mybatis/wiki/5.resultType%E7%BB%93%E6%9E%9C%E9%9B%86%E5%A4%84%E7%90%86 "Markdown")
+[6.resultMap结果集处理](https://github.com/FuriousPws002/mini-mybatis/wiki/6.resultMap%E7%BB%93%E6%9E%9C%E9%9B%86%E5%A4%84%E7%90%86 "Markdown")
diff --git a/src/main/java/org/apache/ibatis/builder/MapperBuilderAssistant.java b/src/main/java/org/apache/ibatis/builder/MapperBuilderAssistant.java
index 47e8ede..d74130c 100644
--- a/src/main/java/org/apache/ibatis/builder/MapperBuilderAssistant.java
+++ b/src/main/java/org/apache/ibatis/builder/MapperBuilderAssistant.java
@@ -1,13 +1,18 @@
package org.apache.ibatis.builder;
+import java.lang.reflect.Field;
+import java.util.List;
import java.util.Objects;
+import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
+import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.type.TypeHandler;
/**
* @author furious 2024/4/7
@@ -43,11 +48,45 @@ public void addMappedStatement(String id, SqlCommandType sqlCommandType, SqlSour
configuration.addMappedStatement(statement);
}
+ public void addMappedStatement(String id, SqlCommandType sqlCommandType, SqlSource sqlSource, Class> resultTypeClass, String resultMap) {
+ id = currentNamespace + "." + id;
+ MappedStatement statement = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
+ .resource(resource)
+ .resultMap(getStatementResultMap(resultTypeClass, resultMap))
+ .build();
+ configuration.addMappedStatement(statement);
+ }
+
+
+ public ResultMapping buildResultMapping(Class> resultType, String property, String column, String nestedResultMap) throws Exception {
+ Field field = FieldUtils.getDeclaredField(resultType, property, true);
+ Class> propertyType = field.getType();
+ final TypeHandler> typeHandler = configuration.getTypeHandlerRegistry().getTypeHandler(propertyType);
+ ResultMapping resultMapping = new ResultMapping(configuration, property, column, typeHandler);
+ resultMapping.setNestedResultMapId(nestedResultMap);
+ return resultMapping;
+ }
+
+ public ResultMap addResultMap(String id, Class> type, List resultMappings) {
+ ResultMap resultMap = new ResultMap(configuration, type);
+ resultMap.setId(currentNamespace + "." + id);
+ resultMap.setResultMappings(resultMappings);
+ configuration.addResultMap(resultMap);
+ return resultMap;
+ }
+
private ResultMap getStatementResultMap(Class> resultType) {
- if (Objects.isNull(resultType)) {
+ return getStatementResultMap(resultType, null);
+ }
+
+ private ResultMap getStatementResultMap(Class> resultType, String resultMap) {
+ if (Objects.isNull(resultType) && Objects.isNull(resultMap)) {
return null;
}
- return new ResultMap(configuration, resultType);
+ if (Objects.nonNull(resultType)) {
+ return new ResultMap(configuration, resultType);
+ }
+ return configuration.getResultMap(currentNamespace + "." + resultMap);
}
}
diff --git a/src/main/java/org/apache/ibatis/builder/xml/XMLMapperBuilder.java b/src/main/java/org/apache/ibatis/builder/xml/XMLMapperBuilder.java
index 8439100..62efae7 100644
--- a/src/main/java/org/apache/ibatis/builder/xml/XMLMapperBuilder.java
+++ b/src/main/java/org/apache/ibatis/builder/xml/XMLMapperBuilder.java
@@ -1,12 +1,16 @@
package org.apache.ibatis.builder.xml;
import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.apache.ibatis.builder.BaseBuilder;
import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.builder.MapperBuilderAssistant;
+import org.apache.ibatis.mapping.ResultMap;
+import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.parsing.XPathParser;
import org.apache.ibatis.session.Configuration;
@@ -43,6 +47,7 @@ private void configurationElement(XNode context) {
if (Objects.isNull(namespace) || namespace.isEmpty()) {
throw new BuilderException("mapper namespace can not be empty");
}
+ resultMapElements(context.evalNodes("resultMap"));
buildStatementFromContext(context.evalNodes("insert|select"));
} catch (Exception e) {
throw new BuilderException("parse mapper xml error", e);
@@ -55,4 +60,44 @@ private void buildStatementFromContext(List list) {
statementParser.parseStatementNode();
}
}
+
+ private void resultMapElements(List list) {
+ for (XNode resultMapNode : list) {
+ try {
+ resultMapElement(resultMapNode);
+ } catch (Exception ignored) {
+ }
+ }
+ }
+
+ private ResultMap resultMapElement(XNode resultMapNode) throws Exception {
+ return resultMapElement(resultMapNode, Collections.emptyList(), null);
+ }
+
+ private ResultMap resultMapElement(XNode resultMapNode, List additionalResultMappings, Class> enclosingType) throws Exception {
+ String type = resultMapNode.getAttribute("type", resultMapNode.getAttribute("ofType"));
+ Class> typeClass = resolveClass(type);
+ List resultMappings = new ArrayList<>(additionalResultMappings);
+ List resultChildren = resultMapNode.getChildren();
+ for (XNode resultChild : resultChildren) {
+ resultMappings.add(buildResultMappingFromContext(resultChild, typeClass));
+ }
+ String id = resultMapNode.getAttribute("id", resultMapNode.id());
+ return builderAssistant.addResultMap(id, typeClass, resultMappings);
+ }
+
+ private ResultMapping buildResultMappingFromContext(XNode context, Class> resultType) throws Exception {
+ String property = context.getAttribute("property");
+ String column = context.getAttribute("column");
+ String nestedResultMap = processNestedResultMappings(context, Collections.emptyList(), resultType);
+ return builderAssistant.buildResultMapping(resultType, property, column, nestedResultMap);
+ }
+
+ private String processNestedResultMappings(XNode context, List resultMappings, Class> enclosingType) throws Exception {
+ if (Objects.equals(context.getName(), "collection")) {
+ ResultMap resultMap = resultMapElement(context, resultMappings, enclosingType);
+ return resultMap.getId();
+ }
+ return null;
+ }
}
diff --git a/src/main/java/org/apache/ibatis/builder/xml/XMLStatementBuilder.java b/src/main/java/org/apache/ibatis/builder/xml/XMLStatementBuilder.java
index 86e9f7d..61271d0 100644
--- a/src/main/java/org/apache/ibatis/builder/xml/XMLStatementBuilder.java
+++ b/src/main/java/org/apache/ibatis/builder/xml/XMLStatementBuilder.java
@@ -38,7 +38,8 @@ public void parseStatementNode() {
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
SqlSource sqlSource = configuration.getLanguageDriver().createSqlSource(configuration, context, null);
String resultType = context.getAttribute("resultType");
+ String resultMap = context.getAttribute("resultMap");
Class> resultTypeClass = resolveClass(resultType);
- builderAssistant.addMappedStatement(id, sqlCommandType, sqlSource,resultTypeClass);
+ builderAssistant.addMappedStatement(id, sqlCommandType, sqlSource, resultTypeClass, resultMap);
}
}
diff --git a/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java b/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java
index b5aca6c..61e4f9f 100644
--- a/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java
+++ b/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java
@@ -1,18 +1,27 @@
package org.apache.ibatis.executor.resultset;
import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
+import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
@@ -54,9 +63,80 @@ private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List multipleResults) throws SQLException {
- handleRowValuesForSimpleResultMap(rsw, resultMap, multipleResults);
+ if (resultMap.hasNestedResultMaps()) {
+ handleRowValuesForNestedResultMap(rsw, resultMap, multipleResults);
+ } else {
+ handleRowValuesForSimpleResultMap(rsw, resultMap, multipleResults);
+ }
+ }
+
+ private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, List