You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iBATIS迁移MyBatis时discriminator遇null实例化抽象类问题

MyBatis 3.5.14 discriminator处理null值时实例化抽象类的问题及解决方案

问题背景

从iBATIS迁移至MyBatis 3.5.14时,在resultMap的discriminator使用场景中遇到异常:当discriminator对应的列值为null时,MyBatis会尝试实例化resultMap的type属性指定的抽象类,触发java.lang.InstantiationException(抽象类无法实例化),而该场景在iBATIS中可正常处理。

示例代码

ResultMap配置

<resultMap id="Sample1Result" type="com.test.AbstractSample">
    <discriminator javaType="int" column="sample1_type">
        <case value="52" resultMap="SampleImpl1Result"/>
        <case value="53" resultMap="OtherSampleImpl1Result"/>
    </discriminator>
</resultMap>

<resultMap id="Sample2Result" type="com.test.AbstractSample">
    <discriminator javaType="int" column="sample2_type">
        <case value="52" resultMap="SampleImpl2Result"/>
        <case value="53" resultMap="OtherSampleImpl2Result"/>
    </discriminator>
</resultMap>

<resultMap id="AugmentedSampleResult" type="Sample" extends="BaseSample">
    ...
    <collection property="sample1" resultMap="Sample1Result"/>
    <collection property="sample2" resultMap="Sample2Result"/>
</resultMap>

Java类定义

public abstract class AbstractSample {
    private int id;
    // getters and setters
}

public class SampleImpl1 extends AbstractSample {
    private String value1;
    // getters and setters
}

public class OtherSampleImpl1 extends AbstractSample {
    private String value2;
    // getters and setters
}

public class SampleImpl2 extends AbstractSample {
    private String value3;
    // getters and setters
}

public class OtherSampleImpl2 extends AbstractSample {
    private String value4;
    // getters and setters
}

// 用于处理null场景的默认实现类
public class DefaultSample extends AbstractSample {
    // 可选添加默认字段
}

报错信息

当discriminator列(sample1_type或sample2_type)为null时,抛出如下异常:

Caused by: org.apache.ibatis.reflection.ReflectionException: Error instantiating class com.test.AbstractSample with invalid types () or values (). Cause: java.lang.InstantiationException
    at org.apache.ibatis.reflection.factory.DefaultObjectFactory.instantiateClass(DefaultObjectFactory.java:86)
    at org.apache.ibatis.reflection.factory.DefaultObjectFactory.create(DefaultObjectFactory.java:53)
    at org.apache.ibatis.reflection.factory.DefaultObjectFactory.create(DefaultObjectFactory.java:45)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(DefaultResultSetHandler.java:687)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(DefaultResultSetHandler.java:659)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:440)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyNestedResultMappings(DefaultResultSetHandler.java:1070)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:449)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForNestedResultMap(DefaultResultSetHandler.java:1026)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:310)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:202)
    at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:66)
    at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:80)
    at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:65)
    at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:336)
    at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:158)
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:110)
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:90)
    at org.mybatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:154)
    at org.mybatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)
    at org.mybatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:142)
    at org.mybatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:75)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:425)
    ... 60 common frames omitted
Caused by: java.lang.InstantiationException: null
    at java.base/jdk.internal.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:48)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486)
    at org.apache.ibatis.reflection.factory.DefaultObjectFactory.instantiateClass(DefaultObjectFactory.java:62)

现有可行方案

通过在discriminator中添加value="null"的case配置,并指定对应的具体默认实现类的resultMap,可解决该问题。修改后的配置如下:

<resultMap id="Sample1Result" type="com.test.AbstractSample">
    <discriminator javaType="int" column="sample1_type">
      <case value="5240" resultMap="SampleImpl1Result"/>
      <case value="5241" resultMap="OtherSampleImpl1Result"/>
      <case value="null" resultMap="DefaultSample"/> <!-- 处理null场景 -->
    </discriminator>
</resultMap>

<resultMap id="Sample2Result" type="com.test.AbstractSample">
    <discriminator javaType="int" column="sample2_type">
      <case value="5240" resultMap="SampleImpl2Result"/>
      <case value="5241" resultMap="OtherSampleImpl2Result"/>
      <case value="null" resultMap="DefaultSample"/> <!-- 处理null场景 -->
    </discriminator>
</resultMap>

<resultMap id="AugmentedSampleResult" type="Sample" extends="BaseSample">
    ...
    <collection property="sample1" resultMap="Sample1Result"/>
    <collection property="sample2" resultMap="Sample2Result"/>
</resultMap>

疑问与建议请求

是否存在无需为每个抽象映射添加默认case和对应实现类的配置方式,能让MyBatis在discriminator列值为null时避免实例化抽象类?或者添加null默认case是唯一可行的解决方案?希望得到相关建议。

内容的提问来源于stack exchange,提问作者Anshu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 12:44:51