gpt4 book ai didi

java - 具有条件隐藏成员的 Jackson 自定义序列化程序会生成无效的 JSON

转载 作者:行者123 更新时间:2023-12-02 04:33:37 26 4
gpt4 key购买 nike

我需要创建一个有条件地跳过字段的自定义序列化器。与中描述的情况相反 Skip objects conditionally when serializing with jackson我的类包含一个 POJO 成员。PersonalInfo 有一个地址作为成员。如果地址被隐藏,生成的 JSON 仍然具有“地址”标签,但没有值。我不知道如何解决这个问题。

在 ObjectMapper 上创建自定义序列化程序(请参阅 http://www.baeldung.com/jackson-custom-serialization 中的 3)会产生完全相同的结果。

以下是显示问题的引用问题的改编代码:

public class JacksonHide {
@JsonIgnoreProperties("hidden")
public static interface IHideable {
boolean isHidden();
}

public static class Address implements IHideable {
public final String city;
public final String street;
public final boolean hidden;

public Address(String city, String street, boolean hidden) {
this.city = city;
this.street = street;
this.hidden = hidden;
}

@Override
public boolean isHidden() {
return hidden;
}
}

public static class PersonalInfo implements IHideable {
public final String name;
public final int age;
public final Address address;
public final boolean hidden;

public PersonalInfo(String name, int age, Address address, boolean hidden) {
this.name = name;
this.age = age;
this.address = address;
this.hidden = hidden;
}

@Override
public boolean isHidden() {
return hidden;
}
}

private static class MyBeanSerializerModifier extends BeanSerializerModifier {
@Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
if (IHideable.class.isAssignableFrom(beanDesc.getBeanClass())) {
return new MyIHideableJsonSerializer((JsonSerializer<IHideable>) serializer);
}
return super.modifySerializer(config, beanDesc, serializer);
}

private static class MyIHideableJsonSerializer extends JsonSerializer<IHideable> {
private final JsonSerializer<IHideable> serializer;

public MyIHideableJsonSerializer(JsonSerializer<IHideable> serializer) {
this.serializer = serializer;
}

@Override
public void serialize(IHideable value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
if (!value.isHidden()) {
serializer.serialize(value, jgen, provider);
}

}
}
}

public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.setSerializerModifier(new MyBeanSerializerModifier());
mapper.registerModule(module);

PersonalInfo p1 = new PersonalInfo("John", 30, new Address("A", "B", false), false);
PersonalInfo p2 = new PersonalInfo("Ivan", 20, new Address("C", "D", true), true);
PersonalInfo p3 = new PersonalInfo("Mary", 40, new Address("C", "D", true), false);
Address a1 = new Address("A", "B", false);
Address a2 = new Address("C", "D", true);

System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(Arrays.asList(p1, p2, p3, a1, a2)));
}

}

更新:感谢反馈,我现在有了一个基于 @JSONFilter 的版本,它至少为我提供了有效的 JSON。不幸的是,节点仍然存在,但现在是空的 ({})。我怎样才能彻底摆脱它们?

public class JacksonFilterHide {

@JsonFilter("HiddenFilter")
@JsonIgnoreProperties("hidden")
public static interface IHideable {
boolean isHidden();
}

public static class Address implements IHideable {
public final String city;
public final String street;
public final boolean hidden;

public Address(String city, String street, boolean hidden) {
this.city = city;
this.street = street;
this.hidden = hidden;
}

@Override
public boolean isHidden() {
return hidden;
}
}

public static class PersonalInfo implements IHideable {
public final String name;
public final int age;
public final Address address;
public final boolean hidden;

public PersonalInfo(String name, int age, Address address, boolean hidden) {
this.name = name;
this.age = age;
this.address = address;
this.hidden = hidden;
}

@Override
public boolean isHidden() {
return hidden;
}
}

static final PropertyFilter hiddenFilter = new SimpleBeanPropertyFilter() {
@Override
public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer) throws Exception {
if (include(writer)) {
if (pojo instanceof IHideable && ((IHideable) pojo).isHidden()) {
return;
} else {
writer.serializeAsField(pojo, jgen, provider);
return;
}
} else if (!jgen.canOmitFields()) { // since 2.3
writer.serializeAsOmittedField(pojo, jgen, provider);
}
}

@Override
protected boolean include(BeanPropertyWriter writer) {
return true;
}

@Override
protected boolean include(PropertyWriter writer) {
return true;
}
};

public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
// ObjectMapper mapper = UserInteractionModel.getMapper();
FilterProvider filters = new SimpleFilterProvider().addFilter("HiddenFilter", hiddenFilter);
mapper.setFilters(filters);
mapper.enable(SerializationFeature.INDENT_OUTPUT);

PersonalInfo p1 = new PersonalInfo("John", 30, new Address("A", "B", false), false);
PersonalInfo p2 = new PersonalInfo("Ivan", 20, new Address("C", "D", true), true);
PersonalInfo p3 = new PersonalInfo("Mary", 40, new Address("C", "D", true), false);
Address a1 = new Address("A", "B", false);
Address a2 = new Address("C", "D", true);

System.out.println(mapper.writeValueAsString(Arrays.asList(p1, p2, p3, a1, a2)));
}

}

现在的输出是:

[ { "name" : "John", "age" : 30, "address" : { "city" : "A", "street" : "B" } }, { }, { "name" : "Mary", "age" : 40, "address" : { } }, { "city" : "A", "street" : "B" }, { } ]

预期:

[ { "name" : "John", "age" : 30, "address" : { "city" : "A", "street" : "B" } }, { "name" : "Mary", "age" : 40, }, { "city" : "A", "street" : "B" } ]

更新2通过遍历树并删除空节点来临时修复。丑陋,但目前有效。仍在寻找更好的答案。

private void removeEmptyNodes(JSONObject json) {
Iterator<String> iter = json.keys();
while (iter.hasNext()) {
String key = iter.next();
JSONObject node;
try {
node = json.getJSONObject(key);
} catch (JSONException e) {
continue;
}
if (node.length() == 0) {
iter.remove();
} else {
removeEmptyNodes(node);
}

}
}

受此问题启发的解决方案:How do I remove empty json nodes in Java with Jackson?

最佳答案

您的序列化器已损坏:如果需要,它无法选择不写入值。在写入属性值的情况下,调用者已经写出了属性名称,因此不写入该值确实会破坏输出。这要么导致抛出异常(理想情况下),要么导致输出损坏(不太理想情况下);不管怎样,JsonSerializer 不允许尝试决定是否正在写入值。

要排除正在序列化的属性,您的有效选择包括:

  1. 静态属性注释,例如 @JsonIgnore@JsonIgnoreProperties,始终排除特定的命名属性
  2. 基于值类型的包含的静态注释 @JsonInclude(无空值、无缺席、无空值)
  3. 静态定义,但动态选择要使用的 @JsonView(可以通过与 View 关联动态排除的属性集)
  4. 动态@JsonFilter
  5. 包含属性的类型的自定义序列化程序

关于java - 具有条件隐藏成员的 Jackson 自定义序列化程序会生成无效的 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31121093/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com