Jackson: cómo prevenir la serialización de campo

163

Tengo una clase de entidad con un campo de contraseña:

class User {
    private String password;

    //setter, getter..
}

Quiero que este campo se omita durante la serialización. Pero aún debería ser capaz de DESserializar. Esto es necesario para que el cliente pueda enviarme una nueva contraseña, pero no pueda leer la actual.

¿Cómo logro esto con Jackson?

weekens
fuente
1
¿No quieres serializarlo, pero quieres poder deserializarlo? Eso es imposible, diría yo. Si no coloca una cookie en un cuadro, no podrá recuperarla de este cuadro.
Alexis Dufrenoy
1
@Traroth: pero puedo poner una NUEVA cookie. Solo estoy buscando una anotación conveniente, pero esto seguramente se puede hacer a mano.
Weekens
8
Comentario rápido: es completamente posible, técnicamente, tener un setter que se usa (incluso los privados se detectan automáticamente), y simplemente omitir el descriptor de acceso (sin campo público o getter). También es posible agregar @JsonIgnoreen getter, pero @JsonPropertyen setter, en cuyo caso las cosas no se serializan, pero se pueden deserializar.
StaxMan
44
¿Te importaría aceptar una respuesta a esta pregunta? (Algunos de sus otros tienen algunos años y todavía no son aceptados ... ¡Por favor considere la revisión!) :) Divulgación completa: no tengo respuestas sobre ninguna de estas preguntas.
Barett

Respuestas:

187

Puedes marcarlo como @JsonIgnore.

Con 1.9, puede agregar @JsonIgnorepara getter, @JsonPropertypara setter, para deserializar pero no serializar.

Biju Kunjummen
fuente
66
@JsonIgnore también evita la deserialización. Para transitorios, lo comprobaré.
Weekens
98
Con 1.9, puede agregar @JsonIgnorepara getter, @JsonPropertypara setter, para deserializar pero no serializar.
StaxMan
El comentario de StaxMan debería ser la respuesta, ¿no? ¿Por qué sigue siendo un comentario entonces ...? ..?
Saravanabalagi Ramachandran
transitorio no parece funcionar para mí, marqué el campo "transitorio" que no quiero que sea serilizado / deserializado.
Rohith
Esta respuesta sugería previamente usar transient(como en private transient String password;) pero los campos transitorios con captadores públicos se ignoran a menos que MapperFeature.PROPAGATE_TRANSIENT_MARKER esté habilitado.
tom
96

Ilustrando lo que StaxMan ha declarado, esto funciona para mí

private String password;

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

@JsonProperty
public void setPassword(String password) {
    this.password = password;
}
Gary
fuente
12
¿Qué dependencia de Json usas? Esto no funciona con com.fasterxml.jackson
Alexander Burakevych
3
¡Gracias! @JsonIgnoreNo es necesario en el campo, parece.
Ferran Maylinch
com.fasterxml.jackson.annotation.JsonIgnore de jackson-annotations- <versión> .jar
mvmn
He intentado esto y no me funciona. Yo uso v2.8. ¿Alguna ayuda?
Maz
36

La manera fácil es anotar sus captadores y establecedores.

Aquí está el ejemplo original modificado para excluir la contraseña de texto sin formato, pero luego anotar un nuevo método que solo devuelve el campo de contraseña como texto cifrado.

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

A partir de Jackson 2.6 , una propiedad se puede marcar como de solo lectura o escritura. Es más simple que hackear las anotaciones en ambos accesos y mantiene toda la información en un solo lugar:

public class User {
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private String password;
}
Frank Pavageau
fuente
Esta es una solución increíble, simple, funcional. Gracias.
dhqvinh
17

Aparte de @JsonIgnore, hay un par de otras posibilidades:

  • Use las Vistas JSON para filtrar los campos condicionalmente (de forma predeterminada, no se usa para la deserialización; en 2.0 estará disponible, pero puede usar una vista diferente en la serialización, deserialización)
  • @JsonIgnoreProperties en clase puede ser útil
StaxMan
fuente
10

transientEs la solución para mí. ¡Gracias! es nativo de Java y evita que agregue otra anotación específica del marco.

maxxyme
fuente
2
Eso funciona si su atributo es realmente transitorio, no involucra ORM, por ejemplo ... Descubrí que @JsonIgnore es más interesante en mi caso, aunque estaría encerrado en Jackson, pero es una buena compensación
Joao Pereira
3
No tiene que estar bloqueado para Jackson si crea su propia anotación y JsonIgnore y JacksonAnnotationsInside la anotan. De esa manera, si cambia los serializadores, solo tiene que cambiar su propia anotación.
DavidA
4

Debería preguntarse por qué querría un método de obtención público para la contraseña. Hibernate, o cualquier otro marco ORM, funcionará con un método getter privado. Para verificar si la contraseña es correcta, puede usar

public boolean checkPassword(String password){
  return this.password.equals(anyHashingMethod(password));
}
Albert Waninge
fuente
De hecho, creo que esta es la mejor manera de pensar en la solución. Tiene más sentido hacer que las cosas que necesita sean privadas y controlarlas desde el objeto mismo.
arcynum
2

Jackson tiene una clase llamada SimpleBeanPropertyFilter que ayuda a filtrar campos durante la serialización y deserialización; No globalmente. Creo que eso es lo que querías.

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

    //setter, getter..
}

Luego en tu código:

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

Esto evitará que el passwordcampo se serialice. También podrá deserializar los passwordcampos tal como están. Solo asegúrese de que no se apliquen filtros en el objeto ObjectMapper.

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

establecer variable como

@JsonIgnore

Esto permite que json serializer omita la variable

Pravin
fuente