When working with business entities, many of them will involve a mix of complicated logic, and plain CRUD data. Often we will have some update or create method where an incoming DTO or Request object will have a subset of fields to source details to update the target entity. Even when trying to restrict the scope of the DTO to what an operation needs (an idea I am a big fan of), it may still be course-grained enough for that scope, and still have nullable/optional fields. The resultant code will need to do null checks and decide what to source and what to ignore. Simple example:
1class User {
2 private String firstName;
3 private String lastName;
4
5 // ... getters ...
6
7 // private setters
8 private void setFirstName(String value) {
9 firstName = value;
10 }
11
12 private void setLastName(String value) {
13 lastName = value;
14 }
15
16 public void update(UserDto dto) {
17 if (dto.getFirstName() != null) {
18 setFirstName(dto.getFirstName());
19 }
20
21 if (dto.getLastName() != null) {
22 setLastName(dto.getLastName());
23 }
24 }
25/*
26Digression: generally, I avoid public setters entirely.. business
27objects need specific business methods to manipulate/update them. We
28should stop (yeah... like since 2000 at least) thinking of them as
29anaemic wrappers of fields.
30
31However... private setters can sometimes be useful for encapsulating
32internal checks.
33*/
34}
The issue here is with the null checks. Prior to Java 8, for simple values like Strings, there was no way to factor out the annoying null checks (well, not without more verbose artifacts like wrappers to create, or lose type safety and use reflection, blergh…).
What I really want to say is: setIfNotNotNull(fieldToSet, valueToUseIfNotNull).
Now, since String refs are immutable, we can’t pass them in to update in setIfNotNull(…), the local ref will simply be overwritten with a new value… enter our setters, which have a common format of void setFoo(T val). Making use of Java 8 Method References we can achieve what we want in a typesafe manner:
1class User {
2 // ...
3
4 public void update(UserDto dto) {
5 setIfNotNull(this::setFirstName, dto.getFirstName());
6 setIfNotNull(this::setLastName, dto.getLastName());
7 }
8
9 // note the use of java.util.function.Consumer -- a suitable archetype
10 // for setter methods.
11 private <T> void setIfNotNull(final Consumer<T> setter, final T value) {
12 if (value != null) {
13 setter.accept(value);
14 }
15 }
16}
Voila!
Of course, you can use lambda expressions where we used method references, but in this case, the existing methods encapsulate the logic we need.
Now, to see how far I can take this… I am reminded of Simplicity, Clarity, Generality… it never ceases to amaze me that the timeless 3 traits, more often than not, support each other.
PS. to get up to date with Java 8, Java 8 for the Really Impatient does a stellar job. However, you will have to be patient in parts (I did anyway :P).
PPS. I am still coming to grips with Optional types, and hence have not mentioned this as an alternative to null checks.
PPPS. Sorry about using the term ‘pattern’, it was an attempt to sugar coat the phrase ‘crappy-as rote work’. (There, Tommy). 😛