How to convert Bean objects gracefully

Classify Beans one by one! For example, a table of car_tb, so he has two classes, one is called CarPo, the attributes in it are exactly the same as the table fields. The other is called CarVo, used for Car display on the page!
But when outsourcing Han was doing CarPo to CarVo conversion, the code was written like this, the pseudo code is as follows:

CarPo carPo = this.carDao.selectById(1L);
CarVo carVo = new CarVo();
carVo.setId(carPo.getId());
carVo.setName(carPo.getName());
//omit a bunch of
return carVo;
Voiceover: Is it particularly cordial to see this string of codes? I took over a bunch of codes left behind by outsourcing. That's how I wrote it, a mountain of shit! For a type of thousands of rows, half of them are in the set attribute.

As it happens, Ah Xiong passed by by hitting the water! The Chicken Thief's Axiong glanced at the screen of Outsourcing Korea and saw the series of codes of Outsourcing Korea! Going up for an education, I don’t feel elegant enough! Axiong thinks that BeanUtils.copyProperties should be used to simplify writing, like the following!

CarPo carPo = this.carDao.selectById(1L);
CarVo carVo = new CarVo();
BeanUtils.copyProperties(carPo, carVo);
return carVo;
However, outsourcing Han stared at this code and said: "Online is not about reflection efficiency Slow, do you write this, there is no performance problem?"
Axiong said: "If you use Apache's BeanUtil class, it does have a big performance problem. For example, Alibaba's code scanning plug-ins are prohibited from using this class, as shown below !"

"However, if you are using a class like Spring's BeanUtils, you will not be able to clearly feel the lag when the number of calls is sufficient." Axiong added.

"Wow, Ah Xiong is awesome!" Outsourcing Han was very excited!

Looking at the atmosphere full of emotion in this office. The cleaner who was mopping the floor beside him---sweeping smoke, he decided not to be silent anymore.

I saw the sweeping cigarette throw away the mop in my hand, and said desperately, "We don't consider performance. From the perspective of scalability! BeanUtils still has many problems!"

When copying an object, the field types are inconsistent, resulting in failure to assign values. How do you solve it? Expand yourself?
When copying objects, the field names are inconsistent. For example, it is called carName in CarPo and name in CarVo, which causes the assignment to fail. How do you solve it? Expand yourself?
If it is a copy of a collection, for example, List is converted to List, how do you deal with it?
(Ten thousand words omitted...)
"What should I do?" After listening to the description of Sweeping Smoke, Outsourcing Han asked in confusion!

"It's very simple. In fact, in the process of converting beans, the logic of set is fixed, and the only thing that changes is the conversion rules. Therefore, if we only need to write conversion rules, the conversion code is automatically generated by the system according to the rules, which is much more convenient. ! Using the above example, it is called carName in CarPo and name in CarVo. The attribute names are inconsistent. We will pass an annotation

@Mapping(source = "carName", target = "name"),
specify the corresponding conversion rule. The system recognizes this annotation and generates code

If carVo.setName(carPo.getCarName())
can be automatically generated by the system in this way, the flexibility of the bean conversion logic will be greatly enhanced, and there will be no performance problems in this way!" Way!

"Then what tools are used to generate these set logic?" Outsourced Han and Ah Xiong asked together!

"The name of the tool is MapStruct!"

Ok, the story above is here, it's over! There is no need to ask about the ending, there is only one ending, outsourcing Han and Axiong to be happy and happy...(10000 words omitted)...
Then let’s talk about MapStruct specifically!

MapStruct's tutorial
Here is an introduction to this plugin from three perspectives of usage, principle, and advantages. As for the detailed tutorial, please refer to the official documentation.

Usage
Import the pom file as follows

org.mapstruct mapstruct-jdk8 1.2.0.Final org.mapstruct mapstruct-processor 1.2.0.Final In preparing two entity classes, in order to facilitate the demonstration, the lombok plug-in is used. Prepare two entity classes, one is CarPo

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CarPo { private Integer id; private String brand; } There is another CarVo



@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CarVo { private Integer id; private String brand; } Here is another conversion interface



@Mapper
public interface CarCovertBasic {
CarCovertBasic INSTANCE =
Mappers.getMapper(CarCovertBasic.class);

CarVo toConvertVo(CarPo source);

} The
test code is as follows:

//Actually take
CarPo from the database carPo = CarPo.builder().id(1)
.brand("BMW")
.build();
CarVo carVo = CarCovertBasic.INSTANCE.toConvertVo(carPo);
System.out.println( carVo); The
output is as follows

CarVo(id=1, brand=BMW)
can see that the attribute value of carPo is copied to carVo. Of course, in this case, the function is similar to BeanUtils, and there is no advantage! Well, let’s talk about it later, let’s talk about the principle first!

Principle
In fact, the principle is that the MapStruct plug-in will recognize our interface and generate an implementation class. In the implementation class, the set logic is implemented for us!
For example, in the above example, an implementation class CarCovertBasicImpl is implemented for the CarCovertBasic interface. We can use the decompiler tool to see the source code as shown in the figure below

Next, let’s talk about the advantages

Advantages
(1) The attributes of the two types are inconsistent.
At this time, one attribute of CarPo is carName, and the attribute corresponding to CarVo is name!

We can add the corresponding relationship on the interface, as shown below

@Mapper
public interface CarCovertBasic {
CarCovertBasic INSTANCE = Mappers.getMapper(CarCovertBasic.class);

@Mapping(source = “carName”, target = “name”)
CarVo toConvertVo(CarPo source);
}The
test code is as follows

CarPo carPo = CarPo.builder().id(1)
.brand("BMW")
.carName("BMW")
.build();
CarVo carVo = CarCovertBasic.INSTANCE.toConvertVo(carPo);
System.out.println( carVo); The
output is as follows

CarVo (id=1, brand=BMW, name=BMW)
can see that carVo has recognized the carName attribute in carPo and the assignment is successful. The decompiled diagram is as follows

Voiceover: If there are multiple mapping relationships, you can use @Mappings annotations, nest multiple @Mapping annotations to achieve, as explained later!

(2) Collection type conversion
What if we want to convert from List to List?
Simple, just add a method to the interface

@Mapper
public interface CarCovertBasic { CarCovertBasic INSTANCE = Mappers.getMapper(CarCovertBasic.class);

@Mapping(source = "carName", target = "name")
CarVo toConvertVo(CarPo source);

List<CarVo> toConvertVos(List<CarPo> source);

}
As shown in the code, we can add a toConvertVos method. When mapStruct generates the code, it will help us to call the toConvertVo method cyclically, and show you the decompiled code, which is clear at a glance

(3) Types are inconsistent
. Add a createTime with an attribute of Date type to CarPo, and add a createTime with an attribute of String type to CarVo, then the code is as follows

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CarPo {
private Integer id;
private String brand;
private String carName;
private Date createTime;
}

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CarVo {
private Integer id;
private String brand;
private String name;
private String createTime;
}

The interface can be written like this

@Mapper
public interface CarCovertBasic {
CarCovertBasic INSTANCE = Mappers.getMapper(CarCovertBasic.class);
@Mappings({
@Mapping(source = “carName”, target = “name”),
@Mapping(target = “createTime”, expression = “java(com.guduyan.util.DateUtil.dateToStr(source.getCreateTime()))”)
})
CarVo toConvertVo(CarPo source);

List<CarVo> toConvertVos(List<CarPo> source);

}In
this way, the problem of inconsistent types can be solved in the code! When the set method is generated, the DateUtil class is automatically called for conversion. Because it is relatively simple, I will not post the decompiled picture!

(4) Many-to-one
In actual business situations, we sometimes encounter the situation of mapping two Beans to one Bean. Assuming that we also have a class called AtrributePo at this time, we need to map CarPo and AttributePo to CarBo at the same time , We can write

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AttributePo {
private double price;
private String color;
}

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CarBo {
private Integer id;
private String brand;
private String carName;
private Date createTime;
private double price;
private String color;
}

The interface changes as follows

@Mapper
public interface CarCovertBasic {
CarCovertBasic INSTANCE = Mappers.getMapper(CarCovertBasic.class);
@Mappings({
@Mapping(source = “carName”, target = “name”),
@Mapping(target = “createTime”, expression = “java(com.guduyan.util.DateUtil.dateToStr(source.getCreateTime()))”)
})
CarVo toConvertVo(CarPo source);

List<CarVo> toConvertVos(List<CarPo> source);

CarBo toConvertBo(CarPo source1, AttributePo source2);

}
Absorbing material: www.goodsmaterial.com

Guess you like

Origin blog.csdn.net/weixin_45032957/article/details/108444461