Java lombok Tutorial | Part 2


@Data Annotation

A shortcut for @ToString@EqualsAndHashCode@Getter on all fields, @Setter on all non-final fields, and @RequiredArgsConstructor!


@Data is a convenient shortcut annotation that bundles the features of @ToString@EqualsAndHashCode@Getter / @Setter and @RequiredArgsConstructor together: In other words, @Data generates all the boilerplate that is normally associated with simple POJOs (Plain Old Java Objects) and beans: getters for all fields, setters for all non-final fields, and appropriate toStringequals and hashCode implementations that involve the fields of the class, and a constructor that initializes all final fields, as well as all non-final fields with no initializer that have been marked with @NonNull, in order to ensure the field is never null.



package tutorial.interviewbubble.LombokSampleApplication;

/**
 * Driver Application to test Lombok Project
 *
 */
public class App 
{
    public static void main( String[] args )
    {

    Person person = new Person("Tom", 23);
    
    System.out.println("Printing Object "+person);

    }


}

package tutorial.interviewbubble.LombokSampleApplication;

import lombok.Data;
import lombok.NonNull;

/* in Project use only import lombok.* here i am using All imports to show you which classes from lomlok project we are using */
@Data
public class Person {
final private String firstName;
    final private String lastName="Welch";
    @NonNull private int age;
private double salary;
}


Output:
Printing Object Person(firstName=Tom, lastName=Welch, age=23, salary=0.0)


  • All generated getters and setters will be public. To override the access level, annotate the field or class with an explicit @Setter and/or @Getter annotation. You can also use this annotation (by combining it with AccessLevel.PACKAGE) to suppress generating a getter and/or setter altogether.
  • no constructor will be generated if any explicitly written constructors already exist
  • parameters of these annotations (such as callSuperincludeFieldNames and exclude) cannot be set with @Data. If you need to set non-default values for any of these parameters, just add those annotations explicitly; @Data is smart enough to defer to those annotations.
  • At first glance it looks very convenient (one annotation instead of five) but, unfortunately, we cannot specify the fields for @EqualsAndHashCode and @ToString so it is not a good idea to use the @Data annotation unless the class is really a very simple POJO, without complex fields
  • @Data does not generated automatically a no args constructor, required by JavaBeans and XML conversions so a @NoArgsConstructor annotation is also needed.

@Data can handle generics parameters for fields just fine. In order to reduce the boilerplate when constructing objects for classes with generics, you can use the staticConstructor parameter to generate a private constructor, as well as a static method that returns a new instance. 

@Data(staticConstructor="of")
  public static class Exercise {
    private final String name;
    private final T value;
  }


 public static class Exercise {
    private final String name;
    private final T value;
    
    private Exercise(String name, T value) {
      this.name = name;
      this.value = value;
    }
    
    public static  Exercise of(String name, T value) {
      return new Exercise(name, value);
    }

// GEETER SETTER EQUALS HASHCODE FUNCTIONS
}

@Value Annotation

@Value is the immutable variant of @Data
  1. all fields are made private and final by default, and 
  2. setters are not generated. 
  3. The class itself is also made final by default, because immutability is not something that can be forced onto a subclass. 
  4. Like @Data, useful toString()equals() and hashCode() methods are also generated, each field gets a getter method, and 
  5. a constructor that covers every argument (except final fields that are initialized in the field declaration) is also generated.
Note: It is possible to override the final-by-default and private-by-default behavior using either an explicit access level on a field, or by using the @NonFinal or @PackagePrivate annotations.
It is possible to override any default behavior for any of the 'parts' that make up @Value by explicitly using that annotation



package tutorial.interviewbubble.LombokSampleApplication;

import lombok.Value;

/* in Project use only import lombok.* here i am using All imports to show you which classes from lomlok project we are using */
@Value
public class Person {
String firstName;
    String lastName="Welch";
    int age;
double salary;
}



package tutorial.interviewbubble.LombokSampleApplication;

import lombok.Value;
import lombok.AccessLevel;
import lombok.experimental.NonFinal;
import lombok.experimental.Wither;

/* in Project use only import lombok.* here i am using All imports to show you which classes from lomlok project we are using */
@Value
public class Person {
String firstName;
    String lastName="Welch";
    @Wither(AccessLevel.PACKAGE) @NonFinal int age;
double salary;
}




package tutorial.interviewbubble.LombokSampleApplication;

/**
 * Driver Application to test Lombok Project
 *
 */
public class App 
{
    public static void main( String[] args )
    {

    Person person = new Person("Tom", 23,3232323.22);
    
    System.out.println("Printing Object "+person);

    }

}

OutPut: 
Printing Object Person(firstName=Tom, lastName=Welch, age=23, salary=3232323.22)



@Cleanup Annotation

Automatic resource management: Call your close() methods safely with no hassle.

Lombok provides a way of achieving Automatic resource release, and more flexibly via @Cleanup. Use it for any local variable whose resources you want to make sure are released. No need for them to implement any particular interface, you’ll just get its close() method called.

@Cleanup InputStream is = this.getClass().getResourceAsStream("res.txt");

Your releasing method has a different name? No problem, just customize the annotation:

@Cleanup("dispose") JFrame mainFrame = new JFrame("Main Window");
Note: By default, the cleanup method is presumed to be close(). A cleanup method(Hereit is dispose) that takes 1 or more arguments cannot be called via @Cleanup.

Suggestion For Developers: 
If you are on Java7 or aboue don't use @Cleanup Annotation use Try-with-resources. Try-with-resources supports handling of multiple resources at once. Also it is build-in feature of Java.



@Builder Annotation

@Builder can be placed 

1. on  a class, or 

2. on a constructor, or 

3. on a method. 

While the "on a class" and "on a constructor" mode are the most common use-case, 


1. @Builder Annotations on a method: @Builder is most easily explained with the "method" use-case.

A method annotated with @Builder (from now on called the target) causes the following 7 things to be generated:
  • An inner static class named FooBuilder, with the same type arguments as the static method (called the builder).
  • In the builder: One private non-static non-final field for each parameter of the target.
  • In the builder: A package private no-args empty constructor.
  • In the builder: A 'setter'-like method for each parameter of the target: It has the same type as that parameter and the same name. It returns the builder itself, so that the setter calls can be chained, as in the above example.
  • In the builder: A build() method which calls the method, passing in each field. It returns the same type that the target returns.
  • In the builder: A sensible toString() implementation.
  • In the class containing the target: A builder() method, which creates a new instance of the builder.


2. @Builder Annotations on a constructor:
Now that the "method" mode is clear, putting a @Builder annotation on a constructor functions similarly; effectively, constructors are just static methods that have a special syntax to invoke them: Their 'return type' is the class they construct, and their type parameters are the same as the type parameters of the class itself.


3. @Builder Annotations on a class: 
Finally, applying @Builder to a class is as if you added @AllArgsConstructor(access = AccessLevel.PACKAGE) to the class and applied the @Builder annotation to this all-args-constructor. This only works if you haven't written any explicit constructors yourself. If you do have an explicit constructor, put the @Builder annotation on the constructor instead of on the class.



package tutorial.interviewbubble.LombokSampleApplication;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;

@Getter
@EqualsAndHashCode
@AllArgsConstructor
@Builder
public class BuilderExample {
  private final String firstname;
  private final String lastname;
  private final String email;
}




@Builder and generics

package tutorial.interviewbubble.LombokSampleApplication;

import lombok.Builder;

@Builder
public class LombokAndGenerics {
  private T name;
}



@Builder and Inheritance



package tutorial.interviewbubble.LombokSampleApplication;

import lombok.AllArgsConstructor;
import lombok.Builder;

@AllArgsConstructor
class Parent {
  private String a;
}

public class lombokBuilderInheritance extends Parent {

  private String b;
  @Builder
  private lombokBuilderInheritance(String a, String b){
    super(a);
    this.b = b;
  }
}


















Comments