简体   繁体   English

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

[英]Jackson ObjectMapper - specify serialization order of object properties

I'm implementing a RESTful web service where user has to send a signed verification token along with the request so that I could ensure that the request has not been tampered by a middle man.我正在实现一个 RESTful Web 服务,其中用户必须随请求一起发送签名验证令牌,以便我可以确保请求没有被中间人篡改。 My current implementation is as follows.我目前的实现如下。

Verification token is a VerifData object serialized into a String and then hashed and encrypted.验证令牌是一个 VerifData 对象序列化为一个字符串,然后散列和加密。

class VerifData {
    int prop1;
    int prop2;
}

In my service, I put data to be serialized into an instance of VerifData and then serialize it using Jackson ObjectMapper and passed along to the verification engine along with the verification token.在我的服务中,我将要序列化的数据放入 VerifData 的实例中,然后使用 Jackson ObjectMapper 对其进行序列化,并与验证令牌一起传递给验证引擎。

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

But it seems that each time the application container is started, the order of properties being mapped into a string by ObjectMapper changes.但是似乎每次启动应用程序容器时,ObjectMapper 将属性映射到字符串的顺序都会发生变化。

Ex: one time it would be例如:有一次是

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

and another time it would be还有一次是

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

So if client has serialized the VerifData instance as into the first String, there is 50% chance of it being failed even though it is correct.因此,如果客户端将 VerifData 实例序列化为第一个字符串,即使它是正确的,它也有 50% 的机会失败。

Is there a way to get around this?有没有办法解决这个问题? Can I specify the order of properties to map by ObjectMapper (like in ascending order)?我可以通过 ObjectMapper 指定要映射的属性的顺序(如升序)吗? Or is there any other way to best implement this verification step.或者有没有其他方法可以最好地实施此验证步骤。 Both client and server implementations are developed by me.客户端和服务器实现都是由我开发的。 I use Java Security API for signing and verifying.我使用 Java Security API 进行签名和验证。

The annotations are useful, but can be a pain to apply everywhere.注释很有用,但在任何地方应用可能会很痛苦。 You can configure your whole ObjectMapper to work this way with您可以将整个ObjectMapper配置为以这种方式使用

Current Jackson versions:当前的杰克逊版本:

objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)

Older Jackson versions:较旧的杰克逊版本:

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

From the 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)

In Spring Boot you can add this behaviour globally by adding the following to your Application entry point class:在 Spring Boot 中,您可以通过将以下内容添加到Application入口点类来全局添加此行为:

  @Bean
  public Jackson2ObjectMapperBuilder objectMapperBuilder() {

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

    return builder;
  }

The following 2 ObjectMapper configuration are required:需要以下2 个ObjectMapper 配置:

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

defines the property serialization order used for POJO fields定义用于 POJO 字段的属性序列化顺序
Note : does not apply to java.util.Map serialization!不适用于java.util.Map系列化!

and

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

Feature that determines whether java.util.Map entries are first sorted by key before serialization确定java.util.Map条目在序列化之前是否首先按键排序的功能


Spring Boot config example (yaml): Spring Boot 配置示例(yaml):

spring:
  jackson:
    mapper:
      SORT_PROPERTIES_ALPHABETICALLY: true
    serialization:
      ORDER_MAP_ENTRIES_BY_KEYS: true

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

spring.jackson.mapper.sort_properties_alphabetically=true

In Jackson 2.x, which you are probably using today, use:在您今天可能正在使用的 Jackson 2.x 中,使用:

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

If you care about looks, you may also consider SerializationFeature.INDENT_OUTPUT as well.如果您关心外观,您也可以考虑SerializationFeature.INDENT_OUTPUT

Note that you must serialize Maps or Objects for this to sort correctly.请注意,您必须序列化MapsObjects才能正确排序。 If you serialize a JsonNode for example (from readTree ), that won't be properly indented.例如,如果您序列化一个JsonNode (从readTree ),它将无法正确缩进。

Example例子

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

results in:结果是:

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

From Duncan McGregor's answer: Its better to use it like this:来自 Duncan McGregor 的回答:最好像这样使用它:

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

as MapperFeature is for XMLs and comes with jackson-databind which is not required...因为 MapperFeature 适用于 XML,并且带有不需要的 jackson-databind ...

I realize this is an old thread, but since I was looking or an answer and landed here, some additional info could be handy for other people.我意识到这是一个旧线程,但由于我正在寻找或回答并登陆这里,因此一些其他信息可能对其他人很方便。
The @JsonProperty annotation I am using currently (jackson-annotations-2.11.2) accepts, besides the "value" argument, an "index" (numeric) argument that specifies the order of the fields during serialization.我当前使用的 @JsonProperty 注释 (jackson-annotations-2.11.2) 除了“value”参数之外,还接受一个“index”(数字)参数,用于指定序列化期间字段的顺序。

I discovered yet another way today in case alphabetic is not your desired sorting order.我今天发现了另一种方法,以防字母不是您想要的排序顺序。 It turns out adding a @JsonProperty annotation on a field places it last when writing if the rest of the fields are not annotated.事实证明,如果其余字段未注释,则在字段上添加 @JsonProperty 注释会在写入时将其放在最后。 I discovered that when I wanted to specify a property name which did not conform to java naming conventions.我发现当我想指定一个不符合 java 命名约定的属性名称时。

By Adding an index attribute you can define the order.通过添加索引属性,您可以定义顺序。 Lowest index is placed first.最低的索引放在最前面。

@JsonProperty(index=20)
String prop1;

@JsonProperty(index=10)
String prop2;

Would render:将呈现:

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

而不是使用标志参数:

objectMapper.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);

You can use mix-in and specify the order of properties as you like:您可以使用 mix-in 并根据需要指定属性的顺序:

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 {}

}

As @Gary Rowe mentioned, we can use Jackson2ObjectMapperBuilder to sort the properties globally.正如@Gary Rowe 提到的,我们可以使用 Jackson2ObjectMapperBuilder 对属性进行全局排序。 However for this to work, you must have Jackson2ObjectMapperBuilder in your classpath.但是,要使其正常工作,您的类路径中必须有 Jackson2ObjectMapperBuilder。 It is not part of the Jackson library.它不是杰克逊图书馆的一部分。

As per this documentation , spring-web dependency has Jackson2ObjectMapperBuilder file and should be in your classpath.根据本文档,spring-web 依赖项具有 Jackson2ObjectMapperBuilder 文件,应该在您的类路径中。

@Bean
  public Jackson2ObjectMapperBuilder objectMapperBuilder() {

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

    return builder;
  }

You can refer to this for other possible solutions您可以参考了解其他可能的解决方案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM