Jackson: Wie man eine Feldserialisierung verhindert

163

Ich habe eine Entitätsklasse mit einem Passwortfeld:

class User {
    private String password;

    //setter, getter..
}

Ich möchte, dass dieses Feld während der Serialisierung übersprungen wird. Aber es sollte immer noch in der Lage sein, zu deserialisieren. Dies ist erforderlich, damit der Client mir ein neues Passwort senden kann, aber das aktuelle nicht lesen kann.

Wie schaffe ich das mit Jackson?

Wochen
quelle
1
Sie möchten es nicht serialisieren, aber Sie möchten es deserialisieren können? Das ist unmöglich, würde ich sagen. Wenn Sie kein Cookie in eine Box legen, können Sie es nicht aus dieser Box abrufen.
Alexis Dufrenoy
1
@ Traroth: aber ich kann einen NEUEN Cookie setzen. Ich bin nur auf der Suche nach einer geeigneten Anmerkung, aber dies kann sicherlich von Hand erfolgen.
Wochen
8
Kurzer Kommentar: Technisch gesehen ist es durchaus möglich, einen Setter zu verwenden (auch private werden automatisch erkannt) und den Accessor einfach wegzulassen (kein öffentliches Feld oder Getter). Es ist auch möglich, @JsonIgnoreGetter, aber @JsonPropertySetter hinzuzufügen. In diesem Fall werden die Dinge nicht serialisiert, sondern können deserialisiert werden.
StaxMan
4
Würde es Ihnen etwas ausmachen, eine Antwort auf diese Frage zu akzeptieren? (Einige Ihrer anderen sind ein paar Jahre alt und auch noch nicht akzeptiert ... Bitte beachten Sie die Bewertung!) :) Vollständige Offenlegung - Ich habe keine Antwort auf eine dieser Fragen.
Barett

Antworten:

187

Sie können es als markieren @JsonIgnore.

Mit 1.9 können Sie @JsonIgnorefür Getter, @JsonPropertyfür Setter hinzufügen , damit es deserialisiert, aber nicht serialisiert wird.

Biju Kunjummen
quelle
6
@JsonIgnore verhindert auch die Deserialisierung. Für vorübergehend - ich werde es überprüfen.
Wochen
98
Mit 1.9 können Sie @JsonIgnorefür Getter, @JsonPropertyfür Setter hinzufügen , damit es deserialisiert, aber nicht serialisiert wird.
StaxMan
StaxMans Kommentar sollte die Antwort sein, nicht wahr? Warum ist es dann immer noch ein Kommentar ...! ..?
Saravanabalagi Ramachandran
transient scheint bei mir nicht zu funktionieren, ich habe das Feld "transient" markiert, damit es nicht serilisiert / deserialisiert wird.
Rohith
Diese zuvor vorgeschlagene Antwort verwendet transient(wie in private transient String password;), aber vorübergehende Felder mit öffentlichen Gettern werden ignoriert, sofern MapperFeature.PROPAGATE_TRANSIENT_MARKER nicht aktiviert ist.
Tom
96

Dies funktioniert für mich, um zu veranschaulichen, was StaxMan gesagt hat

private String password;

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

@JsonProperty
public void setPassword(String password) {
    this.password = password;
}
Gary
quelle
12
Welche Json-Abhängigkeit verwenden Sie? Dies funktioniert nicht mit com.fasterxml.jackson
Alexander Burakevych
3
Vielen Dank! @JsonIgnoreist auf dem Feld nicht notwendig, wie es scheint.
Ferran Maylinch
com.fasterxml.jackson.annotation.JsonIgnore von jackson-annotations- <version> .jar
mvmn
Ich habe es versucht und es funktioniert nicht für mich. Ich benutze v2.8. Irgendeine Hilfe?
Maz
36

Der einfache Weg ist, Ihre Getter und Setter mit Anmerkungen zu versehen.

Hier ist das ursprüngliche Beispiel, das geändert wurde, um das Nur-Text-Kennwort auszuschließen, aber dann eine neue Methode mit Anmerkungen zu versehen, die nur das Kennwortfeld als verschlüsselten Text zurückgibt.

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
quelle
21

Ab Jackson 2.6 kann eine Eigenschaft als schreibgeschützt oder schreibgeschützt markiert werden. Es ist einfacher als das Hacken der Anmerkungen auf beiden Accessoren und bewahrt alle Informationen an einem Ort auf:

public class User {
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private String password;
}
Frank Pavageau
quelle
Dies ist eine großartige Lösung, einfach und funktionierend. Vielen Dank.
Dhqvinh
17

Abgesehen davon @JsonIgnoregibt es noch einige andere Möglichkeiten:

  • Verwenden Sie JSON-Ansichten , um Felder bedingt herauszufiltern (standardmäßig nicht für die Deserialisierung verwendet; in 2.0 ist verfügbar, Sie können jedoch eine andere Ansicht für die Serialisierung und Deserialisierung verwenden).
  • @JsonIgnoreProperties auf Klasse kann nützlich sein
StaxMan
quelle
10

transientist die Lösung für mich. Vielen Dank! Es ist in Java integriert und verhindert, dass Sie eine weitere Framework-spezifische Anmerkung hinzufügen.

maxxyme
quelle
2
Das funktioniert, wenn Ihr Attribut wirklich vorübergehend ist und beispielsweise kein ORM beteiligt ist. @JsonIgnore war in meinem Fall interessanter, obwohl ich an Jackson gebunden wäre, aber es ist ein guter Kompromiss
Joao Pereira,
3
Sie müssen nicht an Jackson gebunden sein, wenn Sie Ihre eigene Anmerkung erstellen und diese von JsonIgnore und JacksonAnnotationsInside kommentieren lassen. Auf diese Weise müssen Sie beim Ändern von Serialisierern nur Ihre eigenen Anmerkungen ändern.
DavidA
4

Man sollte sich fragen, warum Sie eine öffentliche Getter-Methode für das Passwort wünschen. Der Ruhezustand oder ein anderes ORM-Framework funktioniert mit einer privaten Getter-Methode. Um zu überprüfen, ob das Passwort korrekt ist, können Sie verwenden

public boolean checkPassword(String password){
  return this.password.equals(anyHashingMethod(password));
}
Albert Waninge
quelle
Ich denke tatsächlich, dass dies der beste Weg ist, über die Lösung nachzudenken. Es ist sinnvoller, Dinge, die Sie benötigen, privat zu machen und sie vom Objekt selbst aus zu steuern.
Arcynum
2

Jackson hat eine Klasse namens SimpleBeanPropertyFilter, mit deren Hilfe Felder während der Serialisierung und Deserialisierung gefiltert werden können. nicht global. Ich denke, das wolltest du.

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

    //setter, getter..
}

Dann in Ihrem 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);

Dadurch wird verhindert, dass das passwordFeld serialisiert wird. Außerdem können Sie passwordFelder so wie sie sind deserialisieren . Stellen Sie einfach sicher, dass keine Filter auf das ObjectMapper-Objekt angewendet werden.

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

Variable setzen als

@JsonIgnore

Dadurch kann die Variable vom json serializer übersprungen werden

Pravin
quelle