【问题标题】:jackson custom serialization with filtering带过滤的杰克逊自定义序列化
【发布时间】:2014-04-08 06:33:42
【问题描述】:

我需要在 Jackson 中自定义 POJO 的序列化,以便我可以根据用户输入对属性应用过滤器

我在 POJO 上应用了以下注释。

@JsonFilter("userFilter")
@JsonSerialize(using = UserSerializer.class)

自定义序列化器类如下。

public class UserSerializer  extends JsonSerializer<User> {


    @Override
    public void serialize(User value, JsonGenerator jgen,
            SerializerProvider provider) throws IOException,
            JsonProcessingException {

        ObjectMapper mapper = new ObjectMapper();
        SimpleFilterProvider sfp = new SimpleFilterProvider();

        // create a  set that holds name of User properties that must be serialized
        Set userFilterSet = new HashSet<String>();
        userFilterSet.add("firstName");
        userFilterSet.add("corporateOrgs");
        userFilterSet.add("rights");
        userFilterSet.add("requirements");


        sfp.addFilter("userFilter",SimpleBeanPropertyFilter.filterOutAllExcept(userFilterSet));

        // create an objectwriter which will apply the filters 
        ObjectWriter writer = mapper.writer(sfp);

        String json = writer.writeValueAsString(value);


    }

}

我可以看到 Jackson 正在尝试使用定义的自定义序列化程序序列化 POJO。然而,它最终以无限递归/stackoverflow 结束,因为 writer.writeValueAsString(value) 最终再次调用自定义序列化程序。

显然我这里没有一些基本的东西。如果过滤是在 serialize 方法之外完成的(例如在从 main() 调用的方法中),过滤将按预期工作。

任何人都可以提供有关如何利用自定义序列化来利用过滤的见解/文档链接。

【问题讨论】:

    标签: serialization jackson


    【解决方案1】:

    可以使用 JsonFilter 过滤掉字段,或者您可以创建一个仅写出某些字段的自定义 JsonSerialize 序列化程序。

    独立于 JsonFilter 的使用,尝试在具有对象映射器的用户定义的序列化器中递归地重新序列化要序列化的同一对象(覆盖的 serialize 方法的第一个参数)将导致无限循环。相反,在自定义序列化程序中,您宁愿使用 JsonGenerator 方法(被覆盖的 serialize 方法的第二个参数)来写出字段名称/值。

    在下面的答案中,两个变体(@JsonFilter 和 @JsonSerialize)都被演示了,其中只有一部分可用字段被序列化为 JSON。

    @JsonFilter

    要根据用户输入对属性应用过滤器,您不需要扩展 JsonSerializer。相反,您使用 JsonFilter 注释 POJO 并应用过滤。

    基于您的代码的独立示例如下所示:

    package com.software7.test;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
    import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
    
    import java.util.HashSet;
    import java.util.Set;
    
    public class Main {
    
        public static void main(String[] args) {
            Main m = new Main();
            try {
                m.serialize();
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
    
        void serialize() throws JsonProcessingException {
            ObjectMapper mapper = new ObjectMapper();
            SimpleFilterProvider sfp = new SimpleFilterProvider();
    
            Set<String> userFilterSet = new HashSet<>();
            userFilterSet.add("firstName");
            userFilterSet.add("corporateOrgs");
            userFilterSet.add("rights");
            userFilterSet.add("requirements");
    
            sfp.addFilter("UserFilter",
                    SimpleBeanPropertyFilter.filterOutAllExcept(userFilterSet));
    
            mapper.setFilterProvider(sfp);
    
            User user = new User("Brownrigg", "Don", "none", "+rwx", "n/a",
                    "some", "superfluous", "properties");
            System.out.println(user);
            System.out.println(">>>> serializing >>>>");
            String s = mapper.writeValueAsString(user);
            System.out.println(s);
        }
    }
    

    用户 POJO

    package com.software7.test;
    
    import com.fasterxml.jackson.annotation.JsonFilter;
    
    @JsonFilter("UserFilter")
    public class User {
        public String lastName;
        public String firstName;
        public String corporateOrgs;
        public String rights;
        public String requirements;
        public String a, b, c;
    
        public User(String lastName, String firstName, String corporateOrgs, String rights, String requirements,
                    String a, String b, String c) {
            this.lastName = lastName;
            this.firstName = firstName;
            this.corporateOrgs = corporateOrgs;
            this.rights = rights;
            this.requirements = requirements;
            this.a = a;
            this.b = b;
            this.c = c;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "lastName='" + lastName + '\'' +
                    ", firstName='" + firstName + '\'' +
                    ", corporateOrgs='" + corporateOrgs + '\'' +
                    ", rights='" + rights + '\'' +
                    ", requirements='" + requirements + '\'' +
                    ", a='" + a + '\'' +
                    ", b='" + b + '\'' +
                    ", c='" + c + '\'' +
                    '}';
        }
    }
    

    测试

    上述程序的调试输出如下所示:

    User{lastName='Brownrigg', firstName='Don', corporateOrgs='none', rights='+rwx', requirements='n/a', a='some', b='superfluous', c='properties'}
    >>>> serializing >>>>
    {"firstName":"Don","corporateOrgs":"none","rights":"+rwx","requirements":"n/a"}
    

    测试成功!如您所见,lastNameabc 属性已被删除。

    @JsonSerialize 替代方案

    如果您想使用客户序列化程序,您可以这样做:

    替换注释:

    @JsonFilter("UserFilter")
    

    @JsonSerialize(using = UserSerializer.class)
    

    但不要同时使用。

    UserSerializer 类可能如下所示:

    package com.software7.test;
    
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.JsonSerializer;
    import com.fasterxml.jackson.databind.SerializerProvider;
    
    import java.io.IOException;
    
    public class UserSerializer extends JsonSerializer<User> {
        @Override
        public void serialize(User user, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                throws IOException, JsonProcessingException {
            jsonGenerator.writeStartObject();
            jsonGenerator.writeObjectField("firstName", user.firstName);
            jsonGenerator.writeObjectField("corporateOrgs", user.corporateOrgs);
            jsonGenerator.writeObjectField("rights", user.rights);
            jsonGenerator.writeObjectField("requirements", user.requirements);
            jsonGenerator.writeEndObject();
        }
    }
    

    最后,序列化方法如下所示:

    void serialize() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
    
        User user = new User("Brownrigg", "Don", "none", "+rwx", "n/a",
                "some", "superfluous", "properties");
        System.out.println(user);
        System.out.println(">>>> serializing >>>>");
        String s = mapper.writeValueAsString(user);
        System.out.println(s);
    }
    

    这个例子的结果是一样的。哪种变体更适合取决于具体的用例或个人喜好。

    【讨论】:

    • 非常感谢您的详尽回答。我在使用 /@JsonFilter 时遇到类似“InvalidDefinitionException:无法使用 id 解析 PropertyFilter”的错误,但现在我可以从您的示例中运行 /@JsonFilter 和 /@JsonSerialize。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-19
    • 2012-05-29
    • 2015-07-11
    • 2014-01-31
    • 1970-01-01
    相关资源
    最近更新 更多