FindBugs-детектор для атрибутов Builder NonNull Lombok

setTimeout принимает функцию как параметр. То, что вы делаете, сразу же выполняет функцию и передает возвращаемое значение функции exected. Пропустите GetUsersNumber вместо GetUsersNumber(). () уже выполняет функцию.

setTimeout(GetUsersNumber, 50000);

На боковой ноте:

  • Большинство современных браузеров поддерживают XMLHttpRequest изначально. Таким образом, использование ActiveXObject не требуется.
  • Для старых браузеров условие if в любом случае даст ошибку. Сделайте это: if(window.XMLHttpRequest)
14
задан John Bupit 13 July 2018 в 16:00
поделиться

2 ответа

это может показаться ничтожным выбором ...

... но имейте в виду, что ни одно из них:

  • Findbugs
  • Валидация боба (JSR303)
  • Проверка бина 2.0 (JSR380)

происходит во время компиляции, что очень важно в этом обсуждении.

Проверка бонуса происходит во время выполнения и, как таковая, требует явного вызова в коде или управляемой среде, неявно делает это (например, Spring или JavaEE), создавая и вызывая валидаторы.

FindBugs - это статический анализатор байт-кода и, следовательно, после компиляции. Он использует умную эвристику, но не выполняет код и поэтому не на 100% водонепроницаем. В вашем случае он следил за проверкой недействительности только в мелком корпусе и пропустил строителя.

Также обратите внимание, что вручную создавая компоновщик и добавляя необходимые аннотации @NotNull, FindBugs не включались бы, если бы вы не назначали какое-либо значение, как против назначения null. Еще один пробел - отражение и десериализация.

Я понимаю, что вы хотели бы, чтобы контракт, выраженный в аннотациях проверки (например, @NotNull), был проверен как можно скорее.

способ сделать это на SomeClassBuilder.build() (все еще время работы!), но это немного связано и требует создания пользовательского построителя:

, возможно, его можно было бы сделать общим для размещения многих классов - somoeone, пожалуйста, отредактируйте!

@Builder
class SomeObject {
  @NonNull String mandatoryField1;
  @NonNull String mandatoryField2;
  Integer optionalField;
  ...

  public static SomeObjectBuilder builder() { //class name convention by Lombok
    return new CustomBuilder();
  }

  public static class CustomBuilder extends SomeObjectBuilder {
    private static ValidationFactory vf = Validation.buildDefaultValidationFactory();
    private Validator validator = vf.getValidator();

    @Overrride
    public SomeObject build() {
      SomeObject result = super.build();
      validateObject(result);
      return result;
    }

    private void validateObject(Object object) {
      //if object is null throw new IllegalArgException or ValidationException
      Set<ConstraintVioletion<Object>> violations = validator.validate(object);

      if (violations.size() > 0) { 
        //iterate through violations and each one has getMessage(), getPropertyPath() 
        // - to build up detailed exception message listing all violations
        [...]
        throw new ValidationException(messageWithAllViolations) }

    }        
}
4
ответ дан diginoise 17 August 2018 в 12:56
поделиться
  • 1
    Спасибо за ввод. Однако мой код уже не работает с NPE (из-за @NonNull), когда выполняется .build(). Единственное преимущество с этим CustomBuilder, похоже, заключается в добавлении проверенного файла ValidationException, который, возможно, не скомпилирует компиляцию, если не обрабатывается должным образом. – John Bupit 23 July 2018 в 09:45
  • 2
    хороший отзыв о @NonNull! – diginoise 23 July 2018 в 12:48

Ломбок учитывает эти @NonNull аннотации при генерации @AllArgsConstructor. Это также имеет место для конструктора, который порождается @Builder. Это примерный код конструктора в вашем примере:

SomeObject(@NonNull final String mandatoryField1, @NonNull final String mandatoryField2, final Integer optionalField) {
    if (mandatoryField1 == null) {
        throw new java.lang.NullPointerException("mandatoryField1 is marked @NonNull but is null");
    }
    if (mandatoryField2 == null) {
        throw new java.lang.NullPointerException("mandatoryField2 is marked @NonNull but is null");
    }
    this.mandatoryField1 = mandatoryField1;
    this.mandatoryField2 = mandatoryField2;
    this.optionalField = optionalField;
}

Таким образом, FindBugs теоретически может найти проблему, потому что нулевая проверка присутствует в конструкторе, который позже вызывается с помощью null в вашем примере. Тем не менее, FindBugs, вероятно, недостаточно мощный, чтобы сделать это (пока?), И я не знаю какого-либо настраиваемого детектора, который способен на это.

Остается вопрос, почему ломбок не добавляет эти проверки к методам setter строителя (что облегчило бы FindBugs выявить проблему). Это связано с тем, что вполне нормально работать с экземпляром построителя, который по-прежнему имеет @NonNull поля, установленные на null. Рассмотрим следующий прецедент:

Вы можете, например, создать новый строитель из экземпляра с использованием метода toBuilder(), а затем удалить одно из своих обязательных полей, вызвав mandatoryField1(null) (возможно, потому, что вы хотите чтобы избежать утечки значения экземпляра). Затем вы можете передать его другому методу, чтобы он снова заполнил обязательное поле. Таким образом, lombok не должен и не должен добавлять эти нулевые проверки к различным методам настройки сгенерированного построителя. (Разумеется, ломбок может быть расширен таким образом, чтобы пользователи могли «отказаться» от генерации более нулевых проверок, см. это обсуждение в GitHub . Однако это решение зависит от поддерживающих ломбок).

TLDR: проблема может быть найдена теоретически, но FindBugs недостаточно эффективен. С другой стороны, ломбок не должен добавлять дополнительные проверки, потому что он нарушит законные варианты использования.

6
ответ дан Jan Rieke 17 August 2018 в 12:56
поделиться
  • 1
    Вполне возможно, что Ломбок останется как есть. Я просто ищу компиляцию (или посткомпилировать в этом случае) предупреждение, вместо того, чтобы потерпеть неудачу с NPE. Более того, в случае использования, которое вы упомянули, действительно ли mandatoryField1 действительно @NonNull? – John Bupit 23 July 2018 в 09:50
  • 2
    IMHO, @NonNull в переменной класса не должен говорить что-то о строителе (по крайней мере, не по умолчанию), потому что строитель просто представляет промежуточное предварительное состояние будущего объекта, который должен быть сконструирован, а не сам объект. Поэтому: Да, mandatoryField1 все еще @NonNull. Что касается расширения ломбока: я думаю, что (необязательно) создание дополнительных нулевых проверок в сочетании с методом builder(), который принимает параметры, было бы хорошим дополнением. – Jan Rieke 23 July 2018 в 10:03
  • 3
    Я бы не согласился. IMO, если поле @NonNull, то оно не должно быть нулевым - в промежуточном состоянии или иным образом. Я считаю, что такого промежуточного состояния не должно быть (... или, по крайней мере, это то, что я хотел бы обеспечить в своем коде). – John Bupit 23 July 2018 в 10:50
  • 4
    Но никогда не будет экземпляра с этим полем == null, поэтому он @NonNull. Это может быть только null в построителе. Одна из основных идей шаблона построителя заключается в том, что он обеспечивает управление по шагам процесса построения. Таким образом, большинство пользователей этого шаблона хотят поэтапной конструкции, поэтому они также ожидают наличия временных ограничений в конструкторе. Таким образом, ломбок не должен добавлять дополнительные ограничения по умолчанию, IMHO. Если вы хотите обеспечить ограничения даже в построителе, то предлагаемое расширение ломбок будет решением. – Jan Rieke 23 July 2018 в 12:00
Другие вопросы по тегам:

Похожие вопросы: