You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Play 2.6中JSR-303与Validatable验证执行顺序问题咨询

Got it, let's figure out how to fix this. Play 2.6 changed the default validation execution behavior—instead of running your annotation-based checks (like @Constraints.Required) first and then your Validatable logic sequentially, it now runs all validators in parallel. That’s why your validate() method is firing even when annotation rules fail, forcing you to add extra null checks and workarounds. Here are two reliable ways to get back the old sequential flow:

Option 1: Manually trigger bean validation inside your Validatable class

This keeps your controller code clean, but requires updating each Validatable implementation to check annotation-based rules first. Here's how to implement it:

import play.data.validation.ValidationError;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class YourForm implements Validatable<List<ValidationError>> {

    @Constraints.Required
    private String requiredField;

    @Override
    public List<ValidationError> validate() {
        List<ValidationError> errors = new ArrayList<>();

        // Step 1: Run annotation-based bean validation first
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();
        Set<javax.validation.ConstraintViolation<YourForm>> violations = validator.validate(this);

        if (!violations.isEmpty()) {
            // Convert bean validation errors to Play's ValidationError format
            for (javax.validation.ConstraintViolation<YourForm> violation : violations) {
                errors.add(new ValidationError(
                    violation.getPropertyPath().toString(),
                    violation.getMessage()
                ));
            }
            // Exit early if annotation checks fail—skip custom logic entirely
            return errors;
        }

        // Step 2: Run your custom validation logic only if annotations pass
        if (customValidationFails(requiredField)) {
            errors.add(new ValidationError("requiredField", "Custom error message"));
        }

        return errors;
    }

    private boolean customValidationFails(String fieldValue) {
        // Replace with your actual custom validation logic
        return fieldValue.length() < 5;
    }
}

Option 2: Split validation steps in your controller

If you don't want to modify every Validatable class, adjust your controller code to run annotation validation first, then trigger the Validatable logic manually:

import play.data.Form;
import play.data.FormFactory;
import play.mvc.Controller;
import play.mvc.Result;
import javax.inject.Inject;
import java.util.List;

public class YourController extends Controller {

    private final FormFactory formFactory;

    @Inject
    public YourController(FormFactory formFactory) {
        this.formFactory = formFactory;
    }

    public Result submitForm() {
        Form<YourForm> form = formFactory.form(YourForm.class).bindFromRequest();

        // First: Check if annotation-based validation failed
        if (form.hasErrors()) {
            return badRequest(form.errorsAsJson());
        }

        // Second: Run custom Validatable logic only if annotations passed
        YourForm formData = form.get();
        List<ValidationError> customErrors = formData.validate();

        if (!customErrors.isEmpty()) {
            // Attach custom errors to the form and return a bad request
            form = form.withErrors(customErrors);
            return badRequest(form.errorsAsJson());
        }

        // All validation passed—proceed with your business logic
        return ok("Form submitted successfully!");
    }
}

Why this works

Play 2.6 switched to parallel validation to boost performance, but this broke the sequential dependency your code relied on. Both options above enforce the original order: annotation checks complete first, and your custom Validatable logic only runs if those checks pass. Pick Option 1 if you want validation logic encapsulated in the form class, or Option 2 if you prefer keeping form classes clean and handling the order in controllers.

内容的提问来源于stack exchange,提问作者Florian Schaetz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:27:37