Expedia是如何摆脱Java Bean转换器的

作者:Fabio Borriello

2019 年 4 月 16 日

Expedia是如何摆脱Java Bean转换器的

本文关键点


  • 让开发人员用一些上班时间用于创新,可能会他们展现出他们的潜力,在日常工作中创造出有用的解决方案

  • 开源,一个解决共性问题的产品或解决方案可能会帮到其他的人

  • 充满激情是打造优秀软件的关键要素

  • BULL能有效地加速开发阶段,同时减少引入错误的可能性

  • 在实际应用中,BULL不会对性能造成任何负面影响


在分层体系结构中,会通过将变化封装为特定的数据对象并传播到其他层,以创建出抽象级别,这种对象映射过程可能会变得强制且繁琐。


传统上,这种数据对象映射由手动编码转换器来处理,这些转换器在实体(或 Java bean)之间复制数据。


从不同的数据对象映射到不同的数据对象,需要大量的时间和成千上万行代码,当然,具体取决于你需要转换的数量。


这需要巨大的工作量,特别是如果还考虑到必要的测试用例的数量的话。这种类型的转换代码编写起来相当枯燥,而且极易出错,所以为什么不自动执行呢?


问题


幸运的是,有很多基于 Web 的映射框架可以为我们做这件事,所以我们不必担心!


但是,如果您的 Java bean 遵循常见的安全最佳实践是不可变的,会是什么情况呢?其结果是,没有哪款映射框架能够以一种简单的方式转换你的对象。


解决方案


一个能够自动转换各种 Java bean(包括不可变的、可变的和混合的)的类库可以生我们免去大量的工作,BULL就是这样做的。



好处


为了更好地展示这个库的好处,让我们来看一个例子:假设您正在处理一个多层应用程序,其结构如下:



FooController 包含一个 Rest API,它在输入中获取一个请求,并在执行了一组操作之后返回一个响应。


为获得响应,FooController 需要在这三层移动请求/响应数据(由类似于这样的领域对象进行映射),所以我们需要为它们中的每一个都实现一个转换器(及其测试),它从一个对象复制数据到下一层的另一个对象,并按照需要进行修改。


综上所述,对于每一层,我们将需要划分如下 20 个类:


  • 1个服务类

  • 1个服务类的测试

  • 6个领域对象

  • 6个转换器

  • 6个转换器的测试


3 层相乘共计 60 个类。


现在让我们用 BULL 来分析相同的场景:



现在的情况看起来很不一样了:不再需要转换类了,所有 3 层总共需要的类减少到了 24 个,总体来说代码减少了 60%。这意味着:


  • 更短的开发时间(从而直接降低成本)

  • 减少引入错误的可能性

  • 更容易维护的代码


BULL 能做什么


BULL 旨在使它的使用尽可能简单,实际上,转换一个对象只需要一行代码:


ToBean toBean = new BeanUtils().transform(fromBean, ToBean.class);
复制代码


从今天看来,可能以下功能会有用:


  • 支持不可变bean的副本。

  • 支持可变bean的副本。

  • 支持混合bean的副本(有些字段是私有的,有些不是)。

  • 支持没有getter和setter的Java bean副本。

  • 支持通过注释进行验证

  • 支持带有Java基本类型的副本

  • 支持带有Java集合类型的副本

  • 支持带有嵌套的map字段的副本

  • 支持包含基本类型而不是对象类型的数组的副本

  • 支持带有字段名称映射的副本

  • 支持带有递归副本的副本

  • 支持lambda函数字段转换


在此,提供了一份完整的特性列表,包括示例在内一直在更新。


现实世界中的转换


我们知道,在现实世界中,其实很少只需要在两个几乎相同的 Java bean 之间复制信息,通常会发生以下情况:


  • 目标对象的结构与源对象完全不同

  • 在复制特定字段值之前,我们需要对它执行一些操作

  • 必须验证目标对象的字段

  • 目标对象比源对象多一个额外的字段,它的内容需要取自不同的源


怎么解决这些情况呢?BULL 让你有条件在一个特定的字段上执行任何类型的操作!


利用lambda表达式,开发人员可以定义自己的方法,在复制一个值前首先应用这个方法。


让我们来看一个例子,它可以更好地解释这一点,假设源类如下:


public class FromFoo {  private final String id;  private final String val;  private final List<FromSubFoo> nestedObjectList;
// 所有参数的构造函数 // getters函数}以及目标类如下:public class MixedToFoo { public String id;
@NotNull private final Double val;
// 构造函数 // getters 和setters函数}
复制代码


假设 val 字段需要乘以转换器中的一个随机值,我们有两个问题:


  1. val字段的类型与源对象不同,一个是String类型,一个是Double类型

  2. 我们需要指导该类库如何应用数学运算


其实,这很简单,你只需要定义你自己的 Lambda 表达式:


FieldTransformer<String, Double> valTransformer =     new FieldTransformer<>("val",                      n -> Double.valueOf(n) * Math.random());
复制代码


该表达式将应用于目标对象中名为“val”的字段。


最后一步是将函数传递给 BULL 实例:


beanUtils.getTransformer()      .withFieldTransformer(valTransformer)      .transform(fromFoo, MixedToFoo.class);
复制代码


关于“字段验证”这一方面,它甚至更简单,因为您只需要从现有的javax.validation.constraints中根据需要选择一个(或定义一个自定义的约束)注释您的字段,仅此而已。


我们是怎么做到的?


当我们过去实现大量的 Java Bean 转换器时,所需的时间常常比在核心特性上投入的还要多,于是我们决定开始着手加速我们的开发过程,处理可能对所有人都有益的同样的问题。


得益于 Hotels.com 的公司文化,我们每周有半天的时间用于创新项目。利用这个机会来实现这件事,以及其他产品,现在正在显示它们的好处。在这个具体的事例中,我们显著地缩短了我们正在做的几个特性的开发时间。


为什么开源


  1. 开源软件也具有长期的生存能力。它是由一个全球社区创建和支持的,这个全球社区由许多组织和个体开发人员组成,其中许多开发人员也以协作和志愿服务等开源价值观作为生活的信念。

  2. 开源软件是由开发人员社区支持的。这些开发工作室不断地审查他们所支持的开源软件代码,就像有全世界成千上万的独立开发人员致力于这个项目一样。于是,就有了一个庞大的同行审查过程,以确保安全和责任。

  3. 开源软件有很强的价值观——而且通常情况下,开源软件工作室和开发人员持有相似的价值观——他们提倡更多的社区参与、协作和志愿服务。他们相信,要共同努力,打造免费、高质量的产品,让营利性和非营利性组织都能获得这些产品。


这种信念强调了最好的开源软件工作室和开发人员的使命。它促使他们构建新的特性,并将这些特性贡献给社区。直接的结果是,流行的开源软件项目往往都站在技术的最前沿。


有用的链接



结论和本文关键点


  1. 让开发人员用一些上班时间用于创新,可能会他们展现出他们的潜力,在日常工作中创造出有用的解决方案

  2. 开源,一个解决共性问题的产品或解决方案可能会帮到其他的人

  3. 充满激情是打造优秀软件的关键要素

  4. BULL能有效地加速开发阶段,同时减少引入错误的可能性

  5. 在实际应用中,BULL不会对性能造成任何负面影响


关于作者


Fabio Borriello 拥有计算机工程硕士学位和 Web 技术硕士学位。他是一位才华横溢、充满激情的 J2EE 软件工程师,在面向对象的分析和设计方面具有成熟的专业知识,具有负责软件开发生命周期的所有方面(从分析和设计到实现和维护)的优异记录。每次他需要面对一些新的东西的时候,都将其视为是一个挑战和学习新东西的好机会。


查看英文原文How Expedia Is Getting Rid of Java Bean Transformers


2019 年 4 月 16 日 08:004314

评论 3 条评论

发布
用户头像
个人感觉没什么吸引力,如果是同字段,BeanUtil就可以了,如果字段不同写字段映射还不如直接setter了
2019 年 04 月 16 日 13:44
回复
人家的努力到你这里一句话就否定了,真的是章口就莱。
2019 年 04 月 16 日 20:11
回复
没办法,实话实说
2019 年 05 月 08 日 13:53
回复
没有更多评论了
发现更多内容

架構師訓練營第 1 期 - 第 04 周總結

Panda

架構師訓練營第 1 期

第四周总结

饭桶

数字货币交易所定制开发,区块链交易系统搭建

135深圳3055源中瑞8032

spring-boot-route(十二)整合redis做为缓存

Java旅途

Java redis Spring Boot

数字人民币真的来了 六年历程全回顾

CECBC区块链专委会

数字货币 DCEP

架构师训练营第 4 周学习总结

netspecial

极客大学架构师训练营

架構師訓練營 week4 作業

ilake

LeetCode题解:144. 二叉树的前序遍历,使用栈,JavaScript,详细注释

Lee Chen

LeetCode 前端进阶训练营

技术创新+产业升级,区块链为白酒行业带来更多机遇

CECBC区块链专委会

区块链技术 防伪溯源

区块链数字钱包技术开发,数字货币钱包源码搭建

135深圳3055源中瑞8032

架構師訓練營第 1 期 - 第 04 周作業

Panda

架構師訓練營第 1 期

第四周课后练习

大大猫

极客大学架构师训练营

架构师训练营 - 第四周作业

一个节点

极客大学架构师训练营

架构师训练营 - 第四周总结

一个节点

极客大学架构师训练营

随记-- 一件事要不要做,值不值得做?

wyzwlj

承兑商USDT支付系统平台,区块链支付软件开发

135深圳3055源中瑞8032

区块链挖矿系统开发,云算力矿机平台

135深圳3055源中瑞8032

第四周作业

alpha

极客大学架构师训练营

第三周课后练习

大大猫

极客大学架构师训练营

MySQL-技术专题-MySQL索引面试题

李浩宇/Alex

大型网站架构总结

黄立

架构师训练营第4周作业

悠哉

week04_系统架构

……

区块链思维是赋能未来经济的关键思维

CECBC区块链专委会

区块链 经济 技术创新

第四周课后练习

饭桶

配置Ubuntu工作环境

Rayjun

第4周 作业一

bearlu

CPU 执行程序的秘密,藏在了这 15 张图里

小林coding

操作系统 计算机基础 计算机 编译器、程序语言、CPU 指令

架构师训练营 -week04-作业

大刘

极客大学架构师训练营

浅析 Java 内存模型 二

朱华

Java JMM

架构师训练营第 4 周作业

netspecial

极客大学架构师训练营

Expedia是如何摆脱Java Bean转换器的-InfoQ