Orika是一个简单、快速的JavaBean拷贝框架,它能够递归地将数据从一个JavaBean复制到另一个JavaBean。
Orika底层采用了javassist类库生成Bean映射的字节码,因此效率要远高于通过反射来实现的BeanUtils.copyProperties()。
官方地址:http://orika-mapper.github.io/orika-docs/
- maven依赖:
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>compile</scope>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1-jre</version>
</dependency>
- 测试的实体对象:
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class Role {
private Integer id;
private String name;
}
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@Data
@Accessors(chain = true)
public class User {
private String id;
private String name;
private Integer age;
List<User> userList;
List<Role> roles;
}
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@Data
@Accessors(chain = true)
public class UserDto {
private String id;
private String name;
private String userName;
private Integer age;
List<User> userList;
List<Role> roleList;
}
- 封装的Orika工具类:
/**
* 基于Orika的属性映射工具类 - Orika是一个简单、快速的JavaBean拷贝框架,它能够递归地将数据从一个JavaBean复制到另一个JavaBean,Orika底层采用了javassist类库生成Bean映射的字节码
* <p>
* 1. 支持模糊类型映射(如:Integer <-> Long, Integer <-> String)
* 2. 支持对象中的list映射
* <p>
* 性能:手动拷贝 > cglib beanCopier > orika mapper > spring beanUtils > apache commons beanUtils
*
*/
public class OrikaMapperUtils {
/**
* 默认字段工厂
*/
private static final MapperFactory MAPPER_FACTORY = new DefaultMapperFactory.Builder().build();
/**
* 默认字段实例
*/
private static final MapperFacade MAPPER_FACADE = MAPPER_FACTORY.getMapperFacade();
/**
* 实例缓存
*/
private final static Cache<Object, Object> CACHE_MAPPER_FACADE_MAP = CacheBuilder.newBuilder().maximumSize(100)
.concurrencyLevel(10)
.expireAfterWrite(60L, TimeUnit.SECONDS)
.recordStats()
.build();
/**
* 映射实体(默认字段)
*
* @param data 源数据(对象)
* @param toClass 映射类对象
* @return 映射类对象
*/
public static <E, T> E map(T data, Class<E> toClass) {
return MAPPER_FACADE.map(data, toClass);
}
/**
* 映射实体(自定义配置)
*
* @param data 源数据(对象)
* @param toClass 映射类对象
* @param configMap 自定义配置
* - 用于处理源对象与目标对象字段名不匹配的情况 - 格式:{key=源对象中的字段名 : value=目标对象中的字段名}
* @return 映射类对象
*/
public static <E, T> E map(T data, Class<E> toClass, Map<String, String> configMap) {
MapperFacade mapperFacade = getMapperFacade(toClass, data.getClass(), configMap);
return mapperFacade.map(data, toClass);
}
/**
* 映射集合(默认字段)
*
* @param data 源数据(集合)
* @param toClass 映射类对象
* @return 映射类对象(集合)
*/
public static <E, T> List<E> mapAsList(Collection<T> data, Class<E> toClass) {
if (Objects.isNull(data)) {
return Collections.emptyList();
} else {
return MAPPER_FACADE.mapAsList(data, toClass);
}
}
/**
* 映射集合(自定义配置)
*
* @param data 源数据(集合)
* @param toClass 映射类
* @param configMap 自定义配置
* - 用于处理源对象与目标对象字段名不匹配的情况 - 格式:{key=源对象中的字段名 : value=目标对象中的字段名}
* @return 映射类对象(集合)
*/
public static <E, T> List<E> mapAsList(Collection<T> data, Class<E> toClass, Map<String, String> configMap) {
if (Objects.isNull(data)) {
return Collections.emptyList();
}
Optional<T> first = data.stream().findFirst();
if (first.isPresent()) {
MapperFacade mapperFacade = getMapperFacade(toClass, first.get().getClass(), configMap);
return mapperFacade.mapAsList(data, toClass);
} else {
return Collections.emptyList();
}
}
/**
* 获取自定义映射
*
* @param toClass 映射类
* @param dataClass 数据映射类
* @param configMap 自定义配置
* @return 映射类对象
*/
private static <E, T> MapperFacade getMapperFacade(Class<E> toClass, Class<T> dataClass, Map<String, String> configMap) {
String mapKey = dataClass.getCanonicalName() + "_" + toClass.getCanonicalName();
Object o = CACHE_MAPPER_FACADE_MAP.getIfPresent(mapKey);
MapperFacade mapperFacade;
if (Objects.isNull(o)) {
MapperFactory factory = new DefaultMapperFactory.Builder().build();
ClassMapBuilder classMapBuilder = factory.classMap(dataClass, toClass);
configMap.forEach(classMapBuilder::field);
classMapBuilder.byDefault().register();
mapperFacade = factory.getMapperFacade();
CACHE_MAPPER_FACADE_MAP.put(mapKey, mapperFacade);
} else {
mapperFacade = (MapperFacade) o;
}
return mapperFacade;
}
}
- 测试类:
import java.util.*;
public class OrikaMapperTest {
public static void main(String[] args) {
User userA = new User().setId("111").setName("张三").setAge(20);
userA.setUserList(Arrays.asList(new User[]{new User().setId("121").setName("张三1").setAge(21), new User().setId("122").setName("张三2").setAge(22)}));
userA.setRoles(Arrays.asList(new Role[]{new Role().setId(1).setName("老师"), new Role().setId(2).setName("班主任")}));
Map<String, String> map = new HashMap<String, String>() {
{
put("roles", "roleList");
}
};
UserDto userDto = OrikaMapperUtils.map(userA, UserDto.class, map);
System.out.println("无configMap的对象映射(源):" + userA);
System.out.println("无configMap的对象映射(目标):" + userDto);
Map<String, String> configMap = new HashMap<String, String>() {
{
put("name", "userName");
}
};
UserDto userDto2 = OrikaMapperUtils.map(userA, UserDto.class, configMap);
System.out.println("带configMap的对象映射(源):" + userA);
System.out.println("带configMap的对象映射(目标):" + userDto2);
//A对象
List<User> listA = Arrays.asList(new User().setId("123").setName("张三").setAge(20));
List<UserDto> userDtos = OrikaMapperUtils.mapAsList(listA, UserDto.class);
System.out.println("无configMap的list映射(源):" + listA);
System.out.println("无configMap的list映射(目标):" + userDtos);
List<UserDto> userDtos2 = OrikaMapperUtils.mapAsList(listA, UserDto.class, configMap);
System.out.println("带configMap的list映射(源):" + listA);
System.out.println("带configMap的list映射(目标):" + userDtos2);
}
}
- 输出结果:
- 无configMap的对象映射(源):User(id=111, name=张三, age=20, userList=[User(id=121, name=张三1, age=21, userList=null, roles=null), User(id=122, name=张三2, age=22, userList=null, roles=null)], roles=[Role(id=1, name=老师), Role(id=2, name=班主任)])
- 无configMap的对象映射(目标):UserDto(id=111, name=张三, userName=null, age=20, userList=[User(id=121, name=张三1, age=21, userList=null, roles=null), User(id=122, name=张三2, age=22, userList=null, roles=null)], roleList=[Role(id=1, name=老师), Role(id=2, name=班主任)])
- 带configMap的对象映射(源):User(id=111, name=张三, age=20, userList=[User(id=121, name=张三1, age=21, userList=null, roles=null), User(id=122, name=张三2, age=22, userList=null, roles=null)], roles=[Role(id=1, name=老师), Role(id=2, name=班主任)])
- 带configMap的对象映射(目标):UserDto(id=111, name=张三, userName=null, age=20, userList=[User(id=121, name=张三1, age=21, userList=null, roles=null), User(id=122, name=张三2, age=22, userList=null, roles=null)], roleList=[Role(id=1, name=老师), Role(id=2, name=班主任)])
- 无configMap的list映射(源):[User(id=123, name=张三, age=20, userList=null, roles=null)]
- 无configMap的list映射(目标):[UserDto(id=123, name=张三, userName=null, age=20, userList=null, roleList=null)]
- 带configMap的list映射(源):[User(id=123, name=张三, age=20, userList=null, roles=null)]
- 带configMap的list映射(目标):[UserDto(id=123, name=张三, userName=null, age=20, userList=null, roleList=null)]