如何在MyBatis中使用Guava不可变集合?
解决MyBatis返回Guava ImmutableList的实例化异常问题
问题原因
MyBatis默认的DefaultObjectFactory通过反射实例化集合类,但ImmutableList是抽象类,没有公开的无参构造器,无法通过直接反射创建实例,因此抛出InstantiationException。
解决方案
方案1:转成标准集合后再包装(最简单直接)
修改Mapper接口返回Java标准List,在业务层调用Guava的静态方法转成ImmutableList:
修改后的Mapper接口:
@Mapper public interface UtilityRepository { List<Integer> getAllIds(); }
业务层转换:
@ApplicationScoped @AllArgsConstructor public class UtilityService { private final UtilityRepository repository; public ImmutableList<Integer> getAllIds() { return ImmutableList.copyOf(repository.getAllIds()); } }
这种方式无需修改MyBatis配置,代码侵入性低,适合大多数场景。
方案2:自定义ObjectFactory支持Guava不可变集合
如果项目中大量使用Guava不可变集合,可以自定义MyBatis的ObjectFactory,让它自动处理ImmutableList等类型的实例化:
自定义GuavaObjectFactory:
import com.google.common.collect.ImmutableList; import org.apache.ibatis.reflection.factory.DefaultObjectFactory; import java.util.Collection; import java.util.List; public class GuavaObjectFactory extends DefaultObjectFactory { @Override public <T> T create(Class<T> type) { // 处理空集合的情况 if (ImmutableList.class.isAssignableFrom(type)) { return type.cast(ImmutableList.of()); } return super.create(type); } @Override public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { // 处理已有集合转ImmutableList的情况 if (ImmutableList.class.isAssignableFrom(type) && constructorArgs.size() == 1 && constructorArgs.get(0) instanceof Collection) { return type.cast(ImmutableList.copyOf((Collection<?>) constructorArgs.get(0))); } return super.create(type, constructorArgTypes, constructorArgs); } }
配置MyBatis使用自定义ObjectFactory:
- 如果是XML配置文件:
<configuration> <objectFactory type="com.yourpackage.GuavaObjectFactory"/> </configuration>
- 如果是Spring Boot/Quarkus等配置文件(以application.properties为例):
mybatis.configuration.object-factory=com.yourpackage.GuavaObjectFactory
配置完成后,Mapper接口可以直接返回ImmutableList<Integer>,无需额外转换。
内容的提问来源于stack exchange,提问作者acanthite
相关产品推荐
相关产品推荐

