I have an object with attributes like below:
public class Model1 {
private String aa;
private List<String> bb;
private List<CC> list;
}
public class CC{
private String cc1;
private List<String> cc2;
}
When I use javers, I am able to get changes made to aa and bb. But for List<CC> it just says, list/2 was added or list/0 was removed but it does not give exact data that was added or removed.
How do I get the complete data of CC object which was added, removed or changed from list?
Related
I'm having trouble knowing how this is possible or a potential work around. I am looking at configuring variables that are in the form of "foo,bar,baz" into a List as separate elements. Currently the code looks like
#RefreshScope
#Configuration
#Getter
public class fakeConfiguration {
#Value("#{PropertySplitter.toSet('${properties:}')}")
private final Set<String> field = new HashSet<>();
}
#Component("PropertySplitter")
#SuppressWarnings("unused")
public class PropertySplitter {
public Set<String> toSet(String property) {
Set<String> set = new HashSet<>();
if(!property.trim().isEmpty()){
Collections.addAll(set, property.split("\\s*,\\s*"));
}
return set;
}
}
This properly evaluates the String list into a Set however the refreshScope never gets triggered properly. If I use
#Value("${properties:}")
private final String fieldAsString;
I can see the field properly refresh, but I'd like to actively convert the value to a list as it is changed. Is this possible?
In newer version of spring-boot below works for application.properties and Application.yml
#Value("#{${props.list}}")
private List<String> fieldList;
If you use Application.yml you can arrange the objects
props:
list:
- val1
- val2
and then use in code
#Value("${props.list}")
private List<String> ymlList
Last, You can try the below as well
#Value("#{'${props.list}'.split(',')}")
private List<String> myList;
I trying to user Dozer in my app, so I have 2 classes:
public MyEntity{
private String name;
private Stirng age;
private String user;
private Integer day;
}
public class MyVO{
private String name;
private String age;
}
So, first I read the Entity from my db(with all fields filled) then I call the dozer to copy the values from VO to Entity
MyEntity entity = myRepo.findById(1);
entity = mapper.map(myVo, MyEntity.class);
but dozzer first sets null to all props in myEntity and then copy the values from myVo,
It`s possible to keep that props (who does not exist in both object) and copy only that fields that exists(or are mapped in my .xml) file
mapper.map(myVo, MyEntity.class);
This call to Dozer tells it to create a new MyEntity instance and then map the values from myVo. This is why some of your fields are null in the resulting entity.
If you want to update an existing instance using Dozer, call Dozer with the instance instead of the class name, i.e.
mapper.map(myVo, entity);
Note, this does not return the entity back to you since it modifies it in place.
i'm new to Javers, and i`m currently using it to create a patch update for my entity. But i'm having some struggle with one specific scenario
I want to compare a Entity against a EntityDTO/VO and get only the changes in values, the current comparison only returns that is a NewObject and ObjectRemoved changes.
Example:
public class Entity{
private ObjectId id;
private String name;
private String description;
}
public class EntityDTO{
private String name;
}
//
Entity oldState = new Entity(new ObjectId(), "oldName" , "oldDescription);
EntityDTO newState = new EntityDTO( "newName" );
JaversBuilder.javers().build().compare(oldState, newState).getChanges();
//This is returning only NewObject/ObjectRemoved changes, and the intended is to be ValueChange/ReferenceChange
The questions is, is there a way to compare only the similar attributes between the objects?
No, in JaVers, you can compare only objects of the same type.
Below code simply creates two objects with two lists having same object marked with id only the content of the element is changed. The diff object generates a diff without any reference to parent list element but rather to the actual rop
public class JaversTest {
public static void main(String[] args) {
User u1 = new User();
User u2 = new User();
Email e1 = new Email();
e1.setId("id1");
e1.setMail("Vikrant5mahajan#gmail.com");
Email e2 = new Email();
e2.setId("id1");
e2.setMail("Vikrant6mahajan#gmail.com");
u1.setEmails(Collections.singletonList(e1));
u2.setEmails(Collections.singletonList(e2));
Javers javers = JaversBuilder.javers().build();
Diff diff = javers.compare(e1, e2);
System.out.println(diff.prettyPrint());
}
#Data
public static class User {
List<Email> emails = new ArrayList<>();
}
#Data
public static class Email {
#Id
String id;
String mail;
}
}
The output i get is
1. ValueChange{globalId:'com.practo.test.api.diff.JaversTest$Email/id1', property:'mail', oldVal:'Vikrant5mahajan#gmail.com', newVal:'Vikrant6mahajan#gmail.com'}
The JaVers diff is perfectly right. I'm not sure what you expect but in your snippet you have created two versions of an email object, and then you compare them. Since the mail field is changed, you get the ValueChange.
What else could you get from the diff engine? Your emails have no references to users or lists, so, obviously, javers is unaware of them.
Btw, your mapping is wrong. Email is a typical Value Object not an Entity, try to remove #Id ann.
I have a one to many relationship namely A and B. A may refer to many B instances. B instances also can be managed independently.
That's why, B class looks like this:
public class B {
#Id
private String id;
private String appId;
}
A class will refer to a list of B instances. So it looks like this:
public class A {
#Id
private String id;
private int age;
private List<B> bInstances;
}
When bInstances are filled with B instances and then A instance is saved, id fields of the B instances are removed from the JSON document since it is annotated with #Id.
I simply need to add this field to JSON when B is embedded into another class.
And when B instance is saved independently, #Id field can be used as the regular key.
How may I do this?
To answer your question specifically, yes the field annotated #Id won't get written to the serialized json. Your best bet here is to duplicate the field and set its value in either the constructor or a setter, for example:
public class B {
#Id
private String metaId;
private String id;
private String appId;
public setMetaId(String metaId) {
this.metaId = metaId;
this.id = metaId;
}
}
You can #JsonIgnore one of them if you don't want to see the duplication in your serializations.
Note: I totally agree with Robin's answer, but there are cases where you want to save the data as-it-was and you want to refer to it in the future.. so you don't care if B instance changed one week after you saved the data. So it really depends on your scenario.
I would strongly advise you to not store the instances of B directly in a document of A. Doing this would result in data inconsistencies if an instance of B is changed in another context than A. Additionally you duplicate data unnecessarily if an instance of B is stored in multiple documents of class A.
The desired way to store instances of one class in another is to save the document ids instead. So your class A should look like this:
public class A {
#Id
private String id;
private int age;
private List<String> bInstanceIds;
}