web-dev-qa-db-ja.com

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

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

検証トークンは、文字列にシリアル化され、ハッシュおよび暗号化された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によって文字列にマッピングされるプロパティの順序が変わるようです。

例:1回

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

そして別の時間になるだろう

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

したがって、クライアントがVerifDataインスタンスを最初の文字列にシリアル化した場合、正しいにもかかわらず、失敗する可能性は50%です。

これを回避する方法はありますか? ObjectMapperによってマッピングするプロパティの順序(昇順など)を指定できますか?または、この検証手順を最適に実装する他の方法はありますか。クライアントとサーバーの両方の実装は私によって開発されました。署名と検証にJava Security APIを使用します。

62
Lihini

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)
64
wgitscht

注釈は便利ですが、どこにでも適用するのは面倒です。このように動作するようにObjectMapper全体を設定できます

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

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

69
Duncan McGregor

Spring Bootでは、Applicationエントリポイントクラスに以下を追加することにより、この動作をグローバルに追加できます。

  @Bean
  public Jackson2ObjectMapperBuilder objectMapperBuilder() {

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

    return builder;
  }
9
Gary Rowe

Spring Bootでは、プロパティを指定することで簡単な方法があります(例:application.propertiesで:

spring.jackson.mapper.sort_properties_alphabetically=true
8
Wim Deblauwe

おそらく今日使用しているジャクソン2.xでは、次を使用します。

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

見た目が気になる場合は、SerializationFeature.INDENT_OUTPUTも考慮する必要があります。

正しくソートするには、MapsまたはObjectsをシリアル化する必要があることに注意してください。たとえば、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"
  }
}
3
user2089674

Duncan McGregor's answer:このように使用する方が良い:

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

mapperFeatureはXML用であり、必須ではないjackson-databindが付属しているため...

3
Nemes Nisano

フラグ引数を使用する代わりに:

objectMapper.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);
0
Leon