Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

java

mapstruct

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;
}
like image 475
TwoThe Avatar asked Feb 14 '17 12:02

TwoThe


People also ask

How does MapStruct generate implementation?

MapStruct is an open-source Java-based code generator which creates code for mapping implementations. It uses annotation-processing to generate mapper class implementations during compilation and greatly reduces the amount of boilerplate code which would regularly be written by hand.

Does MapStruct work with Java 11?

Yes, it works on a Java 11 / Spring Boot 2 project at work, and we use Mapstruct without issues.

How do I ignore mapping in MapStruct?

To do this, we use the MapStruct unmappedTargetPolicy to provide our desired behavior when there is no source field for the mapping: ERROR: any unmapped target property will fail the build – this can help us avoid accidentally unmapped fields. WARN: (default) warning messages during the build. IGNORE: no output or ...

How do I map a MapStruct collection?

In general, mapping collections with MapStruct works the same way as for simple types. Basically, we have to create a simple interface or abstract class, and declare the mapping methods. Based on our declarations, MapStruct will generate the mapping code automatically.


2 Answers

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.

like image 179
m4rtin Avatar answered Oct 06 '22 23:10

m4rtin


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);
}
like image 31
xardbaiz Avatar answered Oct 07 '22 00:10

xardbaiz