32

I have a class with variables I don't want it to be null or empty. Is there a way to use Lombok builder to set the property? I can use @NonNull but I won't be able to verify if it is empty or not. Obviously the other option is to write my own builder which does all these checks. For example:

class Person {
    @NonNull
    private String firstName;
    @NonNull
    private String lastName;

    public static class PersonBuilder() {
        // .
        // .
        // .
        public Person build() {
            //do checks for empty etc and return object
        }
    }
}
kryger
  • 12,906
  • 8
  • 44
  • 65
user1692342
  • 5,007
  • 11
  • 69
  • 128

4 Answers4

26

Maxim Kirilov's answer is incomplete. It doesn't check for blank/empty Strings.

I've faced the same issue before, and I realized that in addition to using @NonNull and @Builder from Lombok, overload the constructor with a private access modifier, where you can perform the validations. Something like this:

private Person(final String firstName, final String lastName) {
    if(StringUtils.isBlank(firstName)) {
        throw new IllegalArgumentException("First name can't be blank/empty/null"); 
    }
    if(StringUtils.isBlank(lastName)) {
        throw new IllegalArgumentException("Last name can't be blank/empty/null"); 
    }
    this.firstName = firstName;
    this.lastName = lastName;
}

Also, throwing IllegalArgumentException makes more sense (instead of NPE) when String has blank, empty or null values.

Kedar Prabhu
  • 316
  • 3
  • 6
20

The builder annotation should solve your issue:

@Builder
class Person {
    @NonNull
    private String firstName;
    @NonNull
    private String lastName;
}

The generated code is:

class Person {
    @NonNull
    private String firstName;
    @NonNull
    private String lastName;

    @ConstructorProperties({"firstName", "lastName"})
    Person(@NonNull String firstName, @NonNull String lastName) {
        if(firstName == null) {
            throw new NullPointerException("firstName");
        } else if(lastName == null) {
            throw new NullPointerException("lastName");
        } else {
            this.firstName = firstName;
            this.lastName = lastName;
        }
    }

    public static Person.PersonBuilder builder() {
        return new Person.PersonBuilder();
    }

    public static class PersonBuilder {
        private String firstName;
        private String lastName;

        PersonBuilder() {
        }

        public Person.PersonBuilder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public Person.PersonBuilder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }

        public Person build() {
            return new Person(this.firstName, this.lastName);
        }

        public String toString() {
            return "Person.PersonBuilder(firstName=" + this.firstName + ", lastName=" + this.lastName + ")";
        }
    }
}

In this case the null validation will take place during object construction.

Maxim Kirilov
  • 2,639
  • 24
  • 49
3

I did something like this,

class Person {
    private String mFristName;
    private String mSecondName;

    @Builder
    Person(String firstName, String secondName) {
        mFristName = PreCondition.checkNotNullOrEmpty(firstName);
        mSecondName = PreCondition.checkNotNullOrEmpty(secondName);
    }
}

class PreCondition {

    static <T> T checkNotNullOrEmpty(T instance) {
        if (instance == null || (instance instanceof String && ((String) instance).isEmpty())) {
            throw new NullOrEmptyException();
        }
        return instance;
    }

    static class NullOrEmptyException extends RuntimeException {
        NullOrEmptyException() {
            super("Null or Empty");
        }
    }
}
Suryavel TR
  • 3,576
  • 1
  • 22
  • 25
  • 2
    I wondered why your precondition was generic, then I realised you can also use it to verify other types for being not null, but the empty check would be omitted. I would prefer an overloaded method in that case but I like the idea. I guess an IllegalArgumentException could suffice too. – BitfulByte Jun 19 '18 at 05:24
0

Have you tried "@NotEmpty"? It's in the javax.validation.constraints package

https://javaee.github.io/javaee-spec/javadocs/javax/validation/constraints/NotEmpty.html

tyler2cr
  • 73
  • 1
  • 1
  • 9
  • 8
    That does nothing but it's own, it's requires to use a validation framework like Hibernate Validation. I think some IDE with some plugin will use it as an informative annotation so when it checks the code will highlight the chances to be empty. But nothing else. – kszosze Jun 30 '20 at 09:20
  • Tyler, Question in an answer? – AlikElzin-kilaka May 03 '22 at 06:07