Utiliser uniquement @JsonIgnore pendant la sérialisation, mais pas la désérialisation

325

J'ai un objet utilisateur qui est envoyé vers et depuis le serveur. Lorsque j'envoie l'objet utilisateur, je ne veux pas envoyer le mot de passe haché au client. J'ai donc ajouté @JsonIgnorela propriété de mot de passe, mais cela l'empêche également d'être désérialisé dans le mot de passe, ce qui rend difficile l'inscription des utilisateurs lorsqu'ils n'ont pas de mot de passe.

Comment puis-je seulement @JsonIgnoreappliquer à la sérialisation et non à la désérialisation? J'utilise Spring JSONView, donc je n'ai pas une tonne de contrôle sur ObjectMapper.

Ce que j'ai essayé:

  1. Ajouter @JsonIgnoreà la propriété
  2. Ajouter @JsonIgnoreuniquement sur la méthode getter
chubbsondubs
la source

Réponses:

481

La façon exacte de procéder dépend de la version de Jackson que vous utilisez. Cela a changé autour de la version 1.9 , avant cela, vous pouvez le faire en ajoutant @JsonIgnoreau getter.

Ce que vous avez essayé:

Ajoutez @JsonIgnore sur la méthode getter uniquement

Faites cela et ajoutez également une @JsonPropertyannotation spécifique pour votre nom de champ "mot de passe" JSON à la méthode de définition du mot de passe sur votre objet.

Des versions plus récentes de Jackson ont ajouté READ_ONLYet WRITE_ONLYdes arguments d'annotation pour JsonProperty. Vous pouvez donc aussi faire quelque chose comme:

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

Les documents peuvent être trouvés ici .

pb2q
la source
2
gist.github.com/thurloat/2510887 pour Jackson JSON ignorer uniquement sur désérialisation
Hadas
1
AFAIK vous devez encore implémenter le setter et l'annoter. Je veux juste le getter pour la sérialisation. De quel transitoire parlez-vous? C'est une annotation JPA AFAIK
Matt Broekhuis
3
Assurez-vous également de supprimer @JsonProperty du champ lui-même, sinon cela annulera vos annotations getter / setter
Anton Soradoi
15
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
Mikhail Batcer
1
Jackson-annotations 2.5 n'a pas la dernière fonctionnalité. Jackson-annotations 2.6.3 does
radiantRazor
98

Pour ce faire, il suffit de deux annotations:

  1. @JsonIgnore
  2. @JsonProperty

Utiliser @JsonIgnoresur le membre de classe et son getter, et @JsonPropertysur son setter. Un exemple d'illustration aiderait à faire ceci:

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
la source
2
c'est la seule chose qui a fonctionné pour moi avec jackson 2.6.4. J'ai fait de mon mieux pour utiliser @JsonProperty (access = Access.WRITE_ONLY) mais cela n'a pas fonctionné pour moi.
cirovladimir
77

Depuis la version 2.6: une manière plus intuitive est d'utiliser l' com.fasterxml.jackson.annotation.JsonPropertyannotation sur le terrain:

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

Même s'il existe un getter, la valeur du champ est exclue de la sérialisation.

JavaDoc dit:

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

Si vous en avez besoin dans l'autre sens, utilisez-le Access.READ_ONLY.

Daniel Beer
la source
1
Je ne comprends pas pourquoi il y a si peu de votes positifs, c'est une façon élégante de résoudre ce problème, ça marche comme un charme. Il n'est pas nécessaire d'annoter getter, setter et field. Seul champ. Merci.
CROSP
Ceci est disponible depuis la version 2.6, voir plus rapidexml.github.io/jackson-annotations/javadoc/2.6/com/…
Daniel Beer
Probablement la meilleure réponse pour les utilisateurs 2.6+.
David Dossot
Assurez-vous que vous n'utilisez pas l' importation org.codehaus.jackson.annotate . @ La solution de DanielBeer fonctionne pour Jackson 2.6.3. Cela devrait être la réponse acceptée maintenant que Jackson a été mis à jour.
Kent Bull
13

Dans mon cas, j'ai Jackson (dé) sérialise automatiquement les objets que je renvoie d'un contrôleur Spring MVC (j'utilise @RestController avec Spring 4.1.6). J'ai dû utiliser com.fasterxml.jackson.annotation.JsonIgnoreau lieu de org.codehaus.jackson.annotate.JsonIgnore, car sinon, cela n'a tout simplement rien fait.

Alex Beardsley
la source
1
c'est une réponse extrêmement utile qui m'a vraiment aidé à trouver la raison pour laquelle @JsonIgnore n'était pas honoré par Jackson ... merci!
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
la source
4
Il pourrait être utile à l'avenir de donner même une brève description du fonctionnement du code.
KWILLIAMS
D'accord !! Qu'essayez-vous ici? Obtenir plus de votes? lol
Balaji Boggaram Ramanarayan
0

Un autre moyen simple de gérer cela est d'utiliser l'argument allowSetters=truedans l'annotation. Cela permettra de désérialiser le mot de passe dans votre dto mais il ne le sérialisera pas dans un corps de réponse qui utilise contient un objet.

exemple:

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

Les deux fooet barsont remplis dans l'objet, mais seul foo est écrit dans un corps de réponse.

Dhandley
la source
C'était mon erreur, je ne savais pas que vous aviez déjà corrigé l'extrait. En regardant vos changements, il semble que mes années d'écriture dans Groovy m'ont eu et ma traduction en Java était un peu rude. Désolé!
Dhandley