Jackson ObjectMapper – 指定对象属性的序列化顺序

我正在实现一个RESTful Web服务,用户必须发送一个签名的validation令牌以及请求,这样我才能确保请求没有被中间人篡改。 我目前的实施情况如下。

validation令牌是VerifData对象,序列化为一个string,然后进行散列和encryption。

class VerifData { int prop1; int prop2; } 

在我的服务中,我将数据序列化为VerifData实例,然后使用Jackson ObjectMapper对其进行序列化,并与validation令牌一起传递给validation引擎。

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

但是似乎每次启动应用程序容器时,ObjectMapper映射到一个string的属性的顺序都会改变。

例如:有一次

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

还有一次呢

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

所以,如果客户端已经将VerifData实例序列化为第一个string,那么即使它是正确的,它也有50%的机会失败。

有没有办法解决这个问题? 我可以通过ObjectMapper指定要映射的属性的顺序吗(就像升序一样)? 或者还有其他的方式来最好地实施这个validation步骤。 客户端和服务器实现都是由我开发的。 我使用Java安全API进行签名和validation。

从文档:

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

http://fasterxml.github.io/jackson-annotations/javadoc/2.3.0/com/fasterxml/jackson/annotation/JsonPropertyOrder.html

注释是有用的,但可能是一个无处不在的痛苦。 你可以configuration你的整个ObjectMapper以这种方式工作

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

在Spring Boot中,您可以通过将以下内容添加到Application入口点类来全局添加此行为:

  @Bean public Jackson2ObjectMapperBuilder objectMapperBuilder() { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.featuresToEnable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY); return builder; } 

在Spring Boot中有一个简单的方法,通过指定一个属性(例如在application.properties中:

 spring.jackson.mapper.sort_properties_alphabetically=true 

从邓肯麦格雷戈的答案:它更好地使用它是这样的:

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

因为MapperFeature是用于XML的,并且不需要jackson-databind …

在jackson2.x,你今天可能使用,使用:

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

如果你关心外观,你也可以考虑SerializationFeature.INDENT_OUTPUT

请注意,您必须序列化地图对象才能正确sorting。 例如,如果你序列化JsonNode (来自readTree ),那么将不会正确缩进。

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

结果是:

 { "hello" : { "cruel" : "world" } }