2

I have an entity class Account. It has a bunch of fields. Most of them for now are exposed in REST calls except where I explicitly ignore the password field with @JsonIgnore, but I will be adding more fields and I don't want to forget adding @JsonIgnore to something new that shouldn't be exposed.

Can I invert the exposure, so that I explicitly have to enable fields to be exported, with the default being that it won't be exposed?

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import lombok.Data;
import lombok.ToString;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import com.fasterxml.jackson.annotation.JsonIgnore;

@Data
@ToString(exclude = "password")
@Entity
public class Account {

    public static final PasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder();

    private @Id @GeneratedValue Long id;

    private String name;

    @JsonIgnore private String password;

    private String[] roles;

    public void setPassword(String password) {
        this.password = PASSWORD_ENCODER.encode(password);
    }

    protected Account() {}

    public Account(String name, String password, String... roles) {

        this.name = name;
        this.setPassword(password);
        this.roles = roles;
    }

}

Using Spring Data REST here, so everything else that is there is just repositories, there is no extra layer to do something smart.

Sebastiaan van den Broek
  • 5,818
  • 7
  • 40
  • 73

1 Answers1

2

There is two main ways to get the "white-list" properties effect in Jackson library

First Way:

Remove @Data annotation from your Account class and add getters only to fields you want to expose. To make sure that properties without getters will not be excludes add @JsonIgnoreProperties(ignoreUnknown=true) to your Account class

Second Way:

Wrap your Account class with AccountForJson class. for example :

public class AccountForJson {

private Account account;

public MyClassForJson(Account accountToWrapped) {
    this.account = accountToWrapped;
}

/**
 * Example of property that you want to expose
 */
public String getName() {
    return this.account.getName();
 }
}

p.s : there is an open issuse in Jackson github repository for that feature, here is the link for watching that issuse - Add @JsonIncludeProperties(propertyNames) (reverse of @JsonIgnoreProperties)

Ron Badur
  • 1,873
  • 2
  • 15
  • 34
  • Thanks! I could go with the 2nd option, the first is hard because I do want to access some fields from classes within my application, while not exposing them through rest. It seems a bit of a workaround though, was hoping for an option within Jackson or Spring. – Sebastiaan van den Broek Mar 03 '18 at 13:14
  • 2
    Third way: create a dedicate data class (Dto) to expose only the fields you want :) – Dherik Mar 03 '18 at 13:33
  • @Dherik could you elaborate in an answer a bit? That seems a bit hard to do in a Spring Data REST application that automatically exposes Repository classes providing the entities through REST. – Sebastiaan van den Broek Mar 06 '18 at 08:52
  • @SebastiaanvandenBroek with Spring Data Rest is [not so easy](https://stackoverflow.com/a/45401735/2387977), you are right. My "third way" would not use Spring Data Rest: you create some "Dto"s for the endpoints and populate them with the entity informations with some mapper lib, exposing only the fields you want. It's a extra layer, for sure. Spring Data Rest is not so flexible and, for me, incentives a bad practice. – Dherik Mar 06 '18 at 11:02
  • 1
    @Dherik yeah I’m really considering just dropping Spring Data Rest altogether. What bad practices would you say it incentives? – Sebastiaan van den Broek Mar 06 '18 at 11:06
  • 1
    @SebastiaanvandenBroek, 1. expose the entity in your "view" layer (this alone brings a lot of problems: reduces your flexibility, some changes in entity will change your REST contract, difficult to have different representations for the same entity, etc); 2. mix your entity with Json annotations, Validation annotations, JPA annotations, etc (this is a nightmare for maintenance, IMHO), 3. violates the SRP (your entity have a lot of responsibilities). – Dherik Mar 06 '18 at 11:46