定制杰克逊序列化器在特定领域

时间:2017-11-06 04:54:01

标签: java json serialization jackson

我希望基于自定义注释为同一个对象设置多个jackson反序列化器。

理想情况下,我只有一个POJO:

public class UserInfo {
   @Redacted    
   String ssn;

   String name;
}

在“正常”条件下,我希望以默认方式序列化此对象:

{"ssn":"123-45-6789", "name":"Bob Smith"}

但是为了记录目的(例如)我想编辑SSN,因此它不会保存在我们的日志中:

{"ssn":"xxx-xx-xxxx", "name":"Bob Smith"}

我还研究过使用 @JsonSerialize 并提出:

public class UserInfo {

    @JsonSerialize(using = RedactedSerializer.class, as=String.class)
    String firstName;
    String lastName;

}

这个问题是它总是使用这个规则。可以添加多个@JsonSerializers,并且只在运行时代码中使用指定的一个吗?

我也看过“观点”,但理想情况下,我想至少表明该字段在请求中出现 - 即使我不知道它的价值。

2 个答案:

答案 0 :(得分:3)

100%安全的方法是在不同的请求中使用不同的DTO。但是,如果你不能这样做,请使用@JsonView和自定义序列化程序,如:

class Views {
    public static class ShowSSN {}
}

private static class MyBean{
    @JsonSerialize(using = MyBeanSerializer.class)
    @JsonView(Views.ShowSSN.class)
    String ssn;
    //getter setter constructor
}

private class MyBeanSerializer extends JsonSerializer<String> {
    @Override
    public void serialize(String value, JsonGenerator gen,
                          SerializerProvider serializers) throws IOException {
        Class<?> jsonView =  serializers.getActiveView();
        if (jsonView == Views.ShowSSN.class) 
            gen.writeString(value); // your custom serialization code here
        else 
            gen.writeString("xxx-xx-xxxx");
    }
} 

并使用它:

public static void main(String[] args) throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    MyBean bean = new MyBean("123-45-6789");

    System.out.println(mapper.writerWithView(Views.ShowSSN.class)
                             .writeValueAsString(bean));
    // results in {"ssn":"123-45-6789"}

    System.out.println(mapper.writeValueAsString(bean));
    // results in {"ssn":"xxx-xx-xxxx"}
}

另外,例如在春天,它将非常容易使用

@Controller
public class MyController {
    @GetMapping("/withView")       // results in {"ssn":"123-45-6789"}
    @JsonView(Views.ShowSSN.class)
    public @ResponseBody MyBean withJsonView() {
        return new MyBean("123-45-6789");
    }

    @GetMapping("/withoutView")    // results in {"ssn":"xxx-xx-xxxx"}
    public @ResponseBody MyBean withoutJsonView() {
        return new MyBean("123-45-6789");
    }

}

答案 1 :(得分:1)

我认为你可以通过编码而不是注释动态地实现这一点, 在你的方法中,你可以设置正确的Serializer并在它们之间切换

(代码取决于您的Jackson版本)

ObjectMapper mapper = new ObjectMapper();
SimpleModule testModule = new SimpleModule("MyModule", new Version(1, 0, 0, null));
testModule.addSerializer(new RedactedSerializer()); // assuming serializer declares correct class to bind to
mapper.registerModule(testModule);

https://github.com/FasterXML/jackson-docs/wiki/JacksonHowToCustomSerializers