[java] Jackson ObjectMapper-객체 속성의 직렬화 순서 지정

사용자가 요청과 함께 서명 된 인증 토큰을 보내야하는 RESTful 웹 서비스를 구현하여 요청이 중개자에 의해 변조되지 않았는지 확인할 수 있습니다. 내 현재 구현은 다음과 같습니다.

확인 토큰은 문자열로 직렬화 된 VerifData 객체이며 해시되고 암호화됩니다.

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에 의해 문자열로 매핑되는 속성의 순서가 변경되는 것 같습니다.

예 : 한 번은

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

그리고 또 다른 시간은

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

따라서 클라이언트가 VerifData 인스턴스를 첫 번째 문자열로 직렬화 한 경우 정확하더라도 실패 할 확률이 50 %입니다.

이 문제를 해결할 방법이 있습니까? ObjectMapper로 매핑 할 속성의 순서를 지정할 수 있습니까 (예 : 오름차순)? 또는이 확인 단계를 가장 잘 구현할 수있는 다른 방법이 있습니까? 클라이언트와 서버 구현 모두 제가 개발했습니다. 서명 및 확인을 위해 Java Security API를 사용합니다.



답변

로부터 잭슨 주석 문서 :

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


답변

주석은 유용하지만 모든 곳에 적용하기가 어려울 수 있습니다. 이 방식으로 작동하도록 전체 ObjectMapper를 구성 할 수 있습니다.

현재 Jackson 버전 :
objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)

이전 Jackson 버전 :
objectMapper.configure(SerializationConfig.Feature.SORT_PROPERTIES_ALPHABETICALLY, true);


답변

오늘날 사용하고있는 Jackson 2.x에서는 다음을 사용합니다.

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

외모에 관심이 있다면 고려할 수도 있습니다 SerializationFeature.INDENT_OUTPUT.

올바르게 정렬하려면 Maps 또는 Objects 를 직렬화해야 합니다. JsonNode예를 들어 (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));

결과 :

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


답변

Spring Boot에서는 Application진입 점 클래스에 다음을 추가하여이 동작을 전역 적으로 추가 할 수 있습니다 .

  @Bean
  public Jackson2ObjectMapperBuilder objectMapperBuilder() {

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

    return builder;
  }


답변

속성을 지정하여 Spring Boot에서 더 쉬운 방법이 있습니다 ( application.properties예 :

spring.jackson.mapper.sort_properties_alphabetically=true


답변

다음 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


답변

Duncan McGregor의 답변에서 : 다음과 같이 사용하는 것이 좋습니다.

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

MapperFeature는 XML 용이며 필요하지 않은 jackson-databind와 함께 제공됩니다.