Apenas usando @JsonIgnore durante a serialização, mas não desserialização

325

Eu tenho um objeto de usuário que é enviado para e do servidor. Quando envio o objeto de usuário, não quero enviar a senha com hash para o cliente. Então, adicionei @JsonIgnorea propriedade da senha, mas isso também impede que a desserialização seja feita na senha, o que dificulta a inscrição de usuários quando eles não têm uma senha.

Como posso @JsonIgnoreaplicar apenas à serialização e não à desserialização? Estou usando o Spring JSONView, então não tenho muito controle sobre o ObjectMapper.

Coisas que tentei:

  1. Adicionar @JsonIgnoreà propriedade
  2. Adicione @JsonIgnoreapenas o método getter
chubbsondubs
fonte

Respostas:

481

Exatamente como fazer isso depende da versão do Jackson que você está usando. Isso mudou em torno da versão 1.9 . Antes disso, você poderia fazer isso adicionando @JsonIgnoreao getter.

Que você tentou:

Adicione @JsonIgnore apenas ao método getter

Faça isso e inclua também uma @JsonPropertyanotação específica para o nome do campo "senha" JSON no método setter da senha em seu objeto.

Versões mais recentes de Jackson adicionaram argumentos de anotação READ_ONLYe WRITE_ONLYpara JsonProperty. Então você também pode fazer algo como:

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

Os documentos podem ser encontrados aqui .

pb2q
fonte
2
gist.github.com/thurloat/2510887 para Jackson JSON ignorar somente desserializar #
Hadas
1
AFAIK você ainda precisa implementar o setter e anotá-lo. Eu só quero o getter para serialização. Qual é o transitório de que você fala? Essa é uma anotação do JPA AFAIK
Matt Broekhuis
3
Além disso, certifique-se de remover @JsonProperty do campo em si caso contrário ele irá substituir o seu apanhador / anotações setter
Anton Soradoi
15
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
21416 Mikhail Batcer
1
As anotações de Jackson 2.5 não possuem o recurso posterior. Jackson-anotações 2.6.3 faz
radiantRazor
98

Para conseguir isso, tudo o que precisamos é de duas anotações:

  1. @JsonIgnore
  2. @JsonProperty

Use @JsonIgnoreno aluno e @JsonPropertyem quem recebe e em quem faz o preparo. Uma ilustração de exemplo ajudaria a fazer isso:

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;
    }
}
Balaji Boggaram Ramanarayan
fonte
2
é a única coisa que funcionou para mim com o jackson 2.6.4. Eu tentei o meu melhor para usar @JsonProperty (access = Access.WRITE_ONLY), mas não funcionou para mim.
Cirovladimir 17/02
77

Desde a versão 2.6: uma maneira mais intuitiva é usar a com.fasterxml.jackson.annotation.JsonPropertyanotação no campo:

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

Mesmo que exista um getter, o valor do campo é excluído da serialização.

O JavaDoc diz:

/**
 * 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

Caso você precise do contrário, basta usar Access.READ_ONLY.

Daniel Beer
fonte
1
Eu não entendo por que há tão poucos votos, essa é uma maneira elegante de resolver esse problema, funciona como um encanto. Não há necessidade de anotar getter, setter e field. Somente campo. Obrigado.
CROSP
Isto está disponível desde a versão 2.6, veja mais rápido em mlml.github.io/jackson-annotations/javadoc/2.6/com/…
Daniel Beer
Provavelmente a melhor resposta para mais de 2,6 usuários.
David Dossot
Verifique se você não está usando a importação org.codehaus.jackson.annotate . A solução do @ DanielBeer funciona para Jackson 2.6.3. Essa deve ser a resposta aceita agora que Jackson foi atualizado.
Kent Touro
13

No meu caso, tenho Jackson (des) serializando automaticamente objetos que retorno de um controlador Spring MVC (estou usando o @RestController com o Spring 4.1.6). Eu tive que usar em com.fasterxml.jackson.annotation.JsonIgnorevez de org.codehaus.jackson.annotate.JsonIgnore, caso contrário, simplesmente não fez nada.

Alex Beardsley
fonte
1
esta é uma resposta extremamente útil que realmente me ajudou a encontrar a fonte do motivo pelo qual @JsonIgnore não estava sendo homenageado por Jackson ... obrigado!
Clint Eastwood
2
"user": {
        "firstName": "Musa",
        "lastName": "Aliyev",
        "email": "[email protected]",
        "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
fonte
4
No futuro, pode ser útil fornecer uma breve descrição de como o código funciona.
KWILLIAMS
Tudo bem !! O que você está tentando aqui? Obtendo mais votos? lol
Balaji Boggaram Ramanarayan
0

Outra maneira fácil de lidar com isso é usar o argumento allowSetters=true na anotação. Isso permitirá que a senha seja desserializada no seu dto, mas não a serializará em um corpo de resposta que usa o objeto contém.

exemplo:

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

Ambos fooe barsão preenchidos no objeto, mas apenas foo é gravado em um corpo de resposta.

Dhandley
fonte
Esse foi o meu erro, eu não sabia que você já havia corrigido o trecho. Observando suas alterações, parece que meus anos de escrita no Groovy me atraíram e minha tradução para Java foi um pouco difícil. Desculpe!
Dhandley