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

Lih*_*ini 64 java serialization json jackson

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

验证令牌是序列化为String的VerifData对象,然后进行散列和加密.

class VerifData {
    int prop1;
    int prop2;
}
Run Code Online (Sandbox Code Playgroud)

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

VerfiData verifData = new VerifData(12345, 67890);
ObjectMapper mapper = new ObjectMapper();
String verifCodeGenerated = mapper.writeValueAsString(verifData);
Run Code Online (Sandbox Code Playgroud)

但似乎每次启动应用程序容器时,ObjectMapper映射到字符串的属性顺序都会发生变化.

例如:有一次

{"prop1":12345,"prop2":67890}
Run Code Online (Sandbox Code Playgroud)

它将是另一次

{"prop2":67890,"prop1":12345}
Run Code Online (Sandbox Code Playgroud)

因此,如果客户端已将VerifData实例序列化为第一个String,则即使它是正确的,也有50%的可能性失败.

有办法解决这个问题吗?我可以通过ObjectMapper指定要映射的属性的顺序(如升序)吗?或者是否有其他方法可以最好地实施此验证步骤.客户端和服务器实现都是由我开发的.我使用Java Security API进行签名和验证.

Dun*_*gor 73

注释很有用,但在任何地方都可以使用.您可以将整个ObjectMapper配置为以这种方式工作

目前杰克逊版本: objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)

老杰克逊版本: objectMapper.configure(SerializationConfig.Feature.SORT_PROPERTIES_ALPHABETICALLY, true);

  • 在以后的版本中,您必须使用`.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY,true)` (20认同)
  • 这在2.7.4中不再起作用 (2认同)
  • 这并不完全正确(或者至少在所有情况下都不起作用)——请参阅 /sf/answers/3238725451/ 以获取有效的完整示例。 (2认同)
  • @ user2089674 - 您的示例仅适用于 Map 键。OP 要求为对象字段提供解决方案。 (2认同)

wgi*_*cht 68

来自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)
Run Code Online (Sandbox Code Playgroud)

  • 如下所述,如果您的目标是在所有位置应用排序,而不是在序列化特定对象时,请参见/sf/answers/3238725451/。 (2认同)

mag*_*ter 10

需要以下2 个ObjectMapper 配置:

ObjectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
或者
ObjectMapper.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)

定义用于POJO属性系列化顺序字段
:确实适用java.util.Map系列化!


ObjectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true)
或者
ObjectMapper.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)

确定java.util.Map条目在序列化之前是否首先按键排序的功能


Spring Boot 配置示例(yaml):

spring:
  jackson:
    mapper:
      SORT_PROPERTIES_ALPHABETICALLY: true
    serialization:
      ORDER_MAP_ENTRIES_BY_KEYS: true
Run Code Online (Sandbox Code Playgroud)


use*_*674 9

在您今天可能正在使用的 Jackson 2.x 中,使用:

ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
Run Code Online (Sandbox Code Playgroud)

如果你在意外观,你也可以考虑一下SerializationFeature.INDENT_OUTPUT

请注意,您必须序列化MapsObjects才能正确排序。JsonNode例如,如果您序列化 a (from 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));
Run Code Online (Sandbox Code Playgroud)

结果是:

{
  "hello" : {
    "cruel" : "world"
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 只有一个地图条目。因此我看不到它的顺序。 (6认同)

Gar*_*owe 8

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

  @Bean
  public Jackson2ObjectMapperBuilder objectMapperBuilder() {

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

    return builder;
  }
Run Code Online (Sandbox Code Playgroud)


Wim*_*uwe 8

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

spring.jackson.mapper.sort_properties_alphabetically=true
Run Code Online (Sandbox Code Playgroud)