How to use the @Value annotation from Project Lombok

by

in

In this post, we discuss what the @Value annotation from Project Lombok does and how to use it. We will also discuss frequently asked questions such as the difference between @Value and @Data.

If you haven’t already, please check out our own Lombok annotations cheat sheet in order to get started with Lombok and the different functionalities that it offers.

What is the @Value annotation from Lombok

The @Value annotation is one of the annotations from Project Lombok that is added to Java classes to make them and their instances immutable. Immutable is just fancy word for non-changeable. This means that immutable objects cannot have their fields changed once they are initialized.

The @Value annotation will do the following when added to a class:

  • It will generate a constructor with all fields in the class as arguments. No zero argument constructor will be generated.
  • It will add getters for every field in the class. No setters will be added.
  • All class fields will be declared final.
  • The class itself will also be declared final. This means that you will no longer be able to inherit from it.
  • A toString, a hashCode and an equals method will be added to the class.

Example of using the @Value annotation

The following class is an example usage of the @Value annotation.

package com.nullbeans.demo.indicators;

import lombok.Value;

@Value
public class ValueClass {

    private int x;

    private float y;

    private String z;

}

As discussed, the class and it’s instances will become unchangeable. The following code highlights all the operations that are generated by Lombok for our test class.

        //Generated constructor
        ValueClass valueClass1 = new ValueClass(1, 2.0f, "3");
        ValueClass valueClass2 = new ValueClass(2, 3.0f, "abc");

        //Generated getters
        int x = valueClass1.getX();
        float y = valueClass1.getY();
        String z = valueClass1.getZ();

        //Generated toString
        String valStr = valueClass1.toString();

        //Generated equals
        boolean isEqual = valueClass1.equals(valueClass2);

        //Generated hashCode
        int hashCode = valueClass1.hashCode();

Notice that there are no setters and there is no zero args constructor. The equivalent vanilla Java code of our test class is as follows.

package com.nullbeans.demo.indicators;

public final class ValueClass {

    private final int x;

    private final float y;

    private final String z;

    public ValueClass(int x, float y, String z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public int getX() {
        return this.x;
    }

    public float getY() {
        return this.y;
    }

    public String getZ() {
        return this.z;
    }

    public boolean equals(final Object o) {
        if (o == this) return true;
        if (!(o instanceof ValueClass)) return false;
        final ValueClass other = (ValueClass) o;
        if (this.getX() != other.getX()) return false;
        if (Float.compare(this.getY(), other.getY()) != 0) return false;
        final Object this$z = this.getZ();
        final Object other$z = other.getZ();
        if (this$z == null ? other$z != null : !this$z.equals(other$z)) return false;
        return true;
    }

    public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        result = result * PRIME + this.getX();
        result = result * PRIME + Float.floatToIntBits(this.getY());
        final Object $z = this.getZ();
        result = result * PRIME + ($z == null ? 43 : $z.hashCode());
        return result;
    }

    public String toString() {
        return "ValueClass(x=" + this.getX() + ", y=" + this.getY() + ", z=" + this.getZ() + ")";
    }
}

Frequently asked questions (FAQ)

What is the difference between @Value and @Data in Project Lombok?

The @Value and @Data annotations perform a similar functionality, but with one key difference. Both annotations generate boilerplate code related to POJO items. However, the @Data annotation does not make your class immutable.

@Value @Data
Makes the annotated class final.Does not make the annotated class final.
Makes all non-static class fields final.Does not make fields final.
Generates an all args constructor.Generates a constructor with only the required fields.
Generates getters. Does not generate any setters.Generates getters. Generates setters for non final fields.
Generates the toString, equals and hashCode methods. Generates the toString, equals and hashCode methods.
Used to make classes and their instances immutable.Used for classic POJO operations

Can you inherit from classes with the @Value annotation?

No. It is not possible. The @Value annotation will declare the annotated class as final and you will no longer be able to inherit from it.

Can you exclude specific fields in the constructor?

No. It is not possible. Only static fields are excluded from the all arguments constructor.

What happens to static fields in classes annotated with @Value?

I would not recommend adding static fields to classes annotated with @Value. These fields are skipped from the all args constructor. No getters are generated for these fields either. However, I noticed that even when I declared these fields public, Lombok changed them to private.

Also, it seems that these fields are declared final when you Delombok the class, even though they are still editable within the class before delomboking. For example, the following code is allowed:

@Value
public class ValueClass {

    private int x;

    private float y;

    private String z;

    public static String xx;

    public static void setXX(String xa){
        xx = xa;
    }

    public static String getXX(){
        return xx;
    }
}

But if you delombok the class, you will get the following code which throws a compile time error.

.........

    public static final String xx; // COMPILE ERROR HERE

    public ValueClass(int x, float y, String z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public static void setXX(String xa){
        xx = xa;
    }

    public static String getXX(){
        return xx;
    }

................

What happens when you combine @Value with @Setter

Nothing happens. The @Value will mark the fields as final and the @Setter will not generate setters for final class fields.

Further info

In this post, we discussed the @Value annotation and the effects it has on classes annotated with it.

Before you go, I would highly recommend that you check out our post regarding the advantages and disadvantages of using Project Lombok. In the post, we compiled the list of pros and cons of using Lombok in your software project, which will help you to be aware of both the benefits and limitations of the framework. This could save you a lot of trouble down the road.

I would also recommend that you take a look at the book “Head First Design Patterns” (click to check info on Amazon). I cannot think of a better book to learn about all the different design patterns from. I found the book full of time tested examples and best practices.

It is important to be knowledgeable about these best practices as it keeps you on paar with other developers and helps you keep your code maintainable and clean even when using frameworks such as Lombok and Spring.