Es gibt mehrere Bibliotheken, die häufig beim Kopieren von Beans mit Java verwendet werden.
Von diesen empfehle ich am meisten "mapstruct". Der Grund ist, dass mapstruct
** am schnellsten ** ist. In den folgenden Quellen wird die Zeit angegeben, die für jede Bean-Kopie unter Verwendung der oben genannten fünf Bibliotheken benötigt wird.
@Slf4j
public class CopyDemoTest {
public UserMainBO bo;
public static int count = 1000000;
@Before
public void init(){
bo = new UserMainBO();
bo.setId(1L);
}
@Test
public void mapstruct() {
UserMainVOMapping INSTANCE = Mappers.getMapper( UserMainVOMapping.class );
log.info("star------------");
for (int i = 1; i <=count; i++) {
UserMainVO vo = INSTANCE.toVO(bo);
}
log.info("end------------");
}
@Test
public void beanCopier() {
log.info("star------------");
BeanCopier copier = BeanCopier.create(UserMainBO.class, UserMainVO.class, false);
for (int i = 1; i <=count; i++) {
UserMainVO vo = new UserMainVO();
copier.copy(bo, vo, null);
}
log.info("end------------");
}
@Test
public void springBeanUtils(){
log.info("star------------");
for (int i = 1; i <=count; i++) {
UserMainVO vo = new UserMainVO();
BeanUtils.copyProperties(bo, vo);
}
log.info("end------------");
}
@Test
public void apacheBeanUtils() throws InvocationTargetException, IllegalAccessException {
for (int i = 1; i <=count; i++) {
UserMainVO vo = new UserMainVO();
org.apache.commons.beanutils.BeanUtils.copyProperties(bo, vo);
}
log.info("end------------");
}
@Test
public void apachePropertyUtils() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
log.info("star------------");
for (int i = 1; i <=count; i++) {
UserMainVO vo = new UserMainVO();
PropertyUtils.copyProperties(bo, vo);
}
log.info("end------------");
}
}
Prüfergebnis:
1,000 mal | 10,000 mal | 100,000 mal | 1,000,000 mal | |
---|---|---|---|---|
apache.BeanUtils | 550ms | 1085ms | 4287ms | 32088ms |
apache.PropertyUtils | 232ms | 330ms | 2080ms | 20681ms |
cglib.BeanCopier | 73ms | 106ms | 102ms | 99ms |
mapstruct | 91ms | 5ms | 7ms | 12ms |
spring.BeanUtils | 5ms | 188ms | 336ms | 844ms |
Aus den obigen Überprüfungsergebnissen kann bestätigt werden, dass mapstruct eine weitaus bessere Leistung als andere Bibliotheken aufweist.
Um MapStruct verwenden zu können, müssen Sie die MapStruct-Bibliothek in Ihr Projekt importieren. Das Folgende ist ein Beispiel für die Verwendung von Maven.
pom.xml
<properties>
<org.mapstruct.version>1.3.1.Final</org.mapstruct.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source> <!-- depending on your project -->
<target>1.8</target> <!-- 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>
Bei Verwendung von MapStruct mit der Version 1.2.0.Final oder früher und lombok zusammen sind die folgenden Einstellungen erforderlich:
pom.xml
<properties>
<org.mapstruct.version>1.1.0.Final</org.mapstruct.version>
<org.projectlombok.version>1.18.12</org.projectlombok.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source> <!-- depending on your project -->
<target>1.8</target> <!-- depending on your project -->
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
Da das Innere von swagger-ui eine alte Version von MapSruct verwendet, muss die Abhängigkeit von MapSruct aus der swagger-ui-Bibliothek ausgeschlossen werden, wenn es zusammen mit swagger-ui verwendet wird.
pom.xml
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox-swagger.version}</version>
<exclusions>
<exclusion>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox-swagger.version}</version>
<exclusions>
<exclusion>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
</exclusion>
</exclusions>
</dependency>
Es gibt zwei Bohnenklassen unten.
Student.java
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class Student {
private String name;
private String address;
private String phone;
}
Person.java
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Person {
private String name;
private String address;
private String telephone;
}
Von nun an Bean-Kopie vom Personenobjekt zum Schülerobjekt. Vor dem Kopieren der Bean muss die Mapper-Klasse im Voraus vorbereitet werden.
StudentMapper.java
import model.Person;
import model.Student;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface StudentMapper {
StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);
Student personToStudent(Person person); //Der Methodenname ist beliebig
}
Kopieren wir die Bohne.
main_method
Person person = new Person("lisa", "Tokyo", "12345");
Student student = StudentMapper.INSTANCE.personToStudent(person);
System.out.println(student);
//Ausgabe
// Student(name=Lisa, address=Tokyo, phone=null)
Standardmäßig wird jedes Feld mit einer Namensinkongruenz automatisch ** ignoriert ** und kann nicht von "Telefon" auf "Telefon" kopiert werden.
Wenn die Feldnamen von Quelle und Ziel nicht übereinstimmen, müssen Sie beim Kopieren "@ Mapping" angeben.
StudentMapper.java
import model.Person;
import model.Student;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
public interface StudentMapper {
StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);
@Mapping(source = "telephone", target = "phone")
Student personToStudent(Person person);
}
Ausführungsergebnis:
Student(name=Lisa, address=Tokyo, phone=12345)
Wenn Sie keine Felder kopieren möchten, können Sie sie über das Attribut "Ignorieren" von "@ Mapping" vom Kopieren ausschließen.
StudentMapper.java
import model.Person;
import model.Student;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
public interface StudentMapper {
StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);
@Mapping(source = "telephone", target = "phone")
@Mapping(target = "address", ignore = true)
Student personToStudent(Person person);
}
Ausführungsergebnis:
Student(name=Lisa, address=null, phone=12345)
MapStruct kann Felder von mehreren Beans auf eine Bean kopieren.
LoginInfo.java
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginInfo {
private String id;
private String password;
}
UserProfile.java
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserProfile {
private String email;
private String address;
}
UserInfo.java
@ToString
@Data
public class UserInfo {
private String id;
private String password;
private String email;
private String address;
}
Bereiten Sie Mapper vor.
UserInfoMapper.java
import model.LoginInfo;
import model.UserInfo;
import model.UserProfile;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
public interface UserInfoMapper {
UserInfoMapper INSTANCE = Mappers.getMapper(UserInfoMapper.class);
@Mapping(target = "id", source = "loginInfo.id")
@Mapping(target = "password", source = "loginInfo.password")
@Mapping(target = "email", source = "userProfile.email")
@Mapping(target = "address", source = "userProfile.address")
UserInfo fromLoginInfoAndUserProfile(LoginInfo loginInfo, UserProfile userProfile);
}
eine Kopie machen.
main_method
LoginInfo loginInfo = new LoginInfo("12345", "54321");
UserProfile userProfile = new UserProfile("[email protected]", "Tokyo");
UserInfo userInfo = UserInfoMapper.INSTANCE.fromLoginInfoAndUserProfile(loginInfo, userProfile);
System.out.println(userInfo);
//Ausgabe
// UserInfo(id=12345, password=54321, [email protected], address=Tokyo)
MapStruct kann nicht nur Beans kopieren und erstellen, sondern auch erstellte Beans aktualisieren.
Fügen Sie UserInfoMapper.java
die folgende Quelle hinzu:
UserInfoMapper.java
@Mapping(target = "email", source = "email")
@Mapping(target = "address", source = "address")
void updateUserProfile(UserProfile userProfile, @MappingTarget UserInfo userInfo);
Lassen Sie uns aktualisieren:
main_method
LoginInfo loginInfo = new LoginInfo("12345", "54321");
UserProfile userProfile = new UserProfile("[email protected]", "Tokyo");
UserInfo userInfo = UserInfoMapper.INSTANCE.fromLoginInfoAndUserProfile(loginInfo, userProfile);
System.out.println(userInfo);
//Ausgabe
// UserInfo(id=12345, password=54321, [email protected], address=Tokyo)
userProfile = new UserProfile("[email protected]", "Fukuoka");
UserInfoMapper.INSTANCE.updateUserProfile(userProfile, userInfo);
System.out.println(userInfo);
//Ausgabe
// UserInfo(id=12345, password=54321, [email protected], address=Fukuoka)
In MapStruct können Sie beim Konvertieren von Datum / lokalem Datum in Zeichenfolge und beim Konvertieren von int in Zeichenfolge das Format angeben und konvertieren.
Person.java
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.time.LocalDate;
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private String name;
private LocalDate birthday;
private int salary;
}
Employee.java
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class Employee {
private String name;
private String birthday;
private String salary;
}
PersonMapper.java
import model.Employee;
import model.Person;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
@Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy/MM/dd")
@Mapping(source = "salary", target = "salary", numberFormat = "#,###")
Employee personToEmployee(Person person);
}
main_method
Person person = new Person("lisa", LocalDate.of(1990, 1, 20), 1234567);
Employee employee = PersonMapper.INSTANCE.personToEmployee(person);
System.out.println(employee);
//Ausgabe
// Employee(name=lisa, birthday=1990/01/20, salary=1,234,567)
3.7 expression
Wenn beim Kopieren einer Bean die Komplexität konvertiert werden muss, kann dies leicht mit expression
realisiert werden.
Großschreiben Sie beispielsweise das Feld "Name", wenn Sie von einem Personenobjekt in ein Mitarbeiterobjekt kopieren.
PersonMapper.java
import model.Employee;
import model.Person;
import org.apache.commons.lang3.StringUtils;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper(imports = {StringUtils.class}) //StringUtils importieren
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
@Mapping(target = "name", expression = "java(StringUtils.upperCase(person.getName()))")
Employee personToEmployee(Person person);
}
Ab Java8 kann die Schnittstelle die Standardmethode unterstützen. MapStruct kann auch die Standardmethode verwenden, um eine komplexe Kopierlogik zu erstellen.
PersonMapper.java
import model.Employee;
import model.Person;
import org.apache.commons.lang3.StringUtils;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.time.format.DateTimeFormatter;
@Mapper(imports = {StringUtils.class})
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
default Employee personToEmployee(Person person, String dateFormat) {
Employee employee = new Employee();
//Großschreibung des Namens
employee.setName(StringUtils.upperCase(person.getName()));
//Konvertieren Sie den Geburtstag in das angegebene Format
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat);
employee.setBirthday(person.getBirthday().format(dateTimeFormatter));
return employee;
}
}
Führen Sie die Standardmethode aus.
main_method
Person person = new Person("lisa", LocalDate.of(1990, 1, 20), 1234567);
Employee employee = PersonMapper.INSTANCE.personToEmployee(person, "JJJJ Jahr MM Monat TT Tag");
System.out.println(employee);
//Ausgabe
// Employee(name=LISA, birthday=20. Januar 1990, salary=null)