JavaBean相互转换

在升级公司架构过程中,发现有大量Entity与DTO相互转换的问题,并且其中还伴随DTO中的数据字典翻译,所以特意写个工具类,主要利用spring提供的BeanUtils工具类,用redis翻译字典

其中功能包括:

  • 翻译JavaBean中带有@CacheFormat的属性

     /**
    * 翻译当前类中需要翻译的字典值
    *
    * @param source 待翻译的对象
    */
    public static <T> void dataFormatter(T source) { //判断原对象是否为null
    Assert.notNull(source, "待翻译的原对象不能为null"); //获取所有属性并翻译字典
    Field[] declaredFields = source.getClass().getDeclaredFields();
    //翻译字典:找出所有含有@CacheFormatter的属性
    Stream<Field> fieldStream = Arrays.stream(declaredFields)
    //排除没有注解@CacheFormatter的字段
    .filter(field -> field.isAnnotationPresent(CacheFormat.class));
    //翻译
    doFormatter(fieldStream, source, source.getClass());
    }
  • 翻译List中带有@CacheFormat的属性

     /**
    * 翻译当前集合类中需要翻译的字典值
    *
    * @param sources 待翻译的集合对象
    */
    public static <T> void dataFormatter(List<T> sources) { //当翻译的集合为空时,返回空的集合
    if (sources == null || sources.isEmpty()) {
    return;
    } Class targetClass = sources.get(0).getClass();
    //获取所有属性并翻译字典
    Field[] declaredFields = targetClass.getDeclaredFields();
    //翻译字典:找出所有含有@CacheFormat的属性集合
    List<Field> formatterFields = Arrays.stream(declaredFields)
    //排除没有注解@CacheFormat的字段
    .filter(field -> field.isAnnotationPresent(CacheFormat.class))
    .collect(Collectors.toList());
    //循环列表(并行操作)
    sources.parallelStream().forEach(target -> {
    //翻译
    doFormatter(formatterFields.stream(), target, targetClass);
    });
    }
  • Entity 与DTO互转

    /**
    * 把原对象转换成目标类的对象,并翻译目标类的属性字典
    * 只针对目标类没有范型或者范型与原对象一样
    * @param source 原对象
    * @param targetClass 目标类
    * @return 目标对象
    */
    public static <T> T dataConvert(Object source, Class<T> targetClass) { Assert.isTrue(source != null && targetClass != null, "原对象或目标class不能为null"); T target = BeanUtils.instantiateClass(targetClass);
    //把目标对象的属性设置成原对象中对应的属性
    BeanUtils.copyProperties(source, target); dataFormatter(target);
    return target;
    } /**
    * 实体属性互转
    *
    * @param source 原对象
    * @param target 目标对象
    * @return 目标对象
    */
    public static <T> T dataObjConvert(Object source, T target) { Assert.isTrue(source != null && target != null, "待转换的原对象或目标对象不能为null");
    //转换
    BeanUtils.copyProperties(source, target);
    //翻译
    dataFormatter(target);
    return target;
    }
  • List与List互转

    /**
    * 批量把原对象转换成目标对象,并翻译目标对象的属性字典
    * 如果想返回指定类型的集合即List的子类,参考{@link HyBeanUtils#dataConverts2}
    *
    * @param sources 原对象集合
    * @param targetClass 目标对象的类
    * @return 返回转换后的目标集合
    */
    public static <T, E> List<T> dataConverts(List<E> sources, Class<T> targetClass) { Assert.notNull(targetClass, "转换的目标Class不能为null"); //当翻译的集合为空时,返回空的集合
    if (sources == null || sources.isEmpty()) {
    List<T> targetList = new ArrayList<>();
    return targetList;
    }
    //获取原集合的类型
    Class<? extends List> aClass = sources.getClass();
    //目标集合
    List<T> targetList = BeanUtils.instantiateClass(aClass); //把目标对象的属性设置成原对象中对应的属性(并行操作)
    sources.parallelStream().forEach(item -> {
    T target = BeanUtils.instantiateClass(targetClass);
    BeanUtils.copyProperties(item, target);
    targetList.add(target);
    }); //翻译字典
    dataFormatter(targetList); return targetList;
    }
  • 这个是List转换的升级版 T与T互转,这里的T是List的子类

    之所以写这个,就是为了解决mybatis的Page转换问题

    /**
    * 返回指定类型的方法,这里的类型必须是List的子类
    * 批量把原对象转换成目标对象,并翻译目标对象的属性字典,
    *
    * @param sources 原对象集合
    * @param targetClass 目标对象的类
    * @param returnType 返回值类型
    * @return 返回转换后的目标集合
    */
    public static <T, E, R extends List<T>> R dataConverts2(List<E> sources, Class<T> targetClass, Class<R> returnType) { Assert.notNull(targetClass, "转换的目标Class不能为null");
    Assert.notNull(returnType, "返回值类型Class不能为null"); //当翻译的集合为空时,返回空的集合
    if (sources == null || sources.isEmpty()) {
    return null;
    }
    //目标集合
    R targetList = BeanUtils.instantiateClass(returnType); //把目标对象的属性设置成原对象中对应的属性(并行操作)
    sources.parallelStream().forEach(item -> {
    T target = BeanUtils.instantiateClass(targetClass);
    BeanUtils.copyProperties(item, target);
    targetList.add(target);
    }); //翻译字典
    dataFormatter(targetList); return targetList;
    }
  • 上述所用到的公共方法

    /**
    * 对目标类需要翻译的字段进行翻译
    *
    * @param stream
    * @param target 目标对象
    * @param targetClass 目标对象类
    */
    private static <T> void doFormatter(Stream<Field> stream, Object target, Class<T> targetClass) { //排除目标对象中字段值为null的字段
    stream.filter(field -> {
    PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(targetClass, field.getName());
    Object invoke = null;
    try {
    invoke = propertyDescriptor.getReadMethod().invoke(target, new Object[]{});
    } catch (IllegalAccessException e) {
    logger.warn("待翻译的字段的get是无法访问的", e);
    } catch (InvocationTargetException e) {
    logger.warn("调用待翻译的字段的get方法时报错", e);
    } catch (Exception e) {
    logger.warn("确保属性有get,set方法", e);
    }
    return invoke != null;
    //遍历需要翻译的字段
    }).forEach(field -> {
    CacheFormat annotation = field.getAnnotation(CacheFormat.class); //缓存系统编号,如果不指定则默认为当前系统编号
    String systemCode = "system_code";
    if (StringUtils.isNotBlank(annotation.systemCode())) {
    systemCode = annotation.systemCode();
    }
    //缓存key,如果不指定,则默认为字段名称
    String key = annotation.key();
    if (StringUtils.isBlank(key)) {
    key = field.getName();
    } //判断注解@CacheFormatter是否指定把字典翻译到另一个字段上
    String formatterField = annotation.destination();
    if (StringUtils.isBlank(formatterField)) {
    //当注解中不指定其他字段时,默认翻译到加注解的属性上
    formatterField = field.getName();
    } try {
    PropertyDescriptor orginPropertyDescriptor = BeanUtils.getPropertyDescriptor(targetClass, field.getName());
    Object value = orginPropertyDescriptor.getReadMethod().invoke(target, new Object[]{});
    //设置目标字段值
    PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(targetClass, formatterField);
    //取缓存
    String cacheValue = RedisUtils.hget(systemCode +":valueset:" + key, value + "");
    //如果数据字典中查询不到,则取业务缓存中取
    if (StringUtils.isBlank(cacheValue)) {
    cacheValue = RedisUtils.hget(systemCode + ":valueset:" + key, value + "");
    } Assert.hasLength(cacheValue, "在缓存" + key + "中没有找到" + value + "对应的缓存");
    //设置缓存值到属性字段中
    propertyDescriptor.getWriteMethod().invoke(target, cacheValue); } catch (IllegalAccessException e) {
    logger.warn("待翻译的字段的set是无法访问的", e);
    } catch (InvocationTargetException e) {
    logger.warn("调用待翻译的字段的set方法时报错", e);
    } catch (Exception e) {
    e.printStackTrace();
    logger.warn("调用待翻译的字段的set方法时报错,推测类型不匹配", e);
    }
    }); }
  • 注解 CacheFormat

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface CacheFormat { /**
    * 缓存key
    * @return
    */
    String key(); /**
    * 指定翻译值存放字段, 例如:userType的翻译结果放到userTypeName上
    * @return
    */
    String destination() default ""; /**
    * 系统编号
    * @return
    */
    String systemCode() default "";

注意:该翻译只关注第一层即当前对象的属性,并不会递归翻译

比如:当前类有一个属性为对象实例,该对象也有被@CacheFormat注解的属性

这时该工具类不会去翻译这个属性中的属性,需要开发者先用当前工具类转换该属性

然后再设置到目标类中

BeanUtils——JavaBean相互转换及字典翻译的更多相关文章

  1. Git-it字典翻译

    Git-it字典翻译 下面的内容翻译自git-it/dictionary 水平有限,翻译欠佳. Git准备工作 创建一个新的文件夹(目录) $ mkdir <目录名称> 切换到这个目录 ( ...

  2. poj 2503:Babelfish(字典树,经典题,字典翻译)

    Babelfish Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 30816   Accepted: 13283 Descr ...

  3. hdu 1075:What Are You Talking About(字典树,经典题,字典翻译)

    What Are You Talking About Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/204800 K ...

  4. 字典翻译@Dict

    1.编写翻译字典@Dict /** * 数据字典翻译注解 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) publ ...

  5. BeanUtils JavaBean 工具包使用

    感谢原文作者:小老弟 原文链接:https://www.cnblogs.com/syncmr/p/10523576.html 目录 简介 BeanUtils类 使用示例 ConvertUtils 功能 ...

  6. HDOJ1075字典翻译(map应用)

    #include<iostream> #include<cstdio> #include<map> #include<string> #include& ...

  7. kettle系列-6.kettle实现多字段字典快速翻译

    在数据清洗转换中,常见的字典翻译,如性别在原表中是1(男).2(女)等,类似还有很多较大的字典需要翻译,若同一个表中有很多个字典需要翻译,采用[数据库查询]方式翻译的话效率就会相当低下. 这里采用ja ...

  8. java将一个javabean转化为另一个javabean

    公司的项目是用webservice来进行前后台对接,启动后台后需要刷服务才能在前台生成对应的代码,但是有一个很恶心的地方,它给每个service都生成了一个model,于是出现后台只有一个javabe ...

  9. JavaBean转换为XML的源码

    package com.cmge.utils; import java.util.Iterator; import com.cmge.org.oa.bean.OADepartment; import ...

随机推荐

  1. 三、vue依赖收集

    Vue 会把普通对象变成响应式对象,响应式对象 getter 相关的逻辑就是做依赖收集,这一节我们来详细分析这个过程 Dep Dep 是整个 getter 依赖收集的核心,它的定义在 src/core ...

  2. BZOJ 1912:[Apio2010]patrol 巡逻(树直径)

    1912: [Apio2010]patrol 巡逻 Input 第一行包含两个整数 n, K(1 ≤ K ≤ 2).接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ ...

  3. Tensorflow 载入数据的三种方式

    Tensorflow 数据读取有三种方式: Preloaded data: 预加载数据 Feeding: Python产生数据,再把数据喂给后端. Reading from file: 从文件中直接读 ...

  4. 利用MapReduce计算平均数

    利用mapreduce求出股票价格的开盘和收盘平均数 下图为采集到的股票信息,共计1416支股票的信息 因为在linux系统下默认采用utf-8的编码格式,而在win下txt默认采用ANSI编码格式. ...

  5. [poj] 3090 Visible Lattice Points

    原题 欧拉函数 我们发现,对于每一个斜率来说,这条直线上的点,只有gcd(x,y)=1时可行,所以求欧拉函数的前缀和.2*f[n]+1即为答案. #include<cstdio> #def ...

  6. POJ 1389 Area of Simple Polygons | 扫描线

    请戳此处 #include<cstdio> #include<algorithm> #include<cstring> #define N 1010 #define ...

  7. 洛谷 P2173 [ZJOI2012]网络 解题报告

    P2173 [ZJOI2012]网络 题目描述 有一个无向图G,每个点有个权值,每条边有一个颜色.这个无向图满足以下两个条件: 对于任意节点连出去的边中,相同颜色的边不超过两条. 图中不存在同色的环, ...

  8. DP———3.最长上升子序列的和

    Nowadays, a kind of chess game called “Super Jumping! Jumping! Jumping!” is very popular in HDU. May ...

  9. 结构型设计模式之适配器模式(Adapter)

    结构 意图 将一个类的接口转换成客户希望的另外一个接口.A d a p t e r 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 适用性 你想使用一个已经存在的类,而它的接口不符合你 ...

  10. python自动化测试windows gui

    http://sourceforge.net/projects/pywinauto/files/pywinauto/ http://www.microsoft.com/en-us/download/c ...