티스토리 뷰

MapStruct는 매핑 코드를 자동으로 해주는 라이브러리이다. 예를 들어 Controller DTO에서 Service DTO로 변환할 때, 또는 ServiceDTO에서 Entity 객체로 변환할 때 매핑 작업을 해준다. 하지만 이렇게 일일이 작업을 하게 되면 오류가 발생할 위험이 있고, 또 무엇보다 귀찮다. MapStruct는 이러한 작업을 자동화 시켜준다. 하지만 잘못 사용하게 되면 아까운 시간을 날릴 수 있다. 

 

문제 상황

아래는 User 엔티티를 UserInfo(ResponseDTO라고 봐도 무방하다.)로 변환하는 로직을 MapStruct를 써서 간단하게 구현한 코드이다. 만약 데이터가 다르다면 아래와 같이 Mapping으로 명시해주어야 한다. 

@Mapper(
    componentModel = "spring",
    injectionStrategy = InjectionStrategy.CONSTRUCTOR,
    unmappedTargetPolicy = ReportingPolicy.ERROR,
)
interface UserMapper {
    @Mappings(
        value = [
            Mapping(source = "email.value", target = "email"),
            Mapping(source = "nickname.value", target = "nickname"),
            Mapping(source = "image.value", target = "profileImg"),
            Mapping(source = "name.value", target = "name"),
        ]
    )
    fun of(user: User): UserInfo.Profile
}

 

soruce = "variable.value"로 명시해준 이유는, 원시타입을 포장했기 때문에 실제 값은 포장 클래스 안에 있는 value변수에 담겨있다. 예를 들어 email 원시타입을 Email 임베디드 타입 클래스로 분리하고 접근할 때는 email.value로 접근한다.

@Entity
@Table(name = "tbl_user")
class User(
    @Embedded private val email: Email,
    @Embedded private var password: Password,
    @Embedded private var nickname: Nickname,
    @Embedded private var image: Image,
    @Embedded private var name: Name,
) : BaseTimeEntity() {
    ...
}

 

Email.java

@Embeddable
class Email(
    @field:NotNull
    @Column(name = "email")
    private val value: String,
) {
    ...
}

 

UserInfo는 아래와 같이 받고 있다.

class UserInfo {

    class Profile(
        val email: String,
        val nickname: String,
        val profileImg: String,
        val name: String,
    )
}

 

하지만 build해보면 아래 오류가 뜬다. 분명히 데이터를 잘 맞춰준 것 같지만, email.value를 찾을 수 없다는 문구를 띄운다.

 

 

해결

원인은 역시 찾지 못한 Email에 문제가 있었다. 

@Entity
@Table(name = "tbl_user")
class User(
    @Embedded private val email: Email,
    @Embedded private var password: Password,
    @Embedded private var nickname: Nickname,
    @Embedded private var image: Image,
    @Embedded private var name: Name,
) : BaseTimeEntity() {

    ...
}

 

바로 private 때문이었다. MapStruct의 특별한 점은, 리플렉션 같은 것을 쓰지 않고 자바 코드를 그대로 호출한다. 아래 사진의 빨간 박스를 보면 단순히 null로 초기화 된 변수에다가 매개변수로 들어온 값을 넣고, 반환 객체를 생성한 후 인자로 변수들을 넣고 있다. 이렇게 자바 코드를 그대로 사용함으로써 안전하며 이해하기가 쉽다. 

 

 

MapStruct 공식 사이트에서도 안전함과 빠른 이해를 할 수 있다는 것을 장점으로 내세우고 있다.

 

 

private이 문제가 되는 이유는, 위 코드에서도 봤듯이 명시해준 해당 변수에 들어가야 되는데 접근 제한이 막혀 있어 찾지 못했다는 오류를 일으킨 것이다. 해결하는 법은 간단하다. private을 빼면 된다. 그리고 다시 build해보면 정상적으로 돌아가는 것을 볼 수 있다!

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday