次の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を構成することは可能ですか?
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
この問題を解決するもう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
(シリアル化に使用)と組み合わせて使用されます。- すべてのargumentに
JsonProperty
またはJacksonInject
の注釈が付けられ、バインドするプロパティの名前を示すコンストラクタ/ファクトリメソッドまた、パラメータ名を検出できる拡張モジュールのいずれかを使用しない限り、すべての
JsonProperty
アノテーションは実際の名前(「デフォルト」の空の文字列ではない)を指定する必要があることに注意してください。これは、8より前のデフォルトのJDKバージョンでは、バイトコードからパラメーター名を保存または取得できないためです。ただし、JDK 8(またはParanamerなどのヘルパーライブラリ、またはScalaやKotlinなどの他のJVM言語を使用)では、名前の指定はオプションです。
Lombokでこのケースを処理するには、次の回避策を使用しました。
@Value
@AllArgsConstructor(onConstructor = @__(@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)))
class SomeClassName {...}
Lombokのバージョンを「org.projectlombok:lombok:1.18.0」にアップグレードしましたが、うまくいきました。