I would like to use JaVers to track changes of my Java objects. The basic examples are working fine, but I can't get it to detect changes on objects stored in a collection.
If I extend the ChangeLogExample.class example to change e.g. one of the sub-ordinates:
public static void main(String[] args) {
Javers javers = JaversBuilder.javers().build();
Employee bob = new Employee("Bob", 9_000, "Scrum master" );
javers.commit("hr.manager", bob);
// do some changes and commit
bob.setPosition("Team Lead");
bob.setSalary(11_000);
javers.commit("hr.director", bob);
bob.addSubordinates(new Employee("Trainee One"), new Employee("Trainee Two"));
javers.commit("hr.manager", bob);
bob.getSubordinates().get(0).setAge(42); // <<<< This is the change I want to detect
javers.commit("hr.manager", bob);
// when:
List<Change> changes = javers.findChanges(
QueryBuilder.byInstanceId("Bob", Employee.class).withChildValueObjects().build());
String changeLog = javers.processChangeList(changes, new SimpleTextChangeLog());
// then:
System.out.println(changeLog);
}
This is the changelog that is printed:
commit 3.0, author: hr.manager, 2017-06-06 11:17:17
changed object: Employee/Bob
list changed on 'subordinates' property: [(0).added:'Employee/Trainee One', (1).added:'Employee/Trainee Two']
commit 2.0, author: hr.director, 2017-06-06 11:17:17
changed object: Employee/Bob
value changed on 'position' property: 'Scrum master' -> 'Team Lead'
value changed on 'salary' property: '9000' -> '11000'
So the change to the age of the first subordinate doesn't show up in the changelog.
Using withChildValueObjects()
does not make a difference.
I get the change to the trainee's age when I commit the change to the Employee instance separately, but that is not want I expected (nor what I want).
So my question is: how to get the change to the age show up in the ChangeLog?
I am using JaVers 3.2.0
The Employee
class is unchanged from the JaVers examples: https://github.com/javers/javers/tree/master/javers-core/src/test/java/org/javers/core/examples/model
The main()
method is simply the Test from https://github.com/javers/javers/blob/master/javers-core/src/test/java/org/javers/core/examples/ChangeLogExample.java
Ok, a few issues here.
First of all, Empolyee
objects are mapped as Entities
. So in JaVers, there is no
parent/child relationship between them (in fact any kind of relationship).
That's why withChildValueObjects()
filter doesn't apply here.
It works only for ValueObjects
owned by Entities
, see http://javers.org/documentation/jql-examples/#child-value-objects-filter
Still, there are two ways to improve your query.
Ask directly for the Entity instance you want to trace.
Use the new Shadow API with Query Scopes, see http://javers.org/documentation/jql-examples/#query-for-shadows It's a new feature and will be improved in the feature. You can use it already if snapshots of both Entities will be selected by the query.
See code below:
def "should ... "(){
given:
Javers javers = JaversBuilder.javers().build()
Employee bob = new Employee("Bob", 9_000, "Scrum master" )
javers.commit("hr.manager", bob)
// do some changes and commit
bob.setPosition("Team Lead")
bob.setSalary(11_000)
javers.commit("hr.director", bob)
bob.addSubordinates(new Employee("Trainee One"), new Employee("Trainee Two"))
javers.commit("hr.manager", bob)
bob.getSubordinates().get(0).setAge(42) // <<<< This is the change I want to detect
bob.salary++ // !
javers.commit("hr.manager", bob)
when: "ask for the the right Entity instance"
List changes = javers.findChanges(
QueryBuilder.byInstanceId("Trainee One", Employee.class).build())
then:
println( javers.processChangeList(changes, new SimpleTextChangeLog()) )
true
when: "use the new Shadows"
List shadows = javers.findShadows(
QueryBuilder.byInstanceId("Bob", Employee.class)
.withShadowScopeDeep().build())
then:
shadows.each {
assert it.get() instanceof Employee
}
Employee lastBobShadow = shadows[0].get()
assert shadows[0].commitMetadata.id.majorId == 4
assert lastBobShadow.subordinates[0].name == "Trainee One"
assert lastBobShadow.subordinates[0].age == 42
}