DEV Community

Angela
Angela

Posted on

How to automatically inject a validated property's name in the bean validation message

A project I've worked on in the past required us to inject the property path in validation error messages. To prevent repetitive work, I've written a rough MessageInterpolator implementation to add the property path as an expression variable:

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.internal.engine.MessageInterpolatorContext;

import javax.validation.MessageInterpolator;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;

/**
 * <p>Allows interpolation of messages with a {@code ${propertyPath} expression variable},
 * which will resolve to the property path of the value being validated.</p>
 */
@Slf4j
@RequiredArgsConstructor
public class PropertyPathAddingMessageInterpolator implements MessageInterpolator {

    private final MessageInterpolator delegateInterpolator;

    @Override
    public String interpolate(String messageTemplate, Context context) {
        Optional<Context> replacementContext = replacementContextFrom(context);
        return delegateInterpolator.interpolate(messageTemplate, replacementContext.orElse(context));
    }

    @Override
    public String interpolate(String messageTemplate, Context context, Locale locale) {
        Optional<Context> replacementContext = replacementContextFrom(context);
        return delegateInterpolator.interpolate(messageTemplate, replacementContext.orElse(context), locale);
    }

    private Optional<Context> replacementContextFrom(Context context) {
        if (!(context instanceof MessageInterpolatorContext)) {
            return Optional.empty();
        }
        MessageInterpolatorContext interpolatorContext = (MessageInterpolatorContext) context;
        Map<String, Object> expressionVariables = new HashMap<>(interpolatorContext.getExpressionVariables());
        expressionVariables.put("propertyPath", interpolatorContext.getPropertyPath());

        Context replacementContext = new MessageInterpolatorContext(
            interpolatorContext.getConstraintDescriptor(),
            interpolatorContext.getValidatedValue(),
            interpolatorContext.getRootBeanType(),
            interpolatorContext.getPropertyPath(),
            interpolatorContext.getMessageParameters(),
            expressionVariables,
            interpolatorContext.getExpressionLanguageFeatureLevel(),
            interpolatorContext.isCustomViolation()
        );
        return Optional.of(replacementContext);
    }

}
Enter fullscreen mode Exit fullscreen mode

This allows us to automatically populate ${propertyPath} in validation messages such as the following:

javax.validation.constraints.NotNull.message=${propertyPath} must not be null
Enter fullscreen mode Exit fullscreen mode

You must configure your ValidatorFactory to use this MessageInterpolator.

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs