views:

6027

answers:

10

This question is somewhat related to http://stackoverflow.com/questions/305880/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?

+4  A: 

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

duffymo
+2  A: 

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.

toolkit
This is funny! :) But it's an implementation-specific behavior, I'm sure. I
Vladimir Dyuzhev
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.
Maurice Perry
+1  A: 

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).
01es
A: 

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

Vladimir Dyuzhev
Problem is that you cannot mix field access and property access in a POJO - you have to choose one
Martin OConnor
Really? I must have forgotten it. Anyway, I always use POJO an d accessors.
Vladimir Dyuzhev
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.
mtpettyp
+7  A: 

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

Miguel Ping
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.
Rob
I don't understand the above code, how could a `void` function return something? This must be a typo.
Rosdi
@Rosdi - This probably was a typo, I edited the post to fix it.
Hanno Fietz
+4  A: 

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.

Justin Standard
A: 

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

Grubhart
A: 

Hi

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

sundary
+1  A: 

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.
Pascal Thivent
A: 

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.

HDave