- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我有很多使用 Lombok 构建器的带有 @NonNull
字段的类。
@Builder
class SomeObject {
@NonNull String mandatoryField1;
@NonNull String mandatoryField2;
Integer optionalField;
...
}
但是,这使调用者可以选择在不设置 mandatoryField
的情况下创建对象,这在使用时会导致运行时失败。
SomeObject.builder()
.mandatoryField1("...")
// Not setting mandatoryField2
.build();
我正在寻找在构建时捕获这些错误的方法。
有非 Lombok 方法(如 StepBuilders 甚至构造函数)来确保始终设置必填字段,但我对使用 Lombok 构建器实现此目的的方法很感兴趣。
此外,我知道设计类(如 step-builder 或 @AllArgsConstructor
)以进行编译时检查会产生很多笨拙的代码 - 这就是为什么我'我有动力构建一个检测这些问题的编译后 FindBugs 步骤。
现在,当我将 @NonNull
字段显式设置为 null
时,FindBugs 会失败:
FindBugs 检测到此故障,
new SomeObject().setMandatoryField1(null);
但它没有检测到这一点:
SomeObject.builder()
.mandatoryField1(null)
.build();
它也没有检测到这个:
SomeObject.builder()
.mandatoryField1("...")
//.mandatoryField2("...") Not setting it at all.
.build();
这似乎正在发生,因为 Delomboked 构建器看起来像,
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);
}
}
我观察到:
@NonNull
,也不向非空字段添加任何空检查。SomeObject.set*
方法,以便 FindBugs 捕获这些失败。我有以下问题:
@NonNull
属性,是否有任何方式以导致构建时失败(在运行 FindBugs 或其他方式时)的方式使用 Lombok 构建器?最佳答案
Lombok 在生成 @AllArgsConstructor
时会考虑这些 @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 可能还不够强大(还没有?),而且我不知道有任何自定义检测器能够做到这一点。
问题仍然存在,为什么 lombok 不将这些检查添加到构建器的 setter 方法中(这将使 FindBugs 更容易发现问题)。这是因为使用仍将 @NonNull
字段设置为 null
的构建器实例是完全合法的。考虑以下用例:
例如,您可以使用 toBuilder()
方法从一个实例创建一个新的构建器,然后通过调用 mandatoryField1(null)
删除其必填字段之一(可能是因为您想避免泄漏实例值)。然后您可以将它传递给其他一些方法,让它重新填写必填字段。因此,lombok 不会也不应该将那些 null 检查添加到生成的构建器的不同 setter 方法中。 (当然,可以扩展 lombok,以便用户可以“选择加入”以生成更多空检查;请参阅 this discussion at GitHub。但是,该决定取决于 lombok 维护者。)
TLDR:理论上可以找到问题,但 FindBugs 不够强大。另一方面,lombok 不应该添加进一步的空检查,因为它会破坏合法的用例。
关于java - NonNull Lombok 构建器属性的 FindBugs 检测器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51324922/
你能比较一下属性吗 我想禁用文本框“txtName”。有两种方式 使用javascript,txtName.disabled = true 使用 ASP.NET, 哪种方法更好,为什么? 最佳答案 我
Count 属性 返回一个集合或 Dictionary 对象包含的项目数。只读。 object.Count object 可以是“应用于”列表中列出的任何集合或对
CompareMode 属性 设置并返回在 Dictionary 对象中比较字符串关键字的比较模式。 object.CompareMode[ = compare] 参数
Column 属性 只读属性,返回 TextStream 文件中当前字符位置的列号。 object.Column object 通常是 TextStream 对象的名称。
AvailableSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。 object.AvailableSpace object 应为 Drive 
Attributes 属性 设置或返回文件或文件夹的属性。可读写或只读(与属性有关)。 object.Attributes [= newattributes] 参数 object
AtEndOfStream 属性 如果文件指针位于 TextStream 文件末,则返回 True;否则如果不为只读则返回 False。 object.A
AtEndOfLine 属性 TextStream 文件中,如果文件指针指向行末标记,就返回 True;否则如果不是只读则返回 False。 object.AtEn
RootFolder 属性 返回一个 Folder 对象,表示指定驱动器的根文件夹。只读。 object.RootFolder object 应为 Dr
Path 属性 返回指定文件、文件夹或驱动器的路径。 object.Path object 应为 File、Folder 或 Drive 对象的名称。 说明 对于驱动器,路径不包含根目录。
ParentFolder 属性 返回指定文件或文件夹的父文件夹。只读。 object.ParentFolder object 应为 File 或 Folder 对象的名称。 说明 以下代码
Name 属性 设置或返回指定的文件或文件夹的名称。可读写。 object.Name [= newname] 参数 object 必选项。应为 File 或&
Line 属性 只读属性,返回 TextStream 文件中的当前行号。 object.Line object 通常是 TextStream 对象的名称。 说明 文件刚
Key 属性 在 Dictionary 对象中设置 key。 object.Key(key) = newkey 参数 object 必选项。通常是 Dictionary 
Item 属性 设置或返回 Dictionary 对象中指定的 key 对应的 item,或返回集合中基于指定的 key 的&
IsRootFolder 属性 如果指定的文件夹是根文件夹,返回 True;否则返回 False。 object.IsRootFolder object 应为&n
IsReady 属性 如果指定的驱动器就绪,返回 True;否则返回 False。 object.IsReady object 应为 Drive&nbs
FreeSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。只读。 object.FreeSpace object 应为 Drive 对象的名称。
FileSystem 属性 返回指定的驱动器使用的文件系统的类型。 object.FileSystem object 应为 Drive 对象的名称。 说明 可
Files 属性 返回由指定文件夹中所有 File 对象(包括隐藏文件和系统文件)组成的 Files 集合。 object.Files object&n
我是一名优秀的程序员,十分优秀!