MyBatis抽象类结果映射失败:如何正确实例化对应子类?
在使用MyBatis映射包含抽象密封类TariffDetails的UtilityDetails对象时,抛出java.lang.InstantiationException异常。原因是MyBatis尝试实例化抽象类TariffDetails,尽管已在Mapper XML中配置了discriminator,通过tariff_type字段区分TariffDetails的三个子类(TariffDualRateDetails、TariffSingleRateDetails、TariffSubscriptionDetails),但问题仍未解决。
当前配置中,子类resultMap继承了抽象父类的tariffMap,MyBatis在处理时会优先尝试实例化父类(抽象类),再尝试转换为子类,这直接触发了实例化异常。此外,父类resultMap仅包含discriminator,未明确跳过父类实例化逻辑,导致MyBatis误执行抽象类的实例化流程。
调整Mapper XML的resultMap配置,确保MyBatis直接根据discriminator的值实例化对应的子类,避免尝试实例化抽象父类。具体修改如下:
移除子类resultMap对父resultMap的继承
子类resultMap无需继承抽象父类的resultMap,直接独立配置构造函数映射即可。确保
tariff_type字段返回有效值
检查SQL中的case语句,确保每个查询结果都能返回匹配子类的tariff_type值(DUAL_RATE/SINGLE_RATE/SUBSCRIPTION),避免null值导致MyBatis找不到对应子类而尝试实例化父类。
修改后的Mapper XML核心配置:
<resultMap id="utilityDetails" type="org.upc.model.UtilityDetails"> <constructor> <idArg name="id" column="u_id"/> <arg name="name" column="u_name"/> <arg name="createdAt" column="u_created_at"/> <arg name="archived" column="u_archived"/> <arg name="sortOrder" column="u_sort_order"/> <arg name="currentTariff" resultMap="tariffMap"/> </constructor> </resultMap> <resultMap id="tariffDualRate" type="org.upc.model.TariffDualRateDetails"> <constructor> <idArg name="id" column="t_id"/> <arg name="utilityId" column="u_id"/> <arg name="createdAt" column="t_created_at"/> <arg name="threshold" column="tdr_threshold"/> <arg name="unitSize" column="tdr_unit_size"/> <arg name="thresholdComparison" column="tdr_threshold_comparison"/> <arg name="priceAboveThreshold" column="tdr_price_above_threshold"/> <arg name="priceBelowThreshold" column="tdr_price_below_threshold"/> </constructor> </resultMap> <resultMap id="tariffSingleRate" type="org.upc.model.TariffSingleRateDetails"> <constructor> <idArg name="id" column="t_id"/> <arg name="utilityId" column="u_id"/> <arg name="createdAt" column="t_created_at"/> <arg name="price" column="tsr_price"/> <arg name="unitSize" column="tsr_unit_size"/> </constructor> </resultMap> <resultMap id="tariffSubscription" type="org.upc.model.TariffSubscriptionDetails"> <constructor> <idArg name="id" column="t_id"/> <arg name="utilityId" column="u_id"/> <arg name="createdAt" column="t_created_at"/> <arg name="price" column="ts_price"/> </constructor> </resultMap> <resultMap id="tariffMap" type="org.upc.model.TariffDetails"> <discriminator javaType="string" column="tariff_type"> <case value="DUAL_RATE" resultMap="tariffDualRate"/> <case value="SINGLE_RATE" resultMap="tariffSingleRate"/> <case value="SUBSCRIPTION" resultMap="tariffSubscription"/> </discriminator> </resultMap>
- 确认SQL返回的
tariff_type值与discriminator的case值大小写完全匹配 - 验证子类构造函数的参数顺序、名称与resultMap中
arg标签的name属性一一对应 - 若使用低版本MyBatis,建议升级至3.5.0+版本,确保对抽象类判别器的支持
内容的提问来源于stack exchange,提问作者acanthite

