如何使用MapStruct将HashMap<String, Object>映射为ComponentStyleDTO?
问题分析与解决方案
你遇到的空值问题核心原因是MapStruct不知道要将整个HashMap对象传递给工具类的方法,另外还有一些用法上的不规范可能导致潜在问题,下面逐一说明并给出修正方案:
核心错误:缺少source = "."指定
你的@Mapping注解没有指定source属性,MapStruct默认会尝试从源对象(HashMap)中寻找与目标字段同名的属性(比如attribute),但HashMap并没有这个属性,因此工具类的attribute()和value()方法根本没有被调用,目标字段自然保持为空。
要让MapStruct把整个HashMap作为参数传递给工具类的方法,必须在@Mapping中添加source = "."(.代表整个源对象)。
次要问题:Spring组件模型与静态工厂冲突
你在Mapper上设置了componentModel = "spring",说明希望MapStruct生成Spring管理的Bean,但同时又定义了静态的MAPPER实例通过Mappers.getMapper()获取。这种用法是矛盾的:
- 当使用Spring组件模型时,应该通过
@Autowired注入Mapper实例,而不是静态工厂获取 - 静态工厂获取的实例不会被Spring管理,可能导致后续依赖注入相关的问题(虽然这不是本次空值的直接原因,但需要修正)
潜在风险:空指针异常
你的工具类方法没有处理HashMap为空的情况,当传入空Map时,entrySet().stream().findFirst().get()会直接抛出NoSuchElementException,需要增加空值判断。
修正后的完整代码
1. 修正ComponentStyleMapper接口
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = "spring", uses = ComponentStyleMapperUtil.class) public interface ComponentStyleMapper { @Mappings({ @Mapping(target = "attribute", source = ".", qualifiedBy = ComponentStyleMapperUtil.Attribute.class), @Mapping(target = "value", source = ".", qualifiedBy = ComponentStyleMapperUtil.Value.class) }) ComponentStyleDTO hashMapToComponentStyleDTO(HashMap<String, Object> hashMap); }
2. 修正工具类ComponentStyleMapperUtil
public class ComponentStyleMapperUtil{ @Qualifier @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Attribute { } @Qualifier @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Value { } @Attribute public String attribute(HashMap<String, Object> in){ if (in == null || in.isEmpty()) { return null; } return (String) in.entrySet().stream().findFirst().get().getKey(); } @Value public Object value(HashMap<String, Object> in) { if (in == null || in.isEmpty()) { return null; } Object value = in.entrySet().stream().findFirst().get().getValue(); if(value instanceof String){ return value; }else if(value instanceof LinkedHashMap){ List<ComponentStyleDTO> childs = new ArrayList<>(); HashMap<String, Object> child = (HashMap<String, Object>) value; for(String key: child.keySet()){ ComponentStyleDTO schild = new ComponentStyleDTO(); schild.setAttribute(key); // 去掉强制类型转换,避免类型不匹配报错 schild.setValue(child.get(key)); childs.add(schild); } return childs; }else{ return value; } } }
3. 正确使用Mapper(Spring注入方式)
// 在需要使用的类中注入Mapper @Service // 或者@Component/Controller等Spring组件类 public class YourService { @Autowired private ComponentStyleMapper componentStyleMapper; public void yourMethod(YourAttrType attr) { HashMap<String, Object> hmap = new HashMap<>(); hmap.put(attr.getKey(), attr.getValue()); ComponentStyleDTO componentDTO = componentStyleMapper.hashMapToComponentStyleDTO(hmap); // 后续逻辑 } }
可选:不使用Spring组件模型的方案
如果你不想依赖Spring,可以移除componentModel = "spring",保留静态MAPPER实例,同样需要添加source = ".":
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, uses = ComponentStyleMapperUtil.class) public interface ComponentStyleMapper { ComponentStyleMapper MAPPER = Mappers.getMapper(ComponentStyleMapper.class); @Mappings({ @Mapping(target = "attribute", source = ".", qualifiedBy = ComponentStyleMapperUtil.Attribute.class), @Mapping(target = "value", source = ".", qualifiedBy = ComponentStyleMapperUtil.Value.class) }) ComponentStyleDTO hashMapToComponentStyleDTO(HashMap<String, Object> hashMap); }
使用时直接调用静态实例:
ComponentStyleDTO componentDTO = ComponentStyleMapper.MAPPER.hashMapToComponentStyleDTO(hmap);
内容的提问来源于stack exchange,提问作者davis
相关产品推荐
相关产品推荐

