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


84

사용자가 요청과 함께 서명 된 인증 토큰을 보내야하는 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를 사용합니다.

답변:


82

로부터 잭슨 주석 문서 :

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

"모든 codehaus 서비스가 종료 된"링크에서
앤드류 노먼

2
아래에서 언급했듯이 특정 객체를 직렬화 할 때가 아니라 모든 곳에 순서를 적용하는 것이 목표 인 경우 stackoverflow.com/a/46267506/2089674를 참조하십시오 .
user2089674

91

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

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

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


이것은 정확하지 않습니다 (또는 적어도 모든 시나리오에서 작동하지 않습니다)- 작동하는 것의 완전한 예는 stackoverflow.com/a/46267506/2089674 를 참조하십시오 .
user2089674

2
@ user2089674-예제는 Map 키에만 적용됩니다. OP는 개체 필드에 대한 솔루션을 요청했습니다.
Dave

10

오늘날 사용하고있는 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"
  }
}

6
지도 항목이 하나만 있습니다. 그러므로 나는 그것이 순서를 볼 수 없습니다.
Ben

9

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

  @Bean
  public Jackson2ObjectMapperBuilder objectMapperBuilder() {

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

    return builder;
  }

9

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

spring.jackson.mapper.sort_properties_alphabetically=true

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

3

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

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

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


0

플래그 인수를 사용하는 대신 :

objectMapper.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);

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

}

0

나는 이것이 오래된 스레드라는 것을 알고 있지만 내가 찾고 있거나 대답하고 여기에 도착했기 때문에 몇 가지 추가 정보가 다른 사람들에게 유용 할 수 있습니다.
현재 사용중인 @JsonProperty 주석 (jackson-annotations-2.11.2)은 "값"인수 외에 직렬화 중에 필드의 순서를 지정하는 "인덱스"(숫자) 인수를 허용합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.