我需要创建一个有条件地跳过字段的自定义序列化程序。 与上述情况相反 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)));
}
}
现在输出是:
[{&#34; name&#34; :&#34;约翰&#34;,&#34;年龄&#34; :30,&#34;地址&#34; :{ &#34;城市&#34; :&#34; A&#34;, &#34;街道&#34; :&#34; B&#34; },{},{&#34; name&#34; :&#34;玛丽&#34;,&#34;年龄&#34; :40,&#34;地址&#34; :{}},{&#34; city&#34; :&#34; A&#34;,&#34;街道&#34; :&#34; B&#34; },{}]
预期:
[{&#34; name&#34; :&#34;约翰&#34;,&#34;年龄&#34; :30,&#34;地址&#34; :{ &#34;城市&#34; :&#34; A&#34;, &#34;街道&#34; :&#34; B&#34; },{&#34; name&#34; :&#34;玛丽&#34;,&#34;年龄&#34; :40,},{&#34; city&#34; :&#34; A&#34;,&#34;街道&#34; :&#34; B&#34; }]
UPDATE2 通过遍历树并删除空节点来临时修复。丑陋,但现在工作。仍在寻找更好的答案。
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?
答案 0 :(得分:2)
您的序列化程序已损坏:如果请求,它无法选择不写入值。在写入属性值的情况下,调用者已经写出了属性名称,因此不写入值确实会破坏输出。
这或者导致抛出(理想情况下)异常,或者输出损坏(理想情况下不太好);无论如何,JsonSerializer
不允许尝试决定是否正在写入值。
要排除正在序列化的媒体资源,您的有效选择包括:
@JsonIgnore
和@JsonIgnoreProperties
,始终排除特定的命名属性@JsonInclude
基于值的类型(无空,无缺席,无空值)@JsonView
(可以通过与视图关联动态排除的属性集)@JsonFilter