Total Pageviews

2017/11/07

Using MapStruct to simplify the implementation of mappings between Java bean types

Problem
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());
    }

}






No comments: