1

I'm trying to validate a DTO based on a method using @javax.validation.AssertTrue annotation.

@Getter
@Setter
public class EntityDTO {

    @NotNull
    @Schema(...)
    private String someField;
    @Schema(...)
    private String firstName;
    @Schema(...)
    private String lastName;

    @AssertTrue(message = "either first or last name must be set")
    private boolean isFirstNameOrLastNameSet() {
        return (firstName != null || lastName != null)
    }

}

If I validate this class (using @Valid) where first and lastName is null like this:

save(@Valid EntityDTO);

I get this error:

java.lang.IllegalStateException MESSAGE: JSR-303 validated property
'firstNameOrLastNameSet' does not have a corresponding accessor for Spring data binding
- check your DataBinder's configuration (bean property versus direct field access)

I don't want to change data binding globally because I don't know all the implications it has on other code. (Like suggested here How to configure direct field access on @Valid in Spring?)

I was expecting this to work similarly to a normal @NotNull annotation (it works as expected on someField) . Where it gets validated, and if it fails I get an Exception. Is there a way to achieve this behaviour or am I expecting the wrong thing? How would you validate that at a certain point in the code the isFirstNameOrLastNameSet() returns true?

ch1ll
  • 419
  • 7
  • 20
  • 1
    can you try making the method public? I believe it needs to be proxied and this won't work for private methods. – Emanuel Trandafir Apr 27 '23 at 10:07
  • Making it public did work, thank you! I got an intermediate solution by trial and error by renaming the method to isFirstName(). This probably worked because firstName has a getter so it can be accessed in some way. But honestly not sure how it exactly works. If you post your comment as an answer I could accept it. – ch1ll Apr 27 '23 at 11:16
  • 1
    great. i have added it now. ys, probably it was using the lombok-generated getter :) – Emanuel Trandafir Apr 27 '23 at 11:33

1 Answers1

1

The validation is done through AOP (aspects). This means your object needs to be proxied and so, the method needs to be accessible. In short, making the method public should fix it:

@JsonIgnore // add this to skip json serialization
@AssertTrue(message = "either first or last name must be set")
public boolean isFirstNameOrLastNameSet() {
    return (firstName != null || lastName != null)
}
Emanuel Trandafir
  • 1,526
  • 1
  • 5
  • 13