Skip to content

Commit

Permalink
Merge pull request #6 from FuriousPws002/05-result-set-handler-with-r…
Browse files Browse the repository at this point in the history
…esult-type

05 result set handler with result type
  • Loading branch information
FuriousPws002 authored Apr 12, 2024
2 parents f3bb54f + 144c93f commit 8218983
Show file tree
Hide file tree
Showing 29 changed files with 495 additions and 5 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
[1.注册Mapper接口](https://github.com/FuriousPws002/mini-mybatis/wiki/1.%E6%B3%A8%E5%86%8CMapper%E6%8E%A5%E5%8F%A3 "Markdown") <br>
[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") <br>
[3.执行静态sql](https://github.com/FuriousPws002/mini-mybatis/wiki/3.%E6%89%A7%E8%A1%8C%E9%9D%99%E6%80%81sql "Markdown") <br>
[4.参数绑定](https://github.com/FuriousPws002/mini-mybatis/wiki/4.%E5%8F%82%E6%95%B0%E7%BB%91%E5%AE%9A "Markdown") <br>
[4.参数绑定](https://github.com/FuriousPws002/mini-mybatis/wiki/4.%E5%8F%82%E6%95%B0%E7%BB%91%E5%AE%9A "Markdown") <br>
[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") <br>
15 changes: 14 additions & 1 deletion src/main/java/org/apache/ibatis/binding/MapperMethod.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.apache.ibatis.binding;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Objects;

import org.apache.ibatis.mapping.MappedStatement;
Expand All @@ -23,18 +24,28 @@ public MapperMethod(Class<?> mapperInterface, Method method, Configuration confi
}

public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
Object result = null;
switch (command.getType()) {
case INSERT: {
result = sqlSession.insert(command.getName(), method.convertArgsToSqlCommandParam(args));
break;
}
case SELECT: {
if (method.returnsMany) {
result = executeForMany(sqlSession, args);
}
break;
}
default:
throw new BindingException(command.getType() + " not support");
}
return result;
}

private <T> Object executeForMany(SqlSession sqlSession, Object[] args) {
return sqlSession.selectList(command.getName(), method.convertArgsToSqlCommandParam(args));
}

public static class SqlCommand {

private final String name;
Expand Down Expand Up @@ -63,9 +74,11 @@ public SqlCommandType getType() {
public static class MethodSignature {

private final ParamNameResolver paramNameResolver;
private final boolean returnsMany;

public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
this.paramNameResolver = new ParamNameResolver(method);
returnsMany = Collection.class.isAssignableFrom(method.getReturnType());
}

public Object convertArgsToSqlCommandParam(Object[] args) {
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/org/apache/ibatis/builder/BaseBuilder.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.apache.ibatis.builder;

import java.util.Objects;

import org.apache.commons.lang3.ClassUtils;
import org.apache.ibatis.session.Configuration;

/**
Expand All @@ -16,4 +19,16 @@ public BaseBuilder(Configuration configuration) {
public Configuration getConfiguration() {
return configuration;
}

@SuppressWarnings("unchecked")
protected <T> Class<? extends T> resolveClass(String className) {
if (Objects.isNull(className)) {
return null;
}
try {
return (Class<? extends T>) ClassUtils.getClass(className);
} catch (Exception e) {
throw new BuilderException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.apache.ibatis.builder;


import java.util.Objects;

import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.session.Configuration;
Expand Down Expand Up @@ -30,4 +33,21 @@ public void addMappedStatement(String id, SqlCommandType sqlCommandType, SqlSour
.build();
configuration.addMappedStatement(statement);
}

public void addMappedStatement(String id, SqlCommandType sqlCommandType, SqlSource sqlSource, Class<?> resultTypeClass) {
id = currentNamespace + "." + id;
MappedStatement statement = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
.resource(resource)
.resultMap(getStatementResultMap(resultTypeClass))
.build();
configuration.addMappedStatement(statement);
}

private ResultMap getStatementResultMap(Class<?> resultType) {
if (Objects.isNull(resultType)) {
return null;
}
return new ResultMap(configuration, resultType);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ private void configurationElement(XNode context) {
if (Objects.isNull(namespace) || namespace.isEmpty()) {
throw new BuilderException("mapper namespace can not be empty");
}
buildStatementFromContext(context.evalNodes("insert"));
buildStatementFromContext(context.evalNodes("insert|select"));
} catch (Exception e) {
throw new BuilderException("parse mapper xml error", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Locale;

import org.apache.commons.lang3.ClassUtils;
import org.apache.ibatis.builder.BaseBuilder;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.builder.StaticSqlSource;
Expand Down Expand Up @@ -36,6 +37,8 @@ public void parseStatementNode() {
String nodeName = context.getName();
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
SqlSource sqlSource = configuration.getLanguageDriver().createSqlSource(configuration, context, null);
builderAssistant.addMappedStatement(id, sqlCommandType, sqlSource);
String resultType = context.getAttribute("resultType");
Class<?> resultTypeClass = resolveClass(resultType);
builderAssistant.addMappedStatement(id, sqlCommandType, sqlSource,resultTypeClass);
}
}
3 changes: 3 additions & 0 deletions src/main/java/org/apache/ibatis/executor/Executor.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.apache.ibatis.executor;

import java.sql.SQLException;
import java.util.List;

import org.apache.ibatis.mapping.MappedStatement;

Expand All @@ -10,4 +11,6 @@
public interface Executor {

int update(MappedStatement ms, Object parameter) throws SQLException;

<T> List<T> query(MappedStatement ms, Object parameter) throws SQLException;
}
13 changes: 13 additions & 0 deletions src/main/java/org/apache/ibatis/executor/SimpleExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Objects;

import org.apache.ibatis.executor.statement.StatementHandler;
Expand Down Expand Up @@ -36,6 +37,18 @@ public int update(MappedStatement ms, Object parameter) throws SQLException {
}
}

@Override
public <T> List<T> query(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, null);
stmt = prepareStatement(handler);
return handler.query(stmt);
} finally {
StatementUtil.closeStatement(stmt);
}
}

private Statement prepareStatement(StatementHandler handler) throws SQLException {
Statement stmt;
Connection connection = configuration.getDataSource().getConnection();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.apache.ibatis.executor.result;

/**
* @author furious 2024/4/11
*/
public class ResultMapException extends RuntimeException{

public ResultMapException() {
super();
}

public ResultMapException(String message) {
super(message);
}

public ResultMapException(String message, Throwable cause) {
super(message, cause);
}

public ResultMapException(Throwable cause) {
super(cause);
}

protected ResultMapException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package org.apache.ibatis.executor.resultset;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;

/**
* @author furious 2024/4/12
*/
public class DefaultResultSetHandler implements ResultSetHandler {

private final Configuration configuration;
private final MappedStatement mappedStatement;
private final TypeHandlerRegistry typeHandlerRegistry;

public DefaultResultSetHandler(MappedStatement mappedStatement) {
this.configuration = mappedStatement.getConfiguration();
this.mappedStatement = mappedStatement;
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
}

@Override
public <T> List<T> handleResultSets(Statement stmt) throws SQLException {
final List<Object> multipleResults = new ArrayList<>();
ResultSet rs = stmt.getResultSet();
if (Objects.isNull(rs)) {
return Collections.emptyList();
}
ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);
ResultMap resultMap = mappedStatement.getResultMap();
handleResultSet(rsw, resultMap, multipleResults);
return (List<T>) multipleResults;
}

private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults) throws SQLException {
try {
handleRowValues(rsw, resultMap, multipleResults);
} finally {
closeResultSet(rsw.getResultSet());
}
}

private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults) throws SQLException {
handleRowValuesForSimpleResultMap(rsw, resultMap, multipleResults);
}

private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults) throws SQLException {
ResultSet resultSet = rsw.getResultSet();
while (!resultSet.isClosed() && resultSet.next()) {
Object rowValue = getRowValue(rsw, resultMap);
multipleResults.add(rowValue);
}
}

private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
Object rowValue = createResultObject(resultMap);
applyAutomaticMappings(rsw, rowValue);
return rowValue;
}

private boolean applyAutomaticMappings(ResultSetWrapper rsw, Object rowValue) throws SQLException {
List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, rowValue);
boolean foundValues = false;
if (!autoMapping.isEmpty()) {
for (UnMappedColumnAutoMapping mapping : autoMapping) {
final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
if (value != null) {
foundValues = true;
}
try {
FieldUtils.writeField(rowValue, mapping.property, value, true);
} catch (IllegalAccessException e) {
ExceptionUtils.rethrow(e);
}
}
}
return foundValues;
}

private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, Object rowValue) {
List<UnMappedColumnAutoMapping> autoMapping = new ArrayList<>();
List<String> columnLabels = rsw.getColumnLabels();
for (String columnLabel : columnLabels) {
Field field = FieldUtils.getDeclaredField(rowValue.getClass(), columnLabel, true);
String property = Objects.isNull(field) ? null : columnLabel;
if (Objects.nonNull(property)) {
Class<?> propertyType = field.getType();
if (typeHandlerRegistry.hasTypeHandler(propertyType)) {
final TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(propertyType);
autoMapping.add(new UnMappedColumnAutoMapping(columnLabel, property, typeHandler));
}
}
}
return autoMapping;
}

private Object createResultObject(ResultMap resultMap) throws SQLException {
try {
return resultMap.getType().newInstance();
} catch (Exception e) {
throw new SQLException("create return type fail " + e);
}
}

private void closeResultSet(ResultSet rs) {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ignored) {
}
}

/**
* 数据库中列和对象中属性映射
*/
private static class UnMappedColumnAutoMapping {
private final String column;
private final String property;
private final TypeHandler<?> typeHandler;

public UnMappedColumnAutoMapping(String column, String property, TypeHandler<?> typeHandler) {
this.column = column;
this.property = property;
this.typeHandler = typeHandler;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.apache.ibatis.executor.resultset;

import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

/**
* @author furious 2024/4/11
*/
public interface ResultSetHandler {

<T> List<T> handleResultSets(Statement stmt) throws SQLException;
}
Loading

0 comments on commit 8218983

Please sign in to comment.