setTimeout принимает функцию как параметр. То, что вы делаете, сразу же выполняет функцию и передает возвращаемое значение функции exected. Пропустите GetUsersNumber
вместо GetUsersNumber()
. () уже выполняет функцию.
setTimeout(GetUsersNumber, 50000);
На боковой ноте:
if(window.XMLHttpRequest)
происходит во время компиляции, что очень важно в этом обсуждении.
Проверка бонуса происходит во время выполнения и, как таковая, требует явного вызова в коде или управляемой среде, неявно делает это (например, 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) }
}
}
Ломбок учитывает эти @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 недостаточно эффективен. С другой стороны, ломбок не должен добавлять дополнительные проверки, потому что он нарушит законные варианты использования.
mandatoryField1
действительно @NonNull
?
– John Bupit
23 July 2018 в 09:50
@NonNull
в переменной класса не должен говорить что-то о строителе (по крайней мере, не по умолчанию), потому что строитель просто представляет промежуточное предварительное состояние будущего объекта, который должен быть сконструирован, а не сам объект. Поэтому: Да, mandatoryField1
все еще @NonNull
. Что касается расширения ломбока: я думаю, что (необязательно) создание дополнительных нулевых проверок в сочетании с методом builder()
, который принимает параметры, было бы хорошим дополнением.
– Jan Rieke
23 July 2018 в 10:03
@NonNull
, то оно не должно быть нулевым - в промежуточном состоянии или иным образом. Я считаю, что такого промежуточного состояния не должно быть (... или, по крайней мере, это то, что я хотел бы обеспечить в своем коде).
– John Bupit
23 July 2018 в 10:50
== null
, поэтому он @NonNull
. Это может быть только null
в построителе. Одна из основных идей шаблона построителя заключается в том, что он обеспечивает управление по шагам i> процесса построения. Таким образом, большинство пользователей этого шаблона хотят поэтапной конструкции, поэтому они также ожидают наличия временных ограничений в конструкторе. Таким образом, ломбок не должен добавлять дополнительные ограничения по умолчанию, IMHO. Если вы хотите обеспечить ограничения даже в построителе, то предлагаемое расширение ломбок будет решением.
– Jan Rieke
23 July 2018 в 12:00
@NonNull
), когда выполняется.build()
. Единственное преимущество с этим CustomBuilder, похоже, заключается в добавлении проверенного файлаValidationException
, который, возможно, не скомпилирует компиляцию, если не обрабатывается должным образом. – John Bupit 23 July 2018 в 09:45@NonNull
! – diginoise 23 July 2018 в 12:48