JacksonObjectMapper-オブジェクトプロパティのシリアル化順序を指定します


84

リクエストが仲介者によって改ざんされていないことを確認できるように、ユーザーがリクエストと一緒に署名された検証トークンを送信する必要があるRESTfulWebサービスを実装しています。私の現在の実装は次のとおりです。

検証トークンは、文字列にシリアル化され、ハッシュおよび暗号化された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でマップするプロパティの順序を指定できますか(昇順など)?または、この検証手順を最適に実装する他の方法はありますか。クライアントとサーバーの両方の実装は私が開発しました。署名と検証にはJavaSecurityAPIを使用しています。

回答:


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)

リンクから「すべてのコードハウスサービスが終了しました」
Andrew Norman

2
以下で説明するように、特定のオブジェクトをシリアル化するときではなく、どこにでも順序を適用することが目標である場合は、stackoverflow.com / a / 46267506/2089674を参照してください。
user2089674 2017

91

注釈は便利ですが、どこにでも適用するのは面倒な場合があります。ObjectMapper全体をこのように機能するように構成できます

現在のジャクソンバージョン: objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)

古いジャクソンバージョン: objectMapper.configure(SerializationConfig.Feature.SORT_PROPERTIES_ALPHABETICALLY, true);


これは完全には正しくありません(または少なくともすべてのシナリオで機能するわけではありません)-機能するものの完全な例については、stackoverflow.com / a / 46267506/2089674を参照してください。
user2089674 2017

2
@ user2089674-この例はマップキーに対してのみ機能します。OPは、オブジェクトフィールドのソリューションを要求しました。
デイブ

10

おそらく今日使用しているJackson2.xでは、次を使用します。

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

見た目が気になる場合は、SerializationFeature.INDENT_OUTPUT同様に検討することもできます。

これを正しくソートするには、マップまたはオブジェクトをシリアル化する必要があることに注意してください。JsonNodeたとえば(から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
マップエントリは1つだけです。したがって、私はそれの順序を見ることができません。
ベン

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)は、「value」引数に加えて、シリアル化中のフィールドの順序を指定する「index」(数値)引数を受け入れます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.