Mybatis源码-插件实现
目录
插件实现原理 #
MyBatis框架允许用户通过自定义拦截器的方式改变SQL的执行行为,例如在SQL执行时追加SQL分页语法,从而达到简化分页查询的目的。用户自定义的拦截器也被称为MyBatis插件。
在MyBatis主配置文件中,可以通过<plugins>标签注册用户自定义的插件信息,
<plugins>
<plugin interceptor="com.blog4java.plugin.pager.PageInterceptor">
<property name="databaseType" value="hsqldb"/>
</plugin>
</plugins>
MyBatis的插件实际上就是一个拦截器,Configuration类中维护了一个InterceptorChain的实例,
public class Configuration {
protected final InterceptorChain interceptorChain = new InterceptorChain();
public List<Interceptor> getInterceptors() {
return interceptorChain.getInterceptors();
}
public void addInterceptor(Interceptor interceptor) {
interceptorChain.addInterceptor(interceptor);
}
}
插件xml的解析过程:
// org.apache.ibatis.builder.xml.XMLConfigBuilder#parseConfiguration
pluginElement(root.evalNode("plugins"));
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
// 获取<plugin>标签的interceptor属性
String interceptor = child.getStringAttribute("interceptor");
// 获取拦截器属性,转换为Properties对象
Properties properties = child.getChildrenAsProperties();
// 创建拦截器实例
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
// 设置拦截器实例属性信息
interceptorInstance.setProperties(properties);
// 將拦截器实例添加到拦截器链中
configuration.addInterceptor(interceptorInstance);
}
}
用户自定义的插件只能对MyBatis中的4种组件的方法进行拦截,这4种组件及方法如下:
- Executor(update,query,flushStatements,commit,rollback,getTransaction,close,isClosd)
- ParameterHandler(getParameterObject,setParameters)
- ResultSetHandler(handleResultSets,handleOutputParameters)
- StatementHandler (prpare,parameterize,batch,update,qury)
MyBatis 使用工厂方法创建Executor、ParameterHandler、ResultSetHandler、StatementHandler组件的实例,其中一个原因是可以根据用户配置的参数创建不同实现类的实例;另一个比较重要的原因是可以在工厂方法中执行拦截逻辑。我们不妨看一下Configuration类中这些工厂方法的实现,代码如下:
// 插件的执行地方
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
// 执行拦截器链的拦截逻辑
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
// 执行拦截器链的拦截逻辑
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
// 执行拦截器链的拦截逻辑
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
// 根据executor类型创建对象的Executor对象
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
// 如果cacheEnabled属性为ture,这使用CachingExecutor对上面创建的Executor进行装饰
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
// 执行拦截器链的拦截逻辑
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
// 插件的执行原理
// org.apache.ibatis.plugin.InterceptorChain#pluginAll
// 调用所有拦截器对象的plugin()方法执行拦截逻辑
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
MyBatis中所有用户自定义的插件都必须实现Interceptor接口,该接口的定义如下:
public interface Interceptor {
//intercept()方法用于定义拦截逻辑,该方法会在目标方法调用时执行。。setPropertiesO方法用于设置插件的属性值。需要注意的是,
//intercept()接收一个Invocation对象作为参数,Invocation对象中封装了目标对象的方法及参数信息。Invocation类的实现代码如下:
Object intercept(Invocation invocation) throws Throwable;
// plugin()方法用于创建Executor、ParameterHandler、ResultSetHandler或 StatementHandler的代理对象,该方法的参数即为Executor、ParameterHandler、ResultSetHandler或StatementHandler组件的实例
Object plugin(Object target);
void setProperties(Properties properties);
}
public class Invocation {
// 目标对象,即ParameterHandler、ResultSetHandler、StatementHandler或者Executor实例
private final Object target;
// 目标方法,即拦截的方法
private final Method method;
// 目标方法参数
private final Object[] args;
public Invocation(Object target, Method method, Object[] args) {
this.target = target;
this.method = method;
this.args = args;
}
public Object getTarget() {
return target;
}
public Method getMethod() {
return method;
}
public Object[] getArgs() {
return args;
}
/**
* 执行目标方法
* @return 目标方法执行结果
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
public Object proceed() throws InvocationTargetException, IllegalAccessException {
return method.invoke(target, args);
}
}
如上面的代码所示,Invocation类中封装了目标对象、目标方法及参数信息,我们可以通过Invocation对象获取目标对象(Executor、ParameterHandler、ResultSetHandler或StatementHandler)的所有信息。另外,Invocation 类中提供了一个proceed()方法,该方法用于执行目标方法的逻辑。所以在自定义插件类中,拦截逻辑执行完毕后一般都需要调用proceed()方法执行目标方法的原有逻辑。
Mybatis官方提供的一个插件案例:
@Intercepts({})
public class ExamplePlugin implements Interceptor {
private Properties properties;
@Override
public Object intercept(Invocation invocation) throws Throwable {
// TODO:自定义拦截逻辑
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
// 调用Plugin类的wrap()方法返回一个动态代理对象
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// 设置插件的属性信息
this.properties = properties;
}
public Properties getProperties() {
return properties;
}
}
为了便于用户创建Executor、ParameterHandler、ResultSetHandler 或 StatementHandler 实例的代理对象,MyBatis中提供了一个Plugin工具类。
public class Plugin implements InvocationHandler {
//目标对象,即Executor、ParameterHandler、ResultSetHandler、StatementHandler对象
private final Object target;
// 用户自定义拦截器实例
private final Interceptor interceptor;
// Intercepts注解指定的方法
private final Map<Class<?>, Set<Method>> signatureMap;
private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
this.target = target;
this.interceptor = interceptor;
this.signatureMap = signatureMap;
}
/**
* 该方法用于创建Executor、ParameterHandler、ResultSetHandler、StatementHandler的代理对象
* @param target
* @param interceptor
* @return
*/
public static Object wrap(Object target, Interceptor interceptor) {
// 调用getSignatureMap()方法获取自定义插件中,通过Intercepts注解指定的方法
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 如果该方法是Intercepts注解指定的方法,则调用拦截器实例的intercept()方法执行拦截逻辑
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
if (methods != null && methods.contains(method)) {
return interceptor.intercept(new Invocation(target, method, args));
}
return method.invoke(target, args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
// 获取Intercepts注解信息
Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
if (interceptsAnnotation == null) {
throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
}
// 获取所有Signature注解信息
Signature[] sigs = interceptsAnnotation.value();
Map<Class<?>, Set<Method>> signatureMap = new HashMap<Class<?>, Set<Method>>();
// 对所有Signature注解进行遍历,把Signature注解指定拦截的组件及方法添加到Map中
for (Signature sig : sigs) {
Set<Method> methods = signatureMap.get(sig.type());
if (methods == null) {
methods = new HashSet<Method>();
signatureMap.put(sig.type(), methods);
}
try {
Method method = sig.type().getMethod(sig.method(), sig.args());
methods.add(method);
} catch (NoSuchMethodException e) {
throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
}
}
return signatureMap;
}
/**
* 获取目标类型的接口信息
* @param type
* @param signatureMap
* @return
*/
private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {
Set<Class<?>> interfaces = new HashSet<Class<?>>();
while (type != null) {
for (Class<?> c : type.getInterfaces()) {
if (signatureMap.containsKey(c)) {
interfaces.add(c);
}
}
type = type.getSuperclass();
}
return interfaces.toArray(new Class<?>[interfaces.size()]);
}
}
在Plugin类的getSignatureMap()方法中,首先获取Intercepts 注解,然后获取Intercepts注解中配置的所有Signature注解,接着对所有的Signature注解信息进行遍历,将Signature 注解中指定要拦截的组件及方法添加到Map对象中,其中Key为Executor、ParameterHandler、ResultSetHandler或StatementHandler对应的 Class对象,Value为拦截的所有方法对应的Method对象数组。
当我们需要自定义一个MyBatis插件时,只需要实现Interceptor接口,在intercept()方法中编写拦截逻辑,通过plugin()方法返回一个动态代理对象,通过setProperties()方法设置
执行过程图解 #
自定义分页插件的实现 #
首先定义一个Page类:
public interface Paginable<T> {
/** 总记录数 */
int getTotalCount();
/** 总页数 */
int getTotalPage();
/** 每页记录数 */
int getPageSize();
/** 当前页号 */
int getPageNo();
/** 是否第一页 */
boolean isFirstPage();
/** 是否最后一页 */
boolean isLastPage();
/** 返回下页的页号 */
int getNextPage();
/** 返回上页的页号 */
int getPrePage();
/** 取得当前页显示的项的起始序号 */
int getBeginIndex();
/** 取得当前页显示的末项序号 */
int getEndIndex();
/** 获取开始页*/
int getBeginPage();
/** 获取结束页*/
int getEndPage();
}
public class Page<T> implements Paginable<T> {
public static final int DEFAULT_PAGE_SIZE = 10; // 默认每页记录数
public static final int PAGE_COUNT = 10;
private int pageNo = 1; // 页码
private int pageSize = DEFAULT_PAGE_SIZE; // 每页记录数
private int totalCount = 0; // 总记录数
private int totalPage = 0; // 总页数
private long timestamp = 0; // 查询时间戳
private boolean full = false; // 是否全量更新 //false 不更新totalcount
public int getPageNo() {
return pageNo;
}
public void setPageNo(int pageNo) {
this.pageNo = pageNo;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
int totalPage = totalCount % pageSize == 0 ? totalCount / pageSize : totalCount / pageSize + 1;
this.setTotalPage(totalPage);
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public boolean isFirstPage() {
return pageNo <= 1;
}
public boolean isLastPage() {
return pageNo >= totalPage;
}
public int getNextPage() {
return isLastPage() ? pageNo : (pageNo + 1);
}
public int getPrePage() {
return isFirstPage() ? pageNo : (pageNo - 1);
}
public int getBeginIndex() {
if (pageNo > 0) {
return (pageSize * (pageNo - 1));
} else {
return 0;
}
}
public int getEndIndex() {
if (pageNo > 0) {
return Math.min(pageSize * pageNo, totalCount);
} else {
return 0;
}
}
public int getBeginPage() {
if (pageNo > 0) {
return (PAGE_COUNT * ((pageNo - 1) / PAGE_COUNT)) + 1;
} else {
return 0;
}
}
public int getEndPage() {
if (pageNo > 0) {
return Math.min(PAGE_COUNT * ((pageNo - 1) / PAGE_COUNT + 1), getTotalPage());
} else {
return 0;
}
}
public boolean isFull() {
return full;
}
public void setFull(boolean full) {
this.full = full;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
}
@Intercepts({
@Signature(method = "prepare", type = StatementHandler.class, args = {Connection.class, Integer.class})
})
public class PageInterceptor implements Interceptor {
private String databaseType;
public Object intercept(Invocation invocation) throws Throwable {
// 获取拦截的目标对象
RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
StatementHandler delegate = (StatementHandler) ReflectionUtils.getFieldValue(handler, "delegate");
BoundSql boundSql = delegate.getBoundSql();
// 获取参数对象,当参数对象为Page的子类时执行分页操作
Object parameterObject = boundSql.getParameterObject();
if (parameterObject instanceof Page<?>) {
Page<?> page = (Page<?>) parameterObject;
MappedStatement mappedStatement = (MappedStatement) ReflectionUtils.getFieldValue(delegate, "mappedStatement");
Connection connection = (Connection) invocation.getArgs()[0];
String sql = boundSql.getSql();
if (page.isFull()) {
// 获取记录总数
this.setTotalCount(page, mappedStatement, connection);
}
page.setTimestamp(System.currentTimeMillis());
// 获取分页SQL
String pageSql = this.getPageSql(page, sql);
// 将原始SQL语句替换成分页语句
ReflectionUtils.setFieldValue(boundSql, "sql", pageSql);
}
return invocation.proceed();
}
/**
* 拦截器对应的封装原始对象的方法
*/
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
/**
* 设置注册拦截器时设定的属性
*/
public void setProperties(Properties properties) {
this.databaseType = properties.getProperty("databaseType");
}
/**
* 根据page对象获取对应的分页查询Sql语句,
* 这里只做了三种数据库类型,Mysql、Oracle、HSQLDB
* 其它的数据库都没有进行分页
*
* @param page 分页对象
* @param sql 原始sql语句
* @return
*/
private String getPageSql(Page<?> page, String sql) {
StringBuffer sqlBuffer = new StringBuffer(sql);
if ("mysql".equalsIgnoreCase(databaseType)) {
return getMysqlPageSql(page, sqlBuffer);
} else if ("oracle".equalsIgnoreCase(databaseType)) {
return getOraclePageSql(page, sqlBuffer);
} else if ("hsqldb".equalsIgnoreCase(databaseType)) {
return getHSQLDBPageSql(page, sqlBuffer);
}
return sqlBuffer.toString();
}
/**
* 获取Mysql数据库的分页查询语句
*
* @param page 分页对象
* @param sqlBuffer 包含原sql语句的StringBuffer对象
* @return Mysql数据库分页语句
*/
private String getMysqlPageSql(Page<?> page, StringBuffer sqlBuffer) {
int offset = (page.getPageNo() - 1) * page.getPageSize();
sqlBuffer.append(" limit ").append(offset).append(",").append(page.getPageSize());
return sqlBuffer.toString();
}
/**
* 获取Oracle数据库的分页查询语句
*
* @param page 分页对象
* @param sqlBuffer 包含原sql语句的StringBuffer对象
* @return Oracle数据库的分页查询语句
*/
private String getOraclePageSql(Page<?> page, StringBuffer sqlBuffer) {
int offset = (page.getPageNo() - 1) * page.getPageSize() + 1;
sqlBuffer.insert(0, "select u.*, rownum r from (").append(") u where rownum < ")
.append(offset + page.getPageSize());
sqlBuffer.insert(0, "select * from (").append(") where r >= ").append(offset);
return sqlBuffer.toString();
}
/**
* 获取HSQLDB数据库的分页查询语句
*
* @param page 分页对象
* @param sqlBuffer 包含原sql语句的StringBuffer对象
* @return Oracle数据库的分页查询语句
*/
private String getHSQLDBPageSql(Page<?> page, StringBuffer sqlBuffer) {
int offset = (page.getPageNo() - 1) * page.getPageSize() + 1;
String sql = "select limit " + offset + " " + page.getPageSize() + " * from (" + sqlBuffer.toString() + " )";
return sql;
}
/**
* 给当前的参数对象page设置总记录数
*
* @param page Mapper映射语句对应的参数对象
* @param mappedStatement Mapper映射语句
* @param connection 当前的数据库连接
*/
private void setTotalCount(Page<?> page, MappedStatement mappedStatement, Connection connection) {
BoundSql boundSql = mappedStatement.getBoundSql(page);
String sql = boundSql.getSql();
// 获取总记录数
String countSql = this.getCountSql(sql);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
BoundSql countBoundSql = new BoundSql(mappedStatement.getConfiguration(), countSql, parameterMappings, page);
ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, page, countBoundSql);
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = connection.prepareStatement(countSql);
parameterHandler.setParameters(pstmt);
rs = pstmt.executeQuery();
if (rs.next()) {
int totalCount = rs.getInt(1);
page.setTotalCount(totalCount);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(rs);
IOUtils.closeQuietly(pstmt);
}
}
/**
* 根据原Sql语句获取对应的查询总记录数的Sql语句
*
* @param sql
* @return
*/
private String getCountSql(String sql) {
return "select count(1) " + sql.substring(sql.toLowerCase().indexOf("from"));
}
}
自定义慢SQL插件的实现 #
来编写一个统计慢SQL插件。通过该插件,我们可以把执行时间超过若干秒的SQL语句输出到日志中,这样就可以有针对性地对SQL语句进行优化。该插件代码如下:
@Intercepts({
@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
@Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
@Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})
})
public class SlowSqlInterceptor implements Interceptor {
private Integer limitSecond;
@Override
public Object intercept(Invocation invocation) throws InvocationTargetException, IllegalAccessException {
long beginTimeMillis = System.currentTimeMillis();
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
try {
return invocation.proceed();
} finally {
long endTimeMillis = System.currentTimeMillis();
long costTimeMillis = endTimeMillis - beginTimeMillis;
if (costTimeMillis > limitSecond * 1000) {
BoundSql boundSql = statementHandler.getBoundSql();
// 调用getFormatedSql()方法对参数占位符进行替换
String sql = getFormatedSql(boundSql);
System.out.println("SQL语句【" + sql + "】,执行耗时:" + costTimeMillis + "ms");
}
}
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
String limitSecond = (String) properties.get("limitSecond");
this.limitSecond = Integer.parseInt(limitSecond);
}
private String getFormatedSql(BoundSql boundSql) {
String sql = boundSql.getSql();
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
sql = beautifySql(sql);
if (parameterObject == null || parameterMappings == null || parameterMappings.isEmpty()) {
return sql;
}
String sqlWithoutReplacePlaceholder = sql;
try {
if (parameterMappings != null) {
Class<?> parameterObjectClass = parameterObject.getClass();
if (isStrictMap(parameterObjectClass)) {
DefaultSqlSession.StrictMap<Collection<?>> strictMap = (DefaultSqlSession.StrictMap<Collection<?>>) parameterObject;
if (isList(strictMap.get("list").getClass())) {
sql = handleListParameter(sql, strictMap.get("list"));
}
} else if (isMap(parameterObjectClass)) {
Map<?, ?> paramMap = (Map<?, ?>) parameterObject;
sql = handleMapParameter(sql, paramMap, parameterMappings);
} else {
sql = handleCommonParameter(sql, parameterMappings, parameterObjectClass, parameterObject);
}
}
} catch (Exception e) {
return sqlWithoutReplacePlaceholder;
}
return sql;
}
private String beautifySql(String sql) {
sql = sql.replace("\n", "")
.replace("\t", "")
.replace(" ", " ")
.replace("( ", "(")
.replace(" )", ")")
.replace(" ,", ",");
return sql;
}
private String handleListParameter(String sql, Collection<?> col) {
if (col != null && col.size() != 0) {
for (Object obj : col) {
String value = null;
Class<?> objClass = obj.getClass();
if (isPrimitiveOrPrimitiveWrapper(objClass)) {
value = obj.toString();
} else if (objClass.isAssignableFrom(String.class)) {
value = "\"" + obj.toString() + "\"";
}
sql = sql.replaceFirst("\\?", value);
}
}
return sql;
}
private String handleMapParameter(String sql, Map<?, ?> paramMap, List<ParameterMapping> parameterMappingList) {
for (ParameterMapping parameterMapping : parameterMappingList) {
Object propertyName = parameterMapping.getProperty();
Object propertyValue = paramMap.get(propertyName);
if (propertyValue != null) {
if (propertyValue.getClass().isAssignableFrom(String.class)) {
propertyValue = "\"" + propertyValue + "\"";
}
sql = sql.replaceFirst("\\?", propertyValue.toString());
}
}
return sql;
}
private String handleCommonParameter(String sql, List<ParameterMapping> parameterMappingList,
Class<?> parameterObjectClass,
Object parameterObject) throws Exception {
for (ParameterMapping parameterMapping : parameterMappingList) {
String propertyValue = null;
if (isPrimitiveOrPrimitiveWrapper(parameterObjectClass)) {
propertyValue = parameterObject.toString();
} else {
String propertyName = parameterMapping.getProperty();
Field field = parameterObjectClass.getDeclaredField(propertyName);
field.setAccessible(true);
propertyValue = String.valueOf(field.get(parameterObject));
if (parameterMapping.getJavaType().isAssignableFrom(String.class)) {
propertyValue = "\"" + propertyValue + "\"";
}
}
sql = sql.replaceFirst("\\?", propertyValue);
}
return sql;
}
private boolean isPrimitiveOrPrimitiveWrapper(Class<?> parameterObjectClass) {
return parameterObjectClass.isPrimitive() ||
(parameterObjectClass.isAssignableFrom(Byte.class)
|| parameterObjectClass.isAssignableFrom(Short.class)
|| parameterObjectClass.isAssignableFrom(Integer.class)
|| parameterObjectClass.isAssignableFrom(Long.class)
|| parameterObjectClass.isAssignableFrom(Double.class)
|| parameterObjectClass.isAssignableFrom(Float.class)
|| parameterObjectClass.isAssignableFrom(Character.class)
|| parameterObjectClass.isAssignableFrom(Boolean.class));
}
private boolean isStrictMap(Class<?> parameterObjectClass) {
return parameterObjectClass.isAssignableFrom(DefaultSqlSession.StrictMap.class);
}
private boolean isList(Class<?> clazz) {
Class<?>[] interfaceClasses = clazz.getInterfaces();
for (Class<?> interfaceClass : interfaceClasses) {
if (interfaceClass.isAssignableFrom(List.class)) {
return true;
}
}
return false;
}
private boolean isMap(Class<?> parameterObjectClass) {
Class<?>[] interfaceClasses = parameterObjectClass.getInterfaces();
for (Class<?> interfaceClass : interfaceClasses) {
if (interfaceClass.isAssignableFrom(Map.class)) {
return true;
}
}
return false;
}
}