0
votes

I want to register which changes are made to a certain entity in my app; and I want it to be portable among different implementations of JPA, so I can't use frameworks like Envers (Hibernate) or History Policy (EclipseLink).

So I added a changeLog field to my entity and I'm using an entity listener with the @PreUpdate and @PrePersist annotations to update this field.

The problem is, I'd like to use an annotation to be able to indicate the field in which these changes should be stored, instead of using a fixed name for the field. And when I use reflection to update this field instead of using the set method directly, EclipseLink doesn't seem to be able to detect the change in the changelog field and so, it's not in the generated UPDATE statement

@PreUpdate
@PrePersist
public void updateChangeLog(Object auditable) throws IllegalAccessException {
    Field[] fields = auditable.getClass().getDeclaredFields();
    Field changeLogField = null;

    for (Field field : fields) {
        if (field.getAnnotation(ChangeLog.class) != null) {
            field.setAccessible(true);
            changeLogField = field;
        }
    }


    String changeLog = generateChangeLog();


    // This works
    // ((MyEntity)auditable).setChangeLog(changeLog);

    // This doesn't work!
    changeLogField.set(auditable, changeLog);
}

Is this a bug in EclipseLink or is this the expected behavior? Is there a way to mark the changelog field as dirty so that EclipseLink updates its value?

1

1 Answers

1
votes

EclipseLink's weaving defaults to using change tracking where possible for performance reasons. This means that changes to fields made directly will not be picked up. You can change the values using the accessor methods, which will get picked up by the change listener. Otherwise, you would have to turn off change tracking as described here: http://eclipse.org/eclipselink/documentation/2.5/jpa/extensions/a_changetracking.htm

or turn off weaving.