[스프링] ModelMapper

gyeol·2024년 8월 17일

스프링

목록 보기
42/50
post-thumbnail

스프링을 이용해 쇼핑몰을 만들고 있는데 ModelMapper 라이브러리를 사용하게 되어서 정리해본다.

ModelMapper

ModelMapper는 어떤 객체에 있는 필드값을 원하는 객체에 자동으로 매핑시켜주는 라이브러리이다.
주로 DTO와 같은 클래스로 데이터를 받은 후 원하는 클래스에 넣어줄 때, Getter/Setter를 이용해 필드를 복사/붙여넣기 하는 작업을 거친다. 이때 매핑해야할 필드가 다른 경우도 많다. 다른 모델의 객체를 매핑해줘야 하는 작업이 발생할 수 있는데 이런 번거로움을 해결하기 위해 사용되는 라이브러리이다.

의존성 추가

  • Gradle
implementation 'org.modelmapper:modelmapper:{version}'
  • Maven
<dependency>
  <groupId>org.modelmapper</groupId>
  <artifactId>modelmapper</artifactId>
  <version>{version}</version>
</dependency>

예시

@Getter @Setter
class Order{
	Customer customer;
    Address billingAddress;
}

@Getter @Setter
class Customer{
	Name name;
}

@Getter @Setter
class Name{
	String firstName;
    String lastName;
}

@Getter @Setter
class Address{
	String street;
    String city;
}


class OrderDto{
	String customerFirstName;
    String customerLastName;
    String billingStreet;
    String billingCity;

이와 같은 클래스가 정의되었다고 가정하자. 우리는 ModelMapper.map(Object source, Class<D> destinationType)를 사용해 order 객체를 orderDto에 매핑할 수 있다.

Order order = new Order(
	new Customer(new Name("LastName", "FirstName")),
    new Address("Street", "City");
);

ModelMapper mapper = new ModelMapper();

// 매핑하기
OrderDto orderDto = mapper.map(order, OrderDto.class);


이처럼 map(source, destination) 메서드가 호출되면 sourcedestination 타입을 분석해 매칭 전략이나 기타 설정값들에 따라 일치하는 속성을 결정하게 된다. 하지만 속성간의 매핑을 명시적으로 정의해야 하는 경우도 존재한다. 이런 경우에는 TypeMap<> 을 사용한다.

TypeMap<S, D>

class Item{
	private String name;
    private Integer stock;
    private Integer price;
    private Boolean sale;
}

class Bill{
	private String itemName;
    private Integer qty;
    private Integer singlePrice;
    private Double discount;
}

우리는 ItemBill을 매핑시킬 것이다

  • Item.stock -> Bill.qty
  • Item.price -> Bill.singlePrice
  • Item.sale -> Bill.discount
mapper.typeMap(Item.class, Bill.class).addMappinig(m -> {
	m.map(Item::getStock, Bill::setQty);
    m.map(Item::getPrice, Bill::setSinglePrice);
});

Bill bill2 = mapper.map(item, Bill.class);

이렇게되면 stockprice는 각각 잘 매핑된 것을 확인할 수 있지만 sale -> discount 매핑은 타입이 다르기 때문에 Converter 인터페이스를 사용해야한다.

Converter

우리는 이때 mapper.using(Converter<S, D>)을 사용해 타입을 변환해줄 것이다.

mapper.typeMap(Item.class, Bill.class).addMappings(m -> {
	m.map(Item::getStock, Bill::setQty);
    m.map(Item::getPrice, Bill::setSinglePrice);
    m.using((Converter<Boolean, Double>) ctx -> ctx.getSource() ? 30.0 : 0.0)
    	.map(Item::isSale, Bill::setDiscount);
});

Bill bill2 = mapper.map(item, Bill.class);

이렇게되면 sale 까지 모두 정상적으로 매핑된 것을 확인할 수 있다.

profile
공부 기록 공간 '◡'

0개의 댓글