web-dev-qa-db-ja.com

ObjectMapperは、Spring Boot 2にアップグレードした後、デフォルトコンストラクターなしではデシリアライズできません。

次のDTOがあります。

@Value
public class PracticeResults {
    @NotNull
    Map<Long, Boolean> wordAnswers;
}

@Value
public class ProfileMetaDto {

    @NotEmpty
    String name;
    @Email
    String email;
    @Size(min = 5)
    String password;
}

@Valueは、コンストラクターを生成するLombokアノテーションです。つまり、このクラスには引数のないコンストラクタがありません。

Spring Boot 1.4.3.RELEASEを使用し、ObjectMapper Beanはそのようなオブジェクトをjsonからデシリアライズできました。

Spring Boot 2.0.0.M7へのアップグレード後、次の例外が発生します。

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of PracticeResults (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

Spring Boot 1.4.3で使用されるJacksonバージョンは2.8.10で、Spring Boot 2.0.0.M7の場合は2.9.2です。

この問題をGoogleで試してみましたが、@JsonCreatorまたは@JsonPropertyのソリューションのみが見つかりました。

では、なぜSpring Boot 1.4.3で動作し、Spring Boot 2で失敗するのですか?古いバージョンと同じように動作するようにBeanを構成することは可能ですか?

26
solomkinmv

Lombokバージョン1.16.20の重大な変更のため、lombok.configファイルに次のプロパティを設定する必要があります(このファイルがない場合は、プロジェクトルートに作成できます)。

lombok.anyConstructor.addConstructorProperties=true

これは、Lombokの変更ログで説明されています: https://projectlombok.org/changelog

その後、@ ValueはJacksonによって再び受け入れられるはずです。

@Dataについてですが、関連するGitHubの問題をフォローすることもできます。 https://github.com/rzwitserloot/lombok/issues/156

30
Tobias

この問題を解決するもう1つの方法。 Jackson parameter names module を使用します。これは、デフォルトでスプリングブート2に含まれています。この後、ジャクソンはオブジェクトをデシリアライズできます。ただし、オブジェクトに複数のプロパティがある場合にのみ機能します。単一のプロパティの場合、次のエラーメッセージが表示されます。

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `SomeClassName` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

次の理由によります。

関連付けられたクラスの新しいインスタンスをインスタンス化するために使用するものとしてコンストラクターとファクトリーメソッドを定義するために使用できるマーカー注釈。

注:作成者メソッド(コンストラクター、ファクトリーメソッド)に注釈を付ける場合、メソッドは次のいずれかでなければなりません。

  • 引数にJsonPropertyアノテーションを持たない単一引数のコンストラクター/ファクトリーメソッド:その場合、これはいわゆる「デリゲートクリエーター」です。この場合、Jacksonは最初にJSONを引数の型にバインドし、クリエーターを呼び出します。多くの場合、これはJsonValue(シリアル化に使用)と組み合わせて使用​​されます。
  • すべてのargumentJsonPropertyまたはJacksonInjectの注釈が付けられ、バインドするプロパティの名前を示すコンストラクタ/ファクトリメソッド

また、パラメータ名を検出できる拡張モジュールのいずれかを使用しない限り、すべてのJsonPropertyアノテーションは実際の名前(「デフォルト」の空の文字列ではない)を指定する必要があることに注意してください。これは、8より前のデフォルトのJDKバージョンでは、バイトコードからパラメーター名を保存または取得できないためです。ただし、JDK 8(またはParanamerなどのヘルパーライブラリ、またはScalaやKotlinなどの他のJVM言語を使用)では、名前の指定はオプションです。

Lombokでこのケースを処理するには、次の回避策を使用しました。

@Value
@AllArgsConstructor(onConstructor = @__(@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)))
class SomeClassName {...}
6
solomkinmv

Lombokのバージョンを「org.projectlombok:lombok:1.18.0」にアップグレードしましたが、うまくいきました。

0
fascynacja