OrikaMapper使用

序言

现有对象拷贝,使用的是spring的BeanUtils或者直接JSON转换,效率比较低,在大数据量情况下会占用大量资源(性能对比)。因此,引入orika,提高效率。

简介

引入

<dependency>
            <groupId>ma.glasnost.orika</groupId>
            <artifactId>orika-core</artifactId>
            <version>1.4.1</version>
</dependency>

基本概念

MapperFactory用于注册字段映射,配置转换器,自定义映射器等,而我们主要使用的为字段映射这个特性,在自定义映射时就是用MapperFactory来匹配特殊字段。
MapperFacade相当于spring的BeanUtils,负责对象间的映射,也就是实现对象拷贝所使用的类。

跳过的坑

1、 OrikaMapper根据get/set方法获取属性,那么对于使用@Data注解的实体类中,最好不要出现类似于pName的属性。因为@Data注解会将这类属性的get/set方法写成getPName/setPName,在映射时可能会报“pName does not belong to OrikaTestBO”的错误。相类似的,这个错误在后端与前端交互时也会出现,因此最好不使用这一结构命名。

使用

这里注意,以下所说的简单指的是所需映射对象属性全为基本数据类型,若包含自定义对象或者数组,则需要使用自定义映射,否则这些属性会置为null。另外,orika是以属性名称来匹配的,对于非对应属性需要确保没有重名。

source:

/**
 * 测试对象
 * @author 心随
 */
@Data
public class OrikaTestBO {

    private Integer id;

    private String name;

    private BigDecimal price;

    private OrikaTestSonBO orikaTestSonBO;

    private String extraBO;
}


/**
 * orika 测试子对象
 * @author 心随
 */
@Data
public class OrikaTestSonBO {
    private Integer id;

    private String name;

    private BigDecimal price;
}

destination:


/**
 * orika测试对象
 * @author 心随
 */
@Data
public class OrikaTestDTO {

    private Integer id;

    private String name;

    private BigDecimal price;

    private OrikaTestSonDTO orikaTestSonDTO;

    private String extraDTO;
}

/**
 * orika测试子对象
 * @author 心随
 */
@Data
public class OrikaTestSonDTO {
    private Integer id;

    private String name;

    private BigDecimal price;
}

init:

//source初始化
    public static OrikaTestBO init(){
        OrikaTestBO orikaTestBO = new OrikaTestBO();
        orikaTestBO.setId(1);
        orikaTestBO.setName("zzh");
        orikaTestBO.setPrice(BigDecimal.TEN);
        OrikaTestSonBO orikaTestSonBO = new OrikaTestSonBO();
        orikaTestSonBO.setId(2);
        orikaTestSonBO.setName("xxx");
        orikaTestSonBO.setPrice(BigDecimal.ONE);
        orikaTestBO.setOrikaTestSonBO(orikaTestSonBO);
        return orikaTestBO;
    }

简单object

public static OrikaTestDTO singleMap(){
        OrikaTestBO orikaTestBO = init();
        System.out.println(JSON.toJSONString(orikaTestBO));
        OrikaTestDTO orikaTestDTO = OrikaMapperUtils.map(orikaTestBO,OrikaTestDTO.class);
        System.out.println(JSON.toJSONString(orikaTestDTO));
        return orikaTestDTO;
    }

结果

{"extraBO":"啦啦啦啦","id":1,"name":"zzh","orikaTestSonBO":{"id":2,"name":"xxx","price":1},"price":10}
{"id":1,"name":"zzh","price":10}

简单list

public static List<OrikaTestDTO> listMap(){
        List<OrikaTestBO> sourceList = new ArrayList<>();
        sourceList.add(init());
        sourceList.add(init());
        System.out.println(JSON.toJSONString(sourceList));
        List<OrikaTestDTO> destinationList = OrikaMapperUtils.mapList(sourceList,OrikaTestBO.class,OrikaTestDTO.class);
        System.out.println(JSON.toJSONString(destinationList));
        return destinationList;
    }

结果

[{"extraBO":"啦啦啦啦","id":1,"name":"zzh","orikaTestSonBO":{"id":2,"name":"xxx","price":1},"price":10},{"extraBO":"啦啦啦啦","id":1,"name":"zzh","orikaTestSonBO":{"id":2,"name":"xxx","price":1},"price":10}]
[{"id":1,"name":"zzh","price":10},{"id":1,"name":"zzh","price":10}]

自定义

public static OrikaTestDTO specialMap(){
        OrikaTestBO orikaTestBO = init();
        System.out.println(JSON.toJSONString(orikaTestBO));
        //配置特殊化映射
        MapperFactory factory = new DefaultMapperFactory.Builder().build();
        factory.classMap(OrikaTestBO.class,OrikaTestDTO.class)
                .field("orikaTestSonBO","orikaTestSonDTO")
                .byDefault()
                .register();
        factory.classMap(OrikaTestSonBO.class, OrikaTestSonDTO.class)
                .byDefault()
                .register();
        //映射类
        MapperFacade mapper = factory.getMapperFacade();
        OrikaTestDTO orikaTestDTO = mapper.map(orikaTestBO,OrikaTestDTO.class);
        System.out.println(JSON.toJSONString(orikaTestDTO));
        return orikaTestDTO;
    }

结果

{"extraBO":"啦啦啦啦","id":1,"name":"zzh","orikaTestSonBO":{"id":2,"name":"xxx","price":1},"price":10}
{"id":1,"name":"zzh","orikaTestSonDTO":{"id":2,"name":"xxx","price":1},"price":10}

工具类

public class OrikaMapperUtils {
    private static MapperFacade mapper;

    static {
        MapperFactory factory = new DefaultMapperFactory.Builder().build();
        mapper = factory.getMapperFacade();
    }

    private OrikaMapperUtils() {
    }

    /**
     * 简单的复制出新类型对象.
     * <p>
     * 内部实现是通过source.getClass() 获得源Class
     */
    public static <S, D> D map(S source, Class<D> destinationClass) {
        return mapper.map(source, destinationClass);
    }

    /**
     * 极致性能的复制出新类型对象.
     * <p>
     * 预先通过{@link OrikaMapperUtils#getType(Class)} 静态获取并缓存Type类型,在此处传入
     */
    public static <S, D> D map(S source, Type<S> sourceType, Type<D> destinationType) {
        return mapper.map(source, sourceType, destinationType);
    }


    /**
     * 简单的复制出新对象列表到ArrayList
     * <p>
     * 不建议使用{@link MapperFacade#mapAsList(Object[], Class)}} 接口, sourceClass需要在遍历每一个元素的时候反射,实在有点慢
     */
    public static <S, D> List<D> mapList(Iterable<S> sourceList, Class<S> sourceClass, Class<D> destinationClass) {
        return mapper.mapAsList(sourceList, TypeFactory.valueOf(sourceClass), TypeFactory.valueOf(destinationClass));
    }

    /**
     * 极致性能的复制出新类型对象到ArrayList.
     * <p>
     * 预先通过{@link OrikaMapperUtils#getType(Class)} 静态获取并缓存Type类型,在此处传入
     */
    public static <S, D> List<D> mapList(Iterable<S> sourceList, Type<S> sourceType, Type<D> destinationType) {
        return mapper.mapAsList(sourceList, sourceType, destinationType);
    }

    /**
     * 简单复制出新对象列表到数组.
     * <p>
     * 内部实现是通过source.getComponentType() 获得源Class
     *
     * @param destination      要复制到的目标数组
     * @param source           待复制的源数据数组
     * @param destinationClass 要复制到的目标数组数据元素Class
     */
    public static <S, D> D[] mapArray(final D[] destination, final S[] source, final Class<D> destinationClass) {
        return mapper.mapAsArray(destination, source, destinationClass);
    }

    /**
     * 极致性能的复制出新类型对象到数组.
     * <p>
     * 需要预先通过{@link OrikaMapperUtils#getType(Class)} 静态获取并缓存转换所需Type类型,在此处传入
     *
     * @param destination     要复制到的目标数组
     * @param source          待复制的源数据数组
     * @param sourceType      待复制的源数据数组实例类型
     * @param destinationType 要复制到的目标数组类型
     */
    public static <S, D> D[] mapArray(D[] destination, S[] source, Type<S> sourceType, Type<D> destinationType) {
        return mapper.mapAsArray(destination, source, sourceType, destinationType);
    }

    /**
     * 预先获取orika转换所需要的{@link Type},避免每次复制都做转换.
     */
    public static <E> Type<E> getType(final Class<E> rawType) {
        return TypeFactory.valueOf(rawType);
    }
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值