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

时间:2014-12-20 06:32:36

标签: java json serialization jackson

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

Verification令牌是一个VerifData对象,序列化为String,然后进行散列和加密。

class VerifData {
    int prop1;
    int prop2;
}

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

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

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

Ex:有一次会是

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

另一次是

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

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

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

11 个答案:

答案 0 :(得分:65)

注释很有用,但在任何地方都可以使用。您可以使用

配置整个ObjectMapper以这种方式工作

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

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

答案 1 :(得分:61)

来自Jackson Annotations documentation

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

答案 2 :(得分:9)

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

  @Bean
  public Jackson2ObjectMapperBuilder objectMapperBuilder() {

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

    return builder;
  }

答案 3 :(得分:8)

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

spring.jackson.mapper.sort_properties_alphabetically=true

答案 4 :(得分:7)

需要以下 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

答案 5 :(得分:4)

来自Duncan McGregor的回答: 最好像这样使用它:

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

MapperFeature用于XML,并附带jackson-databind,这不是必需的......

答案 6 :(得分:2)

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

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

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

请注意,您必须序列化地图对象才能正确排序。如果您序列化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"
  }
}

答案 7 :(得分:1)

我今天发现了另一种方法,以防字母不是您想要的排序顺序。事实证明,如果其余字段未注释,则在字段上添加 @JsonProperty 注释会在写入时将其放在最后。我发现当我想指定一个不符合java命名约定的属性名称时。

通过添加索引属性,您可以定义顺序。最低的索引放在最前面。

@JsonProperty(index=20)
String prop1;

@JsonProperty(index=10)
String prop2;

将呈现:

{"prop2": "valueProp2", "prop1": "valueProp1"}

答案 8 :(得分:0)

代替使用flag参数:

objectMapper.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);

答案 9 :(得分:0)

您可以使用混入并根据需要指定属性的顺序:

import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public final class ObjectMapperUtils {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    static {
        MAPPER.addMixIn(Object.class, IdFirst.class);
    }

    @Bean
    public ObjectMapper objectMapper() {
        return MAPPER;
    }

    @JsonPropertyOrder({"id", "...", "..."})
    private abstract static class IdFirst {}

}

答案 10 :(得分:0)

我意识到这是一个老话题,但是由于我一直在寻找或回答并着陆于此,因此一些其他信息可能对其他人很方便。
我当前正在使用的@JsonProperty批注(jackson-annotations-2.11.2)接受“ value”参数之外的“ index”(数字)参数,该参数指定序列化期间字段的顺序。