Assume I have two java bean classes, Car and CarDto, I would like to copy Car attributes to CarDto attributes, and vice versa.
The Car class is as bellows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package albert.practice.mapStruct; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; @AllArgsConstructor @NoArgsConstructor @Data @ToString public class Car { private String manufacturer; private int seatCount; private String mfgDateString; } |
The CarDto class is as following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package albert.practice.mapStruct; import java.util.Date; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; @AllArgsConstructor @NoArgsConstructor @Data @ToString public class CarDto { private String make; private int numberOfSeats; private Date mfgDate; } |
The two Java bean classes have two differenet name and even have different data type, how to fulfill this requirement conveniently?
How-To
You can make good use of MapStruct to simplify the implementation of mappings between Java bean types.
Add the following configuration in pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <properties> <org.mapstruct.version>1.1.0.Final</org.mapstruct.version> </properties> <dependencies> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-jdk8</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher --> <version>${org.mapstruct.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.8</source> <!-- or higher, depending on your project --> <target>1.8</target> <!-- or higher, depending on your project --> <annotationProcessorPaths> <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build> |
Create a CarMapper to do column mapping
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | package albert.practice.mapStruct.mapper; import java.util.List; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; import albert.practice.mapStruct.Car; import albert.practice.mapStruct.CarDto; @Mapper(uses = MfgDateMapper.class) public interface CarMapper { // By convention, a mapper interface should define a member called INSTANCE // which holds a single instance of the mapper type: CarMapper CarMapper = Mappers.getMapper(CarMapper.class); @Mapping(target = "mfgDate", source = "mfgDateString") @Mapping(target = "make", source = "manufacturer") @Mapping(target = "numberOfSeats", source = "seatCount") CarDto convertCarToCarDto(Car car); @Mapping(target = "mfgDateString", source = "mfgDate") @Mapping(target = "manufacturer", source = "make") @Mapping(target = "seatCount", source = "numberOfSeats") Car convertCarDtoToCar(CarDto carDto); } |
Create a MfgDateMapper class to convert date string to java.util.Date, and vice versa
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | package albert.practice.mapStruct.mapper; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import com.google.common.base.Strings; public class MfgDateMapper { private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); public Date toDate(String dateString) throws ParseException { Date date = null; if (!Strings.isNullOrEmpty(dateString)) { try { date = dateFormat.parse(dateString); } catch (ParseException e) { throw e; } } return date; } public String toDateString(Date date) { String dateString = ""; if (date != null) { dateString = dateFormat.format(date); } return dateString; } } |
Create a test class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | package albert.practice.mapStruct; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import org.junit.Before; import org.junit.Test; import org.mapstruct.factory.Mappers; import albert.practice.mapStruct.mapper.CarMapper; import lombok.extern.slf4j.Slf4j; @Slf4j public class CarMapperTest { CarMapper carMapper; @Before public void setup() { carMapper = Mappers.getMapper(CarMapper.class); } @Test public void testConvertCarToCarDto() { Car car = new Car("Toyota Camry", 5, "2017-04-01"); CarDto carDto = carMapper.convertCarToCarDto(car); log.debug("[testConvertCarToCarDto] car = " + car.toString()); log.debug("[testConvertCarToCarDto] carDto = " + carDto.toString()); assertTrue(carDto.getMake().equals(car.getManufacturer())); assertTrue(carDto.getNumberOfSeats() == car.getSeatCount()); } @Test public void testConvertCarDtoToCar() { CarDto carDto = new CarDto("MINI Cooper S", 4, new Date()); Car car = carMapper.convertCarDtoToCar(carDto); log.debug("[testConvertCarDtoToCar] carDto = " + carDto.toString()); log.debug("[testConvertCarDtoToCar] car = " + car.toString()); assertTrue(car.getManufacturer().equals(carDto.getMake())); assertTrue(car.getSeatCount() == carDto.getNumberOfSeats()); } } |