lombok
dependency is lombok
available in runtime, so using a plugin will not increase the size of the assembly. To configure Lombok with Gradle (it also works with Maven), simply add the following lines to the build.gradle file: plugins { id 'io.franzbecker.gradle-lombok' version '1.14' id 'java' } repositories { jcenter() // or Maven central, required for Lombok dependency } lombok { version = '1.18.4' sha256 = "" }
@Data
annotation we simplify the basic POJO: @Data public class User { private UUID userId; private String email; }
@Data
is just a convenient annotation that applies several Lombok annotations at once.@ToString
generates an implementation for the toString()
method, which consists of a neat representation of the object: the name of the class, all fields and their values.@EqualsAndHashCode
generates equals
and hashCode
, which by default use non-static and non-stationary fields, but are configurable.@Getter / @Setter
generates getters and setters for private fields.@RequiredArgsConstructor
creates a constructor with the required arguments, where the final fields and fields annotated with @NonNull
(more on this below).@Data
is a fully modifiable class, the abuse of which can increase complexity and limit concurrency, which negatively affects application survivability.User
class, make it immutable, and add a few other useful annotations. @Value @Builder(toBuilder = true) public class User { @NonNull UUID userId; @NonNull String email; @Singular Set<String> favoriteFoods; @NonNull @Builder.Default String avatar = “default.png”; }
@Value
annotation @Value
similar to @Data
except that all fields are private and final by default, and no setters are created. Thanks to this, @Value
objects immediately become immutable. Since all fields are final, there is no argument constructor. Instead, Lombok uses @AllArgsConstructor
. The result is a fully functional, immutable object.@Builder
class comes into effect, automatically generating an internal builder class: User user = User.builder() .userId(UUID.random()) .email(“grubhub@grubhub.com”) .favoriteFood(“burritos”) .favoriteFood(“dosas”) .build()
build()
call returns the instance.@NonNull
can use the @NonNull
annotation to @NonNull
that these fields are not null when an object is instantiated, otherwise NullPointerException
thrown. Notice that the avatar field is annotated @NonNull
, but not specified. The point is that the default @Builder.Default
default points to default.png .favoriteFood
, the only property name in our object. When placing @Singular
annotation on a collection property, Lombok creates special builder methods for adding items to the collection individually, rather than adding the entire collection at the same time. This is especially good for tests, because the ways to create small collections in Java cannot be called simple and fast.toBuilder = true
parameter adds an instance method toBuilder()
, which creates a builder object filled with all the values of that instance. So it is easy to create a new instance, pre-filled with all the values from the source, so that it remains to change only the required fields. This is especially useful for the @Value
classes, since the fields are immutable.@Wither
creates methods withX
for each property. The input is the value, and the output is the clone of the instance with the updated value of one field. @Accessors
allows you to customize automatically created setters. The fluent=true
disables the “get” and “set” convention for getters and setters. In certain situations, this may be a useful replacement for @Builder
.@Data
class, but one getter needs user logic, just implement this getter. Lombok will see that the implementation is already provided, and will not overwrite it with an automatically generated implementation. @Slf4j // also: @CommonsLog @Flogger @JBossLog @Log @Log4j @Log4j2 @XSlf4j public class UserService { // created automatically // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(UserService.class); }
@Slf4j @RequiredArgsConstructor @FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE) public class UserService { @NonNull UserDao userDao; }
@FieldDefaults
adds final and private modifiers to all fields. @RequiredArgsConstructor
creates a constructor that installs an instance of UserDao
. The @NonNull
adds a check in the constructor and UserDao
NullPointerException
if the UserDao
instance is zero.var
keyword appeared in Java 9, you can still reassign the variable. Lombok has a val
keyword that displays the final type of a local variable. // final Map map = new HashMap<Integer, String>(); val map = new HashMap<Integer, String>();
@UtilityClass
annotation. It generates a private constructor that creates an exception, finally displays the class and makes all methods static. @UtilityClass // will be made final public class UtilityClass { // will be made static private final int GRUBHUB = “ GRUBHUB”; // autogenerated by Lombok // private UtilityClass() { // throw new java.lang.UnsupportedOperationException("This is a utility class and cannot be instantiated"); //} // will be made static public void append(String input) { return input + GRUBHUB; } }
@SneakyThrows
. As expected, the implementation is pretty tricky. It does not catch the exception and does not even throw an exception in a RuntimeException
. Instead, it relies on the fact that during execution, the JVM does not check the consistency of the checked exceptions. Only javac does that. Therefore, Lombok disables this check by compile-time conversion bytecode. The result is run code. public class SneakyThrows { @SneakyThrows public void sneakyThrow() { throw new Exception(); } }
@NonNull
annotations @NonNull
not converted). Thus, any IDE with a plug-in installed can convert most annotations into native Java code and back. Let's go back to our User
class. @Value @Builder(toBuilder = true) public class User { @NonNull UUID userId; @NonNull String email; @Singular Set<String> favoriteFoods; @NonNull @Builder.Default String avatar = “default.png”; }
public class User { @NonNull UUID userId; @NonNull String email; Set<String> favoriteFoods; @NonNull @Builder.Default String avatar = "default.png"; @java.beans.ConstructorProperties({"userId", "email", "favoriteFoods", "avatar"}) User(UUID userId, String email, Set<String> favoriteFoods, String avatar) { this.userId = userId; this.email = email; this.favoriteFoods = favoriteFoods; this.avatar = avatar; } public static UserBuilder builder() { return new UserBuilder(); } @NonNull public UUID getUserId() { return this.userId; } @NonNull public String getEmail() { return this.email; } public Set<String> getFavoriteFoods() { return this.favoriteFoods; } @NonNull public String getAvatar() { return this.avatar; } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof User)) return false; final User other = (User) o; final Object this$userId = this.getUserId(); final Object other$userId = other.getUserId(); if (this$userId == null ? other$userId != null : !this$userId.equals(other$userId)) return false; final Object this$email = this.getEmail(); final Object other$email = other.getEmail(); if (this$email == null ? other$email != null : !this$email.equals(other$email)) return false; final Object this$favoriteFoods = this.getFavoriteFoods(); final Object other$favoriteFoods = other.getFavoriteFoods(); if (this$favoriteFoods == null ? other$favoriteFoods != null : !this$favoriteFoods.equals(other$favoriteFoods)) return false; final Object this$avatar = this.getAvatar(); final Object other$avatar = other.getAvatar(); if (this$avatar == null ? other$avatar != null : !this$avatar.equals(other$avatar)) return false; return true; } public int hashCode() { final int PRIME = 59; int result = 1; final Object $userId = this.getUserId(); result = result * PRIME + ($userId == null ? 43 : $userId.hashCode()); final Object $email = this.getEmail(); result = result * PRIME + ($email == null ? 43 : $email.hashCode()); final Object $favoriteFoods = this.getFavoriteFoods(); result = result * PRIME + ($favoriteFoods == null ? 43 : $favoriteFoods.hashCode()); final Object $avatar = this.getAvatar(); result = result * PRIME + ($avatar == null ? 43 : $avatar.hashCode()); return result; } public String toString() { return "User(userId=" + this.getUserId() + ", email=" + this.getEmail() + ", favoriteFoods=" + this.getFavoriteFoods() + ", avatar=" + this.getAvatar() + ")"; } public UserBuilder toBuilder() { return new UserBuilder().userId(this.userId).email(this.email).favoriteFoods(this.favoriteFoods).avatar(this.avatar); } public static class UserBuilder { private UUID userId; private String email; private ArrayList<String> favoriteFoods; private String avatar; UserBuilder() { } public User.UserBuilder userId(UUID userId) { this.userId = userId; return this; } public User.UserBuilder email(String email) { this.email = email; return this; } public User.UserBuilder favoriteFood(String favoriteFood) { if (this.favoriteFoods == null) this.favoriteFoods = new ArrayList<String>(); this.favoriteFoods.add(favoriteFood); return this; } public User.UserBuilder favoriteFoods(Collection<? extends String> favoriteFoods) { if (this.favoriteFoods == null) this.favoriteFoods = new ArrayList<String>(); this.favoriteFoods.addAll(favoriteFoods); return this; } public User.UserBuilder clearFavoriteFoods() { if (this.favoriteFoods != null) this.favoriteFoods.clear(); return this; } public User.UserBuilder avatar(String avatar) { this.avatar = avatar; return this; } public User build() { Set<String> favoriteFoods; switch (this.favoriteFoods == null ? 0 : this.favoriteFoods.size()) { case 0: favoriteFoods = java.util.Collections.emptySet(); break; case 1: favoriteFoods = java.util.Collections.singleton(this.favoriteFoods.get(0)); break; default: favoriteFoods = new java.util.LinkedHashSet<String>(this.favoriteFoods.size() < 1073741824 ? 1 + this.favoriteFoods.size() + (this.favoriteFoods.size() - 3) / 3 : Integer.MAX_VALUE); favoriteFoods.addAll(this.favoriteFoods); favoriteFoods = java.util.Collections.unmodifiableSet(favoriteFoods); } return new User(userId, email, favoriteFoods, avatar); } public String toString() { return "User.UserBuilder(userId=" + this.userId + ", email=" + this.email + ", favoriteFoods=" + this.favoriteFoods + ", avatar=" + this.avatar + ")"; } } }
UserService
class. @Slf4j @RequiredArgsConstructor @FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE) public class UserService { @NonNull UserDao userDao; }
public class UserService { private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(UserService.class); private final UserDao userDao; @java.beans.ConstructorProperties({"userDao"}) public UserService(UserDao userDao) { if (userDao == null) { throw new NullPointerException("userDao is marked @NonNull but is null") } this.userDao = userDao; } }
@NonNull
reduce the likelihood of errors and help our development, which aims to deliver food to your table!Source: https://habr.com/ru/post/438870/