I have a problem with Objectmapper.readerforupdating using different write permissions with the help of views, it is working fine on main entity but not on nested objects. I have the following example:
public class A {
@JsonView(value={WritePermission.Admin})
private String name;
@JsonView(value={WritePermission.User})
private String property;
@JsonView(value={WritePermission.User})
private List<B> list;
}
public class B {
@JsonView(value={WritePermission.Admin})
private String name;
@JsonView(value={WritePermission.User})
private String property;
}
public class WritePermission {
public WritePermission() {
}
public static class Admin extends WritePermission.User {
public Admin() {
}
}
public static class User {
public User() {
}
}
}
For deserialization I use this: objectMapper.readerForUpdating(initialEntityOfAClass).withView(WritePermission.User.class).forType(A.class).readValue(json) and also tried with this but I get the same result: ObjectReader objectReader = objectMapper.readerForUpdating(initialEntityOfAClass);
When I want to deserialize a json with a User write role, I would like to overwrite only the attributes where I have permission, this works fine for attributes from class A (in the name attribute remains the old value cuz I do not have the rights to update, property attribute is updated) but it does not work for the list of B items - instead of changing the B objects just like for A (name remains old value, property is updated from json) creates new objects for the list of B and name remains null because as a User I do not have a permission to write values to name attribute. If I set @JsonMerge on the B list, instead of merge I am getting the old (the ones where the name is already set but property not changed) and the newly created objects (the ones where the property changed but with name=null) in one list... Can anyone help me here, please?
There are two problems here. The first problem is based in
com.fasterxml.jackson.databind.deser.impl.MethodPropertynot reading the property value if a read method is present. So the deserialization for nested objects always starts with anullvalue and therefore constructs a new instance first.The other problem is handling the collection elements that are already part of the list.
To solve the first problem do the following:
com.fasterxml.jackson.databind.deser.SettableBeanPropertyimplementation that does read the property value if a read method is present and then use that value as the basis for deserialization:com.fasterxml.jackson.databind.deser.BeanDeserializerModifierto modify the properties of acom.fasterxml.jackson.databind.deser.BeanDeserializerto use the above implementation if a property read method is presentNote that this will only work for method properties and not for constructor properties for example.
Regarding the second problem I changed collection deserialization to something different so that instead of a plain json representation I have something like this to deserialize the collection from:
The above example will remove values with property
fooequal tofoobaror starting withfoo.from the list first and then add the values specified inelements. You could implement your owncom.fasterxml.jackson.databind.deser.std.CollectionDeserializerbased on your needs. However I found that working with maps instead of lists is easier in such cases but I hadn't such a use case in my example yet. In your example you could use thenameproperty as the map key.