Solo se usa @JsonIgnore durante la serialización, pero no la deserialización

325

Tengo un objeto de usuario que se envía desde y hacia el servidor. Cuando envío el objeto de usuario, no quiero enviar la contraseña cifrada al cliente. Por lo tanto, agregué @JsonIgnorela propiedad de contraseña, pero esto también impide que se deserialice en la contraseña, lo que dificulta el registro de usuarios cuando no tienen una contraseña.

¿Cómo puedo @JsonIgnoresolicitar la serialización y no la deserialización? Estoy usando Spring JSONView, así que no tengo mucho control sobre el ObjectMapper.

Cosas que he probado:

  1. Agregar @JsonIgnorea la propiedad
  2. Agregar @JsonIgnoresolo el método getter
chubbsondubs
fuente

Respuestas:

481

La forma exacta de hacerlo depende de la versión de Jackson que esté utilizando. Esto cambió alrededor de la versión 1.9 , antes de eso, podría hacerlo agregando @JsonIgnoreal getter.

Lo que has probado:

Agregue @JsonIgnore solo en el método getter

Haga esto y también agregue una @JsonPropertyanotación específica para su nombre de campo de "contraseña" JSON al método de establecimiento de la contraseña en su objeto.

Se han agregado versiones más recientes de Jackson READ_ONLYy WRITE_ONLYargumentos de anotación para JsonProperty. Entonces también podrías hacer algo como:

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

Los documentos se pueden encontrar aquí .

pb2q
fuente
2
gist.github.com/thurloat/2510887 para Jackson JSON ignorar solo en deserializar
Hadas
1
AFAIK todavía tiene que implementar el setter y anotarlo. Solo quiero el getter para la serialización. ¿De qué transitorio hablas? Esa es una anotación JPA AFAIK
Matt Broekhuis
3
Además, asegúrese de eliminar @JsonProperty del campo en sí mismo, de lo contrario anulará sus anotaciones getter / setter
Anton Soradoi
15
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
Mikhail Batcer
1
Jackson-annotations 2.5 no tiene la característica posterior. Jackson-anotaciones 2.6.3 hace
radiantRazor
98

Para lograr esto, todo lo que necesitamos son dos anotaciones:

  1. @JsonIgnore
  2. @JsonProperty

Úselo @JsonIgnoreen el miembro de la clase y su captador, y @JsonPropertyen su establecedor. Una ilustración de muestra ayudaría a hacer esto:

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
fuente
2
Es lo único que me funcionó con Jackson 2.6.4. Hice todo lo posible para usar @JsonProperty (access = Access.WRITE_ONLY) pero no funcionó para mí.
cirovladimir
77

Desde la versión 2.6: una forma más intuitiva es usar la com.fasterxml.jackson.annotation.JsonPropertyanotación en el campo:

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

Incluso si existe un captador, el valor del campo se excluye de la serialización.

JavaDoc dice:

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

En caso de que lo necesite al revés, simplemente utilícelo Access.READ_ONLY.

Daniel Beer
fuente
1
No entiendo por qué hay tan pocos votos a favor, esta es una forma elegante de resolver este problema, funciona de maravilla. No es necesario anotar getter, setter y field. Solo campo. Gracias.
CROSP
Está disponible desde la versión 2.6, vea más rápidoxml.github.io
Daniel Beer
Probablemente la mejor respuesta para más de 2.6 usuarios.
David Dossot
Asegúrese de no estar utilizando la importación org.codehaus.jackson.annotate . La solución de @ DanielBeer funciona para Jackson 2.6.3. Esta debería ser la respuesta aceptada ahora que Jackson ha sido actualizado.
Kent Bull
13

En mi caso, tengo Jackson automáticamente (des) serializando objetos que devuelvo de un controlador Spring MVC (estoy usando @RestController con Spring 4.1.6). Tuve que usar en com.fasterxml.jackson.annotation.JsonIgnorelugar de org.codehaus.jackson.annotate.JsonIgnore, de lo contrario, simplemente no hizo nada.

Alex Beardsley
fuente
1
Esta es una respuesta extremadamente útil que realmente me ayudó a encontrar la fuente de por qué Jackson no fue honrado por @JsonIgnore ... ¡gracias!
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
fuente
44
Podría ayudar en el futuro dar incluso una breve descripción de cómo funciona el código.
KWILLIAMS
Bien !! ¿Qué intentas aquí? ¿Conseguir más votos? lol
Balaji Boggaram Ramanarayan
0

Otra forma fácil de manejar esto es usar el argumento allowSetters=trueen la anotación. Esto permitirá que la contraseña se deserialice en su dto, pero no la serializará en un cuerpo de respuesta que use el objeto contiene.

ejemplo:

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

Ambos fooy barse rellenan en el objeto, pero solo foo se escribe en un cuerpo de respuesta.

Dhandley
fuente
Ese fue mi error, no me di cuenta de que ya había corregido el fragmento. Mirando sus cambios, parece que mis años de escritura en Groovy me sorprendieron y mi traducción a Java fue un poco difícil. ¡Lo siento!
Dhandley