Search code examples
javalombokintellij-lombok-plugin

Optional with Lombok custom build method says non-static variable cannot be referenced


Given the following code.

@Getter
@Builder(builderClassName = "Builder", buildMethodName = "build")
public final class BusinessEvent implements BusinessPayload {
  private String action, duration, outcome, provider, trackId, sequence;
  @lombok.Builder.Default private Optional<String> brand, vin, externalTrackId, code = Optional.empty();
  @lombok.Builder.Default private Optional<BusinessEventError> eventError = Optional.empty();

  static class Builder {
    BusinessEvent build() throws MissingRequiredValueException {
      // Custom validation
      return new BusinessEvent(action, duration, outcome, provider, trackId, sequence, brand, vin, externalTrackId, code, eventError);
    }
  }
}

I get the error

java: non-static variable eventError cannot be referenced from a static context

Somehow Optional values are not handled correctly by lombok in this case? I see the same problem in all my builders. This is not shown as an issue by intellij plugin but only when I try to build.

I know you should not use optional as field values but in this case it make the API much clearer and the builder will not get serialized anyways, we have DTOs for that.


Solution

  • To sum up what you want to do:

    • you want a builder generated by lombok
    • you want default values assigned in the builder using @Default
    • you want custom validation inside the build method

    This does not seem to work. Neither with Optional, nor with other objects. Seems to be a limitation in lombok.

    The fact that it is not recognized by IntelliJ as an error does not mean that it is supposed to work. But your compilation fails. This is a real issue.

    Consider the following code, without the @lombok.Builder.Default annotation:

    @Getter
    @Builder(builderClassName = "Builder", buildMethodName = "build")
    public final class BusinessEvent {
        private String action, duration, outcome, provider, trackId, sequence;
        private Optional<String> brand, vin, externalTrackId, code = Optional.empty();
        private Optional<Object> eventError = Optional.empty();
    
        static class Builder {
            BusinessEvent build() {
                if (brand == null) {
                    throw new RuntimeException("brand not set");
                }
                // Custom validation
                return new BusinessEvent(action, duration, outcome, provider, trackId, sequence, brand, vin, externalTrackId, code, eventError);
            }
        }
    
        public static void main(String[] args) {
            BusinessEvent eventWithBrand = BusinessEvent.builder().brand(Optional.of("brand")).build();
            // will throw exception
            BusinessEvent event = BusinessEvent.builder().build();
        }
    }