Kazuki Shimizu opened SPR-15967 and commented

I propose to allow to override a validation message using bean validation message code(like {javax.validation.constraint.Size.message}) at Spring's MessageSource.

e.g) message.properties

javax.validation.constraints.Size.message={0}'s size is must be between {2} and {1}

I know it can be realised using a constraint validation simple class name like as:

Size={0}'s size is must be between {2} and {1}

But there is a case that can't use it.

For example, there is a case that uses composed annotation not work fine as follow:

@Documented
@Constraint(validatedBy = {})
@Target({ TYPE, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Compare(left = "", right = "", operator = Compare.Operator.EQUAL, requireBoth = true) // use composed annotation
public @interface Confirm {

    @OverridesAttribute(constraint = Compare.class, name = "message")
    String message() default "{com.example.sample.domain.validation.Confirm.message}";

    // ...

}

In this case, following definition does not work (can't override a default message generated by bean validation), because bean validation creates a ConstraintViolation of @Compare instead of @Confirm.

Confirm=must be same value with "{4}"
password=Password

I want to override a message corresponding @Confirm using Spring's MessageSource feature as follow:

e.x ) message.properties

com.example.sample.domain.validation.Confirm.message=must be same value with "{4}"
password=Password

I will submit a PR at later.

Thanks.


Affects: 4.3.11, 5.0 RC4

Referenced from: pull request https://github.com/spring-projects/spring-framework/pull/1528

Comment From: spring-projects-issues

Kazuki Shimizu commented

I've submitted the PR.

Comment From: spring-projects-issues

Kazuki Shimizu commented

Memo: There is a workaround using a extension point as follow:

package com.example.infra.spring.validation;

import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

import javax.validation.metadata.ConstraintDescriptor;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class CustomLocalValidatorFactoryBean extends LocalValidatorFactoryBean {

    private Set<Class<? extends Annotation>> targetConstraints = new HashSet<>();

    @Override
    protected String determineErrorCode(ConstraintDescriptor<?> descriptor) {
        // write an extension implementation
        // e.g.
        String messageTemplate = descriptor.getMessageTemplate();
        if (targetConstraints.contains(descriptor.getAnnotation().annotationType())
                && messageTemplate.startsWith("{") && messageTemplate.endsWith("}")) {
            return messageTemplate.substring(1, messageTemplate.length() - 1);
        }
        return super.determineErrorCode(descriptor);
    }

    public void setTargetConstraints(Collection<Class<? extends Annotation>> targetConstraints) {
        this.targetConstraints.addAll(targetConstraints);
    }

}

Comment From: snicoll

Closing in favor of PR #1528

Comment From: snicoll

reopening as the PR above has been declined.