Lombok's @NonNull interfering with javax.validation.constraints.NotNull during validation

Viewed 5554

Lombok's @NonNull annotation interferes with javax.validation.constraints.NotNull annotation during validation in a spring boot app.

I am using Lombok in my JPA entities to drastically shorten the code in them (eliminate getters and setters, hashcode and equals, constructors, etc). I use the @NonNull annotation on each required field and then the @RequiredArgsConstructor annotation on top of the class to generate a constructor accepting only those fields (eliminates the need to send the entity's id, UUID and one-to-many Sets as null when creating the object).

The issue i have is that, since adding Lombok not too long ago, my original @NotNull annotation's message is being replaced by a generic Lombok message for the @NonNull annotation. Take a look at this field for example :

@Digits(integer = 5, fraction = 0, message = "The orders port must be a number from 1 to 65 535!")
@NotNull(message = "The orders port is required!")
@Min(value = 1, message = "The orders port must be a number from 1 to 65 535!")
@Max(value = 65535, message = "The orders port must be a number from 1 to 65 535!")
@Column(nullable = false)
@NonNull
private Integer ordersPort;

When i put nothing in this field, get this message :

Property ordersPort threw exception; nested exception is java.lang.NullPointerException: ordersPort is marked @NonNull but is null

Prior to adding Lombok, this was working fine and i was getting the messages i put above. Is there a way to keep using Lombok but somehow disable it from being considered during validation?

Thanks!

2 Answers

Since lombok.NonNull will emit an if statement directly in the code, which later throws NullPointerException, there is not much you can do. javax.validation requires the bean to be constructed before it's being validated and Lombok will prevent it.

You could remove lombok.NonNull or decrease it to warning with lombok.nonNull.flagUsage=warning but this would allow you to create invalid objects that you would have to manually validate with javax.validation.

So, I had a similar issue with Jackson and Lombok.

I needed javax validations to work when deserializing an input for my Controller but I also wanted to be able to create instances of my POJOs "by hand", using Lombok's validations. Since Lombok's validations were executed while building the objects, javax never had a chance to run validations since lombok's failed first.

My solution was the following:

import com.fasterxml.jackson.annotation.JsonCreator;
import javax.validation.constraints.NotBlank;
import lombok.Builder;
import lombok.NonNull;
import lombok.Value;

@Value
//Make immutable
public class MyObject {

    //javax annotations go here
    @NotBlank
    String fieldOne;

    //javax annotations go here
    @NotBlank
    String fieldTwo;


    //Lombok's validations go here. Lombok will create builder methods
    //for this parameters only and will rewrite this constructor to add 
    //validations
    @Builder
    private MyObject(@NonNull String fieldOne,
                     @NonNull String fieldTwo) {
        this.fieldOne = fieldOne;
        this.fieldTwo = fieldTwo;
    }

    //Constructor for jackson. No lombok validations here
    @JsonCreator
    private MyObject(String fieldOne,
                     String fieldTwo,
                     boolean jacksonHack) {
        this.fieldOne = fieldOne;
        this.fieldTwo = fieldTwo;
    }

}

Here, you have to make sure that javax validations are always processed after deserialization. Otherwise you will end up with an invalid object.

But it looks like it works.

Related