# MapStruct란?

**MapStruct**는 Java Bean 간의 매핑을 쉽게 해주는 코드 생성 기반 매퍼 프레임워크입니다.  
DTO(Data Transfer Object)와 Entity 간의 변환을 할 때 반복되는 getter/setter 작업을 자동화해주며, **런타임이 아닌 컴파일 타임에 매핑 코드를 생성**하므로 성능도 뛰어납니다.

## 주요 특징
- **컴파일 타임에 코드 생성** (런타임 Reflection 사용 X)
- Lombok과 잘 연동됨
- 커스터마이징 가능 (부분 매핑, `@Mapping` 등)
- Spring과 쉽게 통합

---

## Spring Boot에서 MapStruct 사용 예시

### 1. Gradle 설정

```kotlin
dependencies {
    implementation ("org.mapstruct:mapstruct:1.6.3")
    annotationProcessor ("org.mapstruct:mapstruct-processor:1.6.3")
}

tasks.withType(JavaCompile) {
    options.annotationProcessorPath = configurations.annotationProcessor
}
```

---

### 2. DTO 및 Entity 클래스

```java
// User.java (Entity)
@Getter @Setter
public class User {
    private Long id;
    private String name;
    private String email;
}
```

```java
// UserDto.java
@Getter @Setter
public class UserDto {
    private String name;
    private String email;
}
```

---

### 3. 매퍼 인터페이스 작성

```java
@Mapper(componentModel = "spring") // Spring Bean으로 등록
public interface UserMapper {
    UserDto toDto(User user);
    User toEntity(UserDto userDto);
}
```

> `componentModel = "spring"`을 설정하면 Spring의 `@Component`로 등록되므로, 의존성 주입이 가능합니다.

---

### 4. 서비스에서 사용

```java
@Service
@RequiredArgsConstructor
public class UserService {
    private final UserMapper userMapper;

    public UserDto getUserDto(User user) {
        return userMapper.toDto(user);
    }
}
```

---

## 마무리

MapStruct는 반복적인 매핑 코드를 없애고, 명시적이고 빠른 매핑을 제공하는 훌륭한 도구입니다. 특히 **Spring Boot + Lombok**과 함께 사용하면 생산성과 유지보수성이 크게 향상됩니다.

필요하다면 `@Mapping` 어노테이션을 사용해 필드명을 다르게 매핑하거나, 일부 필드만 매핑하는 커스터마이징도 가능합니다.

---

좋습니다! 이번에는 **MapStruct의 고급 기능**들을 소개해드릴게요. 실무에서 자주 쓰이는 매핑 커스터마이징 기능과 예제 중심으로 설명드릴게요.

---

## MapStruct 고급 기능

### 1. **@Mapping**: 이름이 다른 필드 매핑

DTO와 Entity의 필드명이 다를 경우 사용합니다.

```java
@Getter @Setter
public class User {
    private Long id;
    private String fullName;
}
```

```java
@Getter @Setter
public class UserDto {
    private String name;
}
```

```java
@Mapper(componentModel = "spring")
public interface UserMapper {
    @Mapping(source = "fullName", target = "name")
    UserDto toDto(User user);
}
```

> `source`: 원본 객체의 필드  
> `target`: 매핑될 대상 객체의 필드

---

### 2. **@Mapping(target = ..., ignore = true)**: 특정 필드 무시

```java
@Mapping(target = "id", ignore = true)
User toEntity(UserDto dto);
```

`id`는 DB에서 자동 생성되므로 무시할 때 자주 사용합니다.

---

### 3. **@InheritInverseConfiguration**: 역 매핑 정의 재사용

```java
@Mapper(componentModel = "spring")
public interface UserMapper {
    @Mapping(source = "fullName", target = "name")
    UserDto toDto(User user);

    @InheritInverseConfiguration
    User toEntity(UserDto dto);
}
```

> `toDto`에 정의된 매핑 규칙을 `toEntity`에도 반대로 적용합니다.

---

### 4. **@AfterMapping / @BeforeMapping**: 매핑 전후 로직 삽입

```java
@Mapper(componentModel = "spring")
public interface UserMapper {

    UserDto toDto(User user);

    @AfterMapping
    default void enrichDto(@MappingTarget UserDto dto) {
        dto.setName(dto.getName().toUpperCase()); // 예: 이름을 대문자로 처리
    }
}
```

---

### 5. **중첩 객체 매핑 (Nested Mapping)**

```java
@Getter @Setter
public class User {
    private Address address;
}

@Getter @Setter
public class Address {
    private String city;
}
```

```java
@Getter @Setter
public class UserDto {
    private String city;
}
```

```java
@Mapping(source = "address.city", target = "city")
UserDto toDto(User user);
```

> 중첩된 객체의 필드도 `. (dot)` 문법으로 접근 가능합니다.

---

### 6. **Collection 매핑**

```java
List<UserDto> toDtoList(List<User> users);
Set<User> toEntitySet(Set<UserDto> dtos);
```

> List, Set, Map 같은 컬렉션도 자동 매핑됩니다.

---

### 7. **Mapper 간 의존성 (다른 Mapper 사용)**

```java
@Mapper(componentModel = "spring", uses = { AddressMapper.class })
public interface UserMapper {
    UserDto toDto(User user);
}
```

> 복잡한 구조에서는 하위 매퍼를 만들어 분리할 수 있어요.

---

## 정리

MapStruct 고급 기능을 사용하면 다음과 같은 작업이 쉬워집니다:

- 필드명이 다른 경우 매핑
- 무시할 필드 지정
- 매핑 재사용 (`@InheritInverseConfiguration`)
- 후처리 로직 삽입
- 복잡한 구조/컬렉션/다형성 처리

---
좋아요! 이번에는 **MapStruct의 고급 기능** 중에서도 실무에서 자주 사용되는 **Enum 매핑**, **커스텀 매핑 메서드**, **Builder 패턴 지원**에 대해 자세히 설명드릴게요.

---

## 1. Enum 매핑

MapStruct는 기본적으로 **같은 이름을 가진 Enum 상수끼리 자동으로 매핑**합니다.

### 예시: 이름이 같은 Enum 매핑

```java
public enum Role {
    ADMIN, USER
}

public enum RoleDto {
    ADMIN, USER
}
```

```java
@Mapper(componentModel = "spring")
public interface UserMapper {
    RoleDto toDto(Role role);
}
```

> 이름이 같다면 자동으로 매핑됩니다.  
> 이름이 다르면 `@ValueMapping` 또는 `@Mapping`을 사용해야 해요.

### 예시: 이름이 다른 Enum 매핑

```java
public enum Role {
    ADMINISTRATOR, NORMAL_USER
}

public enum RoleDto {
    ADMIN, USER
}
```

```java
@ValueMappings({
    @ValueMapping(source = "ADMINISTRATOR", target = "ADMIN"),
    @ValueMapping(source = "NORMAL_USER", target = "USER")
})
RoleDto toDto(Role role);
```

---

## 2. 커스텀 매핑 메서드

MapStruct는 매핑 중 호출할 **사용자 정의 메서드**도 지원합니다.

### 예시: 날짜 형식 변환

```java
@Getter @Setter
public class User {
    private LocalDateTime registeredAt;
}

@Getter @Setter
public class UserDto {
    private String registeredDate;
}
```

```java
@Mapper(componentModel = "spring")
public interface UserMapper {
    @Mapping(source = "registeredAt", target = "registeredDate")
    UserDto toDto(User user);

    default String map(LocalDateTime dateTime) {
        return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
    }
}
```

> MapStruct는 `LocalDateTime -> String` 변환 시 `map(...)` 메서드를 자동으로 호출합니다.

---

## 3. Builder 패턴 지원

Builder 패턴을 사용하는 객체도 MapStruct에서 지원합니다.  
Lombok의 `@Builder`를 쓰거나 직접 Builder 클래스를 만든 경우에도 동작합니다.

### 예시: Lombok + Builder

```java
@Getter @Setter
@Builder
public class UserDto {
    private String name;
    private String email;
}
```

```java
@Mapper(componentModel = "spring", builder = @Builder(disableBuilder = false))
public interface UserMapper {
    UserDto toDto(User user);
}
```

> MapStruct는 `@Builder`가 붙은 클래스에 대해 자동으로 `.builder().field(...).build()`를 사용해 객체를 생성합니다.

### 주의할 점:
- `@Builder(disableBuilder = true)`이면 Builder 무시
- `@Builder(disableBuilder = false)` 또는 생략하면 Builder 사용
- 커스텀 Builder 클래스의 경우 구조가 달라지면 빌더 매핑이 안 될 수도 있으니 주의

---

## 마무리 정리

| 기능 | 설명 |
|------|------|
| **Enum 매핑** | Enum 이름 자동 매핑, 다를 경우 `@ValueMapping` 사용 |
| **커스텀 메서드** | 복잡한 변환 로직을 메서드로 정의 가능 |
| **Builder 패턴** | `@Builder` 객체도 매핑 가능 (자동 빌더 생성) |

---
