Jackson @JsonView is not working when I have a getter for internal variable

586 views Asked by At

I have these two calsses Human and User and they look like :

public class User{

    @JsonView(ExternalCategoriesViews.CustomCategoryExternalView.class)
    protected Long id;

    @JsonView(ExternalCategoriesViews.CustomCategoryExternalView.class)
    protected String firstname;

    @JsonView(ExternalCategoriesViews.CustomCategoryExternalView.class)
    protected String lastname;
    protected String email;
    protected String address;
    protected String postalCode;
    @JsonView(ExternalCategoriesViews.CustomCategoryExternalView.class)
    protected String city;
    protected String country;

    public User(Long id, String firstname, String lastname, String email, String address,
        String postalCode, String city, String country) {
        this.id = id;
        this.firstname = firstname;
        this.lastname = lastname;
        this.email = email;
        this.address = address;
        this.postalCode = postalCode;
        this.city = city;
        this.country = country;
    }

}
public class Human extends User {

    String sex;
    @JsonView({ExternalCategoriesViews.CustomCategoryExternalView.class})
    String salary;

    public Human(Long id, String firstname, String lastname, String email, String address,
        String postalCode, String city, String country, String sex, String salary) {
        super(id, firstname, lastname, email, address, postalCode, city, country);
        this.sex = sex;
        this.salary = salary;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getSalary() {
        return salary;
    }

    public void setSalary(String salary) {
        this.salary = salary;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        if (!super.equals(o)) {
            return false;
        }
        Human human = (Human) o;
        return Objects.equals(salary, human.salary);
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), salary);
    }
}

And I have a controller that returns Human.

@RequestMapping(method = RequestMethod.GET,
    value = "/test",
    produces = MediaType.APPLICATION_JSON + "; charset=UTF-8")
@ResponseBody
@JsonView(ExternalCategoriesViews.CustomCategoryExternalView.class)
public Human getCustomCategory1() {
    Human n = new Human(1L,"first name","last name", "[email protected]","address","qwe","city","country","male","12000");
    return n;
}

and I have this class for JsonView:

public class ExternalCategoriesViews {
    public interface CustomCategoryExternalView {
    }
}

The issue here is that what I'm anticipating is to get a response without "sex" property, as it's not annotated with @JsonView. so the response should not contain it but it's not the case, because I'm still seeing it.

I noticed that if I remove the getSex() getter then the "sex" property will disappear from the response so I can say @JsonView works.

But unfortunately, I can't get rid of the getter.

And then I understand that @JsonView() uses reflection to access private and protected properties. As soon as you delete the getter, Jackson doesn't know how to serialize/deserialize the properties, so without getters @JsonView() will work properly as it can't reach properties, and only those annotated with @JsonView() will be considerd in the serialization.

My question is, how to make this "sex" property disappear from the response(make @JsonView() work properly) without removing the getter?

1

There are 1 answers

7
João Dias On

If you never want sex property to be available in the JSON response, just use @JsonIgnore as follows:

public class Human extends User {

    @JsonIgnore
    String sex;
    
    @JsonView({ExternalCategoriesViews.CustomCategoryExternalView.class})
    String salary;

    (...)
}

This means that sex will be ignore for serialization and deserialization. If you just want it to be ignored while serializing the object to JSON, then you can use @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) as follows:

public class Human extends User {

    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    String sex;
    
    @JsonView({ExternalCategoriesViews.CustomCategoryExternalView.class})
    String salary;

    (...)
}

You can read more about this in the following reference documentation:


Given that you want to expose it in some Controllers and not it others you need another JsonView for this:

public class ExternalCategoriesViews {
    public interface CustomCategoryExternalView {
    }
    public interface AnotherCustomCategoryExternalView {
    }
}
public class Human extends User {

    @JsonView({ExternalCategoriesViews.AnotherCustomCategoryExternalView.class})
    String sex;

    @JsonView({ExternalCategoriesViews.CustomCategoryExternalView.class})
    String salary;

    (...)
}