Validation

Validation checks that the values of an object are acceptable and reports every problem it finds.

Why you need it

Input comes from many places: a request body, a form, a settings file, a message from a queue. Each value needs checks: a name is not blank, an age is at least 18, an email address looks like one. Writing these checks as if statements in every place is repetitive and easy to forget.

With validation you write the rule once, as an annotation on the property. A validator reads the annotations and reports every broken rule, with an error code that a message file can turn into text for the user.

You do not need it for values that your own code produces and already trusts. You also do not need it for type checks: Dart's type system handles those.

A short example

import 'package:spring_core_dart/spring_core_dart.dart';

// @Introspected lets the generator describe the properties,
// so the validator can read them without reflection.
@Introspected()
class SignupForm {
  @NotBlank()
  @Size(max: 20)
  String name = '';

  @NotNull()
  @Email()
  String? email;

  @Min(18)
  int age = 0;
}
import 'package:my_app/src/beans.dart';
import 'package:my_app/src/signup_form.dart';
import 'package:spring_core_dart/spring_core_dart.dart';

const log = SpringLog('signup');

void main() {
  final context = ApplicationContext.run([appBeans]);

  // Use the context's introspector: it knows the application's classes.
  final validator = BeanValidator(
    introspector: context.getBean<BeanIntrospector>(),
  );

  final form = SignupForm()
    ..name = 'Ada'
    ..age = 17;

  for (final violation in validator.validateObject(form)) {
    // email: must not be null
    // age: must be greater than or equal to 18
    log.warning('${violation.propertyPath}: ${violation.message}');
  }
  context.close();
}

The module appBeans is declared once in the application, as @ComponentScan() final BeanModule appBeans = $appBeans; (see Beans).

Where checks run without your own call

For everything else, call BeanValidator yourself, or use DataBinder to copy string input onto an object and check it in one step.

Pages in this section

In Spring (Java)

The Java counterpart is org.springframework.validation together with Jakarta Bean Validation (usually Hibernate Validator).

class SignupForm {
  @NotBlank @Size(max = 20) private String name;
  @NotNull @Email private String email;
  @Min(18) private int age;
}

Set<ConstraintViolation<SignupForm>> violations = validator.validate(form);

Differences that matter:

See also