java - Jackson custom serializer with conditionally hidden members produces invalid JSON -
i need create custom serializer conditionally skips fields. in contrast case described in skip objects conditionally when serializing jackson class contains pojo member. personalinfo has address member. in case address hidden resulting json still has "address" tag, without value. not figure out how fix this.
creating custom serializer on objectmapper (see 3. @ http://www.baeldung.com/jackson-custom-serialization) leads exact same result.
here adapted code referenced question shows problem:
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))); } }
update: feedback have version based on @jsonfilter gives me @ least valid json. unfortunately nodes still there, empty ({}). how can rid of them?
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))); } }
output is:
[ { "name" : "john", "age" : 30, "address" : { "city" : "a", "street" : "b" } }, { }, { "name" : "mary", "age" : 40, "address" : { } }, { "city" : "a", "street" : "b" }, { } ]
expected:
[ { "name" : "john", "age" : 30, "address" : { "city" : "a", "street" : "b" } }, { "name" : "mary", "age" : 40, }, { "city" : "a", "street" : "b" } ]
update2 temporary fix traversing tree , removing empty nodes. ugly, works now. still looking better answer.
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); } } }
solution inspired question: how remove empty json nodes in java jackson?
your serializer broken: can not choose not write value, if requested. in case of writing property value, caller has written out property name, not writing value indeed break output. either results in exception being thrown (ideally), or broken output (less ideally); regardless, jsonserializer
not allowed try decide whether value being written.
to exclude property being serialized, valid choices include:
- static property annotations
@jsonignore
,@jsonignoreproperties
exclude specific named property - static annotation
@jsoninclude
bases inclusion on type of value (no nulls, no absents, no empty values) - static definition dynamic choice of
@jsonview
use (sets of properties can dynamically exclude associating view) - dynamic
@jsonfilter
- custom serializer type contains property
Comments
Post a Comment