Сериализация древовидной структуры в JSON с использованием фильтров с Джексоном - PullRequest
0 голосов
/ 09 октября 2018

У меня есть RestController, который возвращает следующую древовидную структуру:

@Data
public class TreeNode {
    private String description;
    private boolean enabled;
    private Set<TreeNode> children;
}

В зависимости от входного параметра я хочу скрыть узлы дерева, где enabled равно false, и я 'Я ищу решение, которое не требует перестройки всего дерева.

У меня был некоторый успех с расширением JsonSerializer и добавлением туда этого правила, но довольно громоздко иметь несколько ObjectMapper с в контроллере (один с сериализатором, другой без) и выбрать тот, который основан напараметр.Есть ли более простой способ добиться этого?

1 Ответ

0 голосов
/ 09 октября 2018

Что такое что-то подобное?Вы выходите из корня, ищите всех детей и удаляете их, если отключеныИ если включено, вы рекурсивно вызываете тот же метод обрезки.

Вы не перестраиваете дерево, вы обрезаете ненужные листья:

// Example for this tree:
//          l0
//     l1        l2
//  l11  l12   l21 l22


TreeNode l11 = new TreeNode("leaf 11", true, Collections.emptySet());
TreeNode l12 = new TreeNode("leaf 12", false, Collections.emptySet());
TreeNode l21 = new TreeNode("leaf 21", true, Collections.emptySet());
TreeNode l22 = new TreeNode("leaf 22", true, Collections.emptySet());
TreeNode l1 = new TreeNode("leaf 1", true, new HashSet<>(Arrays.asList(l11, l12)));
TreeNode l2 = new TreeNode("leaf 2", false, new HashSet<>(Arrays.asList(l21, l22)));
TreeNode l0 = new TreeNode("leaf 0", true, new HashSet<>(Arrays.asList(l1, l2)));



@RequestMapping(value="/api/v1/tree", method = RequestMethod.GET)
public TreeNode getTree(@RequestParam("full") int full){
    System.out.println("getTree full: "+full);

    if(full != 1) {
        trim(l0);
    }

    return l0;
}

private void trim(TreeNode treeNode) {
    for(TreeNode tn : treeNode.getChildren()) {
        if(!tn.isEnabled()) {
            treeNode.getChildren().remove(tn);
        } else {
            trim(tn);
        }
    }
}

РЕДАКТИРОВАТЬ

Вероятно, вы можете достичь этого, используя PropertyFilter

Создайте фильтр, который позволяет только разрешать узлы:

class EnabledTreeNodeFilter extends SimpleBeanPropertyFilter {

    @Override
    public void serializeAsField(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider, PropertyWriter propertyWriter) throws Exception {
        if(((TreeNode) o).isEnabled()) {
            propertyWriter.serializeAsField(o, jsonGenerator, serializerProvider);
        }
    }
}

Установите имя фильтра для вашего класса

@JsonFilter("enabledTreeNodeFilter")
class TreeNode {
    private String description;
    private boolean enabled;
    private Set<TreeNode> children;

    // Getters
}

Добавить фильтр в свой маппер

ObjectMapper mapper = new ObjectMapper();

// Add this bit in an if, if you want to filter or not
SimpleFilterProvider filters = new SimpleFilterProvider();
filters.addFilter("enabledTreeNodeFilter", new EnabledTreeNodeFilter());
mapper.setFilters(filters);

// Then you can use your mapper
String treeNodeAsString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(l0);
System.out.println(treeNodeAsString);

Выходы

{
    "description" : "leaf 0",
    "enabled" : true,
    "children" : [ {
        "description" : "leaf 1",
        "enabled" : true,
        "children" : [ {
            "description" : "leaf 11",
            "enabled" : true,
            "children" : [ ]
        }, { } ]
    }, { } ]
}

Почти работает, я не уверен, как избавиться от пустых объектов в дочерних массивах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...