How do I serialize using two different getters bas

2019-08-02 04:02发布

I want the ability to serialize a field in an object based on the JsonView. It doesn't have to be JsonView, it's just what I have been exploring. Basically using @JsonView annotation on RestController class, it would serialize my POJO. However I have a User and Admin view where there is an object:

Map secrets;

That for an Admin view I want both key:value to show up and serialize, but for a User I would only want a List keys or if its simpler, keep Map but only show the key and all of the values switch to '****' 4 asteriks or something.

I thought about having two getters but the JsonView annotation doesn't work like that where two getters can have different views and Jackson knows which one to call.

I'm not sure JsonView is the best thing here. Perhaps a JsonGetter method that serializes based on view or some custom serializer, but I think there might be a more straightforward way to do it with Jackson and few annotations

What I am looking to do is:

Person.java
Map<String,String> secrets;

This would serialize to (for Admin):

{
"person":{
  "secrets":{
     "password":"123456",
     "creditCard":"1234 5678 9101"
   }
 }
}

This would serialize to (for User):

{
"person":{
  "secrets":{
     "password":"****",
     "creditCard":"****"
   }
 }
}

However what I would envision what I could do is something like


@JsonView(View.User.class)
Map<String,String> getSecrets(){
  this.secrets.forEach(value -> "****") //code would be different but basically setting all values to ****
  return secrets;
}

@JsonView(View.Admin.class)
Map<String,String> getSecrets(){
  //Returning secrets as they should be
  return secrets;
}

1条回答
走好不送
2楼-- · 2019-08-02 04:42

You can try defining a custom serializer for the object mapper , so that whenever the object mapper is used for serialization you can check and convert the password and credit card field to the value you choose.For example

public class ItemSerializer extends StdSerializer<Item> {

    public ItemSerializer() {
        this(null);
    }

    public ItemSerializer(Class<Item> t) {
        super(t);
    }

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

        jgen.writeStartObject();
        jgen.writeNumberField("id", value.id);
        jgen.writeStringField("itemName", value.itemName);
        jgen.writeNumberField("owner", value.owner.id);
        jgen.writeEndObject();
    }
}

You can provide an object mapper that utilizes this custom serializer then,

Item myItem = new Item(1, "theItem", new User(2, "theUser"));
ObjectMapper mapper = new ObjectMapper();

SimpleModule module = new SimpleModule();
module.addSerializer(Item.class, new ItemSerializer());
mapper.registerModule(module);

String serialized = mapper.writeValueAsString(myItem);

In your case you can register the objectmapper bean with the custom serializer in the spring context and make jackson use your object mapper bean.

Or using @JsonSerialize annotation like :

public class Event {
    public String name;

    @JsonSerialize(using = CustomDateSerializer.class)
    public Date eventDate;
}


Public class CustomDateSerializer extends StdSerializer<Date> {

    private static SimpleDateFormat formatter 
      = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

    public CustomDateSerializer() { 
        this(null); 
    } 

    public CustomDateSerializer(Class<Date> t) {
        super(t); 
    }

    @Override
    public void serialize(
      Date value, JsonGenerator gen, SerializerProvider arg2) 
      throws IOException, JsonProcessingException {
        gen.writeString(formatter.format(value));
    }
}

Refer:

https://www.baeldung.com/jackson-json-view-annotation

https://www.baeldung.com/jackson-custom-serialization

查看更多
登录 后发表回答