Lombok, a compile time Java annotation preprocessor to minimize code size
In this article we are going to see how can we use lombok inside our regular Java Code to minimize code length & redundancy.
What is lombok?
Lombok , a compile time annotation pre-processor that helps to inject some code in compile time. Before going in detail, i request you should see the video from their site . I am not going live demo like this but I will show how we can use this inside project (including maven life cycle) .
Let’s start with basic understanding. As I have told, lombok is a compile time annotation pre-processor. What does that means?
-> it will work in compile time (we can see effect during writing code)
-> we need dependencies in class path during compilation (with javac command execution)
-> We need to have plug-in support to see effect in IDE while coding.(as IDEs compiles during coding/saving)
Lombok has several Utility / feature . We will go through main items of them that I have used so far.
Note : To know about annotation , you may see my this post.
Installation :
Eclipse : Download from this link, install it (you need to show eclipse installation directory)
(I have checked STS/eclipse Version: 3.7.3.RELEASE)
Intellij IDEA : Just install lombok plug-ins. (File -> Settings -> plugins -> search/brows to see, then install)
Or : Link of plugin
Now : Based on IDE behavior, you may need to enable annotation preprocessor to let the plug-ins works. (usually modern IDE have this default)
From Eclipse :
IntelliJ IDEA :
Project setting up :
I will use Maven (you may use gradle in same manner) . My Maven version is 3.3.9.
Step 1 : In pom.xml , add dependency
dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.8</version> </dependency> </dependencies>
You may get updated version from maven central.
Step 2: As we see, lombok is a compile time pre processor, so, we need compiler. So, adding maven compiler plug-in inside build -> plugins->plugin
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <compilerVersion>1.8</compilerVersion> <source>1.8</source> <target>1.8</target> </configuration> </plugin>
You can see, I have defined the source & target version to 1.8.
Step 3 : Now we need to add lombok plugin for working during project compilation. For this we need entry in plugin Management and add plugin with parameters in build section.
<pluginManagement> <plugins> <plugin> <groupId>org.projectlombok</groupId> <artifactId>lombok-maven-plugin</artifactId> <version>1.16.8.0</version> </plugin> </plugins> </pluginManagement>
adding plugin with parameter
<plugin> <groupId>org.projectlombok</groupId> <artifactId>lombok-maven-plugin</artifactId> <version>1.16.8.0</version> <configuration> <encoding>UTF-8</encoding> </configuration> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>testDelombok</goal> <goal>delombok</goal> </goals> </execution> </executions> </plugin>
Spatial note here :
1. Encoding is necessary
2. you can see I use 2 goals, these are spacial goals defined for lombok for test & source scope definition. I use both as my test code also needs lombok.
So, my Build section is become this.
<build> <pluginManagement> <plugins> <plugin> <groupId>org.projectlombok</groupId> <artifactId>lombok-maven-plugin</artifactId> <version>1.16.8.0</version> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <compilerVersion>1.8</compilerVersion> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.projectlombok</groupId> <artifactId>lombok-maven-plugin</artifactId> <version>1.16.8.0</version> <configuration> <encoding>UTF-8</encoding> </configuration> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>testDelombok</goal> <goal>delombok</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
And, for logging , we need to have dependencies. I will add all type of log example. So adding all of them together
<!--Logging external dependencies--><dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.21</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.21</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-ext</artifactId> <version>1.7.21</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.5</version> </dependency>
So, finally my build section of POM looks like this.
Now, its time to see Each feature Usages :
Note : For both eclipse and IntelliJ , I am using Outline View to look at the effects. To enable outline :
Eclipse : Window -> Show view -> Outline
IntelliJ: View -> Tool Buttons , you will structure.
@Getter @Setter : It heps to make getter setter with variable. It also supports access level parameters to define scopes of getters & setters.
Parameter : Takes a Enum parameter AccessLevel
PUBLIC = Publicly accessible
MODULE, PACKAGE = same as default (not using any modifier)
PROTECTED = same as protected
PRIVATE = same as private
NONE = there will not be implementation
In class level :
Overriding class level getter :
@ToString : This is implementation of toString(), we can use only for the class level.
Parameters :
includeFieldNames() : boolean type => define all field inclusion
callSuper(): boolean type => calling super
doNotUseGetters() : boolean type => avoid using getters of the fields.
exclude() : String array of field names=> define field exclusion
of() : String array of field names = > defines which to be added (explicitly)
@Data : It is combination of multiple annotations.
Where : We can use before a class /type
Parameters :
Note : Data consists of
1. @Getter,
2. @Setter.
3. @RequiredArgsConstructor
4. @Tostring
5. @EqualsAndHashCode
Example :
IntelliJ :
@Value : This is just an immutable value type of @Data.
Parameter : staticConstructor entry will make default constructor as private
@Builder : Adding a default builder class with your class. It is simply a builder (like builder pattern, with parameters, see example in image)
@Singular : For notifying a collection (support guava & java util only) . It include 2 adder methods, single add, add all.
val: This makes local final variable (inside method)
(just immediate after this() or super() called)
Usages :
1. Use like as var(js/c#) , it will act as final
2. Inside foreach loop.
public class ValExample {
val items; public void aMethod() { val store = new Hashtable<String, String>(); store.put("one", new String("Shantonu")); val func = store.get("one"); System.out.println(func.toLowerCase()); store.put("two", "Andrii"); store.put("three", "Oleks"); for(val v: store.entrySet()){ System.out.println("KEY =" +v.getKey()+", VAL = "+ v.getValue()); } } }
@NotNull : This will add null check on variable and throws null pointer exception.
Scope of use : method, parameter, local variable
with @NotNull
@EqualsAndHashCode : It simple add equals(Object other), and hashCode() to class. (so it is class level annotation).
It supports parameters to customize those equals and hash code methods. All parameters are same as @ToString.
@Cleanup: It is a easy way to cleanup the resources. It actually ensures , the resources close() method will be called in finally block of try.
Only Local variable :
Calling close method for resources. if you have another method name, then call you need value=thatMehtodName (like exit)
You can see a simple example from here. No need try catch.
public class CleanupEx { public static void main(String[] args) throws IOException { String pom = System.getProperty("user.dir") + "/pom.xml"; String io = System.getProperty("user.dir") + "/logs/io.txt"; @Cleanup InputStream in = new FileInputStream(pom); @Cleanup OutputStream out = new FileOutputStream(io); int reading; char c; while ((reading=in.read())!=-1){ c=(char)reading; out.write(c); } out.flush(); } }
Note : In my opinion, it is nice to use this when you are not caring about managing resources. If you like to use your resources by your logic, better avoid this. Example, multi threaded resource usages.
Logging using lombok :
@log: This is one of the best usable feature. This picture shows all loggers to gather. My example in github will shows details.
We need to set log before class, thats all. It will provide a static variable log and we can use it based on what type of log we are using.l
Parameter : it takes topic as parameter , by default it is class name. we can set log topic.
Note : for different log implementation we need different type of configuration. Lombok doesn’t provide any configuration help, it just inject code. So, we need to add depend on what type of log I am adding.
My example in github contains all 6 types of log configurations. See pom file carefully to know dependencies as well as resources for configuration files.
Lombok Examples github link : https://github.com/sarkershantonu/practice-projects/tree/master/lombok-examples
Note : There are lot more regular feature and experimantal features I skipped due to not scope of my tests(spatially @Synchronized) . I will add other one by one in github repository and add referrence notes here.
Reference: | Lombok, a compile time Java annotation preprocessor to minimize code size from our JCG partner Shantonu Sarker at the A Test Developer’s blog blog. |