I\'m very new to Java but I\'ve been developing a habit to use final wherever possible declaring immutability which i think is a good thing. (Consider f#)
I\'ve read
Object immutability (note the difference between an immutable object, and declaring a field final - an object is ONLY immutable if ALL fields are final, thus the object's state can't change after creation) is a very sensitive topic. I like them myself, and hibernate supports them through @Immutable.
Don't know about it's status in JPA 2, but to answer the question about final fields: you CAN change their values using reflection - but reflection is severly limited in a Java EE environment.
To enlighten the main problem: if your POJOs are immutable, then how would a persistent solution recreate the objects? Let's say you have two final int fields, and a constructor to initialize them. The persistence layer cannot have any information about their order, or their names (as field and parameter names are erased during compiling).
Koshuke posted a blog about this (in relation to JAXB supporting immutable beans), but can't find it right now.
This may not be exactly what you're striving for, but the immutability principle can easily be supported by non-final private fields having only a getter. The compiler in fact recognizes this and generates code which is pretty much identical to what you'd get with fields declared as final.
This will require you to be conscientious and not change your fields from within the containing class (whereas final
would enforce that), but I think this is not a big price to pay for the flexibility you gain.
Good question. Actually it is a good idea to declare fields as final if they do not change (you get then initialization guarantees from the JMM).
The JPA Spec is clear regarding final fields:
The entity class must not be final. No methods or persistent instance variables of the entity class may be final.
Hoever, not all implementations follow this rule and handle final fields:
OpenJPA does not support final fields, i.e. they are treated as transient. Upon loading the final fields of such an entity are initialized with the values as defined in the parameterless constructor.
The Hibernate implementation however supports final fields. Upon construction the final fields which have been initialized in the parameterless constructor are replaced with the values stored in the database.
So to answer your question: Yes, there are JPA persistence providers which support final fields, however I recommend not using final fields in your entity classes as the behavior is not defined (and actually differs from provider to provider). Moreover, I think it is a bad idea that a JPA provider changes final fields after construction because visibility guarantees may be violated this way.
Final fields can't be modified after creation by design. Doing otherwise is a very bad idea, because somebody can rely on standard behavior.
In general, persistence frameworks deal with hierarchies of "normal" objects. You have objects, that can be only created and removed, not modified. That's very odd, because when you create an entity, you create some kind of ID for it. Through this ID you connect entity to others. When you remove old entity and create another, you (in general) get an entity with another ID. So, all connections (foreign keys) are broken. Is it target behaviour?
This is honestly a strange idea.
By making fields final
, you tell the compiler they'll never change after object creation. As a consequence, it is a reasonable assumption to not persist them, since they will never change. Well, by writing this, I assume you have the java culture, but the question you ask precisely tells the contrary.
In Java, persisted obejcts are "always" assumed to be POJO (in other words, Java Beans). A Java Bean must have (to be considered as such) an empty constructor that will allow persistance frameworks and so on to construct it using its empty constructor, by indirectly calling it through Class.newInstance()/.
There are fields where non empty constructors are used (like IoC containers - Guice, Spring and Tapestry IoC), but it is out of the scope of Java Beans, which have to be considered as data objects.