jackson自定义序列化与过滤

时间:2014-04-08 06:33:42

标签: serialization jackson

我需要在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。然而,当writer.writeValueAsString(value)最终再次调用自定义序列化程序时,它最终会进入无限递归/堆栈溢出。

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

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

2 个答案:

答案 0 :(得分:0)

您应该在示例中使用MixIn功能。简单用法:

@JsonSerialize(using = UserSerializer.class)
interface UserMixIn {

}

现在,在main方法中,您可以通过以下方式启用自定义序列化程序:

public static void main(String[] args) throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    mapper.addMixInAnnotations(User.class, UserMixIn.class);
    System.out.println(mapper.writeValueAsString(new User()));
}

内部ObjectMapper不了解自定义序列化程序,它将使用默认序列化程序。通过这种方式,您可以避免StackOverflow例外。

答案 1 :(得分:0)

可以使用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);
}

在此示例中,结果将相同。哪种版本更合适取决于具体的用例或个人喜好。