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

Viewed 123524

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?

25 Answers

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".

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).

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.

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).

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.

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.

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>

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).

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!".

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

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".

Related