Java beanのマッピングはModelMapperが便利、ただし性能に注意

ビジネス層やプレゼン層のBean、JPA Entity等のマッピング(詰め替え)では、ModelMapperが便利。ただし、取扱うデータ量によっては性能に注意。

使い方

mavenでは以下をpomのdependenciesに追加。

<dependency>
	<groupid>org.modelmapper</groupid>
	<artifactid>modelmapper</artifactid>
	<version>2.3.5</version>
</dependency>

以下のようなマッピングが可能。

  • 同一フィールド名、同一型でマッピング
  • 異なるフィールド名でマッピング
  • Mapからのマッピング

以下のBeanA、BeanBでマッピングする場合を考える。

@Data
public class BeanA {
    String str;
    int i;
    boolean b;
    String onlyInA;
    MutableBean bean;
    List<Detail> details;
 
    BeanA(String str, int i, boolean b, String onlyInA, MutableBean bean, List<Detail> details) {
        this.str = str;
        this.i = i;
        this.b = b;
        this.onlyInA = onlyInA;
        this.bean = bean;
        this.details = details;
    }
 
    @Data
    static class Detail {
        String str;
        int i;
        boolean b;
 
        Detail(String str, int i, boolean b) {
            this.str = str;
            this.i = i;
            this.b = b;
        }
    }
}
@Data
public class BeanB {
    String str;
    int i;
    boolean b;
    String onlyInB;
    MutableBean bean;
    List<Detail> details;
 
    @Data
    static class Detail {
        String str;
        int i;
        boolean b;
    }
}

以下のコードで、BeanAからBeanBにデータがマッピングされる。BeanA、BeanB直下のフィールドだけでなく、Listの格納されたDetailクラスのフィールドもマッピングされる。

BeanA a = new BeanA("string", 5, true, "onlyInA", new MutableBean("data"),
        Arrays.asList(new BeanA.Detail("str1", 1, true), new BeanA.Detail("str2", 2, false),
                new BeanA.Detail("str3", 3, true)));
 
ModelMapper modelMapper = new ModelMapper();
BeanB b = modelMapper.map(a, BeanB.class);

このとき、フィールド名が異なるBeanA.onlyInAはBeanB.onlyInBにマッピングされないが、以下のようにマッピングルールを指定することでマッピングさせることもできる

ModelMapper modelMapper = new ModelMapper();
TypeMap<BeanA, BeanB> typeMap = modelMapper.createTypeMap(BeanA.class, BeanB.class);
typeMap.addMapping(BeanA::getOnlyInA, BeanB::setOnlyInB);

また、以下のようにMapからのマッピングも可能。

Map<String, Object> map = new HashMap<>();
map.put("str", "string");
map.put("i", 5);
map.put("b", true);
 
ModelMapper modelMapper = new ModelMapper();
BeanB b = modelMapper.map(map, BeanB.class);

ModelMapper公式サイトによるとthread safeであるため、SpringなどDIコンテナを使用している場合、Singletonとして各コードから利用することができる。

また、次の機会に定量的な記載をしたいと思うが、List構造などで大量データを扱う場合、ModelMapperでは性能が課題となることがあり、その点は注意する必要がある。