长期以来,Java一直遭受着Bean的痛苦。 要声明一个简单的数据类需要太多的代码。 在JavaOne 2016上,我谈到了代码生成选项--见幻灯片。
可变和不可变的Bean的代码生成
Java的生态系统是庞大的。这么多的库作为开源及以上版本发布,这自然导致了一个问题,即这些库如何沟通。而豆的基本概念才是必不可少的粘合剂,尽管规范很古老。 ORM(Hibernate等)、序列化(Jackson等)和豆映射器(Dozer等)如何沟通?通过getters和setters。
Bean的基本特征已经超越了JavaBeans规范,有时被称为POJOs,这些特征是:
- 可变的
- 无args构造器
- 获取器和设置器
- equals() / hashCode() / toString()
但是手动编写这些是很慢的,繁琐的,容易出错的。 代码生成应该能够在这里帮助我们。
但是我们应该在2016年使用可变豆吗?不,不,不!
现在是编写不可变数据结构(不可变Bean)的时候了。 但唯一实用的方法是代码生成,特别是如果你想拥有构建器的话。
在我在JavaOne 2016的演讲中,我考虑了各种代码生成方法。
IDE代码生成
这种方式就目前而言还不错,但虽然代码生成后很可能立即正确,但仍然不能保证随着类的长期维护,生成的代码会保持正确。
AutoValue、Immutables和VALJOGen
这三个项目--AutoValue、Immutables、VALJOGen--使用注解处理器在编译过程中生成代码。 其想法很简单--开发者编写一个抽象类或接口,工具代码在编译时生成实现。然而,这些工具都专注于不可变的Bean,而不是可变的(Immutables可以生成一个可修改的Bean,但它不符合JavaBeans规范,所以许多工具会拒绝它)。
从好的方面看,没有机会搞乱equals/hashCode/toString。 虽然这些工具都允许在必要时手动编写方法,但大多数时候,默认的方法就是你想要的。 不用手动实现不可变的构建器类也很好。
从不利的一面来看,作为开发者,你必须编写抽象的方法,而不是字段。 方法比字段要多敲几下键盘,而且Javadoc也需要一个@return行。 对于AutoValue来说,这特别痛苦,因为你必须编写构建器类的大纲。 对于Immutables来说,没有这个必要。
在这三个项目中,AutoValue提供了一个直接的简单工具,而且实现类是隐藏的(包范围)。 Immutables提供了一个全功能的工具,有许多选项和生成方式。默认情况下,实现类是公开可见的,并由调用者使用,但有一些方法可以使其成为包范围(由你编写更多的代码)。VALJOGen允许完全定制生成模板。 毫无疑问,Immutables是这三个项目中最全面的。
这三个注释处理工具在使用前都必须进行设置。一般来说,将工具添加到Maven中就可以完成大部分工作(Maven支持度很高)。对于Eclipse和IntelliJ,这些说明很全面。
Lombok
Lombok项目也使用注解来控制代码生成。 不过,它不是作为一个注解处理器,而是黑进Eclipse和Java编译器的内部API。
这种方法允许代码在同一个类中生成,避免了开发者使用抽象类或接口的需要。这意味着,开发者不需要写抽象方法,而是写字段,这是一件更自然的事情。
Lombok的关键问题不是它生成了什么,而是它生成的方式。如果你愿意接受笨拙的方法、IDE的限制以及无法对生成的代码进行调试,那么它就是一个足够整洁的解决方案。
对于Eclipse来说,必须安装Lombok,这相当简单,因为它有一个GUI。其他的工具需要其他的安装方法,请看这个页面。
Joda-Beans
Joda-Beans项目采取了第三种方法来生成代码。 它是一个源代码再生器,在同一个源文件中创建代码,由 "自动生成的开始/结束 "注释来标识。
开发人员编写字段,而不是抽象方法,这更简单,代码更少。他们还将代码生成到同一个类中,如果需要的话,这些代码可以是最终的。
将所有代码生成到同一个类中的一个关键好处是,这些代码在签出时是完全有效的。 不需要安装一个插件或以任何方式配置你的IDE。
与其他选择不同,Joda-Beans还提供了运行时的功能。 它的目的是将C#风格的属性添加到Java中。 这在实践中意味着你可以很容易地将Bean视为一组属性,在属性上循环,并使用标准化的构建器创建实例。 这些特性是序列化框架的理想构件,Joda-Beans提供了XML、JSON和二进制序列化,使用这些属性进行操作,一般不需要反射。 这里的交易是,Joda-Beans是一个运行时依赖,所以只有在你使用额外的属性特性时,它才是最佳选择。
Joda-Beans再生器可以使用插件从Maven中运行。如果你使用标准的Eclipse Maven支持,那么只要在Eclipse中保存文件就能再生。也有一个Gradle插件。
比较
大多数项目都有一些吸引力:
- AutoValue是一个简单的注解处理器,它隐藏了实现类,但需要更多代码来触发它。
- Immutables是一个灵活而全面的注解处理器,可以在很多方面使用。
- Lombok需要开发者编写最少的代码,但其代价是通过内部API实现。
- Joda-Beans的不同之处在于它有一个运行时的依赖性,将C#风格的属性添加到Java中,使代码能够可靠地在Bean上循环。
我更喜欢Joda-Beans(这是我写的),因为我喜欢生成的代码在同一个源文件中,所以调用者看到的是一个正常的最终类,而不是一个接口或抽象类。这也意味着,当从源码控制中签出时,它可以在没有配置过的IDE中立即编译。但是,Joda-Beans真的应该只在你理解它所提供的属性支持的价值时才使用。
如果让我挑选另一个工具,我会使用Immutables。它很全面,只要你投入时间选择最适合你需求的方式来生成Bean,它应该有你需要的一切。
最后,让读者有机会看看所写的代码和生成的代码是很重要的。 为了做到这一点,我创建了compare-beangenGitHub项目。 这个项目包含了上述所有工具的源代码,还有更多,演示了你要写什么。
为了最好地利用该项目,请检查它并将其导入你的IDE。这样,你将体验到代码生成的含义,以及使用它的实用性。(例如,看看当你重命名一个字段/方法/类时会发生什么。代码生成器能应付吗?)
总结
是时候开始编写和使用不可变的Bean而不是可变的Bean了。Strata开源市场风险项目(我的日常工作)没有可变的Bean,所以完全可以做到。 但是要使用不可变的Bean,你就需要一个代码生成器,否则使用起来就太痛苦了。
这篇博客总结了五种代码生成器,并提供了一个不错的GitHub项目,供你自己进行比较。