All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.penglecode.mybatis.ex.ExMapperMethod Maven / Gradle / Ivy

Go to download

mybatis的自定义扩展。 版本1.0.0 支持mybatis 3.2|3.3版本 版本1.0.1 支持mybatis 3.4版本

There is a newer version: 1.0.1
Show newest version
package com.penglecode.mybatis.ex;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.binding.BindingException;
import org.apache.ibatis.binding.MapperMethod.SqlCommand;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ParamNameResolver;
import org.apache.ibatis.reflection.TypeParameterResolver;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;

public class ExMapperMethod {

	private final SqlCommand command;
	private final ExMethodSignature method;

	public ExMapperMethod(Class mapperInterface, Method method, Configuration config) {
		this.command = new SqlCommand(config, mapperInterface, method);
		this.method = new ExMethodSignature(config, mapperInterface, method);
	}

	public Object execute(SqlSession sqlSession, Object[] args) {
		Object result;
		switch (command.getType()) {
		case INSERT: {
			result = executeForInsert(sqlSession, args);
			break;
		}
		case UPDATE: {
			result = executeForUpdate(sqlSession, args);
			break;
		}
		case DELETE: {
			result = executeForDelete(sqlSession, args);
			break;
		}
		case SELECT:
			result = executeForSelect(sqlSession, args);
			break;
		case FLUSH:
			result = sqlSession.flushStatements();
			break;
		default:
			throw new BindingException("Unknown execution method for: " + command.getName());
		}
		if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
			throw new BindingException("Mapper method '" + command.getName()
					+ " attempted to return null from a method with a primitive return type (" + method.getReturnType()
					+ ").");
		}
		return result;
	}
	
	protected Object executeForInsert(SqlSession sqlSession, Object[] args) {
		Object param = method.convertArgsToSqlCommandParam(args);
		return rowCountResult(sqlSession.insert(command.getName(), param));
	}
	
	protected Object executeForUpdate(SqlSession sqlSession, Object[] args) {
		Object param = method.convertArgsToSqlCommandParam(args);
		return rowCountResult(sqlSession.update(command.getName(), param));
	}
	
	protected Object executeForDelete(SqlSession sqlSession, Object[] args) {
		Object param = method.convertArgsToSqlCommandParam(args);
		return rowCountResult(sqlSession.delete(command.getName(), param));
	}
	
	protected Object executeForSelect(SqlSession sqlSession, Object[] args) {
		Object result = null;
		if (method.returnsVoid() && method.hasResultHandler()) {
			executeWithResultHandler(sqlSession, args);
			result = null;
		} else if (method.returnsMany()) {
			result = executeForMany(sqlSession, args);
		} else if (method.returnsMap()) {
			result = executeForMap(sqlSession, args);
		} else if (method.returnsCursor()) {
			result = executeForCursor(sqlSession, args);
		} else {
			Object param = method.convertArgsToSqlCommandParam(args);
			result = sqlSession.selectOne(command.getName(), param);
		}
		return result;
	}

	protected Object rowCountResult(int rowCount) {
		final Object result;
		if (method.returnsVoid()) {
			result = null;
		} else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
			result = rowCount;
		} else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
			result = (long) rowCount;
		} else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
			result = rowCount > 0;
		} else {
			throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: "
					+ method.getReturnType());
		}
		return result;
	}

	protected void executeWithResultHandler(SqlSession sqlSession, Object[] args) {
		MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName());
		if (void.class.equals(ms.getResultMaps().get(0).getType())) {
			throw new BindingException(
					"method " + command.getName() + " needs either a @ResultMap annotation, a @ResultType annotation,"
							+ " or a resultType attribute in XML so a ResultHandler can be used as a parameter.");
		}
		Object param = method.convertArgsToSqlCommandParam(args);
		if (method.hasRowBounds()) {
			RowBounds rowBounds = method.extractRowBounds(args);
			sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args));
		} else {
			sqlSession.select(command.getName(), param, method.extractResultHandler(args));
		}
	}

	protected  Object executeForMany(SqlSession sqlSession, Object[] args) {
		List result;
		Object param = method.convertArgsToSqlCommandParam(args);
		if (method.hasRowBounds()) {
			RowBounds rowBounds = method.extractRowBounds(args);
			result = sqlSession.selectList(command.getName(), param, rowBounds);
		} else {
			result = sqlSession.selectList(command.getName(), param);
		}
		// issue #510 Collections & arrays support
		if (!method.getReturnType().isAssignableFrom(result.getClass())) {
			if (method.getReturnType().isArray()) {
				return convertToArray(result);
			} else {
				return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
			}
		}
		return result;
	}

	protected  Cursor executeForCursor(SqlSession sqlSession, Object[] args) {
		Cursor result;
		Object param = method.convertArgsToSqlCommandParam(args);
		if (method.hasRowBounds()) {
			RowBounds rowBounds = method.extractRowBounds(args);
			result = sqlSession.selectCursor(command.getName(), param, rowBounds);
		} else {
			result = sqlSession.selectCursor(command.getName(), param);
		}
		return result;
	}

	protected  Object convertToDeclaredCollection(Configuration config, List list) {
		Object collection = config.getObjectFactory().create(method.getReturnType());
		MetaObject metaObject = config.newMetaObject(collection);
		metaObject.addAll(list);
		return collection;
	}

	@SuppressWarnings("unchecked")
	protected  Object convertToArray(List list) {
		Class arrayComponentType = method.getReturnType().getComponentType();
		Object array = Array.newInstance(arrayComponentType, list.size());
		if (arrayComponentType.isPrimitive()) {
			for (int i = 0; i < list.size(); i++) {
				Array.set(array, i, list.get(i));
			}
			return array;
		} else {
			return list.toArray((E[]) array);
		}
	}

	protected  Map executeForMap(SqlSession sqlSession, Object[] args) {
		Map result;
		Object param = method.convertArgsToSqlCommandParam(args);
		if (method.hasRowBounds()) {
			RowBounds rowBounds = method.extractRowBounds(args);
			result = sqlSession.selectMap(command.getName(), param, method.getMapKey(), rowBounds);
		} else {
			result = sqlSession.selectMap(command.getName(), param, method.getMapKey());
		}
		return result;
	}

	public static class ExMethodSignature {

		private final boolean returnsMany;
		private final boolean returnsMap;
		private final boolean returnsVoid;
		private final boolean returnsCursor;
		private final Class returnType;
		private final String mapKey;
		private final Integer resultHandlerIndex;
		private final Integer rowBoundsIndex;
		private final ParamNameResolver paramNameResolver;

		public ExMethodSignature(Configuration configuration, Class mapperInterface, Method method) {
			Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
			if (resolvedReturnType instanceof Class) {
				this.returnType = (Class) resolvedReturnType;
			} else if (resolvedReturnType instanceof ParameterizedType) {
				this.returnType = (Class) ((ParameterizedType) resolvedReturnType).getRawType();
			} else {
				this.returnType = method.getReturnType();
			}
			this.returnsVoid = void.class.equals(this.returnType);
			this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType)
					|| this.returnType.isArray());
			this.returnsCursor = Cursor.class.equals(this.returnType);
			this.mapKey = getMapKey(method);
			this.returnsMap = (this.mapKey != null);
			this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
			this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
			this.paramNameResolver = new ParamNameResolver(configuration, method);
		}

		public Object convertArgsToSqlCommandParam(Object[] args) {
			return paramNameResolver.getNamedParams(args);
		}

		public boolean hasRowBounds() {
			return rowBoundsIndex != null;
		}

		public RowBounds extractRowBounds(Object[] args) {
			return hasRowBounds() ? (RowBounds) args[rowBoundsIndex] : null;
		}

		public boolean hasResultHandler() {
			return resultHandlerIndex != null;
		}

		public ResultHandler extractResultHandler(Object[] args) {
			return hasResultHandler() ? (ResultHandler) args[resultHandlerIndex] : null;
		}

		public String getMapKey() {
			return mapKey;
		}

		public Class getReturnType() {
			return returnType;
		}

		public boolean returnsMany() {
			return returnsMany;
		}

		public boolean returnsMap() {
			return returnsMap;
		}

		public boolean returnsVoid() {
			return returnsVoid;
		}

		public boolean returnsCursor() {
			return returnsCursor;
		}

		public static Integer getUniqueParamIndex(Method method, Class paramType) {
			Integer index = null;
			final Class[] argTypes = method.getParameterTypes();
			for (int i = 0; i < argTypes.length; i++) {
				if (paramType.isAssignableFrom(argTypes[i])) {
					if (index == null) {
						index = i;
					} else {
						throw new BindingException(method.getName() + " cannot have multiple "
								+ paramType.getSimpleName() + " parameters");
					}
				}
			}
			return index;
		}

		public static String getMapKey(Method method) {
			String mapKey = null;
			if (Map.class.isAssignableFrom(method.getReturnType())) {
				final MapKey mapKeyAnnotation = method.getAnnotation(MapKey.class);
				if (mapKeyAnnotation != null) {
					mapKey = mapKeyAnnotation.value();
				}
			}
			return mapKey;
		}

	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy