Hibernate Annotations - Which is better, field or property access?
Asked Answered
B

25

155

This question is somewhat related to Hibernate Annotation Placement Question.

But I want to know which is better? Access via properties or access via fields? What are the advantages and disadvantages of each?

Blakeney answered 27/2, 2009 at 12:44 Comment(0)
P
31

I prefer accessors, since I can add some business logic to my accessors whenever I need. Here's an example:

@Entity
public class Person {

  @Column("nickName")
  public String getNickName(){
     if(this.name != null) return generateFunnyNick(this.name);
     else return "John Doe";
  }
}

Besides, if you throw another libs into the mix (like some JSON-converting lib or BeanMapper or Dozer or other bean mapping/cloning lib based on getter/setter properties) you'll have the guarantee that the lib is in sync with the persistence manager (both use the getter/setter).

Preindicate answered 16/4, 2009 at 18:2 Comment(6)
Note this is about how the ORM accesses your fields/properties and not your application code. With field access your getNickName() method would work exactly as you'd expect. The same is not true if you use the persistent 'properties' outside getters/setters. That is where you may hit issues with property access and lazy loading. So no, I don't agree with this argument in general. However, last time I checked Hibernate had issues with field access of @Id fields.Phelps
this answer is not related to the question. Best answer s by duffymoAdriel
there shouldn't be any business logic inside accessors. that's not obvious behaviour.Bosomy
Why is this response mark as correct ? It is not true you can mapping field and provide it a setter/getter in the same way.Perilous
I am about to experiment with this, but could this be inherited through an interface ?Hippopotamus
Every jpa session will generate update query for person, because Person object is always dirty at the end of the sessionExuviate
S
264

There are arguments for both, but most of them stem from certain user requirements "What if you need to add logic for", or "xxxx breaks encapsulation". However, nobody has really commented on the theory, and given a properly reasoned argument.

What is Hibernate/JPA actually doing when it persists an object - well, it is persisting the STATE of the object. That means storing it in a way that it can be easily reproduced.

What is encapsulation? Encapsulations means encapsulating the data (or state) with an interface that the application/client can use to access the data safely - keeping it consistent and valid.

Think of this like MS Word. MS Word maintains a model of the document in memory - the documents STATE. It presents an interface that the user can use to modify the document - a set of buttons, tools, keyboard commands, etc. However, when you persist (Save) that document, it saves the internal state, not the set of keypresses and mouse clicks used to generate it.

Saving the internal state of the object DOES NOT break encapsulation - otherwise, you don't really understand what encapsulation means, and why it exists. It is just like object serialization really.

For this reason, IN MOST CASES, it is appropriate to persist the FIELDS and not the ACCESSORS. This means that an object can be accurately recreated from the database exactly how it was stored. It should not need any validation, because this was done on the original when it was created, and before it was stored in the database (unless, God forbid, you are storing invalid data in the DB!!!!). Likewise, there should be no need to calculate values, as they were already calculated before the object was stored. The object should look just the way it did before it was saved. In fact, by adding additional stuff into the getters/setters you are actually increasing the risk that you will recreate something that is not an exact copy of the original.

Of course, this functionality was added for a reason. There may be some valid use cases for persisting the accessors, however, they will typically be rare. An example may be that you want to avoid persisting a calculated value. However, you may want to ask the question why you don't calculate it on demand in the value's getter, or lazily initialize it in the getter. Personally, I cannot think of any good use case, and none of the answers here really give a "Software Engineering" answer.

Subjunction answered 21/5, 2011 at 21:56 Comment(7)
The software engineering answer is: using accessors violates DRY.Someplace
Very good one. Before I read this I'd been hesitating which one to use.Tan
@Subjunction I have a follow-up question regarding the last paragraph of your answer. You wrote "An example may be that you want to avoid persisting a calculated value". How can you avoid persisting a calculated value by having property based access? I know you are arguing not to do so but I am not getting the point here. Can you please explain?Desdamona
@Desdamona Now that I read it back I'm not entirely sure myself. It's two years since I wrote this answer. I guess a better example might be where you are working with a legacy database, and the data is presented in a different way to your object model - accessors could provide a mapping between the two.Subjunction
A good use case for mapping accessors is when you need to add mapping information to subclasses of third-party entity classes that are not tied to any persistence implementation. Since fields are private in those classes, you have to override accessors and add mapping annotations to them. Another option would be to use XML mapping, but some things are very hard to do there. So, if you want annotations and map third-party classes, subclassing them and adding annotations on accessors is the way to go.Wapentake
@ElnurAbdurrakhimov there we go, an excellent example. Thanks.Subjunction
Make this the answer to the question, adding the use case from the commentWickiup
P
86

I prefer field access, because that way I'm not forced to provide getter/setter for each property.

A quick survey via Google suggests that field access is the majority (e.g., http://java.dzone.com/tips/12-feb-jpa-20-why-accesstype).

I believe field access is the idiom recommended by Spring, but I can't find a reference to back that up.

There's a related SO question that tried to measure performance and came to the conclusion that there's "no difference".

Paratroops answered 27/2, 2009 at 12:53 Comment(7)
if you dont provide setter getter in entity then whats the use of that field...you cant use it anwyhere in the application , becuase fields are privateVermiform
Is not providing a getter and setter for your fields bad practice?, I guess my comment here is not always right, since I was assuming a public field, whilst it could obviously be a private field which is never accessed.Hydrotaxis
@Vermiform I feel I should really address your questions, as that is what encapsulation is all about. Ideally all of your fields should be private, and if possible they should have no getters or setters - that is the best level of encapsulation you can hope for. Consider a password checker. 2 private fields passwordHash and failedAttempts. Both can be private with no getter or setter. They are used by bool checkPassword(string password) which hashes, checks against passwordHash and then updates failedAttempts and returns a result. No need for other code to ever access those two fields.Subjunction
@Vermiform it should be noted that in OOP, getters and setters are an anti-pattern, they come from procedural programming, having a class with them breaks the encapsulation principle, and generates a lot of boilerplate code, that is, the same kind of code repeated over and over again. Objects should be immutable, if modification of its properties is required it should be done through method that do something more than just returning the value of the property.Civilization
Not so. "Anti-pattern" in this case is a matter of opinion, not dogma. With that said, field access is still preferred. A better idea is to shy away from ORM solutions altogether. Learn how to write proper SQL.Paratroops
@UrielArvizu i get it now...after 2 years i gained this with experience ....immutable and mutable both have their place in object oriented world...even in spring framework we have pojos to get the access of its properties..which are required...without getters and setters...we may have problem...and if not used properly...can create problemsVermiform
sadly, just because an anti-pattern is used by these frameworks, doesn't mean it's a good thing and should be used. At the expense of freeing us from the worry of making the connections or injection ourselves, we populate our code with boilerplate code and files of configuration. It's a win-lose situationCivilization
U
41

Here's a situation where you HAVE to use property accessors. Imagine you have a GENERIC abstract class with lots of implementation goodness to inherit into 8 concrete subclasses:

public abstract class Foo<T extends Bar> {

    T oneThing;
    T anotherThing;

    // getters and setters ommited for brevity

    // Lots and lots of implementation regarding oneThing and anotherThing here
 }

Now exactly how should you annotate this class? The answer is YOU CAN'T annotate it at all with either field or property access because you can't specify the target entity at this point. You HAVE to annotate the concrete implementations. But since the persisted properties are declared in this superclass, you MUST used property access in the subclasses.

Field access is not an option in an application with abstract generic super-classes.

Unsupportable answered 6/7, 2010 at 6:34 Comment(4)
touche. I hadn't thought of that. I bet Hibernate kicks out some crazy sql for these.Mummy
This problem sounds mechanically difficult to solve without annotating properties, but I've never ran into a case where I needed an abstract generic class with a lot of implementation that I also wanted to persist. Typically I create a class hierarchy to make my object polymorphic (which making it generic sort of breaks), and not solely for code reuse. And "lots and lots of implementation" often violates SRP anyway, in which case I would probably move it into separate classes. Is there a concrete example that make this use case more obvious?Pierce
The only concrete example I have is my application, which I can't describe in a 500 character comment ;-)Unsupportable
You can use abstract T getOneThing(), and abstract void setOneThing(T thing), and use field access.Milk
I
33

I tend to prefer and to use property accessors:

  • I can add logic if the need arises (as mentioned in the accepted answer).
  • it allows me to call foo.getId() without initializing a proxy (important when using Hibernate, until HHH-3718 get resolved).

Drawback:

  • it makes the code less readable, you have for example to browse a whole class to see if there are @Transient around there.
Invalidism answered 19/5, 2010 at 21:11 Comment(1)
but then if you use a JPA provider that doesn't have "proxies" then you don't have that problem aka "your JPA provider is imposing on you".Astereognosis
P
31

I prefer accessors, since I can add some business logic to my accessors whenever I need. Here's an example:

@Entity
public class Person {

  @Column("nickName")
  public String getNickName(){
     if(this.name != null) return generateFunnyNick(this.name);
     else return "John Doe";
  }
}

Besides, if you throw another libs into the mix (like some JSON-converting lib or BeanMapper or Dozer or other bean mapping/cloning lib based on getter/setter properties) you'll have the guarantee that the lib is in sync with the persistence manager (both use the getter/setter).

Preindicate answered 16/4, 2009 at 18:2 Comment(6)
Note this is about how the ORM accesses your fields/properties and not your application code. With field access your getNickName() method would work exactly as you'd expect. The same is not true if you use the persistent 'properties' outside getters/setters. That is where you may hit issues with property access and lazy loading. So no, I don't agree with this argument in general. However, last time I checked Hibernate had issues with field access of @Id fields.Phelps
this answer is not related to the question. Best answer s by duffymoAdriel
there shouldn't be any business logic inside accessors. that's not obvious behaviour.Bosomy
Why is this response mark as correct ? It is not true you can mapping field and provide it a setter/getter in the same way.Perilous
I am about to experiment with this, but could this be inherited through an interface ?Hippopotamus
Every jpa session will generate update query for person, because Person object is always dirty at the end of the sessionExuviate
D
23

Let me try to summarize the most important reasons for choosing field-based access. If you want to dive deeper, please read this article on my blog: Access Strategies in JPA and Hibernate – Which is better, field or property access?

Field-based access is by far the better option. Here are 5 reasons for it:

Reason 1: Better readability of your code

If you use field-based access, you annotate your entity attributes with your mapping annotations. By placing the definition of all entity attributes at the top of your class, you get a relatively compact view of all attributes and their mappings.

Reason 2: Omit getter or setter methods that shouldn’t be called by your application

Another advantage of field-based access is that your persistence provider, e.g., Hibernate or EclipseLink, doesn’t use the getter and setter methods of your entity attributes. That means that you don’t need to provide any method that shouldn’t be used by your business code. This is most often the case for setter methods of generated primary key attributes or version columns. Your persistence provider manages the values of these attributes, and you should not set them programmatically.

Reason 3: Flexible implementation of getter and setter methods

Because your persistence provider doesn’t call the getter and setter methods, they are not forced to fulfill any external requirements. You can implement these methods in any way you want. That enables you to implement business-specific validation rules, to trigger additional business logic or to convert the entity attribute into a different data type.

You can, for example, use that to wrap an optional association or attribute into a Java Optional.

Reason 4: No need to mark utility methods as @Transient

Another benefit of the field-based access strategy is that you don’t need to annotate your utility methods with @Transient. This annotation tells your persistence provider that a method or attribute is not part of the entity persistent state. And because with field-type access the persistent state gets defined by the attributes of your entity, your JPA implementation ignores all methods of your entity.

Reason 5: Avoid bugs when working with proxies

Hibernate uses proxies for lazily fetched to-one associations so that it can control the initialization of these associations. That approach works fine in almost all situations. But it introduces a dangerous pitfall if you use property-based access.

If you use property-based access, Hibernate initializes the attributes of the proxy object when you call the getter method. That’s always the case if you use the proxy object in your business code. But quite a lot of equals and hashCode implementations access the attributes directly. If this is the first time you access any of the proxy attributes, these attributes are still uninitialized.

Diffract answered 17/12, 2018 at 14:42 Comment(0)
C
18

I prefer using field access for the following reasons:

  1. The property access can lead to very nasty bugs when implementing equals/hashCode and referencing fields directly (as opposed through their getters). This is because the proxy is only initialized when the getters are accessed, and a direct-field access would simply return null.

  2. The property access requires you to annotate all utility methods (e.g. addChild/removeChild) as @Transient.

  3. With field access we can hide the @Version field by not exposing a getter at all. A getter can also lead to adding a setter as well, and the version field should never be set manually (which can lead to very nasty issues). All version incrementation should be triggered through OPTIMISTIC_FORCE_INCREMENT or PESSIMISTIC_FORCE_INCREMENT explicit locking.

Cavalry answered 12/3, 2015 at 8:10 Comment(4)
1. How does field access strategy prevent this? This seems to be a general pitfall with proxies, regardless of the access style. 2. Are you sure, should it be only utility getters? (but a good argument anyway). 3. Exposing accessors for version field is often useful in situations in which DTOs are used instead of detached entities.Maurilla
1. Because of when a Proxy gets initialized. 2. 100% sure. 3. That's a valid point.Cavalry
Pardon my ignorance and possible lack of text interpretation, (I'm no native English speaker). Just to clarify, field access is when no getter/setter methods are needed right, so for a POJO, that is holistic used, the fields are public? But you say something in the first topic and the linked blog post say the contrary. What I did understand was that you can't use equals when utilizing proxies and field access.Protector
No. Field access means that Hibernate uses the fields via reflections to read entity attributes. For more details, check out the Access Type section in the Hibernate User Guide.Cavalry
P
13

That really depends on a specific case -- both options are available for a reason. IMO it boils down to three cases:

  1. setter has some logic that should not be executed at the time of loading an instance from a database; for example, some value validation happens in the setter, however the data coming from db should be valid (otherwise it would not get there (: ); in this case field access is most appropriate;
  2. setter has some logic that should always be invoked, even during loading of an instance from db; for example, the property being initialised is used in computation of some calculated field (e.g. property -- a monetary amount, calculated property -- a total of several monetary properties of the same instance); in this case property access is required.
  3. None of the above cases -- then both options are applicable, just stay consistent (e.i. if field access is the choice in this situation then use it all the time in similar situation).
Paleoecology answered 27/2, 2009 at 18:43 Comment(1)
I'm new to Hibernate and struggling with the same question. I think this post provides the most clear answer. Thank you.Wolfgang
S
12

I would strongly recommend field access and NOT annotations on the getters (property access) if you want to do anything more in the setters than just setting the value (e.g. Encryption or calculation).

The problem with the property access is that the setters are also called when the object is loaded. This has worked for me fine for many month until we wanted to introduce encryption. In our use case we wanted to encrypt a field in the setter and decrypt it in the getter. The problem now with property access was that when Hibernate loaded the object it was also calling the setter to populate the field and thus was encrypting the encrypted value again. This post also mentions this: Java Hibernate: Different property set function behavior depending on who is calling it

This has cause me headaches until I remembered the difference between field access and property access. Now I have moved all my annotations from property access to field access and it works fine now.

Scullion answered 26/7, 2012 at 11:14 Comment(2)
Yes - I have found that if you use property access you really cannot do anything in your setter besides set the field value.Unsupportable
+1 Keep away from getters/setters. I use projectlombok.org and keep them hidden from developers.Jeannettejeannie
F
6

I believe property access vs. field access is subtly different with regards to lazy initialisation.

Consider the following mappings for 2 basic beans:

<hibernate-mapping package="org.nkl.model" default-access="field">
  <class name="FieldBean" table="FIELD_BEAN">
    <id name="id">
      <generator class="sequence" />
    </id>
    <property name="message" />
  </class>
</hibernate-mapping>

<hibernate-mapping package="org.nkl.model" default-access="property">
  <class name="PropBean" table="PROP_BEAN">
    <id name="id">
      <generator class="sequence" />
    </id>
    <property name="message" />
  </class>
</hibernate-mapping>

And the following unit tests:

@Test
public void testFieldBean() {
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    FieldBean fb = new FieldBean("field");
    Long id = (Long) session.save(fb);
    tx.commit();
    session.close();

    session = sessionFactory.openSession();
    tx = session.beginTransaction();
    fb = (FieldBean) session.load(FieldBean.class, id);
    System.out.println(fb.getId());
    tx.commit();
    session.close();
}

@Test
public void testPropBean() {
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    PropBean pb = new PropBean("prop");
    Long id = (Long) session.save(pb);
    tx.commit();
    session.close();

    session = sessionFactory.openSession();
    tx = session.beginTransaction();
    pb = (PropBean) session.load(PropBean.class, id);
    System.out.println(pb.getId());
    tx.commit();
    session.close();
}

You will see the subtle difference in the selects required:

Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        FIELD_BEAN
        (message, id) 
    values
        (?, ?)
Hibernate: 
    select
        fieldbean0_.id as id1_0_,
        fieldbean0_.message as message1_0_ 
    from
        FIELD_BEAN fieldbean0_ 
    where
        fieldbean0_.id=?
0
Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        PROP_BEAN
        (message, id) 
    values
        (?, ?)
1

That is, calling fb.getId() requires a select, whereas pb.getId() does not.

Foetus answered 27/2, 2009 at 14:44 Comment(2)
This is funny! :) But it's an implementation-specific behavior, I'm sure. ISoosoochow
Yes, I guess this is due to the fact that only the persistent classes are instrumented. It's a pitty however because the id field is often the one field that has no business value and would not need any accessor.Algiers
C
6

I think annotating the property is better because updating fields directly breaks encapsulation, even when your ORM does it.

Here's a great example of where it will burn you: you probably want your annotations for hibernate validator & persistence in the same place (either fields or properties). If you want to test your hibernate validator powered validations which are annotated on a field, you can't use a mock of your entity to isolate your unit test to just the validator. Ouch.

Cheroot answered 23/4, 2009 at 12:16 Comment(1)
That's why you put validator-annotations on accessors and persistence-annotations on fieldsDebra
I
5

By default, JPA providers access the values of entity fields and map those fields to database columns using the entity’s JavaBean property accessor (getter) and mutator (setter) methods. As such, the names and types of the private fields in an entity do not matter to JPA. Instead, JPA looks at only the names and return types of the JavaBean property accessors. You can alter this using the @javax.persistence.Access annotation, which enables you to explicitly specify the access methodology that the JPA provider should employ.

@Entity
@Access(AccessType.FIELD)
public class SomeEntity implements Serializable
{
...
}

The available options for the AccessType enum are PROPERTY (the default) and FIELD. With PROPERTY, the provider gets and sets field values using the JavaBean property methods. FIELD makes the provider get and set field values using the instance fields. As a best practice, you should just stick to the default and use JavaBean properties unless you have a compelling reason to do otherwise.

You can put these property annotations on either the private fields or the public accessor methods. If you use AccessType.PROPERTY (default) and annotate the private fields instead of the JavaBean accessors, the field names must match the JavaBean property names. However, the names do not have to match if you annotate the JavaBean accessors. Likewise, if you use AccessType.FIELD and annotate the JavaBean accessors instead of the fields, the field names must also match the JavaBean property names. In this case, they do not have to match if you annotate the fields. It’s best to just be consistent and annotate the JavaBean accessors for AccessType.PROPERTY and the fields for AccessType.FIELD.

It is important that you should never mix JPA property annotations and JPA field annotations in the same entity. Doing so results in unspecified behavior and is very likely to cause errors.

Intangible answered 6/4, 2017 at 13:33 Comment(0)
P
3

Are we there yet

That's an old presentation but Rod suggests that annotation on property access encourages anemic domain models and should not be the "default" way to annotate.

Premedical answered 9/12, 2010 at 10:25 Comment(0)
H
2

I favor field accessors. The code is much cleaner. All the annotations can be placed in one section of a class and the code is much easier to read.

I found another problem with property accessors: if you have getXYZ methods on your class that are NOT annotated as being associated with persistent properties, hibernate generates sql to attempt to get those properties, resulting in some very confusing error messages. Two hours wasted. I did not write this code; I have always used field accessors in the past and have never run into this issue.

Hibernate versions used in this app:

<!-- hibernate -->
<hibernate-core.version>3.3.2.GA</hibernate-core.version>
<hibernate-annotations.version>3.4.0.GA</hibernate-annotations.version>
<hibernate-commons-annotations.version>3.1.0.GA</hibernate-commons-annotations.version>
<hibernate-entitymanager.version>3.4.0.GA</hibernate-entitymanager.version>
Highflier answered 14/3, 2012 at 15:50 Comment(0)
L
2

Another point in favor of field access is that otherwise you are forced to expose setters for collections as well what, for me, is a bad idea as changing the persistent collection instance to an object not managed by Hibernate will definitely break your data consistency.

So I prefer having collections as protected fields initialized to empty implementations in the default constructor and expose only their getters. Then, only managed operations like clear(), remove(), removeAll() etc are possible that will never make Hibernate unaware of changes.

Lyophilic answered 11/6, 2013 at 6:8 Comment(1)
You are not forced to expose anything as the setters can be protected. Also those setters are not part of the interface being implemented so even if they were public, they are not easily accessible.Unsupportable
C
2

I prefer fields, but I've run into one situation that seems to force me to place the annotations on getters.

With the Hibernate JPA implementation, @Embedded doesn't seem to work on fields. So that has to go on the getter. And once you put that on the getter, then the various @Column annotations have to go on the getters too. (I think Hibernate doesn't want mixing fields and getters here.) And once you're putting @Column on getters in one class, it probably makes sense to do that throughout.

Callison answered 1/6, 2014 at 10:58 Comment(0)
G
2

You should choose access via fields over access via properties. With fields you can limit the data sent and received. With via properties you can send more data as a host, and set G denominations (which factory set most of the properties in total).

Goldsmith answered 17/12, 2018 at 14:48 Comment(0)
S
1

Normally beans are POJO, so they have accessors anyway.

So the question is not "which one is better?", but simply "when to use field access?". And the answer is "when you don't need a setter/getter for the field!".

Soosoochow answered 27/2, 2009 at 18:48 Comment(3)
Problem is that you cannot mix field access and property access in a POJO - you have to choose oneBlakeney
Really? I must have forgotten it. Anyway, I always use POJO an d accessors.Soosoochow
Note that with JPA 2.0 (which wasn't around when this question was asked) you can now mix access types using the @AccessType annotation.Lyndseylyndsie
J
1

I had the same question regarding accesstype in hibernate and found some answers here.

Jonajonah answered 27/4, 2010 at 17:33 Comment(0)
K
1

I have solved lazy initialisation and field access here Hibernate one-to-one: getId() without fetching entire object

Klong answered 22/11, 2010 at 12:45 Comment(0)
S
1

We created entity beans and used getter annotations. The problem we ran into is this: some entities have complex rules for some properties regarding when they can be updated. The solution was to have some business logic in each setter that determines whether or not the actual value changed and, if so, whether the change should be allowed. Of course, Hibernate can always set the properties, so we ended up with two groups of setters. Pretty ugly.

Reading previous posts, I also see that referencing the properties from inside the entity could lead to issues with collections not loading.

Bottom line, I would lean toward annotating the fields in the future.

Superstar answered 16/7, 2012 at 15:9 Comment(0)
B
0

i thinking about this and i choose method accesor

why?

because field and methos accesor is the same but if later i need some logic in load field, i save move all annotation placed in fields

regards

Grubhart

Breakage answered 27/2, 2009 at 12:45 Comment(0)
J
0

To make your classes cleaner, put the annotation in the field then use @Access(AccessType.PROPERTY)

Juristic answered 20/7, 2011 at 6:48 Comment(0)
P
0

Both :

The EJB3 spec requires that you declare annotations on the element type that will be accessed, i.e. the getter method if you use property access, the field if you use field access.

https://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/#entity-mapping

Phage answered 18/8, 2018 at 4:9 Comment(0)
I
0

AccessType.PROPERTY: The EJB persistence implementation will load state into your class via JavaBean "setter" methods, and retrieve state from your class using JavaBean "getter" methods. This is the default.

AccessType.FIELD: State is loaded and retrieved directly from your class' fields. You do not have to write JavaBean "getters" and "setters".

Indaba answered 20/8, 2018 at 12:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.