Jackson: jak zapobiec serializacji pola

163

Mam klasę encji z polem hasła:

class User {
    private String password;

    //setter, getter..
}

Chcę, aby to pole zostało pominięte podczas serializacji. Ale nadal powinien być w stanie DEserialize. Jest to potrzebne, aby klient mógł wysłać mi nowe hasło, ale nie może odczytać obecnego.

Jak mam to osiągnąć z Jacksonem?

Weekens
źródło
1
Nie chcesz go serializować, ale chcesz mieć możliwość deserializacji? Powiedziałbym, że to niemożliwe. Jeśli nie umieścisz pliku cookie w pudełku, nie będziesz mógł go odzyskać z tego pudełka.
Alexis Dufrenoy
1
@Traroth: ale mogę umieścić NOWE ciasteczko. Szukam tylko wygodnej adnotacji, ale z pewnością można to zrobić ręcznie.
weekens
8
Krótki komentarz: technicznie jest całkowicie możliwe, aby używać setera (nawet prywatne są wykrywane automatycznie) i po prostu pominąć akcesor (brak pola publicznego lub gettera). Możliwe jest również dodanie @JsonIgnoregettera, ale @JsonPropertysettera, w którym to przypadku rzeczy nie są serializowane, ale mogą być deserializowane.
StaxMan
4
Czy mógłbyś przyjąć odpowiedź na to pytanie? (Kilka innych ma kilka lat i nadal nie zostało zaakceptowanych ... Proszę rozważyć recenzję!) :) Pełne ujawnienie - nie mam odpowiedzi na żadne z tych pytań.
Barett

Odpowiedzi:

187

Możesz oznaczyć to jako @JsonIgnore.

W wersji 1.9 możesz dodać @JsonIgnoredla getter, @JsonPropertydla setter, aby deserializował, ale nie serializował.

Biju Kunjummen
źródło
6
@JsonIgnore zapobiega również deserializacji. Na razie - sprawdzę to.
weekens
98
W wersji 1.9 możesz dodać @JsonIgnoredla getter, @JsonPropertydla setter, aby deserializował, ale nie serializował.
StaxMan
Komentarz StaxMan powinien być odpowiedzią, prawda? Dlaczego więc nadal jest to komentarz ...! ..?
Saravanabalagi Ramachandran
przejściowy nie wydaje się działać dla mnie, zaznaczyłem pole „przejściowe”, że nie chcę, aby było ono poddawane serilizacji / deserializacji.
rohith
Ta odpowiedź wcześniej sugerowała użycie transient(jak w private transient String password;), ale przejściowe pola z publicznymi pobierającymi są ignorowane, chyba że MapperFeature.PROPAGATE_TRANSIENT_MARKER jest włączony.
tom
96

Ilustrując to, co powiedział StaxMan, działa to dla mnie

private String password;

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

@JsonProperty
public void setPassword(String password) {
    this.password = password;
}
Gary
źródło
12
Której zależności Json używasz? To nie działa z com.fasterxml.jackson
Alexander Burakevych
3
Dzięki! @JsonIgnorewydaje się, że na boisku nie jest konieczne.
Ferran Maylinch
com.fasterxml.jackson.annotation.JsonIgnore from jackson-annotations- <wersja> .jar
mvmn
Próbowałem tego i nie działa dla mnie. Używam v2.8. Jakaś pomoc?
Maz,
36

Najłatwiejszym sposobem jest dodanie adnotacji do metod pobierających i ustawiających.

Oto oryginalny przykład zmodyfikowany w celu wykluczenia hasła w postaci zwykłego tekstu, ale następnie dodaj adnotację do nowej metody, która po prostu zwraca pole hasła jako zaszyfrowany tekst.

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
źródło
21

Począwszy od Jacksona 2.6 , właściwość może być oznaczona jako tylko do odczytu lub do zapisu. Jest to prostsze niż hakowanie adnotacji w obu akcesoriach i utrzymuje wszystkie informacje w jednym miejscu:

public class User {
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private String password;
}
Frank Pavageau
źródło
To niesamowite rozwiązanie, proste, działające. Dzięki.
dhqvinh
17

Oprócz tego @JsonIgnoreistnieje kilka innych możliwości:

  • Użyj widoków JSON, aby odfiltrować pola warunkowo (domyślnie nie jest używany do deserializacji; w wersji 2.0 będzie dostępny, ale możesz użyć innego widoku podczas serializacji, deserializacji)
  • @JsonIgnoreProperties na zajęciach może być przydatne
StaxMan
źródło
10

transientjest rozwiązaniem dla mnie. dzięki! jest natywny dla języka Java i pozwala uniknąć dodawania kolejnej adnotacji specyficznej dla platformy.

maxxyme
źródło
2
To działa, jeśli twój atrybut jest naprawdę przejściowy, na przykład nie dotyczy ORM ... Znaleziony @JsonI Ignoruj, aby był bardziej interesujący w moim przypadku, chociaż byłbym zamknięty w Jacksonie, ale to dobry kompromis
Joao Pereira
3
Nie musisz ograniczać się do jacksona, jeśli tworzysz własną adnotację i masz ją opatrzoną adnotacjami JsonIgnore i JacksonAnnotationsInside. W ten sposób, jeśli zmienisz serializatory, wystarczy zmienić własną adnotację.
DavidA
4

Należy zapytać, dlaczego chcesz mieć publiczną metodę pobierania hasła. Hibernate lub jakikolwiek inny framework ORM zrobi z prywatną metodą pobierającą. Aby sprawdzić, czy hasło jest poprawne, możesz użyć

public boolean checkPassword(String password){
  return this.password.equals(anyHashingMethod(password));
}
Albert Waninge
źródło
Właściwie uważam, że to najlepszy sposób myślenia o rozwiązaniu. Bardziej sensowne jest oznaczanie potrzebnych rzeczy jako prywatne i kontrolowanie ich z poziomu samego obiektu.
arcynum
2

Jackson ma klasę o nazwie SimpleBeanPropertyFilter, która pomaga filtrować pola podczas serializacji i deserializacji; nie globalnie. Myślę, że tego chciałeś.

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

    //setter, getter..
}

Następnie w swoim kodzie:

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);

Zapobiegnie passwordto serializacji pola. Będziesz także mógł deserializować passwordpola w obecnej postaci. Upewnij się tylko, że na obiekcie ObjectMapper nie zastosowano żadnych filtrów.

ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(yourJsonStr, User.class);    // user object does have non-null password field
krhitesh
źródło
0

ustaw zmienną jako

@JsonIgnore

Dzięki temu zmienna może zostać pominięta przez serializator json

Pravin
źródło