Stop using BeanUtils. Isn't this PO VO DTO conversion artifact fragrant?

Posted by Prismatic on Fri, 31 Dec 2021 21:17:54 +0100

Click on "end of life", pay attention to the official account.

Daily technical dry goods, delivered at the first time!

1. Foreword

Are old fellow owners often troubled by writing some original code of entity conversion, especially when there are many physical fields. Introduce an open source project mapstruct, which can easily and gracefully convert and simplify your code.

Of course, some people like to write get set or copy with BeanUtils. The code is just a tool. This article just provides an idea.

Post the official website address first: https://mapstruct.org/

No more nonsense, code:

pom.xml configuration:

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <org.mapstruct.version>1.4.1.Final</org.mapstruct.version>
        <org.projectlombok.version>1.18.12</org.projectlombok.version>
</properties>

<dependencies>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${org.mapstruct.version}</version>
        </dependency>

        <!-- lombok dependencies should not end up on classpath -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${org.projectlombok.version}</version>
            <scope>provided</scope>
        </dependency>

        <!-- idea 2018.1.1 The following configuration needs to be added for the previous version, but not for the later version. You can comment it out,
I use it myself.3 -->
     <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>${org.mapstruct.version}</version>
            <scope>provided</scope>
        </dependency>

</dependencies>

About the compatibility of lombok and mapstruct, maven plug-in should use 3.6 0 or above, lombok uses 1.16 Version 16 or above, and don't forget to add the compiled lombok mapstruct plug-in. Otherwise, the following error will appear: no property named "AAA" exists in source parameter (s) Did you mean "null"?

This exception is caused by the lack of get setter method caused by lombok compilation exception. Also, exceptions will be thrown if the constructor is missing.

In addition, pay attention to the public account "final code life", reply to the keyword "data", and obtain video tutorials and the latest interview data!

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private String name;
    private int age;
    private GenderEnum gender;
    private Double height;
    private Date birthday;
}

public enum GenderEnum {
    Male("1", "male"),
    Female("0", "female");
    private String code;
    private String name;

    public String getCode() {
        return this.code;
    }

    public String getName() {
        return this.name;
    }

    GenderEnum(String code, String name) {
        this.code = code;
        this.name = name;
    }
}

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class StudentVO {
    private String name;
    private int age;
    private String gender;
    private Double height;
    private String birthday;
}

@Mapper
public interface StudentMapper {
    StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);
    @Mapping(source = "gender.name", target = "gender")
    @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")
    StudentVO student2StudentVO(Student student);
}

Entity classes are indispensable in the development process. Even if they are generated by tools, there must be some. The part that needs to be handwritten is the Mapper interface. After compilation, the corresponding implementation classes will be automatically generated.

Then you can directly use mapper to convert entities

public class Test {
    public static void main(String[] args) {
        Student student = Student.builder().name("Xiao Ming").age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();
        System.out.println(student);
        //This line of code is the actual code to use
        StudentVO studentVO = StudentMapper.INSTANCE.student2StudentVO(student);
        System.out.println(studentVO);
    }
}

mapper can map fields, change field types, and specify formatting methods, including default processing of some dates.

You can manually specify the formatting method:

@Mapper
public interface StudentMapper {

    StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);

    @Mapping(source = "gender", target = "gender")
    @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")
    StudentVO student2StudentVO(Student student);

    default String getGenderName(GenderEnum gender) {
        return gender.getName();
    }
}

The above is only the simplest entity mapping processing. Here are some advanced usage:

2. List conversion

Attribute mapping is based on the mapping configuration above

@Mapper
public interface StudentMapper {

    StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);

    @Mapping(source = "gender.name", target = "gender")
    @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")
    StudentVO student2StudentVO(Student student);

    List<StudentVO> students2StudentVOs(List<Student> studentList);
}

public static void main(String[] args) {

    Student student = Student.builder().name("Xiao Ming").age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();

    List<Student> list = new ArrayList<>();
    list.add(student);
    List<StudentVO> result = StudentMapper.INSTANCE.students2StudentVOs(list);
    System.out.println(result);
}

3. Convert multiple objects to one object

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private String name;
    private int age;
    private GenderEnum gender;
    private Double height;
    private Date birthday;
}

@Data
@AllArgsConstructor
@Builder
@NoArgsConstructor
public class Course {
    private String courseName;
    private int sortNo;
    private long id;
}

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class StudentVO {
    private String name;
    private int age;
    private String gender;
    private Double height;
    private String birthday;
    private String course;
}

@Mapper
public interface StudentMapper {

    StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);

    @Mapping(source = "student.gender.name", target = "gender")
    @Mapping(source = "student.birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")
    @Mapping(source = "course.courseName", target = "course")

    StudentVO studentAndCourse2StudentVO(Student student, Course course);

}

public class Test {

    public static void main(String[] args) {

        Student student = Student.builder().name("Xiao Ming").age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();
        Course course = Course.builder().id(1L).courseName("language").build();

        StudentVO studentVO = StudentMapper.INSTANCE.studentAndCourse2StudentVO(student, course);
        System.out.println(studentVO);
    }

}

4. Default value

@Mapper
public interface StudentMapper {

    StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);

    @Mapping(source = "student.gender.name", target = "gender")
    @Mapping(source = "student.birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")
    @Mapping(source = "course.courseName", target = "course")
    @Mapping(target = "name", source = "student.name", defaultValue = "Zhang San")
    StudentVO studentAndCourse2StudentVO(Student student, Course course);

}

Source: Toutiao com/i6891531055631696395

PS: in case you can't find this article, you can collect some likes for easy browsing and searching

Topics: Java eureka PostMan