Jackson ObjectMapper - chỉ định thứ tự tuần tự hóa của các thuộc tính đối tượng


84

Tôi đang triển khai dịch vụ web RESTful trong đó người dùng phải gửi mã xác minh đã ký cùng với yêu cầu để tôi có thể đảm bảo rằng yêu cầu không bị người trung gian giả mạo. Cách thực hiện hiện tại của tôi như sau.

Mã thông báo xác minh là một đối tượng VerifData được tuần tự hóa thành một Chuỗi, sau đó được băm và mã hóa.

class VerifData {
    int prop1;
    int prop2;
}

Trong dịch vụ của mình, tôi đặt dữ liệu được tuần tự hóa vào một phiên bản của VerifData và sau đó tuần tự hóa nó bằng cách sử dụng Jackson ObjectMapper và được chuyển đến công cụ xác minh cùng với mã xác minh.

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

Nhưng có vẻ như mỗi khi vùng chứa ứng dụng được khởi động, thứ tự của các thuộc tính được ObjectMapper ánh xạ thành một chuỗi sẽ thay đổi.

Ví dụ: một lần nó sẽ là

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

và lần khác nó sẽ là

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

Vì vậy, nếu khách hàng đã tuần tự hóa cá thể VerifData thành Chuỗi đầu tiên, có 50% khả năng nó bị lỗi mặc dù nó đúng.

Có cách nào để giải quyết vấn đề này không? Tôi có thể chỉ định thứ tự của các thuộc tính để ánh xạ bằng ObjectMapper (như theo thứ tự tăng dần) không? Hoặc có cách nào khác để thực hiện tốt nhất bước xác minh này không. Cả triển khai máy khách và máy chủ đều do tôi phát triển. Tôi sử dụng API bảo mật Java để ký và xác minh.

Câu trả lời:


82

Từ tài liệu Chú thích của Jackson :

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

từ liên kết "tất cả các dịch vụ codehaus đã bị chấm dứt"
Andrew Norman

2
Như đã đề cập bên dưới, nếu mục tiêu của bạn là áp dụng thứ tự ở mọi nơi thay vì khi tuần tự hóa một đối tượng cụ thể, hãy xem stackoverflow.com/a/46267506/2089674 .
user2089674 17/09/17

91

Các chú thích rất hữu ích, nhưng có thể gây khó khăn khi áp dụng ở mọi nơi. Bạn có thể định cấu hình toàn bộ ObjectMapper của mình để hoạt động theo cách này với

Các phiên bản Jackson hiện tại: objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)

Các phiên bản Jackson cũ hơn: objectMapper.configure(SerializationConfig.Feature.SORT_PROPERTIES_ALPHABETICALLY, true);


Điều này không hoàn toàn chính xác (hoặc ít nhất là không hoạt động trong tất cả các trường hợp) - hãy xem stackoverflow.com/a/46267506/2089674 để biết ví dụ đầy đủ về một thứ hoạt động.
user2089674 17/09/17

2
@ user2089674 - ví dụ của bạn chỉ hoạt động cho các phím Bản đồ. OP đã yêu cầu một giải pháp cho các trường Đối tượng.
Dave

10

Trong Jackson 2.x, mà bạn có thể đang sử dụng ngày nay, hãy sử dụng:

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

Nếu bạn quan tâm đến ngoại hình, bạn cũng có thể cân nhắc SerializationFeature.INDENT_OUTPUT.

Lưu ý rằng bạn phải tuần tự hóa Bản đồ hoặc Đối tượng để sắp xếp chính xác. Nếu bạn tuần tự hóa một JsonNodeví dụ (from readTree), nó sẽ không được thụt lề đúng cách.

Thí dụ

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

kết quả trong:

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

6
Chỉ có một mục bản đồ. Do đó tôi không thể thấy nó là thứ tự.
Ben

9

Trong Spring Boot, bạn có thể thêm hành vi này trên toàn cầu bằng cách thêm phần sau Applicationvào lớp điểm đầu vào của bạn :

  @Bean
  public Jackson2ObjectMapperBuilder objectMapperBuilder() {

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

    return builder;
  }

9

Có một cách dễ dàng hơn trong Spring Boot bằng cách chỉ định một thuộc tính ( application.propertiesví dụ:

spring.jackson.mapper.sort_properties_alphabetically=true

7

2 cấu hình ObjectMapper sau là bắt buộc:

ObjectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
hoặc là
ObjectMapper.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)

xác định thứ tự tuần tự hóa thuộc tính được sử dụng cho các trường POJO
Lưu ý : không áp dụng cho java.util.Maptuần tự hóa!


ObjectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true)
hoặc là
ObjectMapper.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)

Tính năng xác định xem java.util.Mapcác mục nhập có được sắp xếp đầu tiên theo khóa trước khi tuần tự hóa hay không


Ví dụ về cấu hình Spring Boot (yaml):

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

3

Từ câu trả lời của Duncan McGregor: Tốt hơn là sử dụng nó như thế này:

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

vì MapperFeature dành cho XML và đi kèm với jackson-databind không bắt buộc ...


0

Thay vì sử dụng đối số cờ:

objectMapper.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);

0

Bạn có thể sử dụng kết hợp và chỉ định thứ tự thuộc tính theo ý muốn:

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

}

0

Tôi nhận ra đây là một chủ đề cũ, nhưng vì tôi đang tìm kiếm hoặc một câu trả lời và hạ cánh ở đây, một số thông tin bổ sung có thể hữu ích cho những người khác.
Chú thích @JsonProperty hiện tôi đang sử dụng (jackson-annotations-2.11.2) chấp nhận, bên cạnh đối số "giá trị", đối số "chỉ mục" (số) chỉ định thứ tự của các trường trong quá trình tuần tự hóa.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.