Verwenden Sie @JsonIgnore nur während der Serialisierung, nicht jedoch während der Deserialisierung

324

Ich habe ein Benutzerobjekt, das zum und vom Server gesendet wird. Wenn ich das Benutzerobjekt versende, möchte ich das Hash-Passwort nicht an den Client senden. Also habe ich @JsonIgnoredie Kennworteigenschaft hinzugefügt , aber dies verhindert auch, dass sie in das Kennwort deserialisiert wird, was es schwierig macht, Benutzer anzumelden, wenn sie kein Kennwort haben.

Wie kann ich mich nur @JsonIgnorefür die Serialisierung und nicht für die Deserialisierung bewerben? Ich verwende Spring JSONView, daher habe ich nicht viel Kontrolle über das ObjectMapper.

Dinge, die ich versucht habe:

  1. @JsonIgnoreZur Eigenschaft hinzufügen
  2. Fügen Sie @JsonIgnorenur die Getter-Methode hinzu
Chubbsondubs
quelle

Antworten:

480

Wie dies genau zu tun ist, hängt von der Version von Jackson ab, die Sie verwenden. Dies hat sich um Version 1.9 geändert. Zuvor konnten Sie dies tun, indem Sie @JsonIgnoredem Getter hinzufügen .

Was du versucht hast:

Fügen Sie @JsonIgnore nur für die Getter-Methode hinzu

Führen Sie dies aus, und fügen @JsonPropertySie der Setter-Methode für das Kennwort für Ihr Objekt eine bestimmte Anmerkung für Ihren JSON-Feldnamen "Kennwort" hinzu.

Neuere Versionen von Jackson haben Argumente für hinzugefügt READ_ONLYund WRITE_ONLYkommentiert JsonProperty. Sie können also auch Folgendes tun:

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

Dokumente finden Sie hier .

pb2q
quelle
2
gist.github.com/thurloat/2510887 für Jackson JSON ignorieren auf deserialize nur
Hadas
1
AFAIK Sie müssen den Setter noch implementieren und mit Anmerkungen versehen. Ich möchte nur den Getter für die Serialisierung. Was ist der Übergang, von dem Sie sprechen? Das ist eine JPA-Anmerkung AFAIK
Matt Broekhuis
3
Stellen Sie außerdem sicher, dass Sie @JsonProperty aus dem Feld selbst entfernen, da sonst Ihre Getter / Setter-Anmerkungen außer Kraft gesetzt werden
Anton Soradoi
15
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
Mikhail Batcer
1
Jackson-Annotations 2.5 hat die spätere Funktion nicht. Jackson-Annotationen 2.6.3 tut
radiantRazor
98

Um dies zu erreichen, benötigen wir lediglich zwei Anmerkungen:

  1. @JsonIgnore
  2. @JsonProperty

Verwenden Sie @JsonIgnorefür das Klassenmitglied und seinen Getter sowie @JsonPropertyfür seinen Setter. Eine Beispielillustration würde dazu beitragen:

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
quelle
2
Es ist das einzige, was bei mir mit Jackson 2.6.4 funktioniert hat. Ich habe mein Bestes versucht, @JsonProperty (access = Access.WRITE_ONLY) zu verwenden, aber es hat bei mir nicht funktioniert.
Cirovladimir
76

Seit Version 2.6: Eine intuitivere Möglichkeit ist die Verwendung der com.fasterxml.jackson.annotation.JsonPropertyAnmerkung auf dem Feld:

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

Selbst wenn ein Getter vorhanden ist, wird der Feldwert von der Serialisierung ausgeschlossen.

JavaDoc sagt:

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

Wenn Sie es umgekehrt brauchen, verwenden Sie es einfach Access.READ_ONLY.

Daniel Beer
quelle
1
Ich verstehe nicht, warum es so wenige positive Stimmen gibt, dies ist eine elegante Art, dieses Problem zu lösen, die wie ein Zauber wirkt. Es ist nicht erforderlich, Getter, Setter und Feld mit Anmerkungen zu versehen. Einziges Feld. Vielen Dank.
CROSP
Dies ist seit Version 2.6 verfügbar, siehe schnellerxml.github.io/jackson-annotations/javadoc/2.6/com/…
Daniel Beer
Wahrscheinlich die beste Antwort für Benutzer ab 2.6.
David Dossot
Stellen Sie sicher, dass Sie den Import org.codehaus.jackson.annotate nicht verwenden . @ DanielBeers Lösung funktioniert für Jackson 2.6.3. Dies sollte die akzeptierte Antwort sein, nachdem Jackson aktualisiert wurde.
Kent Bull
13

In meinem Fall hat Jackson Objekte, die ich von einem Spring MVC-Controller zurückgebe, automatisch (de) serialisiert (ich verwende @RestController mit Spring 4.1.6). Ich musste verwenden, com.fasterxml.jackson.annotation.JsonIgnoreanstatt org.codehaus.jackson.annotate.JsonIgnore, wie sonst, es tat einfach nichts.

Alex Beardsley
quelle
1
Dies ist eine äußerst nützliche Antwort, die mir wirklich geholfen hat, die Quelle zu finden, warum @JsonIgnore von Jackson nicht geehrt wurde ... danke!
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
quelle
4
Es könnte in Zukunft hilfreich sein, auch nur eine kurze Beschreibung der Funktionsweise des Codes zu geben.
KWILLIAMS
In Ordung !! Was versuchst du hier? Mehr Stimmen bekommen? lol
Balaji Boggaram Ramanarayan
0

Eine andere einfache Möglichkeit, dies zu handhaben, besteht darin, das Argument allowSetters=truein der Anmerkung zu verwenden. Dadurch kann das Kennwort in Ihr dto deserialisiert werden, es wird jedoch nicht in einen Antworttext serialisiert, der ein enthaltenes Objekt verwendet.

Beispiel:

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

Beide foound barwerden im Objekt ausgefüllt, aber nur foo wird in einen Antworttext geschrieben.

Dhandley
quelle
Bearbeiten Sie Ihre Antwort mit dem Arbeitscode-Snippet.
dkb
Das war mein Fehler, ich wusste nicht, dass Sie das Snippet bereits korrigiert hatten. Wenn ich mir Ihre Änderungen ansehe, scheint es, dass mich meine Jahre des Schreibens in Groovy erwischt haben und meine Übersetzung nach Java etwas rau war. Es tut uns leid!
Dhandley