Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapstruct: HashMap as source to Object

How could I use a HashMap<String, Object> as source to an object?

Here is my target object:

public class ComponentStyleDTO{
    private String attribute;
    private Object value;
}

I've tried to use this approach that I found and that is also in the documentation, but it's failing for me.

My Mapper:

@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = "spring", uses = ComponentStyleMapperUtil.class)
public interface ComponentStyleMapper {

    ComponentStyleMapper MAPPER = Mappers.getMapper(ComponentStyleMapper.class);

    @Mappings({@Mapping(target = "attribute", qualifiedBy = ComponentStyleMapperUtil.Attribute.class),
    @Mapping(target = "value", qualifiedBy = ComponentStyleMapperUtil.Value.class)})
    ComponentStyleDTO hashMapToComponentStyleDTO(HashMap<String, Object> hashMap);
}

My Util:

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){

        return (String) in.entrySet().stream().findFirst().get().getKey();
    }

    @Value
    public Object value(HashMap<String, Object> in) {
        Object value = in.entrySet().stream().findFirst().get().getValue();

        if(value instanceof String){
            return value;
        }else if(value instanceof LinkedHashMap){
            List<ComponentStyleDTO> childs = new ArrayList<ComponentStyleDTO>();
            HashMap<String, Object> child = (HashMap<String, Object>) value;
            for(String key: child.keySet()){
                ComponentStyleDTO schild = new ComponentStyleDTO();
                schild.setAttribute(key);
                schild.setValue((String) child.get(key));
                childs.add(schild);
            }
            return childs;
        }else{
            return value;
        }

    }

}

And here's how I'm using this:

    HashMap<String, Object> hmap = new HashMap<String, Object>();
    hmap.put(attr.getKey(), attr.getValue());
    ComponentStyleDTO componentDTO = componentStyleMapper.hashMapToComponentStyleDTO(hmap);

But it's returning me empty in attribute and value. Any idea of what I could be doing wrong?

like image 453
davis Avatar asked Feb 08 '19 22:02

davis


3 Answers

Not sure what you are trying to achieve. If your mapping is more complex maybe the best way is indeed to go with the approach in https://stackoverflow.com/a/54601058/1115491.

That a side, the reason why it is not working for you is that you have not defined the source for your mapping. In the example you linked there is a POJO as source parameter and the source is a map in that POJO. In order to make it work your mapper needs to look like:

@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = "spring", uses = ComponentStyleMapperUtil.class)
public interface ComponentStyleMapper {

    @Mapping(target = "attribute", source = "hashMap", qualifiedBy = ComponentStyleMapperUtil.Attribute.class)
    @Mapping(target = "value", source = "hashMap", qualifiedBy = ComponentStyleMapperUtil.Value.class)
    ComponentStyleDTO hashMapToComponentStyleDTO(HashMap<String, Object> hashMap);
}

NB: When using the non default componentModel you should not use the Mappers factory for getting an instance of the mapper. If you do that you will get an NPE when working with other mappers.

like image 85
Filip Avatar answered Sep 23 '22 06:09

Filip


IMHO The best way is the simpliest way:

default ComponentStyleDTO hashMapToComponentStyleDTO(HashMap<String, Object> hashMap){
    ComponentStyleDTO result = new ComponentStyleDTO();
    result.setAtribute1(hashMap.get("atribute1"));
    result.setAtribute2(hashMap.get("atribute2"));
    result.setAtribute3(hashMap.get("atribute3"));
    ...
    return result;
}

or

default List<ComponentStyleDTO> hashMapToComponentStyleDTO(HashMap<String, Object> hashMap){
    return hashMap.entrySet()
                  .stream()
                  .map(e -> new ComponentStyleDTO(e.getKey(), e.getValue()))
                  .collect(Collectors.toList());
}
like image 35
David Pérez Cabrera Avatar answered Sep 25 '22 06:09

David Pérez Cabrera


For future reference. As of Mapstruct 1.5 I think this usecase is supported out of the box. See mapstruct release note

like image 25
msts1906 Avatar answered Sep 24 '22 06:09

msts1906