Make the “propertyPath” available via the “HibernateMessageInterpolatorContext”

Description

We use bean validation intensively for validation of incoming SOAP messages. These SOAP messages contain an (hierarchical) object graph (no backlinks), consisting out of entities (beans) and attributes (bean-properties).
Our failure messages are standardized. They typically start with the failing constraint property and refer to other relevant properties. We have written many custom validators for our domain.

For example, the following ValidationMessages.properties entry describes such a message, called by a custom nl.bro.dto.common.validation.AssertEmpty validator.

ValidationMessages.properties

nl.bro.dto.common.validation.AssertEmpty.message=${validatedAttribute} is missing: ${refAttribute} = ${indicationYesNoValue} determines that it must be present.

Now, all el-expressions value expressions are populated are resolved via the custom AssertEmpty, Constraint annotated annotation. Their values are asserted by the custom AssertEmptyValidator.

The intention is that ${validatedAttribute} and ${refAttribute} are replaced by a parameter. The parameter reflects their position in the object graph and is used in the ValidationMessages.properties resource bundle as key to find the proper name.

So, suppose that we evaluate an object:

Car.java

Car { String hornPresent; Steer steer; }

Steer.java

Steer { Horn horn; }

To achieve this we have written one custom message interpolator. This interpolates the message to:

Intermediate Interpolation Result

nl.bro.dto.common.validation.AssertEmpty.message={Car.steer.horn} is missing: {Car.hornPresent} = ${indicationYesNoValue} determines that it must be present.

However, we can’t fully solve this directly in a custom message interpolator. For this we require the rootBean and the propertyPath. Both are present on the ConstraintViolation but not on the MessageInterpolator.Context. The rootBeanType however can be resolved via unwrapping to the HibernateMessageInterpolatorContext but the propertyPath can’t.

The current solution entails:

  1. Having a custom message interpolator, storing the ConstraintDescriptor as key and the HibernateMessageInterpolatorContext as value in a ThreadLocal.

  1. We wrap all relevant HV classes (ValidatorFactory, Validator, ConstraintViolation) to get to the propertyPath and apply post-interpolation on the violation message by using the ConstraintDescriptor in the ConstraintViolation to get the MessageInterpolator.Context belonging to that particular ConstraintViolation. No need to say this is cumbersome and could be far more simple if we have the proper information available in the custom message interpolator.

NB: I can see that in the interpolation the ConstraintViolation is created almost at the same point as the MessageInterpolator.Context.

Attachments

2

Activity

Show:
Fixed

Details

Assignee

Reporter

Components

Priority

Created October 18, 2018 at 1:48 PM
Updated September 28, 2020 at 3:32 PM
Resolved September 28, 2020 at 3:32 PM