Lombok is a Java library that provides a set of annotations and utility classes to reduce boilerplate code in Java projects. One of its popular annotations is @Singular, which generates builder methods for collections.
When you annotate a collection field or parameter with @Singular, Lombok generates two methods for that collection: a method to add a single element to the collection, and a method to add multiple elements to the collection. These methods have names based on the singular and plural forms of the collection field or parameter. For example, if you annotate a field named items with @Singular, Lombok will generate an item method to add a single item and an items method to add multiple items.
For the reader’s convenience, the Singular.java can be found in the Source Code section of this article.
Here’s an Example in Java:
import lombok.Builder;
import lombok.Singular;
import java.util.List;
@Builder
public class Order {
private final String orderId;
@Singular private final List<String> items;
}
In this example, the Order class has a field named items that is annotated with @Singular. When you use the @Builder annotation to build an instance of Order, Lombok generates a builder() method that you can use to add items to the items field. Here’s an example of how to use the builder:
Order order = Order.builder()
.orderId("123")
.item("item1")
.item("item2")
.items(List.of("item3", "item4"))
.build();
The @Singular annotation from Lombok has a few other options that can be used to customize the behavior of the generated methods:
This option allows you to specify a custom name for the singular method that adds a single element to the collection. By default, Lombok generates this method based on the name of the annotated field.
Example:
import lombok.Builder;
import lombok.Singular;
import java.util.List;
@Builder
public class Order {
private final String orderId;
@Singular("addItem") private final List<String> items;
}
With this option, the singular method for adding an item to the items list will be named addItem() instead of item().
This option allows you to specify whether or not to generate methods for adding elements to the collection if the collection is null. If this option is set to true, Lombok will skip generating the methods if the collection is null.
Example:
import lombok.Builder;
import lombok.Singular;
import java.util.List;
@Builder
public class Order {
private final String orderId;
@Singular(ignoreNullCollections = true) private final List<String> items;
}
With this option set to true, Lombok will not generate the singular and plural methods for the items list if it is null.
This option allows you to specify whether or not to generate methods for adding elements to the collection if the collection is empty. If this option is set to true, Lombok will skip generating the methods if the collection is empty.
import lombok.Builder;
import lombok.Singular;
import java.util.List;
@Builder
public class Order {
private final String orderId;
@Singular(ignoreEmptyCollections = true) private final List<String> items;
}
With this option set to true, Lombok will not generate the singular and plural methods for the items list if it is empty.
This option allows you to suppress any warnings that may be generated by the @Singular annotation.
import lombok.Builder;
import lombok.Singular;
import java.util.List;
@Builder
@SuppressWarnings("lombok:Singular") // suppress any warnings that may be generated
public class Order {
private final String orderId;
@Singular private final List<String> items;
}
With this option set, any warnings generated by the @Singular annotation will be suppressed.
These options can be used individually or in combination to customize the behavior of the @Singular annotation in Lombok.
There are a few more things you may need to know about the @Singular annotation from Lombok:
@Singular generates defensive copies of collections by default. This means that the methods generated by @Singular will create a new copy of the collection before adding or removing elements, which helps prevent unwanted modifications to the original collection.
The @Singular annotation works with several types of collections, including List, Set, and Map.
When using @Singular with Map fields, you can specify the names of the singular and plural methods for adding and removing entries by using the key and entry options.
For example:
import lombok.Builder;
import lombok.Singular;
import java.util.Map;
@Builder
public class Order {
private final String orderId;
@Singular private final Map<String, Integer> items;
}
In this example, the items field is a Map of strings to integers, and @Singular will generate methods for adding and removing entries from the map using the default names item() and items().
If you want to use custom names, you can use the key and entry options to specify them:
import lombok.Builder;
import lombok.Singular;
import java.util.Map;
@Builder
public class Order {
private final String orderId;
@Singular(key = "itemName", entry = "quantity") private final Map<String, Integer> items;
}
In this example, the @Singular annotation is configured to use the names itemName() and quantities() for adding and removing entries from the map, respectively.
@Singular can be used with custom collection types that have a single-argument add method. If you have a custom collection type with a different method for adding elements, you can use the method option to specify its name:
import lombok.Builder;
import lombok.Singular;
import java.util.Deque;
@Builder
public class Order {
private final String orderId;
@Singular(method = "push") private final Deque<String> items;
}
In this example, the @Singular annotation is configured to use the push() method of a Deque to add elements to the collection.
These are some additional details about the @Singular annotation that you may find useful when working with Lombok.
In conclusion, the @Singular annotation from Lombok is a handy tool that simplifies the process of creating and modifying collections in your Java code. By using this annotation, you can generate concise and easy-to-use methods for adding and removing elements from collections, such as lists, sets, maps, and custom collection types. Additionally, the @Singular annotation has various options that allow you to customize the names and behavior of the generated methods to suit your needs. Whether you’re a beginner or an experienced programmer, @Singular can save you time and effort when working with collections.
Here is a snapshot of the Singular.java annotation source code: