Project Lombok Tutorial
How To Use @Value Annotation With Project Lombok in Java Applications
@Value
is frequently used when creating Immutable classes. Check here if you need a guide for defining immutable Objects.
@Value
annotation is like an "all-in-one" special annotation that groups functionalities from multiple annotations namely:-
- It makes your fields private and final by default.
- Getters will be generated for the class. ie
@Getter
. - An "all args constructor" will be generated for initializing non-intialized fields. ie
AllArgsConstructor
. - It adds no setters. i.e
@Setter(AccessLevel.NONE)
. - The annotated class will itself be final by default.
- A toString() method will be generated for the class i.e
@ToString
. - equals() and hashCode() methods will also be generated for the annotated class i.e
@EqualsAndHashCode
.
This is the case, because we would basically achieve the same by annotating our class with final @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter @EqualsAndHashCode @ToString @AllArgsConstructor
# Dev Environment:
- Apache maven (v3.6.1)
- maven-compiler-plugin (v3.8.1)
- lombok (v1.18.8)
- Apache Netbeans (v10.0)
TIP: For those who would like to follow along with this blog, just clone my repository git clone https://github.com/steven7mwesigwa/java-tutorials.git
and navigate to java-tutorials\project-lombok\value
. In there, you should be able to play around with all the source code used in this blog post.
# Demonstration : (Without Lombok)
Before we move on, let's look at how we would normally type out code for a regular Java immutable object without using any lombok specific annotations.
Let's create a Person
class that will have a manual implementation of @Value
annotation. Full code here
//demo1
package com.stevenmwesigwa.value.demo1;
import java.util.Objects;
public final class Person {
private final String firstname;
private final String lastname;
private final String ssn;
public Person(final String firstname, final String lastname, final String ssn) {
this.firstname = firstname;
this.lastname = lastname;
this.ssn = ssn;
}
public String getFirstname() {
return this.firstname;
}
public String getLastname() {
return this.lastname;
}
public String getSsn() {
return this.ssn;
}
@Override
public int hashCode() {
int hash = 7;
hash = 43 * hash + Objects.hashCode(this.firstname);
hash = 43 * hash + Objects.hashCode(this.lastname);
hash = 43 * hash + Objects.hashCode(this.ssn);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Person other = (Person) obj;
if (!Objects.equals(this.firstname, other.firstname)) {
return false;
}
if (!Objects.equals(this.lastname, other.lastname)) {
return false;
}
if (!Objects.equals(this.ssn, other.ssn)) {
return false;
}
return true;
}
@Override
public String toString() {
return "Person{" + "firstname=" + firstname + ", lastname=" + lastname + ", ssn=" + ssn + '}';
}
}
As you would notice, this is a lot of boilerplate code for just 3 fields in our immutable Person class.
It was actually even more painful for me to paste it here, but i had no choice but to show you how big your code can get.
For those who aren't familiar with what's going on, am basically providing:-
- getters - To be able to return field values.
- toString method - To return a more readable string representation of our object.
- equals method - To check if 2 objects are equal.
- hashCode method - Simply returns a hash code value for the object.
- A constructor - A special constructor that takes
one parameter for each
final
field with no initial value. - NOTE: Our class is
final
, our fields areprivate final
and we have no setters defined.
Now, enough with the manual implementation. Let's try out some magic provided by Lombok specific annotations.
# Using @Value
Annotation From Project Lombok Library : (Lombok)
The project Lombok authors decided to work on a quick solution to eliminate all this boilerplate code with just one annotation.
Adding @Value
annotation right on top of your class informs Lombok to automatically generate all the above listed specifications for your immutable class.
Let's create a Person
class, but this time making use of @Value
annotation... Full code here
//demo2
package com.stevenmwesigwa.value.demo2;
import lombok.Value;
@Value
public class Person {
String firstname;
String lastname;
String ssn;
}
Imagine if i had told you that by annotating my class with @Value
annotation, Lombok would generate all the functionalities we had manually implemented in our previous example.
You can now see how small our code looks. As they say, less code less bugs, this allows us to focus on more important parts of our logic.
# Make Lombok Generate A Private Constructor And A Public Static Factory Method For An Immutable Object.
There're cases when you don't want your client to have direct access to call your constructor.
For a case like this, You normally want to make the constructor private
and provide a public static
factory method wrapper to the client so that they're still able to set field values.
This can be achieved with @AllArgsConstructor(staticName="of")
or @RequiredArgsConstructor(staticName="of")
annotation depending on your use case.
This is cool and fine, though you probably should keep in mind that we're able to achieve the same result by passing a staticConstructor
parameter to @Value
annotation.
i.e @Value(staticConstructor="of").
NOTE: You're free to provide your own "staticConstructor" value, though a lot of developers prefer to use "of".
Let's create a Person
class to demonstrate this behaviour. Full code here
//demo3
package com.stevenmwesigwa.value.demo3;
import lombok.Value;
@Value(staticConstructor="of")
public class Person {
String firstname;
String lastname;
String ssn;
}
With the setup above, the client can easily create a new instance of the class like this Person.of(...)
When we create and run an App.java
class that makes use of this Person class Full code here
, we have successfully returned a string representation of our Person object. i.e Person(firstname=Steven, lastname=Mwesigwa, ssn=585-51-6704)
Lastly, You have the flexibility to change the default behaviour of @Value
annotation by explicitly adding various lombok specific annotations i.e @NonFinal
but you should be cautious about breaking the specifications that make an object truly immutable.
I hope you learn a thing or two from this blog. Thanks for checking it out.
If anything is unclear or you wish to make any corrections, don't hesitate to leave a comment below. Your feedback is greatly appreciated.
Sharing is caring. Share this blog to help out others getting started with 'project Lombok' library for Java applications.
Прощай!