Skip to content

Change Tracking and Lazy Loading

Martin Ledvinka edited this page May 27, 2024 · 4 revisions

There are two important features whose implementation is based on similar concepts:

  1. Change tracking
  2. Lazy loading
Change Tracking

Change tracking determines which entity attributes have changed during a transaction and how and writes these changes into the underlying repository. Change tracking works in two ways - if an application loads an entity into the persistence context and makes changes to it, these changes are automatically written out into the repository. The other way is when the application merges a detached entity into the persistence context.

From the change tracking point of view, merging detached instance is simpler - it just means comparing the merged object with the existing data and registering the changes.

Tracking changes on a managed object is more difficult, because entities are just regular POJOs with no special hooks that would register calls to getters and setters.

Lazy Loading

Similarly to tracking changes on managed objects, lazy loading requires a mechanism that would notify the persistence provider that a lazily loaded attribute has been accessed and it should load its value.

Prior to 2.0.0

Before JOPA 2.0.0, AspectJ aspects were used to provide change tracking/lazy loading capabilities. JOPA's entity listening aspect join points had to be weaved into entity classes either at compile or load time. The setter join point would call the setter aspects whenever entity setter was called, so that the corresponding persistence context would be notified of the modification. Analogously, getter join point would notify the persistence context so that it could check whether the attribute was lazily loaded and its value should be fetched.

Weaving was usually done at compile time, requiring the AspectJ Maven plugin to process the entity classes. Getters and setters of a compiled entity class may thus look as follows:

public String getFirstName() {
  JoinPoint var1 = Factory.makeJP(ajc$tjp_0, this, this);
  BeanListenerAspect.aspectOf().beforeGetter(var1);
  return this.firstName;
}

public void setFirstName(String firstName) {
  JoinPoint var2 = Factory.makeJP(ajc$tjp_1, this, this, firstName);
  this.firstName = firstName;
  BeanListenerAspect.aspectOf().afterSetter(var2);
}

However, the weaving step would often bring issues when entity classes would not be correctly woven, and the application would thus fail. This usually happened in IDEs during development, full-blown Maven build typically resolved the issue. The weaving step also brought problems when working with annotation processors and similar compilation-related tools like Lombok.

Clone this wiki locally