Javax validation api. Add a field from the parent bean to the validation message

Hi!

I have a question about the javax validation api, specifically, is it possible to generate a validation message of the following format.

For example, there are classes with a nested structure: Model, Attribute, and Value:

public class Model {
    
    @NotBlank
    private String id;

    @NotBlank
    private String name;
    
    @Size(min = 1)
    private List<Attribute> attributes;

}

public class Attribute {
    
    @NotBlank
    private String id;

    @NotBlank
    private String name;
    
    @Size(min = 1)
    private List<Value> values;

}

public class Value {
    
    @NotBlank
    private String id;

    @NotBlank
    private String name;
   

}

After calling the validation of the model object:

validator.validate(modelObject)

i want to generate validation errors that would contain the object IDs of each of the levels, for example:

M[model_id] A[attribute_id] V [value_id] Value error message
M[model_id] A[attribute_id] Open attribute error message
M[model_id] A[attribute_id] Private attribute error message
M[model_id] A[attribute_id] Attribute error message
M[model_id] Model error message

Is it possible to do something similar?

For business users, this is more readable compared to the default output of the path ’ attributes[0].values[0].names’.

I will be grateful for any help!

Note: i found it in the org.hibernate class.validator.internal.engine.validationcontext. Abstract ValidationContext the processedPathsPerBean field that stores the Path and Bean mapping, but this context is not accessible from the outside ((

I found a solution using the “Extensions of the Path”

  public String createErrorMessageFrom(ConstraintViolation<E> violation) {
    Path path = violation.getPropertyPath();
    StringBuilder targetErrorMessage = new StringBuilder();
    String fieldWithInvalidValue = null;
    if (isRoot(path)) {
      fieldWithInvalidValue = path.toString();
    } else {
      for (Iterator<Path.Node> iterator = violation.getPropertyPath().iterator(); iterator.hasNext(); ) {
        Path.Node nextPathNode = iterator.next();
        fieldWithInvalidValue = nextPathNode.toString();
        if (iterator.hasNext()) {
          NamedEntityDto dto = (NamedEntityDto) nextPathNode.as(PropertyNode.class).getValue();
          targetErrorMessage
              .append(getDtoPrefixForMessage(dto));
        }
      }
    }
    targetErrorMessage.append(String.format("The field '%s' %s", fieldWithInvalidValue, violation.getMessage()));
    return targetErrorMessage.toString();
  }