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

抽象ModelMapper实现通用Entity-DTO转换器时,如何填充类型参数占位符?

如何实现通用的Entity-DTO转换器?

嘿,这个问题问得好!把重复的Entity-DTO转换逻辑抽象成泛型类确实是个减少冗余代码的好思路,不过你遇到的问题其实是Java泛型的类型擦除导致的——在运行时,JVM不知道T和S具体是什么类型,所以ModelMapper没法直接拿到目标类的Class对象。下面给你两种可行的解决方案:

方案一:构造函数传入目标类型Class(推荐,简单直接)

这种方法最直观,通过构造函数把T和S对应的Class对象传入转换器,存在成员变量中供map方法使用。另外建议把ModelMapper实例化一次(放到成员变量),不要每次调用转换方法都新建,能提升性能。

public class Converter<T, S> {
    private final Class<T> entityClass;
    private final Class<S> dtoClass;
    private final ModelMapper modelMapper;

    // 构造时传入两个类型的Class对象
    public Converter(Class<T> entityClass, Class<S> dtoClass) {
        this.entityClass = entityClass;
        this.dtoClass = dtoClass;
        this.modelMapper = new ModelMapper();
    }

    public S convertEntityToDto(T t) {
        return modelMapper.map(t, dtoClass);
    }

    public T convertDtoToEntity(S s) {
        return modelMapper.map(s, entityClass);
    }
}

使用的时候只需要创建实例时传入对应Class:

// 创建UserEntity和UserDto的转换器
Converter<UserEntity, UserDto> userConverter = new Converter<>(UserEntity.class, UserDto.class);
// 转换使用
UserDto dto = userConverter.convertEntityToDto(userEntity);
UserEntity entity = userConverter.convertDtoToEntity(userDto);

方案二:通过反射获取泛型类型(适合固定转换对场景)

如果你不想每次创建转换器都手动传Class,可以利用Java反射从子类的泛型参数中提取实际类型。这种方式需要把Converter改成抽象类,然后针对每个转换对创建子类:

public abstract class Converter<T, S> {
    private final Class<T> entityClass;
    private final Class<S> dtoClass;
    private final ModelMapper modelMapper;

    @SuppressWarnings("unchecked")
    public Converter() {
        // 通过反射获取父类的泛型参数
        Type genericSuperclass = getClass().getGenericSuperclass();
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
        // 第一个泛型参数是T(Entity类型),第二个是S(DTO类型)
        this.entityClass = (Class<T>) parameterizedType.getActualTypeArguments()[0];
        this.dtoClass = (Class<S>) parameterizedType.getActualTypeArguments()[1];
        this.modelMapper = new ModelMapper();
    }

    public S convertEntityToDto(T t) {
        return modelMapper.map(t, dtoClass);
    }

    public T convertDtoToEntity(S s) {
        return modelMapper.map(s, entityClass);
    }
}

使用时创建具体的转换器子类(不用写任何额外代码):

public class UserConverter extends Converter<UserEntity, UserDto> {
    // 直接继承父类方法即可
}

// 使用示例
UserConverter userConverter = new UserConverter();
UserDto dto = userConverter.convertEntityToDto(userEntity);

这种方案的好处是代码更简洁,不用每次传Class,但缺点是必须为每个转换对创建子类,而且反射有轻微的性能开销,适合那些转换关系固定的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 19:29:05