Używaj @JsonIgnore tylko podczas serializacji, ale nie deserializacji

325

Mam obiekt użytkownika, który jest wysyłany do i z serwera. Kiedy wysyłam obiekt użytkownika, nie chcę wysyłać zaszyfrowanego hasła do klienta. Dodałem @JsonIgnorewięc właściwość hasła, ale to również blokuje możliwość przekształcenia go w hasło, które utrudnia rejestrację użytkowników, którzy nie mają hasła.

Jak mogę @JsonIgnorezastosować tylko do serializacji, a nie deserializacji? Korzystam z Spring JSONView, więc nie mam żadnej kontroli nad ObjectMapper.

Rzeczy, których próbowałem:

  1. Dodaj @JsonIgnoredo nieruchomości
  2. Dodaj @JsonIgnoretylko metodę gettera
chubbsondubs
źródło

Odpowiedzi:

481

Dokładnie, jak to zrobić, zależy od używanej wersji Jacksona. Zmieniło się to w stosunku do wersji 1.9 , wcześniej można było to zrobić, dodając @JsonIgnoredo programu pobierającego.

Które próbowałeś:

Dodaj @JsonIgnore tylko do metody pobierającej

Zrób to, a także dodaj specjalną @JsonPropertyadnotację do nazwy pola „hasło” JSON do metody ustawiającej hasło do obiektu.

Dodano nowsze wersje Jacksona READ_ONLYi WRITE_ONLYargumenty adnotacji JsonProperty. Możesz też zrobić coś takiego:

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

Dokumenty można znaleźć tutaj .

pb2q
źródło
2
gist.github.com/thurloat/2510887 dla Jackson JSON ignoruje tylko deserializuj
Hadas
1
AFAIK nadal musisz zaimplementować seter i opatrzyć go adnotacjami. Chcę tylko gettera do serializacji. O czym mówisz o przemijaniu? To adnotacja JPA AFAIK
Matt Broekhuis,
3
Pamiętaj też, aby usunąć @JsonProperty z samego pola, w przeciwnym razie zastąpi on adnotacje pobierające / ustawiające
Anton Soradoi
15
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
Michaił Batcer
1
Adnotacje Jacksona 2.5 nie mają późniejszej funkcji. Adnotacje Jacksona 2.6.3 robi
radiantRazor
98

Aby to osiągnąć, potrzebujemy tylko dwóch adnotacji:

  1. @JsonIgnore
  2. @JsonProperty

Użyj @JsonIgnorena członku klasy i jego narzędziu pobierającym oraz @JsonPropertyna jego ustawniku. Pomoże w tym przykładowa ilustracja:

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
źródło
2
to jedyna rzecz, która działała dla mnie z Jacksonem 2.6.4. Starałem się jak najlepiej użyć @JsonProperty (access = Access.WRITE_ONLY), ale to nie działało dla mnie.
cirovladimir
77

Od wersji 2.6: bardziej intuicyjnym sposobem jest użycie com.fasterxml.jackson.annotation.JsonPropertyadnotacji na polu:

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

Nawet jeśli istnieje moduł pobierający, wartość pola jest wykluczana z serializacji.

JavaDoc mówi:

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

Jeśli potrzebujesz go na odwrót, po prostu użyj Access.READ_ONLY.

Daniel Beer
źródło
1
Nie rozumiem, dlaczego jest tak mało pozytywnych opinii, jest to elegancki sposób rozwiązania tego problemu, działa jak urok. Nie ma potrzeby komentowania gettera, setera i pola. Tylko pole. Dzięki.
CROSP
Jest to dostępne od wersji 2.6, patrz szybciejxml.github.io/jackson-annotations/javadoc/2.6/com/…
Daniel Beer
Prawdopodobnie najlepsza odpowiedź dla użytkowników w wersji 2.6+.
David Dossot,
Upewnij się, że nie korzystasz z importu org.codehaus.jackson.annotate . @ Rozwiązanie DanielBeer działa dla Jackson 2.6.3. To powinna być zaakceptowana odpowiedź teraz, gdy Jackson został zaktualizowany.
Kent Bull
13

W moim przypadku Jackson automatycznie (od) serializuje obiekty, które zwracam ze sterownika Spring MVC (używam @RestController ze Spring 4.1.6). Musiałem użyć com.fasterxml.jackson.annotation.JsonIgnorezamiast org.codehaus.jackson.annotate.JsonIgnore, bo inaczej po prostu nic nie zrobiłem.

Alex Beardsley
źródło
1
jest to niezwykle przydatna odpowiedź, która naprawdę pomogła mi znaleźć źródło, dlaczego Jackson nie docenił @JsonIgnore ... dzięki!
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
źródło
4
W przyszłości pomocne może być podanie nawet krótkiego opisu działania kodu.
KWILLIAMS,
W porządku !! Czego tu próbujesz? Otrzymujesz więcej głosów? lol
Balaji Boggaram Ramanarayan
0

Innym łatwym sposobem na poradzenie sobie z tym jest użycie argumentu allowSetters=true w adnotacji. Umożliwi to przekształcenie hasła do postaci szeregowej w dto, ale nie przekształci go w postać odpowiedzi, która używa obiektu.

przykład:

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

Zarówno fooi barsą wypełniane w obiekcie, ale tylko foo jest napisane w organizmie reakcji.

Dhandley
źródło
To był mój błąd, nie zdawałem sobie sprawy, że już poprawiłeś fragment kodu. Patrząc na twoje zmiany, wydaje mi się, że moje lata pisania w Groovy mnie wciągnęły, a moje tłumaczenie na Javę było trochę trudne. Przepraszam!
Dhandley,