假设我有以下类(class):

public class Employee {
    private Department department;

    // other fields, getters and setters omited for brevtity
}

public class Department {
    private Address address;

    // other fields, getters and setters omited for brevtity
}

public class Address {
    private Location location;

    // other fields, getters and setters omited for brevtity
}

public class Location {
    private String streetName;

    // other fields, getters and setters omited for brevtity
}

现在,我想加载Employee对象并使用ObjectMapper对其进行序列化:
public void serializeEmployee() {
    Employee employee = entityManager.load(Employee.class, 1);
    ObjectMapper mapper = new ObjectMapper();
    System.out.println(mapper.writeValueAsString(student));
}

当我运行上面的代码时,我看到这样的json字符串:
{
    "department" : {
        "address" : {
            "location" : {
                "streetName" : {}
            }
        }
    }
}

但是我想将序列化深度设置为一个级别,我的意思是当代码运行时,我想看到这样的结果:
{
    "department" : {
    }
}

注意

我不想使用 jackson 注释,我想在使用mapper对象时设置配置。用于调用mapper.setConfigmapper.disable的示例。

最佳答案

您可以使用PropertyFilter来限制序列化的深度。这是我想出的一个解决方案。使用此过滤器时要注意几件事,示例中也对此进行了演示:

  • 数组提供了一个附加的深度级别,因此数组条目是父级的depth + 2(这不是错误,它是一个功能:D-如果为数组开始而解析上下文,则可以更改此行为)
  • map 属性在 map 声明为
  • 的级别上完全序列化
  • 深度是按类定义的;如果您需要可变长度,则可以扩展带有DN后缀的基类以进行序列化,或者制作一个恒定的过滤器名称并为每个深度创建专用的ObjectMapper

  • 这是代码。 DeepFieldFilter进行深度计算。必须在ObjectMapper中将其注册为过滤器,并且必须在数据类中标记@JsonFilter批注。
    public class JsonSerializationDeepFun {
    
        @Data
        @JsonFilter("depth_3")
        static class DynamicJsonObject {
            Long id;
            String name;
            BigDecimal price;
    
            List<DynamicJsonObject> children = new ArrayList<>();
    
            @JsonIgnore
            Map<String, Object> properties = new HashMap<>();
    
            @JsonAnySetter
            public void add(String key, String value) {
                properties.put(key, value);
            }
    
            @JsonAnyGetter
            public Map<String, Object> getMap() {
                return properties;
            }
        }
    
    
         /**
         * There're a couple of things to note when using this filter. <a href="https://stackoverflow.com/a/51279460/1961634">Visit stackoverflow for an example</a>
         * <ul>
         * <li>arrays provide an additional depth level, so array entry is depth+2
         * from parent; it's not a bug, it's a feature - this behavior could be
         * changed if JsonStreamContext is parsed for array start</li>
         * <li>map properties are serialized fully at the level the map is declared</li>
         * <li>depth is defined per-class; you could extend base class with DN suffix
         * to serialize if you need variable length, or make a constant filter name
         * and create a dedicated `ObjectMapper` for each depth</li>
         * </ul>
         * @author Dariusz Wawer <dwawer@pretius.com>
         *
         */
        static class DeepFieldFilter extends SimpleBeanPropertyFilter {
            private final int maxDepth;
    
            public DeepFieldFilter(int maxDepth) {
                super();
                this.maxDepth = maxDepth;
            }
    
            private int calcDepth(PropertyWriter writer, JsonGenerator jgen) {
                JsonStreamContext sc = jgen.getOutputContext();
                int depth = -1;
                while (sc != null) {
                    sc = sc.getParent();
                    depth++;
                }
                return depth;
            }
    
            @Override
            public void serializeAsField(Object pojo, JsonGenerator gen, SerializerProvider provider, PropertyWriter writer)
                                            throws Exception {
                int depth = calcDepth(writer, gen);
                if (depth <= maxDepth) {
                    writer.serializeAsField(pojo, gen, provider);
                }
                // comment this if you don't want {} placeholders
                else {
                    writer.serializeAsOmittedField(pojo, gen, provider);
                }
            }
    
        }
    
        public static void main(String[] args) throws IOException {
            ObjectMapper om = new ObjectMapper();
    
            SimpleFilterProvider depthFilters = new SimpleFilterProvider().addFilter("depth_1", new DeepFieldFilter(1))
                                            .addFilter("depth_2", new DeepFieldFilter(2))
                                            .addFilter("depth_3", new DeepFieldFilter(3))
                                            .addFilter("depth_4", new DeepFieldFilter(4))
                                            .addFilter("depth_5", new DeepFieldFilter(5))
            // ...
            ;
            om.setFilterProvider(depthFilters);
    
            om.enable(SerializationFeature.INDENT_OUTPUT);
            DynamicJsonObject obj = new DynamicJsonObject();
            obj.setId(321L);
            obj.setName("name");
            obj.setPrice(BigDecimal.valueOf(10.0));
    
            Map<String, Object> mapD3 = new HashMap<>();
            mapD3.put("depth", "3");
            mapD3.put("info", "gets serialzied at depth 1");
    
            Map<String, Object> mapD2 = new HashMap<>();
            mapD2.put("depth", "2");
            mapD2.put("map", mapD3);
    
            Map<String, Object> mapD1 = new HashMap<>();
            mapD1.put("depth", "1");
            mapD1.put("map", mapD2);
    
            obj.setProperties(mapD1);
    
            DynamicJsonObject child = new DynamicJsonObject();
            child.setId(514L);
            child.setName("actually depth 3, because array");
            child.setPrice(BigDecimal.valueOf(5.1));
            obj.getChildren().add(child);
    
            String jsonStr = om.writeValueAsString(obj);
            System.out.println(jsonStr);
        }
    
    }
    

    10-08 08:26
    查看更多