Deciding on Method or Field access using Java Persistence API

One of the somewhat unclear aspects of the Java Persistence API is exactly how Java entities are populated from database tables. Those of you familiar with Hibernate probably know that you require a setter method in your Java POJO which corresponds to the column that you want mapped. JPA lifts that requirement and instead gives the option of not specifying any accessor methods in favor of reflection. Whether this is good or bad is for your application to decide.

Field Access

When using field access, the fields of the entity class must be annotated:

@Entity
public class Employee {

	@Id
	private Long id;

	@Column(name="emp_name")
	private String name;

	private int age;
}

There’s a few talking points here:

  • id, name and age will be populated using reflection. Even though you might have a setName(String) method in your class, it will not be called when populating the bean.
  • Despite the private access level of the fields, JPA is able to fill in their values because of reflection.
  • Even though age is not annotated, it will still be mapped to the table column. You have two ways to avoid this, either you declare your variable using the transient Java keyword or use the @Transient annotation.
private transient int age;

OR

@Transient
private int age;

Method Access

Now reflection may not be your cup of tea and rightfully so. You can also use Method Access to populate the POJO. This is especially helpful in modifying the values coming from the columns right before storing them in the entity bean.

@Entity
public class Employee {

	private Long id;

	private String name;

	private int age;

	@Id
	public Long getId() {
		return id;
	}

	@Column(name="emp_name")
	public String getName() {
		return name;
	}

	@Transient
	public int getAge() {
		return age;
	}

	// setters omitted for brevity
}

Couple of points to note here:

  • Notice that none of the fields are annotated. Although JPA allows you to specify field and method level annotations at the same time, this is NOT recommended and can have unpredictable results. In the case of TopLink Essentials, if you specify both annotation types, it will pick up annotations on methods first and will ignore field annotations.
  • In this case, we do not want to map age to a table column and must specify the @Transient attribute on the getter for the field to avoid it being mapped to a column.

If you’re using TopLink Essentials as the JPA implementation, their documentation describes Method Accessing in greater detail.

Advertisements

7 thoughts on “Deciding on Method or Field access using Java Persistence API

  1. vanyatka

    thanks for the explanation, but the example could’ve been better. Btw, one of your fields IS annotated in the 2nd example.

    Reply
  2. Hung Tang

    I tried both and I prefer field-level access because it’s much more IDE refactor-friendly and I get to see all the pertinent mapping information upon opening the source file rather than scrolling endlessly down.

    Reply
  3. Jonathan O'Connor

    It’s not clear from your description, why method-level access does not require reflection as well. I can only presume that the implementation uses reflection at class load time to create a loadObject() method via byte-code manipulation, that directly invokes the appropriate setters.

    In the field level access version, the generated loadObject() would, as you wrote, use reflection to set the fields. But, the java.lang.reflect.Field objects could be queried at load time too. So, I believe the reflection overhead is not huge.

    However, we really need to measure the speed of the two approaches.

    Reply
  4. greathr

    Hibernate does not require you to use only the setter method. Take a look at the “default-access” property on the tag on the “hibernate-mapping” tag.

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s