Home > Blockchain >  Using Lombok's SuperBuilder with Hibernate Validator (jakarta.validation.x) annotation on a con
Using Lombok's SuperBuilder with Hibernate Validator (jakarta.validation.x) annotation on a con

Time:01-07

I have a class ActivitiesModel which uses Lombok's SuperBuilder.

import jakarta.validation.NotBlank;

// other imports and statements omitted for brevity.

@Data
@SuperBuilder
@NoArgsConstructor
public class ActivitiesModel {
    public static final String ACTIVITIES_NOT_NULL_MESSAGE = "Activities cannot be null";
    public static final String ACTIVITY_NOT_BLANK_MESSAGE = "Activity cannot be blank";

    @NotNull(message = ACTIVITIES_NOT_NULL_MESSAGE)
    private List<@NotBlank(message = ACTIVITY_NOT_BLANK_MESSAGE) String> activities;
}

I am using this builder to create an object of ActivitiesModel, and then validating it using Hibernate's Validator interface:

// Somewhere else in the application.

// Create an object using the builder method.
ActivitiesModel activitiesModel = ActivitiesModel.builder()
                                    .activities(List.of("hello", "world")) // <----- Point A
                                    .build();

// Validate the object using Hibernate's validator.
validator.validate(activitiesModel);

However, running this code gives me the following error:

java.lang.Error: 
Unresolved compilation problem: 
        Type mismatch: cannot convert from List<String> to List<E>

The stack trace seems to be pointing at Point A.

I have tried the following approaches:

  1. Replacing the @SuperBuilder with @Builder and @AllArgsConstructor.
  2. Replacing the message attribute with a string literal instead of a static final variable, i.e:
private List<@NotBlank(message = "Activity cannot be blank") String> activities;

1st approach seems to fix this error, however, it's not something I can use as I need to extend the builder functionality to a subclass of ActivitiesModel. Also, this issue is also present in another abstract class, so the super builder functionality for parent classes is definitely required.

2nd approach also works in solving the error. However, going with it is a bit problematic because I then need to have the same message string in the validation test for this model class, which is something I would like to avoid as it duplicates the string.

Another thing to note is that this error only seems to occur in the presence of an annotation on the generic type parameter of the container, which is NotBlank in this case. It is not influenced by any annotations which are present directly on the field itself (NotNull in this case).

So, all in all, these are the questions that I would like to get some answers to:

  1. Somehow, Lombok is able to figure out the types in case of a string literal but not in case of a static final String. Why is that?
  2. Am I going about this totally wrong? The problem occurs because I'm trying to store the message string in a variable, and I'm trying to re-use the same variable at two places: the annotation's message attribute, and in the validation test for the model class. Should I not be checking for the presence of the message in my validation tests, but be checking for something else instead?

CodePudding user response:

For anyone who comes across this later on, the research for this issue has led me to believe that comparing message strings in tests is not the way to go about writing validation test cases. Another downside to this approach is that you might have different validation messages for different locales. In that case, the message string itself might be a template e.g. my.message.key with its values in a ResourceBundle provided to Hibernate, i.e. files such as ValidationMessages.properties and ValidationMessages_de.properties.

In such a scenario, you could compare message for one locale in your validation test case, however, a better approach might be to check the annotation and the field for which the validation has failed. We can get both of these pieces of information via the ConstraintViolation and subsequently the ConstraintDescriptor types, provided by Hibernate. This way we can circumvent checking the message itself, but rely on the actual validation annotation which has failed.

As for the solution to this question, it seems it was a build cache issue. Cleaning maven's build cache results in this code working perfectly fine, but VSCode still seems to have an issue. For now, I will choose to ignore that.

  • Related