I'm using Lombok #Builder annotation, but I'd like some of the String fields to be optional and default to "" to avoid NPEs. Is there an easy way to do this? I can't find anything.
Alternately, a way to customize #Getter to return a default value if the variable is null.
Starting from version v1.16.16 they added #Builder.Default.
#Builder.Default lets you configure default values for your fields
when using #Builder.
example:
#Setter
#Getter
#Builder
public class MyData {
private Long id;
private String name;
#Builder.Default
private Status status = Status.NEW;
}
PS: Nice thing they also add warning in case you didn't use #Builder.Default.
Warning:(35, 22) java: #Builder will ignore the initializing
expression entirely. If you want the initializing expression to serve
as default, add #Builder.Default. If it is not supposed to be settable
during building, make the field final.
You have to provide the builder class like the below:
#Builder
public class XYZ {
private String x;
private String y;
private String z;
private static class XYZBuilder {
private String x = "X";
private String y = "Y";
private String z = "Z";
}
}
Then the default value for x, y, z will be "X", "Y", "Z".
Another way to go is to use #Builder(toBuilder = true)
#Builder(toBuilder = true)
public class XYZ {
private String x = "X";
private String y = "Y";
private String z = "Z";
}
and then you use it as follows:
new XYZ().toBuilder().build();
With respect to the accepted answer, this approach is less sensible to class renaming. If you rename XYZ but forget to rename the inner static class XYZBuilder, then the magic is gone!
It's all up to to you to use the approach you like more.
Related
I have object of following class:
#Jacksonized
#Builder
#Getter
public class Request {
private String id;
private String city_id;
private String country_id;
private List<String> product_id;
}
This class doesn't have setters, but does have #Builder. I don't want to build a new object. I need to replace following List with another List:
private List<String> product_id;
How can I change condition of the current object?
Should I use ReflectionUtils or is there something else better?
How to model this in Lombok, constructors which take lesser arguments and supporting get/set for transient methods. How to tweak the following definitions
#NoArgsConstructor
#AllArgsConstructor
#Data
public class SalaryRange {
private Integer from;
private Integer to;
private transient String displayName;
private SalaryRange() {
}
private SalaryRange(Integer from) {
this(from, null);
}
private SalaryRange(Integer from, Integer to) {
this(from, to, null);
}
private SalaryRange(Integer from, Integer to, String displayName) {
this.from = from;
this.to = to;
this.displayName = displayName;
}
..
}
Just use a Builder and NoArgsConstructor
#NoArgsConstructor
#Builder
#Data
public class SalaryRange {
private Integer from;
private Integer to;
private transient String displayName;
}
and then
SalaryRange range = SalaryRange.builder().from(1).to(2).build();
Documentation:
Project Lombok Builder
One additional notice - when using #Builder do not static import Builder class - there is a bug that, as far as I know, is not fixed yet
static import not working in lombok builder in intelliJ
I don't think Lombok provide that much flexibility with constructor annotation. 2 approaches may help:
Use #RequiredArgsConstructor, which takes in all final variables.
#NoArgsConstructor
#AllArgsConstructor
#Data
public class SalaryRange {
private final Integer from;
private final Integer to;
private transient String displayName;
}
Use #Builder to achieve more flexibility. However, you may still need #NoArgsConstructor #AllArgsConstructor sometimes for serialization/deserialization by thirty party tools integration, e.g. spring rest, mybatis, etc. Just try it out and check logs.
Otherwise, just write constructor manually, intellij can generate constructor for you quickly by command + N
You may keep constructors from below, the other two are generated by #NoArgsConstructor and #AllArgsConstructor, constructors are meant to build objects
private SalaryRange(Integer from) {
this(from, null);
}
private SalaryRange(Integer from, Integer to) {
this(from, to, null);
}
Another approach might be to combine #Accessors (experimental feature) with #NoArgsConstructor and #AllArgsConstructor
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Accessors(chain = true)
public class SalaryRange {
private Integer from;
private Integer to;
private transient String displayName;
}
SalaryRange salaryRange1 = new SalaryRange().setFrom(1).setTo(2);
SalaryRange salaryRange2 = new SalaryRange(1, 2, "somename");
You may use #Accessors(chain = true, fluent = true) to have fluent accessors if you don't require the get & set prefix
SalaryRange salaryRange1 = new SalaryRange().from(1).to(2);
PD: Builder pattern has downsides that might lead to an Anti-Pattern and might hide a bad design, so be careful when you decide to use it. I think Builder pattern is overused in this scenario, we don't need to add extra complexity to build an object with three attributes.
https://www.baeldung.com/lombok-accessors
https://www.yegor256.com/2016/02/03/design-patterns-and-anti-patterns.html
I have a class for all static members. The number of static members is more than 10 (which may increase with time).
I am using lombok and I want to generate Getters/Setters for all static members using single #Getter and #Setter annotations on class as we do for non-static members.
I know that
You can also put a #Getter and/or #Setter annotation on a class. In
that case, it's as if you annotate all the non-static fields in that
class with the annotation.
I also know that
We can annotate static fields individually using #Getter #Setter to generate Getters/Setters for static fields.
But this looks ugly and I want to make my class look as clean as possible.
Is there any way I can configure / Override #Getter and #Setter annotation so that I can annotate the class and it generate Getters and Setters for all members including static and non-static members, after all, what do those methods do is return the mentioned variable.
To be more precise, I want the following code snippet to generate Getters and Setters for all class variables-
#Getter
#Setter
public class myClass {
private static String d;
private static SomePojo c;
private String a;
private Integer b;
private SomeClass d;
}
Add #Getter to the static member itself and it should work.
#Getter
private static final String DEFAULT_VAL = "TEST";
For static fields you have to add #Getter to the specific field:
#Getter
#Setter
public class Task {
#Getter
private static int numberOfTasks;
#Getter
private static int taskId;
private String taskName;
private Integer executionTime;
}
I was setting the value of recordId from the child classes using the default constructor and was not using lombok #Builder initially. Eventually i decided to use the Builder here, but the problem now is lombok Builder overrides my default constructor internally hence the value is never set.
How can I put any hook too make lombok #Builder use my default constructor?
Parent class:
#Getter
#Setter
public abstract class Record {
private String recordId;
}
Child class:
#Getter
#Setter
#Builder
#ToString
#AllArgsConstructor
public class SRecord extends Record {
private static final String RECORD_ID = "REC001";
private String street;
private String city;
public SRecord() {
setRecordId(RECORD_ID); //value of recordId being set
}
}
Lombok's #Builder simply does not use the default constructor. It passes its values to an all-args constructor so that this constructor can fill the new instance with these values. #Builder does not use setters or direct access to the fields to do so. So your default constructor is simply ignored by #Builder.
What you can do is write your own all-args constructor. In it, you set your value for recordId and assign the rest of the fields from the parameters.
I think you should create a constructor in your base class:
#Getter
#Setter
public abstract class Record {
private String recordId;
public Record(String recordId) {
this.recordId = recordId;
}
}
Then use it in the constructor of the inherited class:
#Getter
#Setter
#Builder
public class SRecord extends Record {
private static final String RECORD_ID = "REC001";
private String street;
private String city;
public SRecord(String street, String city) {
super(RECORD_ID);
this.street = street;
this.city = city;
}
}
P.S. If you want to use Lombok Builder with inheritance you can use this technique.
If I specify #AllArgsConstructor using Lombok, it will generate a constructor for setting all the declared (not final, not static) fields.
Is it possible to omit some field and this leave generated constructor for all other fields?
No that is not possible. There is a feature request to create a #SomeArgsConstructor where you can specify a list of involved fields.
Full disclosure: I am one of the core Project Lombok developers.
Alternatively, you could use #RequiredArgsConstructor. This adds a constructor for all fields that are either #NonNull or final.
See the documentation
Just in case it helps, initialized final fields are excluded.
#AllArgsConstructor
class SomeClass {
final String s;
final int i;
final List<String> list = new ArrayList<>(); // excluded in constructor
}
var x = new SomeClass("hello", 1);
It makes sense especially for collections, or other mutable classes.
This solution can be used together with the other solution here, about using #RequiredArgsConstructor:
#RequiredArgsConstructor
class SomeClass2 {
final String s;
int i; // excluded because it's not final
final List<String> list = new ArrayList<>(); // excluded because it's initialized
}
var x = new SomeClass2("hello");
A good way to go around it in some cases would be to use the #Builder
This can be done using two annotations from lombok #RequiredArgsConstructor and #NonNull.
Please find the example as follows
package com.ss.model;
import lombok.*;
#Getter
#Setter
#RequiredArgsConstructor
#ToString
public class Employee {
private int id;
#NonNull
private String firstName;
#NonNull
private String lastName;
#NonNull
private int age;
#NonNull
private String address;
}
And then you can create an object as below
Employee employee = new Employee("FirstName", "LastName", 27, "Address");
Lombok is meant to take care of the boilerplate code for your POJOs. Customized constructors/setters/getters/toString/copy etc are not on the boilerplate side of code. For these cases, every Java IDE provide easy to use code generators to help you do things in no time.
In your case a
public MyClass(String firstName, String lastName) {....}
is much more readable and makes more sense than a hypothetic:
#AllArgsConstructor(exclude = "id", exclude = "phone")
Have fun!