12

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;
}
TwoThe
  • 13,879
  • 6
  • 30
  • 54
  • I think that currently this is not possible in MapStruct. However, it looks interesting. Can you create an issue in the MapStruct [issue tracker](https://github.com/mapstruct/mapstruct/issues) as a new feature that might be added if people are interested in it. – Filip Feb 14 '17 at 14:03

2 Answers2

13

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.

m4rtin
  • 2,445
  • 22
  • 34
8

Since version 1.5.0.Beta1 (Jul 2021) MapStruct supports mapping from Map to POJO.

Example:

@Mapper
public interface CustomerMapper {
    @Mapping(target = "name", source = "customerName")
    Customer toCustomer(Map<String, String> map);
}
xardbaiz
  • 684
  • 7
  • 17
  • How to map in the opposite direction? – BartusZak Jun 16 '23 at 10:27
  • 1
    @BartusZak I'm not sure that MapStruct supports that. Fastest solution that came to my mind is using fasterxml ObjectMapper - serialize POJO to JsonObject (witch in fact is a Map) – xardbaiz Jun 20 '23 at 13:24