MapStruct: mapping from java.util.Map to Bean?

TwoThe picture TwoThe · Feb 14, 2017 · Viewed 7.4k times · Source

I currently have a Map<String, String> that contains values in the form key = value and I would like to "expand" those into a real object.

Is it possible to automate that with MapStruct and how would I do that?

To clarify: The code I would write by hand would look something like this:

public MyEntity mapToEntity(final Map<String, String> parameters) {
  final MyEntity result = new MyEntity();
  result.setNote(parameters.get("note"));
  result.setDate(convertStringToDate(parameters.get("date")));
  result.setCustomer(mapIdToCustomer(parameters.get("customerId")));
  // ...
  return result;
}

Answer

m4rtin picture m4rtin · Jan 8, 2018

Method 1

The MapStruct repo gives us useful examples such as Mapping from map.

Mapping a bean from a java.util.Map would look something like :

@Mapper(uses = MappingUtil.class )
public interface SourceTargetMapper {

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

    @Mappings({
        @Mapping(source = "map", target = "ip", qualifiedBy = Ip.class),
        @Mapping(source = "map", target = "server", qualifiedBy = Server.class),
    })
    Target toTarget(Source s);
}

Notice the use of the MappingUtil class to help MapStruct figuring out how to correctly extract values from the Map :

public class MappingUtil {

    @Qualifier
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Ip {
    }

    @Qualifier
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public static @interface Server {
    }

    @Ip
    public String ip(Map<String, Object> in) {
        return (String) in.get("ip");
    }

    @Server
    public String server(Map<String, Object> in) {
        return (String) in.get("server");
    }
}

Method 2

As per Raild comment on the issue related to this post, it is possible to use MapStruct expressions to achieve similar results in a shorter way :

@Mapping(expression = "java(parameters.get(\"name\"))", target = "name")
public MyEntity mapToEntity(final Map<String, String> parameters);

No note on performance though and type conversion may be trickier this way but for a simple string to string mapping, it does look cleaner.