Только используя @JsonIgnore во время сериализации, но не десериализацию

325

У меня есть объект пользователя, который отправляется на сервер и с сервера. Когда я отправляю объект пользователя, я не хочу отправлять хешированный пароль клиенту. Итак, я добавил @JsonIgnoreсвойство пароля, но это также блокирует его десериализацию в пароль, что затрудняет регистрацию пользователей, когда у них нет пароля.

Как я могу получить только @JsonIgnoreприменить к сериализации, а не десериализации? Я использую Spring JSONView, поэтому у меня нет тонны контроля над ObjectMapper.

Вещи, которые я пробовал:

  1. Добавить @JsonIgnoreв собственность
  2. Добавьте @JsonIgnoreтолько метод получения
chubbsondubs
источник

Ответы:

481

Как именно это сделать, зависит от версии Джексона, которую вы используете. Это изменилось в версии 1.9 , до этого вы могли сделать это, добавив @JsonIgnoreв геттер.

Что вы пробовали:

Добавьте @JsonIgnore только для метода получения

Сделайте это, а также добавьте специальную @JsonPropertyаннотацию для вашего имени поля JSON «пароль» в метод установки для пароля вашего объекта.

Более свежие версии Джексона добавили READ_ONLYи WRITE_ONLYаннотации для аргументов JsonProperty. Таким образом, вы также можете сделать что-то вроде:

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

Документы можно найти здесь .

pb2q
источник
2
gist.github.com/thurloat/2510887 для Джексона JSON игнорировать только при десериализации
Хадас
1
AFAIK, вы все равно должны реализовать сеттер и аннотировать его. Я просто хочу геттер для сериализации. О каком переходном процессе вы говорите? Это аннотация JPA AFAIK
Мэтт Брукхёйс
3
Кроме того, обязательно удалите @JsonProperty из самого поля, иначе оно переопределит ваши аннотации геттера / сеттера
Антон Сорадой
15
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
Михаил Батцер
1
Джексон-аннотации 2.5 не имеет более поздней функции. Джексон-аннотации 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, см. Fastxml.github.io/jackson-annotations/javadoc/2.6/com/…
Даниэль Пив,
Вероятно, лучший ответ для 2.6+ пользователей.
Дэвид Доссо
Убедитесь, что вы не используете импорт org.codehaus.jackson.annotate . Решение @ DanielBeer работает на Джексона 2.6.3. Это должно быть принятым ответом теперь, когда Джексон был обновлен.
Кент Булл
13

В моем случае Джексон автоматически (де) сериализует объекты, которые я возвращаю из контроллера Spring MVC (я использую @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
                }
Musa
источник
4
Это может помочь в будущем дать даже краткое описание того, как работает код.
KWILLIAMS
Хорошо !! Что ты здесь пытаешься? Получаете больше голосов? лол
Баладжи Боггарам Раманараян
0

Другой простой способ справиться с этим - использовать аргумент allowSetters=trueв аннотации. Это позволит десериализовать пароль в вашем dto, но не будет сериализовать его в тело ответа, которое использует содержащий объект.

пример:

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

Оба fooи barзаполняются в объекте, но в тело ответа записывается только foo.

Dhandley
источник
Это была моя ошибка, я не осознавал, что вы уже исправили фрагмент. Глядя на ваши изменения, кажется, что мои годы написания на Groovy меня поняли, и мой перевод на Java был немного грубым. Сожалею!
Дандли