I have a REST WS to update a bean object which receives a JSON string as input.
我有一个REST WS来更新一个bean对象,它接收一个JSON字符串作为输入。
ABean entity = svc.findEntity(...);
objectMapper.readerForUpdating(entity).readValue(json);
[...]
svc.save(entity);
ABean is a complex type containing also other objects e.g.:
ABean是一个包含其他对象的复杂类型,例如:
class ABean {
public BBean b;
public CBean c;
public String d;
}
svc.save(...) will save the bean and the embedded objects.
svc.save(...)将保存bean和嵌入对象。
For security reasons I want to filter out some of the properties that can be updated by the JSON string, but I want to do this dynamically, so that for every WS (or user Role) I can decide which properties to prevent to be updated (so I can't simply use the Jackson Views)
出于安全原因,我想过滤掉一些可以通过JSON字符串更新的属性,但我想动态地执行此操作,以便对于每个WS(或用户角色),我可以决定阻止更新哪些属性(所以我不能简单地使用杰克逊观点)
To summarize, is there any way I can dynamically filter out properties during JSON Deserialization?
总而言之,有什么方法可以在JSON反序列化期间动态过滤掉属性?
4 个解决方案
#1
7
Another way is using BeanDeserializerModifier:
另一种方法是使用BeanDeserializerModifier:
private static class BeanDeserializerModifierForIgnorables extends BeanDeserializerModifier {
private java.lang.Class<?> type;
private List<String> ignorables;
public BeanDeserializerModifierForIgnorables(java.lang.Class clazz, String... properties) {
ignorables = new ArrayList<>();
for(String property : properties) {
ignorables.add(property);
}
this.type = clazz;
}
@Override
public BeanDeserializerBuilder updateBuilder(
DeserializationConfig config, BeanDescription beanDesc,
BeanDeserializerBuilder builder) {
if(!type.equals(beanDesc.getBeanClass())) {
return builder;
}
for(String ignorable : ignorables) {
builder.addIgnorable(ignorable);
}
return builder;
}
@Override
public List<BeanPropertyDefinition> updateProperties(
DeserializationConfig config, BeanDescription beanDesc,
List<BeanPropertyDefinition> propDefs) {
if(!type.equals(beanDesc.getBeanClass())) {
return propDefs;
}
List<BeanPropertyDefinition> newPropDefs = new ArrayList<>();
for(BeanPropertyDefinition propDef : propDefs) {
if(!ignorables.contains(propDef.getName())) {
newPropDefs.add(propDef);
}
}
return newPropDefs;
}
}
You can register the modfier to the ObjectMapper with:
您可以使用以下命令将修改器注册到ObjectMapper:
BeanDeserializerModifier modifier = new BeanDeserializerModifierForIgnorables(YourType.class, "name");
DeserializerFactory dFactory = BeanDeserializerFactory.instance.withDeserializerModifier(modifier);
ObjectMapper mapper = new ObjectMapper(null, null, new DefaultDeserializationContext.Impl(dFactory));
Then the defined properties are ignored. You can ignore the updateBuilder method if you use the @JsonAnySetter annotation.
然后忽略定义的属性。如果使用@JsonAnySetter批注,则可以忽略updateBuilder方法。
Greetings, Martin
#2
1
I assume from your description that you can't simply use the @JsonIgnore
annotation to prevent the fields from being serialized for each particular class.
我假设您不能简单地使用@JsonIgnore注释来阻止为每个特定类序列化字段。
Look at using Jakson mix-ins: mix-ins allow you to substitute a class definition - with the necessary annotations - for data binding. During serialization you can choose a particular mix-in class definition to stand in for the actual class being serialized. Define a set of mix-ins to handle every case, then choose which is appropriate when you serialize a particular bean.
看看使用Jakson mix-ins:mix-ins允许你用类定义替换 - 带有必要的注释 - 用于数据绑定。在序列化期间,您可以选择特定的混合类定义来代表要序列化的实际类。定义一组混合来处理每个案例,然后在序列化特定bean时选择合适的混合。
#3
1
You can use @JsonIgnoreType to ignore a java class/interface/enum from serializing. Additionally you can use @JsonIgnoreProperties for ignoring a list of properties and @JsonIgnore for a specific property
您可以使用@JsonIgnoreType忽略序列化中的java类/接口/枚举。另外,您可以使用@JsonIgnoreProperties忽略属性列表,并使用@JsonIgnore来获取特定属性
#4
0
The most powerful, quick and easy solution I came up with is just filtering the JsonNode tree obtained from the deserialization, then pass the filtered result to the readerForUpdating. Something like that:
我提出的最强大,快速和简单的解决方案是过滤从反序列化中获得的JsonNode树,然后将过滤后的结果传递给readerForUpdating。像这样的东西:
public class JacksonHelper {
public JsonNode filterBeanTree(JsonNode o, List<String> includedProperties,
List<String> excludedProperties, int maxDepth) {
JsonNode tree = o.deepCopy();
this.filterBeanTreeRecursive(tree, includedProperties, excludedProperties, maxDepth, null);
return tree;
}
private void filterBeanTreeRecursive(JsonNode tree, List<String> includedProperties,
List<String> excludedProperties, int maxDepth, String key) {
Iterator<Entry<String, JsonNode>> fieldsIter = tree.fields();
while (fieldsIter.hasNext()) {
Entry<String, JsonNode> field = fieldsIter.next();
String fullName = key == null ? field.getKey() : key + "." + field.getKey();
boolean depthOk = field.getValue().isContainerNode() && maxDepth >= 0;
boolean isIncluded = includedProperties != null
&& !includedProperties.contains(fullName);
boolean isExcluded = excludedProperties != null
&& excludedProperties.contains(fullName);
if ((!depthOk && !isIncluded) || isExcluded) {
fieldsIter.remove();
continue;
}
this.filterBeanTreeRecursive(field.getValue(), includedProperties, excludedProperties,
maxDepth - 1, fullName);
}
}
}
#1
7
Another way is using BeanDeserializerModifier:
另一种方法是使用BeanDeserializerModifier:
private static class BeanDeserializerModifierForIgnorables extends BeanDeserializerModifier {
private java.lang.Class<?> type;
private List<String> ignorables;
public BeanDeserializerModifierForIgnorables(java.lang.Class clazz, String... properties) {
ignorables = new ArrayList<>();
for(String property : properties) {
ignorables.add(property);
}
this.type = clazz;
}
@Override
public BeanDeserializerBuilder updateBuilder(
DeserializationConfig config, BeanDescription beanDesc,
BeanDeserializerBuilder builder) {
if(!type.equals(beanDesc.getBeanClass())) {
return builder;
}
for(String ignorable : ignorables) {
builder.addIgnorable(ignorable);
}
return builder;
}
@Override
public List<BeanPropertyDefinition> updateProperties(
DeserializationConfig config, BeanDescription beanDesc,
List<BeanPropertyDefinition> propDefs) {
if(!type.equals(beanDesc.getBeanClass())) {
return propDefs;
}
List<BeanPropertyDefinition> newPropDefs = new ArrayList<>();
for(BeanPropertyDefinition propDef : propDefs) {
if(!ignorables.contains(propDef.getName())) {
newPropDefs.add(propDef);
}
}
return newPropDefs;
}
}
You can register the modfier to the ObjectMapper with:
您可以使用以下命令将修改器注册到ObjectMapper:
BeanDeserializerModifier modifier = new BeanDeserializerModifierForIgnorables(YourType.class, "name");
DeserializerFactory dFactory = BeanDeserializerFactory.instance.withDeserializerModifier(modifier);
ObjectMapper mapper = new ObjectMapper(null, null, new DefaultDeserializationContext.Impl(dFactory));
Then the defined properties are ignored. You can ignore the updateBuilder method if you use the @JsonAnySetter annotation.
然后忽略定义的属性。如果使用@JsonAnySetter批注,则可以忽略updateBuilder方法。
Greetings, Martin
#2
1
I assume from your description that you can't simply use the @JsonIgnore
annotation to prevent the fields from being serialized for each particular class.
我假设您不能简单地使用@JsonIgnore注释来阻止为每个特定类序列化字段。
Look at using Jakson mix-ins: mix-ins allow you to substitute a class definition - with the necessary annotations - for data binding. During serialization you can choose a particular mix-in class definition to stand in for the actual class being serialized. Define a set of mix-ins to handle every case, then choose which is appropriate when you serialize a particular bean.
看看使用Jakson mix-ins:mix-ins允许你用类定义替换 - 带有必要的注释 - 用于数据绑定。在序列化期间,您可以选择特定的混合类定义来代表要序列化的实际类。定义一组混合来处理每个案例,然后在序列化特定bean时选择合适的混合。
#3
1
You can use @JsonIgnoreType to ignore a java class/interface/enum from serializing. Additionally you can use @JsonIgnoreProperties for ignoring a list of properties and @JsonIgnore for a specific property
您可以使用@JsonIgnoreType忽略序列化中的java类/接口/枚举。另外,您可以使用@JsonIgnoreProperties忽略属性列表,并使用@JsonIgnore来获取特定属性
#4
0
The most powerful, quick and easy solution I came up with is just filtering the JsonNode tree obtained from the deserialization, then pass the filtered result to the readerForUpdating. Something like that:
我提出的最强大,快速和简单的解决方案是过滤从反序列化中获得的JsonNode树,然后将过滤后的结果传递给readerForUpdating。像这样的东西:
public class JacksonHelper {
public JsonNode filterBeanTree(JsonNode o, List<String> includedProperties,
List<String> excludedProperties, int maxDepth) {
JsonNode tree = o.deepCopy();
this.filterBeanTreeRecursive(tree, includedProperties, excludedProperties, maxDepth, null);
return tree;
}
private void filterBeanTreeRecursive(JsonNode tree, List<String> includedProperties,
List<String> excludedProperties, int maxDepth, String key) {
Iterator<Entry<String, JsonNode>> fieldsIter = tree.fields();
while (fieldsIter.hasNext()) {
Entry<String, JsonNode> field = fieldsIter.next();
String fullName = key == null ? field.getKey() : key + "." + field.getKey();
boolean depthOk = field.getValue().isContainerNode() && maxDepth >= 0;
boolean isIncluded = includedProperties != null
&& !includedProperties.contains(fullName);
boolean isExcluded = excludedProperties != null
&& excludedProperties.contains(fullName);
if ((!depthOk && !isIncluded) || isExcluded) {
fieldsIter.remove();
continue;
}
this.filterBeanTreeRecursive(field.getValue(), includedProperties, excludedProperties,
maxDepth - 1, fullName);
}
}
}