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);
}
}
This allows us to automatically populate ${propertyPath}
in validation messages such as the following:
javax.validation.constraints.NotNull.message=${propertyPath} must not be null
You must configure your ValidatorFactory
to use this MessageInterpolator
.
Top comments (0)