支持最终字段的Java持久性提供程序

时间:2010-03-16 15:55:11

标签: java persistence

我是Java的新手,但我一直在养成使用final的习惯,尽可能宣布不变性,我认为这是一件好事。 (考虑f#)

我读过JPA不支持最终字段。 Hibernate,TopLink?我不确定这些,但我现在更喜欢JPA。

这在理论上是否可行 - 让我们通过反思说 - 在创建后修改最终字段?我的猜测是...... NO:)

持久性解决方案当然可以支持带参数的构造函数。至少我认为没有理由会让这件事变得不可能。我猜,映射会有点棘手。 这是另一种解决方案。

建议?

编辑:我不熟悉不可变的确切定义,所以我在这篇文章中直观地使用了它。在此声明不变性意味着声明无法更改字段。对不起有误。

5 个答案:

答案 0 :(得分:6)

对象不变性(注意不可变对象之间的区别,并声明字段final - 如果所有字段都是final,则对象只是不可变的,因此对象的状态在创建后不能更改)是一个非常敏感的主题。我自己喜欢它们,而hibernate通过@Immutable支持它们。

不知道它在JPA 2中的状态,但回答有关最终字段的问题:您可以使用反射更改其值 - 但在Java EE环境中反射受到严重限制。

启发主要问题:如果您的POJO是不可变的,那么持久解决方案将如何重新创建对象?假设你有两个最终的int字段,以及一个初始化它们的构造函数。持久层不能包含有关其顺序或其名称的任何信息(因为字段和参数名称在编译期间会被删除)。

Koshuke发布了一篇关于此的博客(关于支持不可变bean的JAXB),但现在找不到它。

答案 1 :(得分:3)

这可能并不完全是您所追求的目标,但不具有吸气剂的非最终私人领域可以轻松支持不变性原则。事实上,编译器会识别这一点,并生成与声明为final的字段完全相同的代码。

这将要求你尽职尽责,不要在包含的类中改变你的字段(而final会强制执行),但我认为这不是为你获得的灵活性付出的代价。 / p>

答案 2 :(得分:1)

好问题。实际上,如果字段没有改变,那么将字段声明为final是个好主意(然后从JMM获得初始化保证)。

JPA Spec对最终字段很清楚:

  

实体类不能是最终的。   实体类的方法或持久化实例变量可能是最终的。

但是,并非所有实现都遵循此规则并处理最终字段:

  • OpenJPA不支持最终字段,即它们被视为瞬态字段。 加载后,使用值as初始化此类实体的最终字段 在无参数构造函数中定义。

  • 然而,Hibernate实现支持最​​终字段。在建造最后的领域 已在无参数构造函数中初始化的值将替换为存储的值 在数据库中。

所以回答你的问题:是的,有JPA持久性提供程序支持最终字段, 但是我建议不要在实体类中使用final字段,因为没有定义行为 (实际上与提供商不同)。而且,我认为这是一个坏主意 JPA提供商在构建后更改最终字段,因为可能会以这种方式违反可见性保证。

答案 3 :(得分:0)

在设计创建后无法修改最终字段。否则是一个非常糟糕的主意,因为有人可以依赖标准行为。

通常,持久性框架处理“普通”对象的层次结构。您有对象,只能创建和删除,不能修改。这很奇怪,因为当你创建一个实体时,你会为它创建一些ID。通过此ID,您可以将实体连接到其他人。当您删除旧实体并创建另一个实体时,您(通常)会获得具有另一个ID的实体。因此,所有连接(外键)都被破坏了。它是目标行为吗?

答案 4 :(得分:-1)

这是一个奇怪的想法。

通过创建字段final,您告诉编译器在创建对象后他们永远不会更改。因此,不坚持它们是合理的假设,因为它们永远不会改变。好吧,通过写这篇文章,我假设你有java文化,但你提出的问题恰恰相反。

在Java中,持久化的obejcts“总是”被假定为POJO(换句话说,Java Bean)。 Java Bean必须具有(被认为是这样)一个空构造函数,它允许持久框架等使用其空构造函数构造它,通过Class.newInstance()/间接调用它。

有些字段使用非空构造函数(如IoC容器 - Guice,Spring和Tapestry IoC),但它超出了Java Bean的范围,必须将其视为数据对象。