JPA allows for two types of access to the data of a persistent class. Field access which means that it maps the instance variables (fields) to columns in the database and Property access which means that is uses the getters to determine the property names that will be mapped to the db. What access type it will be used is decided by where you put the @Id annotation (on the id field or the getId() method).
I have developed a preference for field access mainly for two reasons. First, because I frequently define getter methods that are not property accessors e.g. a getter that does not just return the value of a field but does a calculation and returns the result. In that case (and if you use property access) you have to annotate the getter with @Transient. If you forget to do this (as I did many times) you are looking for trouble. JPA will think that the getter corresponds to a property and funny things will happen.
The second reason I prefer field access is that with property access you have to define getter methods for every field just for use by JPA even if your code will never call them.
Until now I haven't find any argument in favor of property access but I would like to hear if anybody has.
24 comments:
+1 field access
I agree with your reasons, but 95% of the time I will use property access (in hibernate). The reason is that field access breaks encapsulation. Have a look at 3.2.5 of Java Persistence with Hibernate.
A place where I always use field access is the id (because I definitely don't want to provide a setter there - even a private one) and on the version field.
Related posts:
http://www.missiondata.com/blog/java/67/hibernate-and-your-getters-and-setters/
http://crazybob.org/2005/10/i-heart-getters-and-setters.html
@cherouvim
I don't understand how field access (in the JPA sense) breaks encapsulation since all fields are private. By saying that I avoid "property access" I don't mean that I don't have getters and setters. I just don't annotate them instead of fields.
From my point of view the best reason to go the Property way is performance: If you often loop through collections and only read the id of the entities Hibernate doesn't need to fetch the entities from the database if you use property access type.
(Because then Hibernate knows getId() only returns the id it already has, but Hibernate has no clue what your getId() method returns if you have marked @Id Long id;)
I usually use field access type and pretty often end up want to loop through collections and only read their id...but then I need to batch the entities...or query for them... or cheat and make my id public!
/Jens X
A method's intentions and purposes must be clear. Anything other than returning the value of a property in a getter method is unclear by it's name. Also, using reflection it is not possible to access superclass fields without overruling security measures, which should be avoided.
I don't have a hard rule.
When an entity is new (to my project), I start with field access. This is friendly to my eclipse IDE action that creates setters/getters. Dealing with method annotation slows me down at this stage.
Later, only if there is a design intent that would require method annotation would I change over.
Regards.
I also use field access only. It sometimes happens that I have to change something in the annotation and I don't wanna hunt trough the code to find the getter. Also it's very easy for another person analyzing the code to see the entity mapping checking much less code.
Beside that, if you ever plan to check things like Groovy, you'll see you don't even need to declare getters/setters (they are generated by the compiler) ... so even if just for the sake of clarity, field access is the way to go.
I think field access has the advantage that your annotated persistent fields are all neatly organized near the top of your class.
But I have to say that field access breaks encapsulation. Here's an example where it will bite you:
You use hibernate validator and write a unit test to verify that your validations are working. You'd like to use a mock of your entity, but your hibernate validator annotations are on the fields (you would naturally want them in the same place as your persistence annotations). You can mock the 'getProperty()' call to return whatever you want, but the validation will still fail because it is looking at the field and not the 'getProperty()' call.
Just a thought.
As Eduard implied "field" is intuitive. "Simple" is the keyword. If your application design requires twists 'n tweaks you should consider how many engineers will need to hack though how many classes during your application's full life cycle.
I have run into problems using entities from ejbs in the web tier. I get the lazy loading exception when a transactional context has ended. Eager loading does not work because if I have two related classes, sometimes I want one class with its relations and at other times the second class (with a relationship to the first). Making them both eager is a mixed bag and the persistence provider dies creating references in a loop back and forth. Seeing as the annotation is on the entity, I can't switch the logic for different use cases, the entity class is what it is. Therefore, I am reverting to an old pattern I used to use with pre jpa hibernate and try to apply it to jpa annotations. I will have value objects with no annotations or logic, then extend, override the getters and apply the annotations. I will have data transfer objects which may contain many value objects, free of jpa annotations. These will expose various other getters with some JAXB bindings so that the web tier can simply marshal them to the response. This gives me the flexibility to be able to get specific data from an ejb call and keep the business logic and transaction boundaries in the Ejb Tier. I am just about to try and stumbled across this while researching and thought I might use the scenario to suggest a reason for putting annotation on getters...simply, you don't override fields. Thanks for the blog, I hope you enjoy my comments.
Dom
here is a compilation of all pointers regarding the @AccessType annotation in hibernate. I happen to write on this since we were facing a few issues related to this today!
I always preferred field access. Without any reason but I thought field access is more visible.
But recently I have gone through a document of OpenJPA, and found that property access is better.
OpenJPA uses an enhancer, which is required to run over all entities.
If we dont use enhancer then, following is the extract from OpenJPA documentation:
"If you are using field access for your persistent data, then OpenJPA will not be able to track accesses for any instances, including ones that you load from the database. So, OpenJPA will perform state-comparison checks to determine which fields are dirty. These state comparison checks are costly in two ways. First, there is a performance penalty at flush / commit time, since OpenJPA must walk through every field of every instance to determine which fields of which records are dirty. Second, there is a memory penalty, since OpenJPA must hold hard references to all instances that were loaded at any time in a given transaction, and since OpenJPA must keep a copy of all the initial values of the loaded data for later comparison. Additionally, OpenJPA will ignore requests to evict persistent state for these types of instances. Finally, the default lazy loading configuration will be ignored for single-valued fields (one-to-one, many-to-one, and any other non-collection or non-map field that has a lazy loading configuration). If you use fetch groups or programmatically configure your fetch plan, OpenJPA will obey these directives, but will be unable to lazily load any data that you exclude from loading. As a result of these limitations, it is not recommended that you use field access if you are not either running the enhancer or using OpenJPA with a javaagent or in a Java 6 environment."
Thanks. I haven't use anything but hibernate as a persistence provider but this is useful in case of an OpenJPA provider.
they should make changes to Open JPA, field access is more readable!!!
childBean.getParent().getId() incurs a penalty in hibernate if using annotations on fields. If you use the annotation on methods, no penalty arises. We do alot of Dto's so we call alot of these getId methods and don't want it hitting the database!!!! so methods are better for that case. I am not sure they will fix it either as the method invocation on getId is what triggers the lookup and they don't know that getId is simply returning the id field(could be returning the name field) so I think it may stay that way??? though I like putting my annotations on fields better as I hate having to Transient some of my getMethods that take from multiple fields....oh well.
Field access is better because:
1. JPA inherently breaks encapsulation. You use raw data-members in your queries, methods are not supported. Why worry elsewhere?
2. Property setters can have side-effects. Do you really want to run business logic every time an object is restored from the database? Setting an account type (and executing the associated business logic) is a totally different use case to restoring the value of the account type. This is where JPAs @Access becomes useful.
3. Interesting that OpenJPA relies on method access as a way to see if an object changes - but it is not really a valid reason to use setters - just an unfortunate performance optimisation.
This is the major issue here:
"...getter methods that are not property accessors..."
A getter is supposed to be just that: a getter, and nothing else. if getFoo() does anything more than simply returning foo it's evil. Of course, the same holds true for setters.
Besides, moving towards a real (as opposed to anemic) domain model you'll find that you don't always need getters and setters.
Don't you think
private Boolean blocked;
public void block() {
blocked = Boolean.TRUE;
}
public void unBlock() {
blocked = Boolean.FALSE;
}
public boolean isBlocked() {
return blocked;
}
}
is way better than
private Boolean blocked;
public void setBlocked(Boolean blocked) {
this.blocked = blocked;
}
public boolean isBlocked() {
return blocked;
}
}
Good point
I'm just getting started with JPA so maybe I'm missing something but one shortcoming I see with JPA is that it doesn't seem to have an equivalent of Hibernate UserTypes. So what if I want to use Joda Time in my project and persist an object with a Joda DateTime field? One approach I've seen and was planning on using was supplementing my get/setEventDateTime() methods with get/setEventDateTimeAsDate() methods that convert to and from java.sql.Date objects, then mapping those getters/setters. Would that approach be discouraged? It sort of muddles the Java model a bit but it seems like the best way to use the types/libraries you want and persist them with JPA. Thoughts?
I, generally prefer clear getters/setters that do exactly that: get/set fields without any transformation. If you 've read somewhere that your approach is working, then try it out and share your experience. Otherwise, you can try some mixing of hibernate annotations with JPA (it mostly works).
I prefer field access for a reason that I don't think has been mentioned yet.
The state of an object is fully represented by its instance fields. Directly saving and retrieving objects using these values guarantees a retrieved object is in the same state as when it was saved.
I'm sure there are exotic cases where this might not be what is wanted, but usually, it is.
I am about painfully rewriting the application from field access to getters ... because with field acces you have problem.
Entity A, has a lazy binding to the entity B.
In your app you load entity A (that way the B is also semi-loaded (by that I mean, that ID is fetched, but none other fields) ... and later you for example make a select by parameter that selects also you entity B ... and later you use b.graduationDate ... et voila... null ... Happy coding, but it is a pitty you cannot use field access (at least with hibernate).
It's been a year since I commented on this and my thoughts on field vs property access when it comes to working around JPA's lack of a Hibernate UserType equivalent. Although I prefer field access, using property access with getters/setters that do the conversion was the best solution I found. I just wrapped post on the subject and thought I would share for anyone who is interested.
http://workingonthecoolstuff.blogspot.com/2013/01/jpa-alternatives-to-hibernate-usertypes.html
Your summaries are always top-notch. Thanks for keeping us apprised. I’m reading every word here.
Post a Comment