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

时间:2022-02-22 18:02:16

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. My current implementation is as follows.

我正在实现一个RESTful web服务,用户必须在发送请求的同时发送一个签名的验证令牌,以便确保请求没有被中间人篡改。我的当前实现如下所示。

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)? 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.

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

6 个解决方案

#1


46  

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)

#2


46  

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)

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

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

老杰克逊版本:objectMapper.configure(SerializationConfig.Feature。SORT_PROPERTIES_ALPHABETICALLY,真正的);

#3


9  

In Spring Boot you can add this behaviour globally by adding the following to your Application entry point class:

在Spring Boot中,您可以将以下行为添加到应用程序入口点类:

  @Bean
  public Jackson2ObjectMapperBuilder objectMapperBuilder() {

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

    return builder;
  }

#4


6  

There is an easier way in Spring Boot by specifying a property (in application.properties for example:

通过指定属性(在应用程序中),在Spring引导中有一种更简单的方法。例如:属性

spring.jackson.mapper.sort_properties_alphabetically=true

#5


3  

From Duncan McGregor's answer: Its better to use it like this:

邓肯·麦格雷戈的回答是:最好这样使用:

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,这是不需要的……

#6


1  

In Jackson 2.x, which you are probably using today, use:

在杰克逊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. 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"
  }
}

#1


46  

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)

#2


46  

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)

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

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

老杰克逊版本:objectMapper.configure(SerializationConfig.Feature。SORT_PROPERTIES_ALPHABETICALLY,真正的);

#3


9  

In Spring Boot you can add this behaviour globally by adding the following to your Application entry point class:

在Spring Boot中,您可以将以下行为添加到应用程序入口点类:

  @Bean
  public Jackson2ObjectMapperBuilder objectMapperBuilder() {

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

    return builder;
  }

#4


6  

There is an easier way in Spring Boot by specifying a property (in application.properties for example:

通过指定属性(在应用程序中),在Spring引导中有一种更简单的方法。例如:属性

spring.jackson.mapper.sort_properties_alphabetically=true

#5


3  

From Duncan McGregor's answer: Its better to use it like this:

邓肯·麦格雷戈的回答是:最好这样使用:

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,这是不需要的……

#6


1  

In Jackson 2.x, which you are probably using today, use:

在杰克逊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. 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"
  }
}