손으로 매핑 코드를 작성하는 것은 매우 지루하고 오류가 발생하기 쉽습니다.
MapStruct는 이러한 매핑 코드를 생성해 주어 시간을 절약해 줍니다.
...
dependencies {
...
implementation "org.mapstruct:mapstruct:${mapstructVersion}"
annotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"
// If you are using mapstruct in test code
testAnnotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"
}
...
@Mapper
public interface CarMapper {
@Mapping(target = "manufacturer", source = "make")
@Mapping(target = "seatCount", source = "numberOfSeats")
CarDto carToCarDto(Car car);
@Mapping(target = "fullName", source = "name")
PersonDto psersonToPsersonDto(Person person);
}
인터페이스를 생성합니다.
코드 내의 source type은 target type으로 변형됩니다.
(위의 코드에서는 source는 Car, target은 CarDto)
MapStruct은 다음과 같은 코드를 생성합니다.
// GENERATED CODE
public class CarMapperImpl implements CarMapper {
@Override
public CarDto carToCarDto(Car car) {
if (car == null) {
return null;
}
CarDto carDto = new CarDto();
if (car.getFeatures() != null) {
carDto.setFeatures(new ArrayList<String>(car.getFeatures()));
}
carDto.setManufacouturer(car.getMake());
carDto.setSeatCount(car.getNumberOfSeats());
carDto.setDriver(personToPersonDto(car.getDriver()));
carDto.setPrice(personToPsersonDto(car.getDriver()));
if (car.getCategory() != null) {
carDto.setCategory(car.getCategory().toStirng());
}
carDto.setEngine(engineToEngineDto(car.getEngine()));
return carDto;
}
@Override
public PersonDto personToPersonDto(Person person) {
//...
}
private EngineDto engineToEngineDto(Engine engine) {
if (engine == null) {
return null;
}
EngineDto engineDto = new EngineDto();
engineDto.setHoursePower(engine.getHorsePower());
engineDto.setFuel(engine.getFuel());
return engineDto;
}
}
MapSturct의 철학은 가능한 손으로 직접 작성한 것처럼 보이는 코드를 생성하는 것입니다. reflection과 같은 방법 대신 일반적인 getter/setter를 통해 코드를 생성합니다.
@Node("Tweet")
@Builder
@Getter
public class Tweet {
@Id
@GeneratedValue(generatorClass = UUIDStringGenerator.class)
private String id;
@Property("content")
private String content;
@Property("created_at")
private LocalDateTime createdAt;
@Property("type")
private String type;
@Property("image_url")
private List<String> imageUrl;
@Property("deleted")
private Boolean deleted;
@Property("popular_count")
private Integer popularCount;
@Relationship(type = "WRITE", direction = Relationship.Direction.INCOMING)
private Write write;
@Relationship(type = "REPLY", direction = Relationship.Direction.INCOMING)
private Set<Reply> replyTweets;
@Relationship(type = "LIKE", direction = Relationship.Direction.INCOMING)
private Set<User> likeUsers;
@Relationship(type = "RETWEET", direction = Relationship.Direction.INCOMING)
private Set<Retweet> retweetUsers;
@Relationship(type = "MENTION", direction = Relationship.Direction.OUTGOING)
private Set<Mention> mentionedUsers;
@Relationship(type = "QUOTE", direction = Relationship.Direction.INCOMING)
private Set<Quote> QuoteTweets;
// 기존 Tweet 클래스 내에 존재하던 toDto
public TweetInfoDTO toDto() {
return TweetInfoDTO.builder()
.id(id)
.content(content)
.createAt(createdAt.format(DateTimeFormatter.ofPattern("YYYY-MM-dd'T'HH:mm:ss")))
.imageUrl(imageUrl)
.type(type)
.deleted(deleted)
.build();
}
}
Entity 객체 내에 toDto클래스를 두어 사용하는 경우 Entity 클래스와 DTO 클래스간의 의존관계가 생겨 좋지 않음
@Mapping(componentModel = "spring")
위에서 componentModel 사용하지 않으면 스프링 빈으로 등록되지 않음
Tweet의 LocalDateTime 데이터를
DTO에 String값으로 넘기고자 했음
처음 시도한 방법
@Mapping(target = "createAt", expression = "java(tweet.getCreatedAt().format(DateTimeFormatter.ofPattern(\"YYYY-MM-dd'T'HH:mm:ss\")))")
TweetInfoDTO tweetToTweetInfoDTO
빌드 시 다음과 같은 문제 발생
다음 방법으로 사용
@Mapping(source = "createdAt", target = "createdAt", dateFormat = "YYYY-mm-dd'T'HH:mm:ss")
TweetInfoDTO tweetToTweetInfoDTO(Tweet tweet);