Bull(Bean Utils Light Library)是一个将数据从一个对象递归地复制到另一个对象的Java-bean到Javabean转换器。它是通用的,灵活的,可重用的,可配置的,而且非常快。

它是唯一能够在没有任何自定义配置的情况下转换可变、不可变和混合bean的库。

本文介绍了如何使用它,并给出了每个可用特性的具体示例。

1.依赖性

com.hotels.beans

bull-bean-transformer

1.7.1

该项目提供两个不同的构建。,与jdk 8(或以上)jdk 11或者更高。

库的最新版本可以从自述档案或来自变化量g(万一你需要一个jdk 8-兼容版本请参阅Changelog-JDK 8).

2.特征

本文中解释的宏特性如下:

bean变换

bean验证

3.bean变换

bean转换由Transformer对象,该对象可以执行以下指令获得:

BeanTransformer transformer = new BeanUtils().getTransformer();

一旦我们有了BeanTransformer对象实例,我们可以使用该方法transform把我们的对象复制到另一个。

使用的方法是:K transform(T sourceObj, Class targetObject);其中,第一个参数表示原对象,第二个参数表示目标类。

例如,给定源和目标类:

public class FromBean { public class ToBean {

private final String name; public BigInteger id;

private final BigInteger id; private final String name;

private final List subBeanList; private final List list;

private List list; private final List nestedObjectList;

private final FromSubBean subObject; private ImmutableToSubFoo nestedObject;

// all args constructor // constructors

// getters and setters... // getters and setters

} }

转换可以通过以下代码行获得:

ToBean toBean = new BeanUtils().getTransformer().transform(fromBean, ToBean.class);

请注意,字段顺序与此无关。

不同字段名副本

给定两个字段数相同但名称不同的类:

private final String name; private final String differentName;

private final int id; private final int id;

private final List subBeanList; private final List subBeanList;

private final List list; private final List list;

private final FromSubBean subObject; private final ToSubBean subObject;

// all constructors // all args constructor

// getters... // getters...

} }

我们需要定义适当的字段映射并将其传递给Transformer目的:

// the first parameter is the field name in the source object

// the second one is the the field name in the destination one

FieldMapping fieldMapping = new FieldMapping("name", "differentName");

Tansformer transformer = new BeanUtils().getTransformer().withFieldMapping(fieldMapping);

然后,我们可以执行转换:

ToBean toBean = transformer.transform(fromBean, ToBean.class);

源对象和目标对象之间的映射字段

案例1:必须从源对象中的嵌套类中检索目标字段值

假设对象FromSubBean声明如下:

public class FromSubBean {

private String serialNumber;

private Date creationDate;

// getters and setters...

}

我们的源类和目标类描述如下:

private final String name; private final String name;

private final FromSubBean subObject; private final String serialNumber;

private final Date creationDate;

/ all args constructor // all args constructor

// getters... // getters...

.而字段的值serialNumber和creationDate进入ToBean对象需要从subObject,可以定义分隔的属性点的整个路径:

FieldMapping serialNumberMapping = new FieldMapping("subObject.serialNumber", "serialNumber");

FieldMapping creationDateMapping = new FieldMapping("subObject.creationDate", "creationDate");

ToBean toBean = new BeanUtils().getTransformer()

.withFieldMapping(serialNumberMapping, creationDateMapping)

.transform(fromBean, ToBean.class);

案例2:必须从源类根检索目标字段值(在嵌套类中)

前面的示例突出显示了如何从源对象中获取值;而这个示例则解释了如何将值放入嵌套对象中。

给予:

public class FromBean { public class ToBean {

private final String name; private final String name;

private final FromSubBean nestedObject; private final ToSubBean nestedObject;

private final int x;

// all args constructor // all args constructor

// getters... // getters...

} }

以及:

public class ToSubBean {

private final int x;

// all args constructor

} // getters...

假设x应该映射到字段:x载于ToSubBean对象,必须将字段映射定义为:

FieldMapping fieldMapping = new FieldMapping("x", "nestedObject.x");

然后,我们只需要把它传递给Transformer并执行转换:

ToBean toBean = new BeanUtils().getTransformer()

.withFieldMapping(fieldMapping)

.transform(fromBean, ToBean.class);

定义构造器args的不同字段名

还可以通过添加@ConstructorArg构造函数参数旁边的注释。

这个@ConstructorArg接受源对象中对应字段的名称作为输入。

public class FromBean { public class ToBean {

private final String name; private final String differentName;

private final int id; private final int id;

private final List subBeanList; private final List subBeanList;

private final List list; private final List list;

private final FromSubBean subObject; private final ToSubBean subObject;

// all args constructor

// getters...

public ToBean(@ConstructorArg("name") final String differentName,

@ConstructorArg("id") final int id,

} @ConstructorArg("subBeanList") final List subBeanList,

@ConstructorArg(fieldName ="list") final List list,

@ConstructorArg("subObject") final ToSubBean subObject) {

this.differentName = differentName;

this.id = id;

this.subBeanList = subBeanList;

this.list = list;

this.subObject = subObject;

}

// getters...

}

然后:

ToBean toBean = beanUtils.getTransformer().transform(fromBean, ToBean.class);

对特定字段Lambda函数应用自定义转换

我们知道,在现实生活中,很少需要在两个Javabean之间复制几乎相同的信息,经常会发生这样的情况:

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

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

必须验证目标对象的字段

目标对象有一个比源对象更多的字段,需要填充来自不同源的内容。

公牛给出了在特定领域执行任何一种操作的可能性,实际上是利用了Lambda表达式,开发人员可以定义自己的方法,在复制a值之前应用该方法。

让我们用一个例子更好地解释它:

鉴于以下情况Source班级:

public class FromFoo {

private final String id;

private final String val;

private final List nestedObjectList;

// all args constructor

// getters

}

以及以下内容Destination班级:

public class MixedToFoo {

public String id;

@NotNull

private final Double val;

// constructors

// getters and setters

}

假设val在我们的变压器中,场需要乘以一个随机值,我们有两个问题:

这个val字段的类型与Source对象,确实是String一个是Double

我们需要指导图书馆如何应用数学运算。

这很简单,您只需定义自己的lambda表达式即可:

FieldTransformer valTransformer =

new FieldTransformer<>("val",

n -> Double.valueOf(n) * Math.random());

表达式将应用于具有名称的字段。val在目标对象中。

最后一步是将函数传递给Transformer例如:

MixedToFoo mixedToFoo = new BeanUtils().getTransformer()

.withFieldTransformer(valTransformer)

.transform(fromFoo, MixedToFoo.class);

在源对象中缺少字段的情况下指定默认值

有时,在目标对象比源对象具有更多字段的情况下会发生这种情况;在本例中,BeanUtils库将引发异常,通知它它们无法执行映射,因为它们不知道必须从何处检索值。

典型的情况如下:

public class FromBean { public class ToBean {

private final String name; @NotNull

private final BigInteger id; public BigInteger id;

private final String name;

private String notExistingField; // this will be null and no exceptions will be raised

// constructors... // constructors...

// getters... // getters and setters...

} }

但是,我们可以将库配置为为字段类型分配默认值(如:0为int类型,null为String等等)

ToBean toBean = new BeanUtils().getTransformer()

.setDefaultValueForMissingField(true)

.transform(fromBean, ToBean.class);

在源对象中缺少字段的情况下应用转换函数

下面的示例演示如何在源对象中不存在的字段上分配默认值(或lambda函数的结果):

public class FromBean { public class ToBean {

private final String name; @NotNull

private final BigInteger id; public BigInteger id;

private final String name;

private String notExistingField; // this will have value: sampleVal

// all args constructor // constructors...

// getters... // getters and setters...

} }

我们需要做的是分配一个FieldTransformer函数到特定字段:

FieldTransformer notExistingFieldTransformer =

new FieldTransformer<>("notExistingField", () -> "sampleVal");

上述函数将为该字段指定一个固定值。notExistingField,但是我们可以返回任何内容,例如,我们可以调用一个外部方法,该方法返回一组操作后获得的值,如下所示:

FieldTransformer notExistingFieldTransformer =

new FieldTransformer<>("notExistingField", () -> calculateValue());

但是,最后,我们只需要将它传递给Transformer.

ToBean toBean = new BeanUtils().getTransformer()

.withFieldTransformer(notExistingFieldTransformer)

.transform(fromBean, ToBean.class);

将转换函数应用于嵌套对象中的特定字段

案例1:应用于嵌套类中特定字段的Lambda转换函数

给予:

public class FromBean { public class ToBean {

private final String name; private final String name;

private final FromSubBean nestedObject; private final ToSubBean nestedObject;

// all args constructor // all args constructor

// getters... // getters...

} }

以及:

public class FromSubBean { public class ToSubBean {

private final String name; private final String name;

private final long index; private final long index;

// all args constructor // all args constructor

// getters... // getters...

} }

假设lambda转换函数只应用于字段name载于ToSubBean对象时,必须将转换函数定义为:

FieldTransformer nameTransformer = new FieldTransformer<>("nestedObject.name", StringUtils::capitalize);

然后,将函数传递给Transformer目的:

ToBean toBean = new BeanUtils().getTransformer()

.withFieldTransformer(nameTransformer)

.transform(fromBean, ToBean.class);

案例2:应用于特定字段的Lambda转换函数与其位置无关

想象一下在我们Destination类中,有更多相同名称的字段出现在不同的类中,并且我们希望对所有这些类应用相同的转换函数;有一个允许这样做的设置。

以上面的对象为例,并假设我们希望利用name字段独立于它们的位置,我们可以这样做:

FieldTransformer nameTransformer = new FieldTransformer<>("name", StringUtils::capitalize);

然后:

ToBean toBean = beanUtils.getTransformer()

.setFlatFieldTransformation(true)

.withFieldTransformer(nameTransformer)

.transform(fromBean, ToBean.class);

静态变压器功能:

BeanUtils 提供了转换器方法的“静态”版本,当需要在复合lambda表达式中应用时,它可以是一个附加值。

例如:

List fromFooSimpleList = Arrays.asList(fromFooSimple, fromFooSimple);

这一转变应该由以下几个方面来完成:

BeanTransformer transformer = new BeanUtils().getTransformer();

List actual = fromFooSimpleList.stream()

.map(fromFoo -> transformer.transform(fromFoo, ImmutableToFooSimple.class))

.collect(Collectors.toList());

由于这个特性,可以为特定的对象类创建特定的转换器函数:

Function transformerFunction = BeanUtils.getTransformer(ImmutableToFooSimple.class);

然后,可以将列表转换为:

List actual = fromFooSimpleList.stream()

.map(transformerFunction)

.collect(Collectors.toList());

但是,可能发生的情况是,我们已经配置了一个BeanTransformer具有多个字段、映射和转换函数的实例,我们也希望在此转换中使用它,因此我们需要做的是从我们的转换器创建转换器函数:

BeanTransformer transformer = new BeanUtils().getTransformer()

.withFieldMapping(new FieldMapping("a", "b"))

.withFieldMapping(new FieldMapping("c", "d"))

.withTransformerFunction(new FieldTransformer<>("locale", Locale::forLanguageTag));

Function transformerFunction = BeanUtils.getTransformer(transformer, ImmutableToFooSimple.class);

List actual = fromFooSimpleList.stream()

.map(transformerFunction)

.collect(Collectors.toList());

启用Java Bean验证

库提供的特性之一是bean验证。它包括检查转换后的对象是否满足在其上定义的约束。验证在两种默认情况下都有效。javax.constraints还有定制的。

假设字段id在FromBean实例是null.

public class FromBean { public class ToBean {

private final String name; @NotNull

private final BigInteger id; public BigInteger id;

private final String name;

// all args constructor // all args constructor

// getters... // getters and setters...

} }

添加以下配置后,将在转换过程结束时执行验证,在我们的示例中,将抛出一个异常,通知对象无效:

ToBean toBean = new BeanUtils().getTransformer()

.setValidationEnabled(true)

.transform(fromBean, ToBean.class);

在现有实例上复制

即使库能够创建给定类的新实例,并用给定对象中的值填充它,也可能需要在已有实例上注入值,因此给出以下Java bean:

public class FromBean { public class ToBean {

private final String name; private String name;

private final FromSubBean nestedObject; private ToSubBean nestedObject;

// all args constructor // constructor

// getters... // getters and setters...

} }

如果我们需要对已经存在的对象执行副本,则只需将类实例传递给transform职能:

ToBean toBean = new ToBean();

new BeanUtils().getTransformer().transform(fromBean, toBean);

给定字段集上的跳跃变换

如果我们将源对象值复制到已经存在的实例中(某些值已经设置),则可能需要避免转换操作覆盖现有值。下面的示例说明了如何做到这一点:

public class FromBean { public class ToBean {

private final String name; private String name;

private final FromSubBean nestedObject; private ToSubBean nestedObject;

// all args constructor // constructor

// getters... // getters and setters...

} }

public class FromBean2 {

private final int index;

private final FromSubBean nestedObject;

// all args constructor

// getters...

}

如果我们需要跳过一组字段的转换,只需将它们的名称传递给skipTransformationForField方法。例如,如果我们想跳过字段上的转换nestedObject,这就是我们需要做的:

ToBean toBean = new ToBean();

new BeanUtils().getTransformer()

.skipTransformationForField("nestedObject")

.transform(fromBean, toBean);

此功能允许转换保存来自不同源的数据的对象.

为了更好地解释这个函数,让我们假设ToBean(上文定义)应改为:

name字段值已从FromBean对象

nestedObject字段值已从FromBean2对象

可以通过这样做来实现目标:

// create the destination object

ToBean toBean = new ToBean();

// execute the first transformation skipping the copy of: 'nestedObject' field that should come from the other source object

new BeanUtils().getTransformer()

.skipTransformationForField("nestedObject")

.transform(fromBean, toBean);

// then execute the transformation skipping the copy of: 'name' field that should come from the other source object

new BeanUtils().getTransformer()

.skipTransformationForField("name")

.transform(fromBean2, toBean);

字段类型转换

在字段类型与源类和目标不同的情况下,我们有以下示例:

public class FromBean {

public class ToBean {

private final String index;

private int index;

// all args constructor

// constructor

// getters...

// getters and setters...

}

}

它可以使用特定的转换函数进行转换:

FieldTransformer indexTransformer = new FieldTransformer<>("index", Integer::parseInt);

ToBean toBean = new BeanUtils()

.withFieldTransformer(indexTransformer)

.transform(fromBean, ToBean.class);

用Builder模式实现Java Bean的转换

库使用不同类型的Builder模式支持JavaBean的转换:标准模式(默认支持)和自定义模式。让我们详细了解它们,以及如何启用自定义Builder类型转换。

让我们从标准一默认支持:

public class ToBean {

private final Class> objectClass;

private final Class> genericClass;

ToBean(final Class> objectClass, final Class> genericClass) {

this.objectClass = objectClass;

this.genericClass = genericClass;

}

public static ToBeanBuilder builder() {

return new ToBean.ToBeanBuilder();

}

// getter methods

public static class ToBeanBuilder {

private Class> objectClass;

private Class> genericClass;

ToBeanBuilder() {

}

public ToBeanBuilder objectClass(final Class> objectClass) {

this.objectClass = objectClass;

return this;

}

public ToBeanBuilder genericClass(final Class> genericClass) {

this.genericClass = genericClass;

return this;

}

public com.hotels.transformer.model.ToBean build() {

return new ToBean(this.objectClass, this.genericClass);

}

}

}

如前所述,这不需要额外的设置,因此可以通过执行以下操作来执行转换:

ToBean toBean = new BeanTransformer()

.transform(sourceObject, ToBean.class);

自定义生成器模式:

public class ToBean {

private final Class> objectClass;

private final Class> genericClass;

ToBean(final ToBeanBuilder builder) {

this.objectClass = builder.objectClass;

this.genericClass = builder.genericClass;

}

public static ToBeanBuilder builder() {

return new ToBean.ToBeanBuilder();

}

// getter methods

public static class ToBeanBuilder {

private Class> objectClass;

private Class> genericClass;

ToBeanBuilder() {

}

public ToBeanBuilder objectClass(final Class> objectClass) {

this.objectClass = objectClass;

return this;

}

public ToBeanBuilder genericClass(final Class> genericClass) {

this.genericClass = genericClass;

return this;

}

public com.hotels.transformer.model.ToBean build() {

return new ToBean(this);

}

}

}

要转换上面的Bean,要使用的指令是:

ToBean toBean = new BeanTransformer()

.setCustomBuilderTransformationEnabled(true)

.transform(sourceObject, ToBean.class);

4.bean验证

对一组规则的类验证是非常宝贵的,特别是当我们需要确保对象数据符合我们的期望时。

“字段验证”方面是Bull提供的特性之一,它是完全自动的--您只需要用一个现有的javax.validation.约束(或定义一个自定义的约束)对您的字段进行注释,然后对其执行验证。

给定以下bean:

public class SampleBean {

@NotNull

private BigInteger id;

private String name;

// constructor

// getters and setters...

}

上述对象的实例:

SampleBean sampleBean = new SampleBean();

和一行代码,例如:

new BeanUtils().getValidator().validate(sampleBean);

这将抛出一个InvalidBeanException,作为田野id是null.

结语

我试着用例子来解释如何使用Bull项目提供的主要功能。然而,查看完整的源代码可能更有帮助。

可以找到更多的示例,查看在Bull项目上实现的测试用例。这里.

GitHub还包含一个示例弹簧靴项目,该项目使用库在不同层之间转换请求/响应对象,可以找到这里.

为感谢您对我们的认可,特意准备了一些IT入门和进阶的干货

包括:Java、UI设计、H5前端、Python+人工智能、软件测试和新媒体运营六大学科视频资料。以及IT就业大礼包。

线上视频、音频,随时学习观看

关注我们并私信“资料”即可获取。

java bean 转bean_如何用Bull转换任意类型的Java Bean相关推荐

  1. java long类型值不能为0_关于原始类型:Java:为什么不能将int转换为Long

    Java中的所有数字都应为int类型. 以下行在Java> 1.5中是合法的 Short s = 1; // Will compile to Short s = Short.valueOf((s ...

  2. java虚拟机内存模型种类_深入理解volatile类型——从Java虚拟机内存模型角度

    一.前言 在java多线程编程中,volatile可以用来定义轻量级的共享变量,它比synchronized的使用成本更低,因为它不会引起线程上下文的切换和调度.所谓知己知彼.百战不殆.本文从JVM内 ...

  3. .net 转换任意类型不报错

    代码 public T CastAll<T>(object value)         {             T temp = default(T);             tr ...

  4. java 存放大数字_我可以使用什么变量类型在java中保存大量数字(30位数)?

    你可以使用 BigInteger类. BigInteger bi1 = new BigInteger("637824629384623845238423545642384"); B ...

  5. json:JSONObject包的具体使用(JSONObject-lib包是一个beans,collections,maps,java arrays和xml和JSON互相转换的包)...

    1.JSONObject介绍 JSONObject-lib包是一个beans,collections,maps,java arrays和xml和JSON互相转换的包. 2.下载jar包 http:// ...

  6. 如何用Eclipse调试(debug)Java代码?

    如何用Eclipse调试(debug)Java代码? 这是一个目录 如何用Eclipse调试(debug)Java代码? 1.调试展示前的准备 1.1 初始页面展示 1.2 调试代码展示 2.调试步骤 ...

  7. java 对象之间转换_浅谈java对象之间相互转化的多种方式

    浅谈java对象之间相互转化的多种方式,对象,属性,参数,赋值,不支持 浅谈java对象之间相互转化的多种方式 易采站长站,站长之家为您整理了浅谈java对象之间相互转化的多种方式的相关内容. 第一种 ...

  8. java数据类型转化_JAVA基本数据类型及其转换

    Java语言是一种强类型语言.这意味着每个变量都必须有一个声明好的类型.Java语言提供了八种基本类型.六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型.Java另外还提供大数字对 ...

  9. java中的进制输出转换_Java I/O : Java中的进制详解

    作者:李强强 上一篇,泥瓦匠基础地讲了下Java I/O : Bit Operation 位运算.这一讲,泥瓦匠带你走进Java中的进制详解. 一.引子 在Java世界里,99%的工作都是处理这高层. ...

  10. java对象转json字符串日期格式_fastJSON字符串类型数据中的日期转换为Java bean的日期对象...

    fastJSON字符串类型数据中的日期转换为Java bean的日期对象 Person.java import java.io.Serializable; import java.util.Date; ...

最新文章

  1. Springboot swagger2教程
  2. 数据重现之11.5.2:RAID5同步与异步的判断
  3. Android——build.prop 解析
  4. Linux命令--- /dev/null和/dev/tty
  5. Python学习-2.安装IDE
  6. 上海自考计算机及应用,上海交通大学--计算机及应用(独立本科080901)
  7. apollo重要服务之metaService
  8. JAVA实现数学函数图像
  9. 关于MFC窗口隐藏的方法
  10. 小程序常见故障解决方法分享|微信小程序平台常见拒绝情形
  11. [Python]TempConvert.py(温度转换)解释拓展
  12. 毛不易 胡同 伴奏 高品质定制纯伴奏
  13. 升级JSONB列式存储,Hologres助力淘宝搜索2022双11降本增效!
  14. 微服务(四)——统一网关
  15. zsh 自定义命令提示符(PS1/ prompt)
  16. 【Joy of Cryptography 读书笔记】Chapter 1 一次性密码本(one-time pad)Kerckhoffs原则
  17. idea maven 下载源码出现:Cannot download sources Sources not found for: xxx
  18. 2015创新工场涂鸦移动测试题-软件工程师
  19. 什么是ARM,STM32?
  20. linux系统下编译fpga工程,【工程师分享】整合Xilinx PetaLinux工程编译和Open Source U- Boot/Linux编译...

热门文章

  1. 实测 | 分羹无线市场 天融信无线AP究竟有多强?
  2. [HITML]哈工大2020秋机器学习复习笔记
  3. 第四章第六题(圆上的随机点)(Random points on a circle)
  4. uniapp基本语法/组件使用
  5. 期货基础知识(竞价,定价,保证金计算)
  6. ceph-创建使用rule-ssd规则的存储池
  7. MCS51 程序存储器(ROM)
  8. spring默认redis连接库lettuce性能优化,突破性能天花板,获得官方建议方式2倍吞吐量
  9. PTC指定位置安装许可服务器,PTC安装在终端服务器上的問題
  10. java:/comp/env_启动日志中就出现[java:comp/env/spring.liveBeansView.mbeanDomain] not found这个日志...