I'm looking to have multiple jackson deserializers for the same object(s) all based on a custom annotation.
Ideally I'd have a single POJO like:
public class UserInfo {
@Redacted
String ssn;
String name;
}
Under "normal" conditions I want this object to be serialized the default way:
{"ssn":"123-45-6789", "name":"Bob Smith"}
but for logging purposes (for example) I want to redact the SSN so it doesn't get saved in our logs:
{"ssn":"xxx-xx-xxxx", "name":"Bob Smith"}
I've also looked into using @JsonSerialize and come up with:
public class UserInfo {
@JsonSerialize(using = RedactedSerializer.class, as=String.class)
String firstName;
String lastName;
}
The problem with this is that it ALWAYS uses this rule. Can multiple @JsonSerializers be added and only the specified one be used within the runtime code?
I've also seen "views" but ideally I'd like to atleast show that the field was present on the request - even if I dont know the value.
The 100% safe way would be to use different DTO in different requests. But yeah, if you cant do that, use @JsonView
and custom serializer, something like:
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");
}
}
And use it like:
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"}
}
Also for example in spring it would be really easy to use
@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");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With