Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 非空Lombok builder属性的FindBugs检测器_Java_Builder_Findbugs_Lombok_Null Check - Fatal编程技术网

Java 非空Lombok builder属性的FindBugs检测器

Java 非空Lombok builder属性的FindBugs检测器,java,builder,findbugs,lombok,null-check,Java,Builder,Findbugs,Lombok,Null Check,我有很多使用Lombok构建器的类,这些类具有@NonNull字段 @Builder class SomeObject { @NonNull String mandatoryField1; @NonNull String mandatoryField2; Integer optionalField; ... } 但是,这使调用者可以选择在不设置mandatoryField的情况下创建对象,这将导致运行时失败 SomeObject.builder()

我有很多使用Lombok构建器的类,这些类具有
@NonNull
字段

@Builder
class SomeObject {
    @NonNull String mandatoryField1;
    @NonNull String mandatoryField2;
    Integer optionalField;
    ...
}
但是,这使调用者可以选择在不设置
mandatoryField
的情况下创建对象,这将导致运行时失败

SomeObject.builder()
          .mandatoryField1("...")
          // Not setting mandatoryField2
          .build();
我正在寻找在构建时捕获这些错误的方法

有一些非Lombok的方法,比如StepBuilder,甚至是构造函数,可以确保始终设置必填字段,但我对使用Lombok builder实现这一点感兴趣

此外,我知道为了进行编译时检查而设计类(如步骤生成器或
@allargsconstuctor
)会产生大量笨拙的代码——这就是为什么我有动机构建一个编译后FindBugs步骤来检测这些

现在,当我显式地将
@NonNull
字段设置为
null
时,FindBugs确实失败了:

FindBugs检测到此故障

new SomeObject().setMandatoryField1(null);
但它没有检测到这一点:

SomeObject.builder()
          .mandatoryField1(null)
          .build();
SomeObject.builder()
          .mandatoryField1("...")
          //.mandatoryField2("...") Not setting it at all.
          .build();
它也没有检测到这一点:

SomeObject.builder()
          .mandatoryField1(null)
          .build();
SomeObject.builder()
          .mandatoryField1("...")
          //.mandatoryField2("...") Not setting it at all.
          .build();
这似乎是因为戴着假面具的建筑工人看起来像

public static class SomeObjectBuilder {
    private String mandatoryField1;
    private String mandatoryField2;
    private Integer optionalField;

    SomeObjectBuilder() {}

    public SomeObjectBuilder mandatoryField1(final String mandatoryField1) {
        this.mandatoryField1 = mandatoryField1;
        return this;
    }

    // ... other chained setters.

    public SomeObject build() {
        return new SomeObject(mandatoryField1, mandatoryField2, optionalField);
    }
}
我认为:

  • Lombok不会向其内部字段添加任何
    @NonNull
    ,也不会向非null字段添加任何null检查
  • 它不调用任何
    SomeObject.set*
    方法,以便FindBugs捕捉这些失败
我有以下问题:

  • 如果设置了
    @NonNull
    属性,是否有任何方法使用Lombok构建器时会导致构建时失败(在运行FindBugs时或其他情况下)
  • 是否有任何自定义FindBugs检测器检测这些故障
    • 这似乎是个吹毛求疵的问题。。。。。。但请记住,这些都不是:

      • Findbugs
      • Bean验证(JSR303
      • Bean验证2.0JSR380
      在编译时发生,这在本讨论中非常重要

      Bean验证发生在运行时,因此需要在代码中显式调用,或者托管环境通过创建和调用验证器隐式调用(如SpringJavaEE

      FindBugs是一个静态字节码分析器,因此在编译后发生。它使用聪明的启发式,但它不执行代码,因此不是100%无懈可击的。 在您的情况下,它只在浅层情况下执行了可空性检查,而没有执行生成器

      还请注意,通过手动创建生成器并添加必要的
      @NotNull
      注释,FindBugs将不会生效,如果您没有分配任何值,这与分配
      null
      相反。另一个差距是反思和反序列化

      我理解您希望尽快验证以验证注释(如
      @NotNull
      )表示的合同

      有一种方法可以在
      SomeClassBuilder.build()
      (仍然是运行时!)上执行此操作,但它有点复杂,需要创建自定义生成器:

      也许它可以成为通用的,以适应许多类-somoeone请编辑

      @Builder
      类对象{
      @非空字符串mandatoryField1;
      @非空字符串mandatoryField2;
      整数域;
      ...
      公共静态SomeObjectBuilder(){//Lombok的类名约定
      返回新的CustomBuilder();
      }
      公共静态类CustomBuilder扩展了SomeObjectBuilder{
      私有静态ValidationFactory vf=Validation.buildDefaultValidationFactory();
      私有验证器Validator=vf.getValidator();
      @过度
      公共对象生成(){
      SomeObject result=super.build();
      验证对象(结果);
      返回结果;
      }
      私有void validateObject(对象对象){
      //如果对象为null,则抛出新的IllegalArgException或ValidationException
      设置冲突=validator.validate(对象);
      如果(冲突.size()>0){
      //遍历冲突,每个冲突都有getMessage(),getPropertyPath()
      //-建立详细的异常消息,列出所有违规行为
      [...]
      抛出新的ValidationException(messageWithAllViolations)}
      }        
      }
      
      Lombok在生成
      @allargsconstuctor
      时会考虑这些
      @NonNull
      注释。这也适用于由
      @Builder
      生成的构造函数。在您的示例中,这是构造函数的delomboked代码:

      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方法中(这会使Funbbug更容易发现问题)。这是因为使用一个生成器实例仍然是完全合法的,它仍然有<代码> @非null < /COD>字段设置为<代码> null < /C>。考虑以下用例:

      例如,您可以使用
      toBuilder()
      方法从实例创建一个新的生成器,然后通过调用
      mandatoryField1(null)
      删除其中一个必填字段(可能是因为您希望避免泄漏实例值)。然后您可以将其传递给其他方法,让其重新填充必填字段。因此,lombok不会也不应该将这些空检查添加到生成的生成器的不同setter方法中。(当然,可以扩展lombok,以便用户可以“选择加入”要生成更多的空检查,请参阅。但是,这取决于lombok维护人员。)

      TLDR:这个问题可以从理论上找到,但FindBugs不够强大。在oth上