Jackson: comment empêcher la sérialisation des champs

163

J'ai une classe d'entité avec un champ de mot de passe:

class User {
    private String password;

    //setter, getter..
}

Je veux que ce champ soit ignoré lors de la sérialisation. Mais il devrait toujours être en mesure de DEsérialiser. Ceci est nécessaire pour que le client puisse m'envoyer un nouveau mot de passe, mais ne puisse pas lire le mot de passe actuel.

Comment puis-je accomplir cela avec Jackson?

weekens
la source
1
Vous ne voulez pas le sérialiser, mais vous voulez pouvoir le désérialiser? C'est impossible, je dirais. Si vous ne mettez pas de cookie dans une boîte, vous ne pourrez pas le récupérer dans cette boîte.
Alexis Dufrenoy
1
@Traroth: mais je peux mettre un NOUVEAU cookie. Je cherche juste une annotation pratique, mais cela peut sûrement être fait à la main.
weekens
8
Petit commentaire: il est tout à fait possible, techniquement, d'avoir un setter qui est utilisé (même les privés sont auto-détectés), et d'omettre simplement l'accesseur (pas de champ public ni de getter). Il est également possible d'ajouter un @JsonIgnoregetter, mais un @JsonPropertysetter, auquel cas les choses ne sont pas sérialisées, mais peuvent être désérialisées.
StaxMan
4
Accepteriez-vous une réponse à cette question? (Quelques-uns de vos autres ont quelques années et n'ont toujours pas été acceptés aussi ... S'il vous plaît envisager de revoir!) :) Divulgation complète - Je n'ai pas de réponses sur aucune de ces questions.
Barett

Réponses:

187

Vous pouvez le marquer comme @JsonIgnore.

Avec 1.9, vous pouvez ajouter @JsonIgnorepour getter, @JsonPropertypour setter, pour le désérialiser mais pas le sérialiser.

Biju Kunjummen
la source
6
@JsonIgnore empêche également la désérialisation. Pour transitoire - je vais vérifier.
weekens
98
Avec 1.9, vous pouvez ajouter @JsonIgnorepour getter, @JsonPropertypour setter, pour le désérialiser mais pas le sérialiser.
StaxMan
Le commentaire de StaxMan devrait être la réponse, n'est-ce pas? Pourquoi est-ce encore un commentaire alors ...! ..?
Saravanabalagi Ramachandran
transitoire ne semble pas fonctionner pour moi, j'ai marqué le champ "transitoire" que je ne veux pas qu'il soit sérilisé / désérialisé.
rohith
Cette réponse suggérait précédemment d'utiliser transient(comme dans private transient String password;), mais les champs transitoires avec des getters publics sont ignorés sauf si MapperFeature.PROPAGATE_TRANSIENT_MARKER est activé.
tom
96

Illustrant ce que StaxMan a déclaré, cela fonctionne pour moi

private String password;

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

@JsonProperty
public void setPassword(String password) {
    this.password = password;
}
Gary
la source
12
Quelle dépendance Json utilisez-vous? Cela ne fonctionne pas avec com.fasterxml.jackson
Alexander Burakevych
3
Merci! @JsonIgnoren'est pas nécessaire sur le terrain, semble-t-il.
Ferran Maylinch
com.fasterxml.jackson.annotation.JsonIgnore de jackson-annotations- <version> .jar
mvmn
J'ai essayé cela et cela ne fonctionne pas pour moi. J'utilise la v2.8. De l'aide?
Maz
36

Le moyen le plus simple est d'annoter vos getters et setters.

Voici l'exemple original modifié pour exclure le mot de passe en texte brut, mais annoter une nouvelle méthode qui renvoie simplement le champ de mot de passe sous forme de texte chiffré.

class User {

    private String password;

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

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

    @JsonProperty("password")
    public String getEncryptedPassword() {
        // encryption logic
    }
}
Joe Allen
la source
21

À partir de Jackson 2.6 , une propriété peut être marquée en lecture ou en écriture seule. C'est plus simple que de pirater les annotations sur les deux accesseurs et de conserver toutes les informations au même endroit:

public class User {
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private String password;
}
Frank Pavageau
la source
C'est une solution géniale, simple et fonctionnelle. Merci.
dhqvinh
17

En plus @JsonIgnore, il y a quelques autres possibilités:

  • Utilisez les vues JSON pour filtrer les champs de manière conditionnelle (par défaut, non utilisé pour la désérialisation; dans 2.0 sera disponible mais vous pouvez utiliser une vue différente sur la sérialisation, la désérialisation)
  • @JsonIgnoreProperties en classe peut être utile
StaxMan
la source
10

transientest la solution pour moi. Merci! il est natif de Java et vous évite d'ajouter une autre annotation spécifique au framework.

maxxyme
la source
2
Cela fonctionne si votre attribut est vraiment transitoire, pas ORM impliqué, par exemple .... J'ai trouvé que @JsonIgnore était plus intéressant dans mon cas, même si je serais bloqué sur jackson, mais c'est un bon compromis
Joao Pereira
3
Vous n'avez pas besoin d'être verrouillé sur jackson si vous créez votre propre annotation et la faites annoter par JsonIgnore et JacksonAnnotationsInside. De cette façon, si vous modifiez les sérialiseurs, vous n'avez qu'à changer votre propre annotation.
DavidA
4

On devrait se demander pourquoi vous voudriez une méthode publique getter pour le mot de passe. Hibernate, ou tout autre framework ORM, fera l'affaire avec une méthode getter privée. Pour vérifier si le mot de passe est correct, vous pouvez utiliser

public boolean checkPassword(String password){
  return this.password.equals(anyHashingMethod(password));
}
Albert Waninge
la source
Je pense en fait que c'est la meilleure façon de penser à la solution. Il est plus logique de rendre les choses dont vous avez besoin privées et de les contrôler à partir de l'objet lui-même.
arcynum
2

Jackson a une classe nommée SimpleBeanPropertyFilter qui permet de filtrer les champs pendant la sérialisation et la désérialisation; pas globalement. Je pense que c'est ce que tu voulais.

@JsonFilter("custom_serializer")
class User {
    private String password;

    //setter, getter..
}

Puis dans votre code:

String[] fieldsToSkip = new String[] { "password" };

ObjectMapper mapper = new ObjectMapper();

final SimpleFilterProvider filter = new SimpleFilterProvider();
filter.addFilter("custom_serializer",
            SimpleBeanPropertyFilter.serializeAllExcept(fieldsToSkip));

mapper.setFilters(filter);

String jsonStr = mapper.writeValueAsString(currentUser);

Cela empêchera le passwordchamp d'être sérialisé. Vous pourrez également désérialiser les passwordchamps tels quels . Assurez-vous simplement qu'aucun filtre n'est appliqué sur l'objet ObjectMapper.

ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(yourJsonStr, User.class);    // user object does have non-null password field
krhitesh
la source
0

définir la variable comme

@JsonIgnore

Cela permet à la variable d'être ignorée par le sérialiseur json

Pravin
la source