Java

前言

BeanUtils.copyProperties();确实做了很多事情,虽然不能完美完成深拷贝,但是对于po、vo、dto的拷贝已经足够用了。但是其还是有一些不够完美的地方

  • 不足:
  1. 不能拷贝list,而拷贝list的情况又大量存在,因此会有许多重复代码

    1. for (S source : sources) {
    2. T target = new T();
    3. copyProperties(source, target);
    4. list.add(target);
    5. }
  2. 有一些简单的查询,仅仅需要转换一下vo也需要new Vo()

    1. public Vo findById(Integer id) {
    2. Vo vo = new Vo();
    3. Po po = dao.findById(id);
    4. copyProperties(po, vo);
    5. return vo;
    6. }
  3. 这种拷贝方式是没有返回值的,现在jdk8支持stream()操作之后(参考:Jdk8 Stream),支持不是很友好,不方便lambda表达式的使用

因此决定通过集成BeanUtils类,自己造一个方便用的轮子。

使用

将新创建一个轮子BeanConvertUtils,使用如下
当要转换po、vo时,只需要

  1. // 使用前
  2. public Vo findById(Integer id) {
  3. Vo vo = new Vo();
  4. Po po = dao.findById(id);
  5. copyProperties(po, vo);
  6. return vo;
  7. }
  8. // 使用后
  9. public Vo findById(Integer id) {
  10. return BeanConvertUtils.converTo(dao.findById(id), Vo::new);
  11. }
  12. // 使用后,通过lambda表达式特殊处理个别字段
  13. public Vo findById(Integer id) {
  14. return BeanConvertUtils.converTo(dao.findById(id), Vo::new,
  15. (s, t) -> t.setName(s.getName))
  16. );
  17. }

当要拷贝list的时候也很简单

  1. // 使用前
  2. public List<Vo> findAll() {
  3. List<Vo> vos = new ArrayList();
  4. List<Po> pos = dao.findAll();
  5. for (Po po : Pos) {
  6. Vo vo = new Vo();
  7. BeanUtis.copyProperties(po, vo);
  8. vos.add(vo);
  9. }
  10. return vos;
  11. }
  12. // 使用后
  13. public List<Vo> findAll() {
  14. return BeanConvertUtils.converToList(dao.findAll(), Vo::new)
  15. }
  16. // 同样支持自定义lambda
  17. public List<Vo> findAll() {
  18. return BeanConvertUtils.converToList(dao.findAll(), Vo::new,
  19. (s, t) -> t.setName(s.getName))
  20. )
  21. }

代码

  1. /**
  2. * 转换对象工具
  3. */
  4. public class BeanConvertUtils extends BeanUtils {
  5. public static <S, T> T convertTo(S source, Supplier<T> targetSupplier) {
  6. return convertTo(source, targetSupplier, null);
  7. }
  8. /**
  9. * 转换对象
  10. *
  11. * @param source 源对象
  12. * @param targetSupplier 目标对象供应方
  13. * @param callBack 回调方法
  14. * @param <S> 源对象类型
  15. * @param <T> 目标对象类型
  16. * @return 目标对象
  17. */
  18. public static <S, T> T convertTo(S source, Supplier<T> targetSupplier, ConvertCallBack<S, T> callBack) {
  19. if (null == source || null == targetSupplier) {
  20. return null;
  21. }
  22. T target = targetSupplier.get();
  23. copyProperties(source, target);
  24. if (callBack != null) {
  25. callBack.callBack(source, target);
  26. }
  27. return target;
  28. }
  29. public static <S, T> List<T> convertListTo(List<S> sources, Supplier<T> targetSupplier) {
  30. return convertListTo(sources, targetSupplier, null);
  31. }
  32. /**
  33. * 转换对象
  34. *
  35. * @param sources 源对象list
  36. * @param targetSupplier 目标对象供应方
  37. * @param callBack 回调方法
  38. * @param <S> 源对象类型
  39. * @param <T> 目标对象类型
  40. * @return 目标对象list
  41. */
  42. public static <S, T> List<T> convertListTo(List<S> sources, Supplier<T> targetSupplier, ConvertCallBack<S, T> callBack) {
  43. if (null == sources || null == targetSupplier) {
  44. return null;
  45. }
  46. List<T> list = new ArrayList<>(sources.size());
  47. for (S source : sources) {
  48. T target = targetSupplier.get();
  49. copyProperties(source, target);
  50. if (callBack != null) {
  51. callBack.callBack(source, target);
  52. }
  53. list.add(target);
  54. }
  55. return list;
  56. }
  57. /**
  58. * 回调接口
  59. *
  60. * @param <S> 源对象类型
  61. * @param <T> 目标对象类型
  62. */
  63. @FunctionalInterface
  64. public interface ConvertCallBack<S, T> {
  65. void callBack(S t, T s);
  66. }
  67. }

性能

由于只是BeanUtils的一个封装,跟原来的代码性能几乎差不多,如果要说差一点也没错,毕竟多了一层函数堆栈的调用,但是基本可以忽略不计。主要的性能还是由BeanUtils决定。

提醒

有两点要提醒

  • 此方法依旧不能解决深层次的深拷贝问题,详细的可以google一下BeanUtils的深拷贝问题
  • 如果source或者targetSupplier只要有一个为null,本工具类不像BeanUtils一样抛出异常,而是返回null,因为笔者认为调用方如果把null进行准换,那就是想转换为null,为不为空应该由调用方自己负责