java对象转换看这篇就够了
2021-09-30 本文已影响0人
雨中星辰0
java对象转换看这篇就够了
概述
我们在java开发过程中经常遇到对象属性拷贝的需求,总结一下,通常可以使用以下几种办法:
- 通过自定义编码方式
- 优点:灵活、简单
- 缺点:当大量不同的对象需要进行属性拷贝时,工作量大
- 适用场景:少量的对象属性拷贝时
- 通过反射方式
- 原理:通过反射方式获取对象的属性名,然后通过set方法设置对象属性
- 优点:使用简单,可通过
commons-beanutils
或spring BeanUtils
等工具进行转换 - 缺点:只适合对象属性名一致时进行属性拷贝,当属性不一致时,仍需要手动处理
- 适用场景:适合属性名称一致,但类不一致情况下进行属性拷贝
- 通过json方式
- 原理:先将对象转为json字符串,再将json转为另一个类型
- 优点:使用简单
- 缺点:对象转换时,有一些转换逻辑时,不支持。
- 适用场景:1. 类名不一样,但属性名一样时;2. 源类型和目标类型属性名,虽不一样,但是有对应关系时,可通过在源类型上面设置json的属性别名,进行转换。
- 通过mapstruct
- 原理:在转换接口上面配置注解,mapstruct自动生成转换接口的实现。
- 优点:基本能满足各种场景的对象转换
- 缺点:框架较重,开发时偶尔出现,没有实时修改转换实现的情况。
示例
-
自定义编码
public static OperationHistory poseidonFileToTransferHistory(PoseidonFile file){ OperationHistory operationHistory = new OperationHistory(); operationHistory.setExtension(file.getExtension()); operationHistory.setFileName(file.getFileName()); operationHistory.setFileSize(file.getFileSize()); operationHistory.setFileType(file.getFileType()); operationHistory.setFullPath(file.getFullPath()); operationHistory.setFileId(file.getId()); operationHistory.setModifyDate(new Date()); operationHistory.setParentId(file.getParentId()); operationHistory.setReadableSize(file.getReadableSize()); operationHistory.setUserid(file.getUserid()); operationHistory.setUsername(file.getUsername()); operationHistory.setIdPath(file.getIdPath()); operationHistory.setStorePath(file.getStorePath()); return operationHistory; }
-
反射
示例使用的是commons-beanutils。
pom依赖:
<dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.3</version> </dependency>
java示例:
public static OperationHistory poseidonFileToTransferHistory2(PoseidonFile file ) throws InvocationTargetException, IllegalAccessException { OperationHistory operationHistory = new OperationHistory(); BeanUtils.copyProperties(file, operationHistory); return operationHistory; }
-
json
示例的json工具用的是gson,其他json库也类似。
pom依赖
<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.8</version> </dependency>
java示例:
public static OperationHistory poseidonFileToTransferHistory3(PoseidonFile file ) throws InvocationTargetException, IllegalAccessException { Gson gson = new Gson(); String json = gson.toJson(file); return gson.fromJson(json, OperationHistory.class); }
gson中也可以通过@SerializedName注解对属性重命名,这样就解决了源对象属性名与目标对象属性名不一致的问题
import com.google.gson.annotations.SerializedName; public class User { private String account; @SerializedName("code") private String password; private String name; private int age; public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User [account=" + account + ", password=" + password + ", name=" + name + ", age=" + age + "]"; } }
-
mapstruct
由于mapstruct转换代码是自动生成的,所以配置略显复杂。
maven配置:
... <properties> <org.mapstruct.version>1.5.0.Beta1</org.mapstruct.version> </properties> ... <dependencies> <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> <target>1.8</target> <annotationProcessorPaths> <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build> ...
idea配置:
IntelliJ IDEA中安装MapStruct Support插件:File -> Settings -> Plugins 搜索 MapStruct support 安装,同时File -> Settings -> Compiler -> Annotation Processors 勾选“Enable annotation processing”
还要确保您的项目使用的是 Java 1.8 或更高版本(项目属性→“Java 编译器”→“编译合规性级别”)。它不适用于旧版本。
java示例:
import org.mapstruct.Mapper; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; @Mapper public interface CarMapper { CarMapper INSTANCE = Mappers.getMapper( CarMapper.class ); //当源类型与目标类型属性名不一致时 @Mapping(target = "manufacturer", source = "make") @Mapping(target = "seatCount", source = "numberOfSeats") CarDto carToCarDto(Car car); //当源类型与目标类型属性名一致时 @Mappings({}) PersonDto personToPersonDto(Person person); @Override @Mappings({ //当对象属性转换有一些规则时,可调用java方法进行转换,注意:这里的参数名应为方法定义时的参数名一致 @Mapping(target = "service", expression = "java(toService(entity))"), @Mapping(target = "mocks", expression = "java(toMocks(entity))"), @Mapping(target = "params", expression = "java(toRule(entity))"), //当对象的属性需要依赖其他属性转换完后才能转换,可以使用dependsOn进行配置 @Mapping(target = "url", dependsOn = {"service", "params"}, expression = "java(dto2URL(demotionDTO).toFullString())")}) DemotionDTO update2DTO(DemotionUpdateParam entity); default String toService(DemotionUpdateParam entity) { return StringUtils.isEmpty(entity.getGroup()) ? entity.getServiceInf() : entity.getGroup() + "/" + entity.getServiceInf(); } default Map<String, String> toMocks(DemotionUpdateParam entity) { return entity.getMocks() .stream() .filter(i -> StringUtils.split(i, "=").length > 1) .collect(Collectors.toMap( i -> i.split("=")[0], i -> i.split("=")[1] ) ); } default String toRule(DemotionUpdateParam entity) { Map<String, String> map = toMocks(entity); return map.keySet().stream() .map(i -> i + "=" + URL.encode(map.get(i))) .collect(Collectors.joining("&")); } }
-