JPA Implementation Patterns: Field Access vs. Property Access
The JPA specification allows two ways for the persistence provider
to access the persistent state of an entity. The persistence provider
can either invoke JavaBeans style property accessors (getters and
setters) or access the instance fields of the entity directly. Which
method is used depends on whether you have annotated the properties or
the fields of an entity.
The JPA 1.0 specification
does not allow you to mix access types within an entity or even an
entity hierarchy. If you have annotated both fields and properties, the
behaviour is undefined. The JPA 2.0 specification has the @Access annotation that makes it possible mix access types within an entity or entity hierarchy.
But the interesting question remains; which access type to use? A question that has been discussed before, but one I couldn't resist commenting on too.
- Encapsulation - Property access is said to provide better encapsulation, because directly accessing fields is bad, right? Well actually, using property access obliges you to write getters and setters for all your persistent properties. These methods not only allow the JPA provider to set the fields, they also allow any other user of your entity class to do this! Using field access allows you to write only the getters and setters you want to (they're evil, remember?) and also write them as you want them, for example by doing validation in your setters or some calculation in your getters. In contrast, making these methods smarter when using property access is just asking for trouble.
- Performance - Some people prefer field access because it supposedly offers better performance than property access. But that is a very bad reason to choose field access. Modern optimizing JVMs will make property access perform just as fast as field access and in any case database calls are orders of magnitude slower than either field access or method invocations.
- Lazy loading in Hibernate - Hibernate's lazy
loading implementation always initializes a lazy proxy when any method
on that proxy is invoked. The only exception to this is the method
annotated with the @Id
annotation when you use property access. But when you use field access
there is no such method and Hibernate initializes the proxy even when
invoking the method that returns the identity of the entity. While some
propose to use property access until this bug
is fixed, I am not in favour of basing design decisions on framework
bugs. If this bug really hurts your performance you might want to try
and get the id of entity with the following code:
Serializable id = ((HibernateProxy) entity).getHibernateLazyInitializer().getIdentifier()
It's nasty, but at least this code will be localized to where you really need it.
- Field access in Hibernate - It is good to know that while field access is OK for Hibernate to populate your entities, your code should still access those values through methods. Otherwise you will fall into the first of the Hibernate proxy pitfalls mentioned by my colleague Maarten Winkels.
To summarize I think field access is the way to go because it offers better encapsulation (without it properly managing bidirectional associations is impossible) and the performance impact is negligible (#1 on the performance problems top 10 is still the interplay between the database and your Java app). The only downside are some snafu's in Hibernate's lazy loading implementation that require you to take extra care when using field access.
What access type do you prefer? Do you see any difference in the way field access and property access are implemented in JPA providers other than Hibernate? Please let me know by leaving a comment below. See you at the next JPA implementation patterns blog in which I will talk about mapping inheritance hierarchies in JPA.
Vincent Partington has more than 10 years of enterprise Java experience. He has written and presented on topics as diverse as performance, security, RIA, and persistence technologies. Vincent Partington is the Chief Technical Officer of XebiaLabs where he is responsible for their flagship deployment automation product Deployit. Vincent is a DZone MVB and is not an employee of DZone and has posted 14 posts at DZone.
- Login or register to post comments
- 3772 reads
- Printer-friendly version
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)










Comments
Peter replied on Wed, 2009/09/09 - 3:58am
Hi Vincent,
I also prefer the direct field access approach. An object is valid when it is is persisted and it should still be valid when it is rematerialized. So no need for additional check and no need to struggly with partial materialized objects and smart setters.
Peter Veentjer
Multiverse Software Transactional Memory.
Jeroen Wenting replied on Wed, 2009/09/09 - 6:40am
This of course also puts a lie to the argument that field access is faster, because it's actually slower.
Remains the only reason to use field access which is that you may not want a getter and setter for the field (maybe it's a calculated value that's never published, used only by some reporting engine or whatever that queries the datastore directly, but in that case it's arguably better that consumer calculate the value rather than you.
Robin Bygrave replied on Wed, 2009/09/09 - 8:29am
in response to: jwenting
@Jeron Actually field access does not require reflection - code generation can be used instead (for both the "enhancement approach" and the "dynamic proxy approach") - certainly that has a performance improvement over reflection but ... reflection on the server JVM is pretty quick. The differences here end up pretty small when compared with query execution performance.
I'd agree that it generally comes down to whether you put logic in your entity beans and the extra care you need to take with property access when you do that.
For interest some of the Field vs Property debate has occured on a previous thread ... but IMO it didn't quite get concluded unfortunately. Maybe this time :)
http://eclipse.dzone.com/tips/12-feb-jpa-20-why-accesstype
Cheers, Rob.
Robin Bygrave replied on Wed, 2009/09/09 - 8:33am
in response to: alarmnummer
@Peter
> So no need for additional check
What additional check? Property Access has an additional check?
> and no need to struggly with partial materialized objects
Can you explain this a bit more? I don't understand ...
Peter replied on Wed, 2009/09/09 - 10:12am
in response to: rbygrave
@Robin
>What additional check? Property Access has an additional check?
It could be. Especially if you have a non anemic domain model.
>and no need to struggly with partial materialized objects
If setters are used when an object is 'rematerialized' from the database, all fields need to be set one after another. So untill all fields are set, the object is in an 'undefined' state. If you have added logic to the setters, and non materialized fields are read, strange things could happen.
class Person{ int dateOfBirth; int dateOfDeath; public void setDateOfBirth(int newDateOfBirth){ if(newDateOfBirth>dateOfDeath){ throw error } this.dateOfBirth = newDateOfBirth; } public void setDateOfDeath(int newDateOfDeath){ ...something similar } }If a Person is rematerialized, the fields are not set to the correct value (yet). If the dateOfBirth is set first, you get an error because the newDateOfBirth will be larger than the dateOfDeath. The only reason why this problem can happen is that the Person object is not (yet) in a valid state when methods are called and this could cause all kinds of strange problems. So that is why I prefer field level access.Andy Jefferson replied on Wed, 2009/09/09 - 11:13am
in response to: alarmnummer
If using a JPA implementation that employs bytecode enhancement I fail to see how this "partial materialization" problem can happen. All field access is enhanced, hence triggering any load of fields.
--Andy (DataNucleus)
Robin Bygrave replied on Wed, 2009/09/09 - 5:31pm
in response to: alarmnummer
@Peter - ok, I see where you are coming from. The assumption being that the ORM itself is using the setter method to populate the bean when Property Access is used.
Hmmm... I wonder what exactly the JPA spec says... does it say say the ORM will use the setter method to populate the bean. I guess this is implied by the definition of Java Beans Property.
The other approach an JPA vendor can make is to internally not use the setter method (when populating the bean) - so the setter method (and the logic in it) is only used by application code calling the setter. Another method is generated and used internally to populate the bean (so it might be possible to get different behaviour from different JPA vendors).
The reason an vendor might do this (not use the setter but use its own method to populate the bean) would be to provide support for PropertyChangeListeners etc.
@Andy - for PropertyAccess does DataNucleus use the setter?
NB: For what its worth Ebean ORM doesn't use the setter (generates it's own method) but its not strictly a JPA implementation.
Andy Jefferson replied on Thu, 2009/09/10 - 4:48am
in response to: rbygrave
> for PropertyAccess does DataNucleus use the setter?
DataNucleus doesn't "use" any setter since that is dependent on a user defining one. Look at the JDO spec for standardised bytecode enhancement providing field access detection.
--Andy (DataNucleus)
mgira replied on Thu, 2009/09/10 - 6:47am
I think that field access is a more natural representation of what persistence is about: Persisting the internal state of an object.
Saying that it breaks encapsulation is imho a proof that the concept of persistence has been misunterstood.
The fact that HIbernate requires a workaround is just another point on my personal "Workarounds & things to keep in mind when using Hibernate" list, i'm glad i don't use Hibernate anymore, it's getting anoying to have to use tricks & workarounds in my projects just to make them work with hibernate, "non invasive" persistence is different.