Використання @JsonIgnore лише під час серіалізації, але не десеріалізації


325

У мене є об’єкт користувача, який надсилається на сервер і з нього. Коли я надсилаю об'єкт користувача, я не хочу надсилати хешований пароль клієнту. Отже, я додав @JsonIgnoreвластивість пароля, але це також блокує його десеріалізацію в пароль, що ускладнює реєстрацію користувачів, коли вони не отримали пароль.

Як я можу лише @JsonIgnoreподати заявку на серіалізацію, а не на десеріалізацію? Я використовую Spring JSONView, тому я не маю тони контролю над ObjectMapper.

Що я спробував:

  1. Додайте @JsonIgnoreдо власності
  2. Додайте @JsonIgnoreлише метод getter

Відповіді:


481

Як саме це зробити, залежить від версії Джексона, яку ви використовуєте. Це змінилося у версії 1.9 , до цього ви могли це зробити, додавши @JsonIgnoreдо геттера.

Що ви пробували:

Додайте @JsonIgnore лише для методу getter

Зробіть це, а також додайте спеціальну @JsonPropertyпримітку до імені поля "пароль" JSON до методу встановлення пароля на вашому об'єкті.

Додано ще більш пізні версії Джексона READ_ONLYі WRITE_ONLYаргументи анотації JsonProperty. Тож ви також можете зробити щось на кшталт:

@JsonProperty(access = Access.WRITE_ONLY)
private String password;

Документи можна знайти тут .


2
gist.github.com/thurloat/2510887 для Джексона JSON ігнорує лише десеріалізувати
Hadas

1
AFAIK вам все одно доведеться реалізувати сеттер і коментувати його. Я просто хочу геттер для серіалізації. Про що минуще ви говорите? Це анотація JPA AFAIK
Метт Брукхуйс

3
Також переконайтесь, що вилучите @JsonProperty з самого поля, інакше це перекриє ваші анотації на геттер / сетер
Антон Сорадой

15
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
Михайло Батцер

1
Пізніші примітки Джексона 2.5 не мають більш пізньої функції. Jackson-анотації 2.6.3 робить
radiantRazor

98

Для цього потрібно лише дві примітки:

  1. @JsonIgnore
  2. @JsonProperty

Використовуйте @JsonIgnoreдля учасника класу та його геттера та @JsonPropertyйого сетератора. Зразок ілюстрації допоможе зробити це:

class User {

    // More fields here
    @JsonIgnore
    private String password;

    @JsonIgnore
    public String getPassword() {
        return password;
    }

    @JsonProperty
    public void setPassword(final String password) {
        this.password = password;
    }
}

2
це єдине, що працювало для мене з Джексоном 2.6.4. Я намагався використовувати @JsonProperty (access = Access.WRITE_ONLY), але це не спрацювало для мене.
cirovladimir

77

Оскільки версія 2.6: інтуїтивнішим способом є використання com.fasterxml.jackson.annotation.JsonPropertyанотації на полі:

@JsonProperty(access = Access.WRITE_ONLY)
private String myField;

Навіть якщо геттер існує, значення поля виключається з серіалізації.

JavaDoc каже:

/**
 * Access setting that means that the property may only be written (set)
 * for deserialization,
 * but will not be read (get) on serialization, that is, the value of the property
 * is not included in serialization.
 */
WRITE_ONLY

Якщо вам це потрібно навпаки, просто використовуйте Access.READ_ONLY.


1
Я не розумію, чому так мало відгуків, це елегантний спосіб вирішити цю проблему, працює як шарм. Не потрібно коментувати геттер, сетер та поле. Тільки поле. Дякую.
CROSP

Це доступно з версії 2.6, дивіться швидшеxml.github.io/jackson-annotations/javadoc/
Daniel Beer

Мабуть, найкраща відповідь для користувачів 2,6+.
Девід Доссот

Переконайтесь, що ви не використовуєте імпорт org.codehaus.jackson.annotate . @ Рішення DanielBeer працює для Джексона 2.6.3. Це має бути прийнятою відповіддю тепер, коли Джексона було оновлено.
Кент Булл

13

У моєму випадку у мене Джексон автоматично (де) серіалізує об'єкти, які я повертаю з контролера MVC Spring (я використовую @RestController з Spring 4.1.6). Мені довелося використовувати com.fasterxml.jackson.annotation.JsonIgnoreзамість цього org.codehaus.jackson.annotate.JsonIgnore, як інакше, воно просто нічого не робило.


1
це надзвичайно корисна відповідь, яка дійсно допомогла мені знайти джерело, чому Джексон не вшанував @JsonIgnore ... дякую!
Клінт Іствуд

2
"user": {
        "firstName": "Musa",
        "lastName": "Aliyev",
        "email": "klaudi2012@gmail.com",
        "passwordIn": "98989898", (or encoded version in front if we not using https)
        "country": "Azeribaijan",
        "phone": "+994707702747"
    }

@CrossOrigin(methods=RequestMethod.POST)
@RequestMapping("/public/register")
public @ResponseBody MsgKit registerNewUsert(@RequestBody User u){

        root.registerUser(u);

    return new MsgKit("registered");
}  

@Service
@Transactional
public class RootBsn {

    @Autowired UserRepository userRepo;

    public void registerUser(User u) throws Exception{

        u.setPassword(u.getPasswordIn());
        //Generate some salt and  setPassword (encoded -  salt+password)
        User u=userRepo.save(u);

        System.out.println("Registration information saved");
    }

}

    @Entity        
@JsonIgnoreProperties({"recordDate","modificationDate","status","createdBy","modifiedBy","salt","password"})
                    public class User implements Serializable {
                        private static final long serialVersionUID = 1L;

                        @Id
                        @GeneratedValue(strategy=GenerationType.AUTO)
                        private Long id;

                        private String country;

                        @Column(name="CREATED_BY")
                        private String createdBy;

                        private String email;

                        @Column(name="FIRST_NAME")
                        private String firstName;

                        @Column(name="LAST_LOGIN_DATE")
                        private Timestamp lastLoginDate;

                        @Column(name="LAST_NAME")
                        private String lastName;

                        @Column(name="MODIFICATION_DATE")
                        private Timestamp modificationDate;

                        @Column(name="MODIFIED_BY")
                        private String modifiedBy;

                        private String password;

                        @Transient
                        private String passwordIn;

                        private String phone;

                        @Column(name="RECORD_DATE")
                        private Timestamp recordDate;

                        private String salt;

                        private String status;

                        @Column(name="USER_STATUS")
                        private String userStatus;

                        public User() {
                        }
                // getters and setters
                }

4
Це може допомогти в майбутньому дати навіть короткий опис того, як працює код.
KWILLIAMS

Добре !! Що ви тут намагаєтеся? Отримати більше голосів? lol
Баладжі Боггарам Раманараян

0

Ще один простий спосіб вирішити це - використовувати аргумент allowSetters=trueв анотації. Це дозволить десеріалізувати пароль у вашому dto, але не буде його серіалізувати у орган відповіді, який використовує об'єкт містить.

приклад:

@JsonIgnoreProperties(allowSetters = true, value = {"bar"})
class Pojo{
    String foo;
    String bar;
}

Обидва fooі barзаселяються в об'єкті, але в тіло відповідей записується лише foo.


Це була моя помилка, я не розумів, що ви вже виправили фрагмент. З огляду на ваші зміни, здається, що мої роки письма в Groovy отримали мене, і мій переклад на Java був трохи грубим. Вибачте!
Дхандлі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.