Java Bean 検証

Spring Framework は、Java Bean 検証 (英語) API のサポートを提供します。

Bean 検証の概要

Bean 検証は、Java アプリケーションの制約宣言とメタデータを介した検証の一般的なメソッドを提供します。これを使用するには、宣言型の検証制約を使用してドメインモデルプロパティにアノテーションを付けてから、ランタイムによって強制されます。組み込みの制約があり、独自のカスタム制約を定義することもできます。

2 つのプロパティを持つ単純な PersonForm モデルを示す次の例を検討してください。

  • Java

  • Kotlin

public class PersonForm {
	private String name;
	private int age;
}
class PersonForm(
		private val name: String,
		private val age: Int
)

Bean 検証では、次の例に示すように制約を宣言できます。

  • Java

  • Kotlin

public class PersonForm {

	@NotNull
	@Size(max=64)
	private String name;

	@Min(0)
	private int age;
}
class PersonForm(
	@get:NotNull @get:Size(max=64)
	private val name: String,
	@get:Min(0)
	private val age: Int
)

Bean 検証バリデーターは、宣言された制約に基づいてこのクラスのインスタンスを検証します。API に関する一般情報については、Bean バリデーション (英語) を参照してください。特定の制約については、Hibernate バリデーター (英語) の資料を参照してください。Bean 検証プロバイダーを Spring Bean としてセットアップする方法については、読み続けてください。

Bean 検証プロバイダーの構成

Spring は、Bean 検証プロバイダーを Spring Bean としてブートストラップするなど、Bean 検証 API を完全にサポートしています。これにより、アプリケーションで検証が必要な場所に jakarta.validation.ValidatorFactory または jakarta.validation.Validator を挿入できます。

次の例に示すように、LocalValidatorFactoryBean を使用して、デフォルトのバリデーターを Spring Bean として構成できます。

  • Java

  • XML

import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

@Configuration
public class AppConfig {

	@Bean
	public LocalValidatorFactoryBean validator() {
		return new LocalValidatorFactoryBean();
	}
}
<bean id="validator"
	class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

前述の例の基本構成は、Bean 検証をトリガーして、デフォルトのブートストラップメカニズムを使用して初期化します。Hibernate Validator などの Bean 検証プロバイダーは、クラスパスに存在すると予想され、自動的に検出されます。

Jakarta Validator を注入

LocalValidatorFactoryBean は jakarta.validation.ValidatorFactory と jakarta.validation.Validator の両方を実装しているため、次の例に示すように、Bean 検証 API を直接操作したい場合は、後者への参照を挿入して検証ロジックを適用できます。

  • Java

  • Kotlin

import jakarta.validation.Validator;

@Service
public class MyService {

	@Autowired
	private Validator validator;
}
import jakarta.validation.Validator;

@Service
class MyService(@Autowired private val validator: Validator)

Spring バリデータの挿入

jakarta.validation.Validator の実装に加えて、LocalValidatorFactoryBean は org.springframework.validation.Validator にも適応するため、Bean が Spring Validation API を必要とする場合は、後者への参照を挿入できます。

例:

  • Java

  • Kotlin

import org.springframework.validation.Validator;

@Service
public class MyService {

	@Autowired
	private Validator validator;
}
import org.springframework.validation.Validator

@Service
class MyService(@Autowired private val validator: Validator)

org.springframework.validation.Validator として使用される場合、LocalValidatorFactoryBean は基になる jakarta.validation.Validator を呼び出し、ContraintViolation を FieldError に適応させ、validate メソッドに渡される Errors オブジェクトに登録します。

カスタム制約の構成

各 Bean 検証制約は、2 つの部分で構成されています。

  • 制約とその構成可能なプロパティを宣言する @Constraint アノテーション。

  • 制約の動作を実装する jakarta.validation.ConstraintValidator インターフェースの実装。

宣言を実装に関連付けるために、各 @Constraint アノテーションは対応する ConstraintValidator 実装クラスを参照します。実行時に、ConstraintValidatorFactory は、ドメインモデルで制約アノテーションが検出されると、参照される実装をインスタンス化します。

デフォルトでは、LocalValidatorFactoryBean は Spring を使用して ConstraintValidator インスタンスを作成する SpringConstraintValidatorFactory を構成します。これにより、カスタム ConstraintValidators は、他の Spring Bean と同様に依存性注入の恩恵を受けます。

次の例は、カスタム @Constraint 宣言の後に、依存性注入に Spring を使用する関連 ConstraintValidator 実装を示しています。

  • Java

  • Kotlin

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyConstraint {
}
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
@Constraint(validatedBy = MyConstraintValidator::class)
annotation class MyConstraint
  • Java

  • Kotlin

import jakarta.validation.ConstraintValidator;

public class MyConstraintValidator implements ConstraintValidator {

	@Autowired;
	private Foo aDependency;

	// ...
}
import jakarta.validation.ConstraintValidator

class MyConstraintValidator(private val aDependency: Foo) : ConstraintValidator {

	// ...
}

上記の例が示すように、ConstraintValidator 実装は、他の Spring Bean と同様に、@Autowired の依存関係を持つことができます。

Spring 駆動のメソッド検証

Bean バリデーションのメソッド検証機能は、MethodValidationPostProcessor Bean 定義を通じて Spring コンテキストに統合できます。

  • Java

  • XML

import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;

@Configuration
public class AppConfig {

	@Bean
	public static MethodValidationPostProcessor validationPostProcessor() {
		return new MethodValidationPostProcessor();
	}
}
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>

Spring 駆動のメソッド検証の対象となるには、ターゲットクラスに Spring の @Validated アノテーションを付ける必要があります。これにより、使用する検証グループをオプションで宣言することもできます。Hibernate 検証プロバイダーおよび Bean 検証プロバイダーのセットアップの詳細については、"MethodValidationPostProcessor (Javadoc) " を参照してください。

メソッドの検証は、インターフェース上のメソッドの JDK 動的プロキシまたは CGLIB プロキシのいずれかである、ターゲットクラスの周囲の AOP プロキシに依存します。プロキシの使用には特定の制限があり、その一部は AOP プロキシについてで説明されています。さらに、プロキシされたクラスでは常にメソッドとアクセサーを使用することを忘れないでください。直接フィールドアクセスは機能しません。

Spring MVC と WebFlux には、同じ基礎となるメソッド検証のサポートが組み込まれていますが、AOP は必要ありません。このセクションの残りの部分を確認し、Spring MVC 検証およびエラーレスポンスセクション、および WebFlux 検証およびエラーレスポンスセクションも参照してください。

メソッド検証の例外

デフォルトでは、jakarta.validation.ConstraintViolationException は jakarta.validation.Validator によって返される ConstraintViolation のセットを使用して生成されます。代わりに、MessageSourceResolvable エラーに適応した ConstraintViolation を使用して MethodValidationException を生成することもできます。有効にするには、次のフラグを設定します。

  • Java

  • XML

import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;

@Configuration
public class AppConfig {

	@Bean
	public static MethodValidationPostProcessor validationPostProcessor() {
		MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
		processor.setAdaptConstraintViolations(true);
		return processor;
	}
}
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">
	<property name="adaptConstraintViolations" value="true"/>
</bean>

MethodValidationException には、メソッドパラメーターごとにエラーをグループ化する ParameterValidationResult のリストが含まれており、それぞれが MethodParameter、引数値、ConstraintViolation から適応された MessageSourceResolvable エラーのリストを公開します。フィールドおよびプロパティでカスケード違反のある @Valid メソッドパラメーターの場合、ParameterValidationResult は org.springframework.validation.Errors を実装し、検証エラーを FieldError として公開する ParameterErrors です。

検証エラーのカスタマイズ

適応された MessageSourceResolvable エラーは、ロケールおよび言語固有のリソースバンドルを使用して構成された MessageSource を通じてユーザーに表示するエラーメッセージに変換できます。このセクションでは説明のための例を示します。

次のクラス宣言があるとします。

  • Java

  • Kotlin

record Person(@Size(min = 1, max = 10) String name) {
}

@Validated
public class MyService {

	void addStudent(@Valid Person person, @Max(2) int degrees) {
		// ...
	}
}
@JvmRecord
internal data class Person(@Size(min = 1, max = 10) val name: String)

@Validated
class MyService {

	fun addStudent(person: @Valid Person?, degrees: @Max(2) Int) {
		// ...
	}
}

Person.name() 上の ConstraintViolation は、次のように FieldError に適合します。

  • エラーコード "Size.person.name""Size.name""Size.java.lang.String""Size"

  • メッセージ引数 "name"101 (フィールド名と制約属性)

  • デフォルトメッセージ「サイズは 1 から 10 の間でなければなりません」

デフォルトのメッセージをカスタマイズするには、上記のエラーコードとメッセージ引数のいずれかを使用して、MessageSource リソースバンドルにプロパティを追加します。また、メッセージ引数 "name" 自体は、エラーコード "person.name" および "name" を持つ MessagreSourceResolvable であり、カスタマイズできることにも注意してください。例:

プロパティ
Size.person.name=Please, provide a {0} that is between {2} and {1} characters long
person.name=username

degrees メソッドパラメーターの ConstraintViolation は、次のように MessageSourceResolvable に適応されます。

  • エラーコード "Max.myService#addStudent.degrees""Max.degrees""Max.int""Max"

  • メッセージ引数「degrees2 および 2」 (フィールド名と制約属性)

  • デフォルトのメッセージ「2 以下である必要があります」

上記のデフォルトメッセージをカスタマイズするには、次のようなプロパティを追加できます。

プロパティ
Max.degrees=You cannot provide more than {1} {0}

追加の構成オプション

ほとんどの場合、デフォルトの LocalValidatorFactoryBean 構成で十分です。メッセージの補間からトラバーサル解決まで、さまざまな Bean 検証コンストラクトの構成オプションが多数あります。これらのオプションの詳細については、LocalValidatorFactoryBean javadoc を参照してください。

DataBinder の構成

Validator を使用して DataBinder インスタンスを構成できます。構成したら、binder.validate() を呼び出して Validator を呼び出すことができます。検証 Errors は、バインダーの BindingResult に自動的に追加されます。

次の例は、DataBinder をプログラムで使用して、ターゲットオブジェクトにバインドした後に検証ロジックを呼び出す方法を示しています。

  • Java

  • Kotlin

Foo target = new Foo();
DataBinder binder = new DataBinder(target);
binder.setValidator(new FooValidator());

// bind to the target object
binder.bind(propertyValues);

// validate the target object
binder.validate();

// get BindingResult that includes any validation errors
BindingResult results = binder.getBindingResult();
val target = Foo()
val binder = DataBinder(target)
binder.validator = FooValidator()

// bind to the target object
binder.bind(propertyValues)

// validate the target object
binder.validate()

// get BindingResult that includes any validation errors
val results = binder.bindingResult

dataBinder.addValidators および dataBinder.replaceValidators を介して、複数の Validator インスタンスで DataBinder を構成することもできます。これは、グローバルに構成された Bean 検証と、DataBinder インスタンスでローカルに構成された Spring Validator を組み合わせるときに役立ちます。Spring MVC 検証構成を参照してください。

Spring MVC 3 検証

Spring MVC の章の検証を参照してください。