javaserializationjacksonjson-view

How to change JsonView for specific properties


Hi I have few UI objects that embedded into each other. Example #1:

class CarUI {
  public UserUI user;
  public UserUI agent;
  ....
  public UserUI getUser() {
    return user;
  }
  public UserUI getAgent() {
    return agent;
  }
}
class UserUI {
  @JsonView({Views.Public.class,Views.Private.class})
  public String name;
  @JsonView({Views.Private.class})
  public String phone;
  ...
}

As you can see if I serialize UserUI as Public I will expose only name but for private I will expose all fields.

Here is my question: when I serialize object CarUI I want to expose only name for "user" and both name+phone for "agent". That essentially means that in the getter for the getUser() I want to change JsonView to Views.Public.class and for getAgent() I want to change it to Views.Private.class

Is there way to overwrite JsonView in getters to make all hierarchy for the returned object now serialize using this new JsonView?

Edited As pointed below you can solve my Example#1 with JsonView inheritance. What about more generic. Here is Example#2:

class CarUI {
  public UserUI user;
  public UserUI agent;
  ....
  public UserUI getUser() {
    return user;
  }
  public UserUI getAgent() {
    return agent;
  }
}
class UserUI {
  @JsonView({Views.Public.class,Views.Private.class})
  public String name;
  @JsonView({Views.Private.class})
  public String phone;
  @JsonView({Views.Public.class})
  public String avatarUrl;
  ...
}

In this example Id like to display name+phone for Agent and name+avatarUrl for User.


Solution

  • @JsonView accepts inheritance. Views.Private fields extends Views.Public fields. This means Views.Private serialization will also look for the Views.Public annotations.

    public Views {
        public Public {}
        public Private extends Public {}
    }
    
    class CarUI {
      public UserUI user;
      public UserUI agent;
      ....
      @JsonView(Views.Public.class)
      public UserUI getUser() {
        return user;
      }
      @JsonView(Views.Private.class)
      public UserUI getAgent() {
        return agent;
      }
    }
    
    class UserUI {
      @JsonView(Views.Public.class)
      public String name;
      @JsonView(Views.Private.class)
      public String phone;
      ...
    }
    

    For Example #2

    You can introduce multiple classes like:

    public Views {
        public Public {}
        public Private1 extends Public {}
        public Private2 extends Public {}
    }
    
    class CarUI {
      public UserUI user;
      public UserUI agent;
      ....
      public UserUI getUser() {
        return user;
      }
      public UserUI getAgent() {
        return agent;
      }
    }
    class UserUI {
      @JsonView(Views.Public.class)
      public String name;
      @JsonView({Views.Private1.class})
      public String phone;
      @JsonView({Views.Private2.class})
      public String avatarUrl;
      ...
    }
    

    Or you can use view-less properties and use no inheritance:

    public Views {
        public Public {}
        public Private {}
    }
    
    class CarUI {
      public UserUI user;
      public UserUI agent;
      ....
      public UserUI getUser() {
        return user;
      }
      public UserUI getAgent() {
        return agent;
      }
    }
    class UserUI {
      // This one is view-less shows every time unless you specificy
      public String name;
      @JsonView({Views.Private.class})
      public String phone;
      @JsonView({Views.Public.class})
      public String avatarUrl;
      ...
    }
    
    ...
    // If you want to hide view-less properties, default is true 
    objectMapper.configure(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION, false); 
    ...