如何用MapStruct将含3个Map的Response映射为ResponseDTO?
问题
能否使用MapStruct将内部包含3个Map的Response对象映射为同样包含3个Map的ResponseDTO对象?相关代码如下:
@Data @AllArgsConstructor @NoArgsConstructor @Builder public class ResponseDTO implements Serializable { private Map<String, Map<String, ResponseItemDTO>> map1; private Map<String, Map<String, ResponseItemDTO>> map2; private Map<String, Map<String, ResponseItemDTO>> map3; } public class ResponseItemDTO implements Serializable { private String id; private String label; private String type; @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "value") @JsonSubTypes({ @JsonSubTypes.Type(value = SimpleString.class, name = "simpleString"), @JsonSubTypes.Type(value = OverrideString.class, name = "overrideString") }) public interface Value {} } @Data @AllArgsConstructor @NoArgsConstructor @Builder @JsonTypeName("simpleString") public class SimpleString implements ResponseItemDTO.Value { @JsonProperty("value") private String value; } @Mapper interface ResponseMapper { ResponseMapper INSTANCE = Mappers.getMapper(ResponseMapper.class); @Mapping(target = "map1", source = "response.map1") @Mapping(target = "map2", source = "response.map2") @Mapping(target = "map3", source = "response.map3") ResponseDTO mapResponseDTO(Response response); // 报错提示需要添加这些映射方法 Map<String, Map<String, ResponseItemDTO>> map1(Map<String, ResponseItem> map1); Map<String,ResponseItemDTO> map(ResponseItem value); }
遇到的错误信息:
java: The return type Map<String,ResponseItemDTO> is an abstract class or interface. Provide a non abstract / non interface result type or a factory method.
尝试添加了默认方法但无效:
default SimpleString createSimpleString() { return new SimpleString(); }
解决方案
问题核心是MapStruct无法自动推断ResponseItem到ResponseItemDTO具体实现类的映射逻辑,且原映射方法返回接口类型,导致框架无法确定实例化的具体类。以下是修复步骤:
编写具体类型的映射方法
为每个ResponseItem对应的DTO实现类编写映射方法,比如:SimpleString mapToSimpleString(ResponseItem source); OverrideString mapToOverrideString(ResponseItem source);MapStruct会自动根据字段名匹配映射,若字段名不一致可添加
@Mapping注解调整。自定义嵌套Map的映射逻辑
替换原有的Map<String,ResponseItemDTO> map(ResponseItem value);方法,改为处理整个Map的自定义逻辑,根据源对象的标识选择具体的映射实现:default Map<String, ResponseItemDTO.Value> mapItemMap(Map<String, ResponseItem> sourceMap) { if (sourceMap == null) return null; Map<String, ResponseItemDTO.Value> targetMap = new HashMap<>(); for (Map.Entry<String, ResponseItem> entry : sourceMap.entrySet()) { ResponseItem item = entry.getValue(); ResponseItemDTO.Value dto; // 根据item的type字段判断要映射到哪个具体DTO类 if ("simpleString".equals(item.getType())) { dto = mapToSimpleString(item); } else if ("overrideString".equals(item.getType())) { dto = mapToOverrideString(item); } else { throw new IllegalArgumentException("未知的ResponseItem类型:" + item.getType()); } targetMap.put(entry.getKey(), dto); } return targetMap; }实现顶层Map的映射
编写处理外层Map的默认方法,调用上面的嵌套Map映射逻辑:default Map<String, Map<String, ResponseItemDTO.Value>> mapTopLevelMap(Map<String, Map<String, ResponseItem>> source) { if (source == null) return null; Map<String, Map<String, ResponseItemDTO.Value>> target = new HashMap<>(); for (Map.Entry<String, Map<String, ResponseItem>> entry : source.entrySet()) { target.put(entry.getKey(), mapItemMap(entry.getValue())); } return target; }简化主映射方法
移除主方法中多余的@Mapping注解,MapStruct会自动匹配上面的自定义映射方法:ResponseDTO mapResponseDTO(Response response);移除无效的默认方法
之前添加的createSimpleString方法对当前场景无用,直接删除即可。
注意:原代码中SimpleString实现的是ResponseItemDTO类而非ResponseItemDTO.Value接口,这会导致类型不匹配,需要修正为implements ResponseItemDTO.Value。
内容的提问来源于stack exchange,提问作者Orby
相关产品推荐
相关产品推荐

