我有一个定制的bean序列化程序,我想应用它,但是当我应用它时,jackson不再包含null属性。
以下代码复制了问题:
import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import lombok.Value;
public class Test {
@Value
public static class Contact {
String first;
String middle;
String last;
String email;
}
public static void main(String[] args) throws Exception {
Contact contact = new Contact("Bob", null, "Barker", null);
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new SimpleModule() {
@Override public void setupModule(SetupContext context) {
super.setupModule(context);
context.addBeanSerializerModifier(new BeanSerializerModifier() {
@Override public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription desc, JsonSerializer<?> serializer) {
// return serializer;
return new JsonSerializer<Object>() {
@Override public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
((JsonSerializer<Object>) serializer).serialize(value, gen, serializers);
}};
}
});
}
});
System.out.println(
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(contact)
);
}
}
上面的代码除了注册一个“自定义”序列化程序(只委托回原始的序列化程序)之外,什么都不做,但是它生成的json没有空属性:
{“first”:“bob”,“last”:“barker”}
如果你把这句话注解掉 return new JsonSerializer<Object>() {...
并按原样返回传入的序列化程序 return serializer;
,然后jackson序列化空属性:
{“first”:“bob”,“middle”:null,“last”:“barker”,“email”:null}
我读过很多看似相关的so文章,但都没有找到解决方案。我已经尝试显式地将Map器设置为 Include.ALWAYS
一点运气都没有。
我唯一的线索是javadoc for jsonserializer中的一条评论:
注:各种 serialize
永远不会用空值调用方法——调用方必须处理空值,通常通过调用{@link serializerprovider#findnullvalueserializer}来获取要使用的序列化程序。
这也意味着自定义序列化程序不能直接用于更改
序列化空值时要产生的输出。
我使用的是Jackson2.11.2版。
我的问题是:如何编写自定义序列化程序并使jackson遵守与null属性序列化相关的include指令?
上下文信息:我的实际自定义序列化程序的工作是有条件地隐藏序列化的属性。我有一个自定义注解, @JsonAuth
这是元注解 @JacksonAnnotationsInside @JsonInclude(Include.NON_EMPTY)
我的自定义序列化程序 ContextualSerializer
)在覆盖的 isEmpty
方法和返回 true
(视为空)如果没有授权。最终的结果是,我有一个可以应用于属性的注解,如果客户机未经授权,该注解将隐藏该属性,使其无法序列化。除了。。。使用自定义序列化程序会产生意外的副作用,即删除所有空属性。
更新:Jackson的 BeanPropertyWriter.serializeAsField(...)
方法将完全忽略指定给属性的任何自定义序列化程序(如果值为null)。
我可以通过向类编写一个小扩展来重写此行为,从而允许我的“isauthorized”逻辑抢占空检查:
public class JsonAuthPropertyWriter extends BeanPropertyWriter {
private final Predicate<Object> authFilter;
private JsonAuthPropertyWriter(BeanPropertyWriter delegate, Predicate<Object> authFilter) {
super(delegate);
this.authFilter = authFilter;
// set null serializer or authorized null values disappear
super.assignNullSerializer(NullSerializer.instance);
}
@Override
public void serializeAsField(
Object bean,
JsonGenerator gen,
SerializerProvider prov) throws Exception {
boolean authorized = authFilter.test(bean);
if (!authorized) return;
super.serializeAsField(bean, gen, prov);
}
}
我用一个 BeanSerializerModifier
:
private static class JsonAuthBeanSerializerModifier extends BeanSerializerModifier {
@Override
public List<BeanPropertyWriter> changeProperties(
SerializationConfig config,
BeanDescription beanDesc,
List<BeanPropertyWriter> beanProperties
) {
for (int i = 0; i < beanProperties.size(); i++) {
BeanPropertyWriter beanPropertyWriter = beanProperties.get(i);
JsonAuth jsonAuth = beanPropertyWriter.findAnnotation(JsonAuth.class);
if (jsonAuth != null) {
Predicate<Object> authPredicate = ...
beanProperties.set(i, new JsonAuthPropertyWriter(beanPropertyWriter, authPredicate));
}
}
return beanProperties;
}
}
1条答案
按热度按时间x4shl7ld1#
我可能误解了你想要什么,但这种方法似乎很有用:
它每隔一段时间序列化带注解的字段,就像使用持久状态的过滤器的示例一样。
请让我知道这是否适合你。
顺便说一句,我同意Jackson有你描述的问题,我不知道如何解决它,所以这是一个解决办法,而不是你原来的问题的答案。