Overriding Lombok's setter doesn't change the builder's behavior, you have to override them both. Let's start with the harder one:
Builder
Lombok's builder is easy to be overridden by defining the skeleton of the builder. The existing parts won't be generated and Lombok only completes the builder. Create athisstatic nested class in Request
:
public static class RequestBuilder {
public final RequestBuilder id(final String id) {
this.id = id;
updateData(id, name, dataList);
return this;
}
public final RequestBuilder name(final String name) {
this.name = name;
updateData(id, name, dataList);
return this;
}
}
What is updateData
? You need to update the dataList
on each builder's method call. The method must be static
otherwise the static builder cannot access it. Define it right in the Request
class:
private static void updateData(final String id, final String name, List<Data> dataList) {
if (dataList == null) {
dataList = new ArrayList<>();
}
if (dataList.isEmpty()) {
dataList.add(new Data(id, name));
} else {
var data = dataList.get(0);
data.setId(id);
data.setName(name);
}
}
Your case when dataList
is null
is not handled, so I rather initialize it here for sure (hence the field cannot be final among the formal parameters of the method).
Setter
This is easy, you need to do basically the same thing like in the builder - just override the correct methods:
public final void setId(final String id) {
this.id = id;
updateData(id, getName(), dataList);
}
public final void setName(final String name) {
this.name = name;
updateData(getId(), name, dataList);
}
You are all set. For sake of simplicity, I have annotated the class Data
with Lombok annotations @lombok.Data
(beware of the name) and @AllArgsConstructor
.
Test
It's always a good practice to write at least some units tests to cover and verify the behavior. I needed to annotate Request
with @AllArgsConstructor
to avoid calling the setters which are subjects of the test. I also would need some helpful methods for assertion and eliminating code duplication:
void assertRequestBeforeTest(final Request request) {
assertThat(request.getId(), nullValue());
assertThat(request.getName(), nullValue());
assertThat(request.getDataList(), hasSize(0));
}
void assertRequestAfterTest(final Request request, final String id, final String name) {
assertThat(request.getId(), is(id));
assertThat(request.getName(), is(name));
assertThat(request.getDataList(), notNullValue());
var data = request.getDataList().get(0);
assertThat(data, notNullValue());
assertThat(data.getId(), is(id));
assertThat(data.getName(), is(name));
}
And the tests:
@Test
void setter_onNullFields() {
var request = new Request(null, null, new ArrayList<>());
assertRequestBeforeTest(request);
request.setId("id-new");
request.setName("name-new");
assertRequestAfterTest(request, "id-new", "name-new");
}
@Test
void setter_onExistingFields() {
var request = new Request("id", "name", new ArrayList<>());
assertRequestBeforeTest(request);
request.setId("id-new");
request.setName("name-new");
assertRequestAfterTest(request, "id-new", "name-new");
}
@Test
void builder() {
var requestBuilder = Request.builder().dataList(new ArrayList<>());
var request = requestBuilder.id("id-new").name("name-new").build();
assertRequestAfterTest(request, "id-new", "name-new");
}