web-dev-qa-db-fra.com

Jackson ObjectMapper - spécifie l'ordre de sérialisation des propriétés de l'objet

J'implémente un service Web RESTful dans lequel l'utilisateur doit envoyer un jeton de vérification signé avec la demande afin que je puisse m'assurer que la demande n'a pas été falsifiée par un intermédiaire. Ma mise en œuvre actuelle est la suivante.

Le jeton de vérification est un objet VerifData sérialisé dans une chaîne, puis haché et chiffré.

class VerifData {
    int prop1;
    int prop2;
}

Dans mon service, j'ai mis les données à sérialiser dans une instance de VerifData, puis à les sérialiser à l'aide de Jackson ObjectMapper et à les transmettre au moteur de vérification avec le jeton de vérification.

VerfiData verifData = new VerifData(12345, 67890);
ObjectMapper mapper = new ObjectMapper();
String verifCodeGenerated = mapper.writeValueAsString(verifData);

Mais il semble qu'à chaque démarrage du conteneur d'applications, l'ordre des propriétés mappées dans une chaîne par ObjectMapper change.

Ex: une fois ce serait

{"prop1":12345,"prop2":67890}

et une autre fois ce serait

{"prop2":67890,"prop1":12345}

Ainsi, si le client a sérialisé l'instance VerifData dans la première chaîne, il y a 50% de chances que cela échoue, même si c'est correct.

Y a-t-il un moyen de contourner ceci? Puis-je spécifier l'ordre des propriétés à mapper par ObjectMapper (comme dans l'ordre croissant)? Ou existe-t-il un autre moyen de mettre en œuvre au mieux cette étape de vérification? Les implémentations client et serveur sont développées par moi. J'utilise Java API de sécurité pour signer et vérifier.

62
Lihini

De la documentation de Jackson Annotations :

// ensure that "id" and "name" are output before other properties
@JsonPropertyOrder({ "id", "name" })

// order any properties that don't have explicit setting using alphabetic order
@JsonPropertyOrder(alphabetic=true)
64
wgitscht

Les annotations sont utiles, mais peuvent être difficiles à appliquer partout. Vous pouvez configurer l’ensemble de votre ObjectMapper pour fonctionner de cette façon avec

Versions actuelles de Jackson: objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)

Anciennes versions de Jackson: objectMapper.configure(SerializationConfig.Feature.SORT_PROPERTIES_ALPHABETICALLY, true);

69
Duncan McGregor

Dans Spring Boot, vous pouvez ajouter ce comportement globalement en ajoutant ce qui suit à votre classe de point d'entrée Application:

  @Bean
  public Jackson2ObjectMapperBuilder objectMapperBuilder() {

    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.featuresToEnable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);

    return builder;
  }
9
Gary Rowe

Il existe un moyen plus simple dans Spring Boot en spécifiant une propriété (dans application.properties par exemple:

spring.jackson.mapper.sort_properties_alphabetically=true
8
Wim Deblauwe

Dans Jackson 2.x, que vous utilisez probablement aujourd'hui, utilisez:

ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);

Si vous vous souciez des apparences, vous pouvez également considérer SerializationFeature.INDENT_OUTPUT.

Notez que vous devez sérialiser Maps ou Objects pour que ce tri soit correct. Si vous sérialisez un JsonNode par exemple (à partir de readTree), cela ne sera pas correctement mis en retrait.

Exemple

import com.fasterxml.jackson.databind.*;

ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);

String input = "{\"hello\": {\"cruel\" : \"world\"} }";
Object pojo = mapper.readValue(input, Object.class);
System.out.println(mapper.writeValueAsString(pojo));

résulte en:

{
  "hello" : {
    "cruel" : "world"
  }
}
3
user2089674

De la réponse de Duncan McGregor: Il est préférable de l'utiliser comme ceci:

objectMapper.configure(SerializationConfig.Feature.SORT_PROPERTIES_ALPHABETICALLY, true);

comme MapperFeature est pour les XML et est livré avec jackson-databind qui n'est pas requis ...

3
Nemes Nisano

Au lieu d'utiliser l'argument flag:

objectMapper.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);
0
Leon