I need to create a custom serializer that conditionally skips fields. In contrast to the case described in Skip objects conditionally when serializing with jackson my class contains a POJO member. A PersonalInfo has a Address as member. In case the Address is hidden the resulting JSON still has the "address" tag, but without value. I could not figure out how to fix this.
Creating a custom serializer on the ObjectMapper (see 3. at http://www.baeldung.com/jackson-custom-serialization) leads to the exact same result.
Here is the adapted code from the referenced question that shows the 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: Thanks to the feedback I have now a version based on @JSONFilter that gives me at least valid JSON. Unfortunately the nodes are still there, but are empty now ({}). How can I completely get 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 now 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 by traversing the tree and removing empty nodes. Ugly, but works for now. Still looking for a 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 by this question: How do I remove empty json nodes in Java with Jackson?