Мне нужно создать собственный сериализатор, который условно пропускает поля. В отличие от случая, описанного в Skip objects conditionally when serializing with jackson В моем классе содержится член POJO. Личный кабинет имеет адрес в качестве участника. В случае, если адрес скрыт, в результате JSON по-прежнему имеет тег «адрес», но без значения. Я не мог понять, как это исправить.Пользовательский сериализатор Jackson с условно скрытыми элементами создает недопустимый JSON
Создание настраиваемого сериализатора на ObjectMapper (см. 3. на http://www.baeldung.com/jackson-custom-serialization) приводит к точному результату.
Вот адаптированный код из ссылочного вопрос, который показывает проблему:
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: Благодаря обратной связи у меня сейчас вариант, основанный на @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)));
}
}
Выход сейчас:
[{ "Имя": "Джон", "возраст": 30, "адрес": { "город": "А", «улица ":" B "}}, {}, {" name ":" Mary "," age ": 40," address ": {}}, {" city ":" A "," street ":" B " }, {}]
Ожидаемое:
[{"name": "John", "age": 30, "address": { "city": "A", "street": "B"}}, {"name": "Mary" , "возраст": 40}, { "город": "а", "улица": "B"}]
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?
Избавление от пустых объектов является немного сложнее, частично, так как, хотя можно включить исключение «пустых» объектов (это обнаруживается с помощью 'JsonSerializer. isEmpty (...) '), это не применяется к массивам или' List'. – StaxMan