This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!

background

If you want to modify a POJO class by adding a field to it, you start reporting errors:

  • The class already has a constructor, but in order not to break the way the class was used, a new constructor is written, leaving the previous constructor unchanged.
  • This class is decorated by Lombok’s @value annotation

To solve

  1. Error message: the variable is not initialized. So the main check is to see if it was initialized.
  2. In the overridden constructor, I have already initialized the variable.
  3. The only unfamiliar thing in this class is the @value annotation, so look at the annotation in the annotation:
/** * Generates a lot of code which fits with a class that is a representation of an immutable entity. *<p> * Equivalent  to {@code@Getter @FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE) @AllArgsConstructor @ToString @EqualsAndHashCode}. *<p> * Complete documentation is found at<a href="<https://projectlombok.org/features/Value>">the project lombok features page for&#64; Value</a>. * *@seelombok.Getter
*@seelombok.experimental.FieldDefaults
*@seelombok.AllArgsConstructor
*@seelombok.ToString
*@seelombok.EqualsAndHashCode
*@seelombok.Data
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Value {
	/**
	 * If you specify a static constructor name, then the generated constructor will be private, and
	 * instead a static factory method is created that other classes can use to create instances.
	 * We suggest the name: "of", like so:
	 * 
	 * <pre>
	 *     public @Value(staticConstructor = "of") class Point { final int x, y; }
	 * </pre>
	 * 
	 * Default: No static constructor, instead the normal constructor is public.
	 * 
	 * @return Name of static 'constructor' method to generate (blank = generate a normal constructor).
	 */
	String staticConstructor(a) default "";
}
Copy the code

The purpose of this annotation is to generate a set of matching code for an immutable entity class. The effect is equivalent to a combination of the following annotations: @Getter@fieldDefaults (makeFinal=true, level= AccessLevel.private) @AllArgsConstructor @ToString @EqualSandHashCode.

One particular annotation is @fielddefaults (makeFinal=true, level= AccessLevel.private). This is an annotation that sets default attributes for fields. The attribute value in the annotation specifies whether to make instance fields final. The access level is set to private.

/** * Adds modifiers to each field in the type with this annotation. *<p> * Complete documentation is found at<a href="<https://projectlombok.org/features/experimental/FieldDefaults>">the project lombok features page for&#64; FieldDefaults</a>. *<p> * If {@codemakeFinal} is {@codetrue}, then each (instance) field that is not annotated with {@code@NonFinal} will have the {@codefinal} modifier added.
 *<p>
* If {@codelevel} is set, then each (instance) field that is package private (i.e. no access modifier) and does not have the {@code@PackagePrivate} annotation will
 * have the appropriate access level modifier added.
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface FieldDefaults {
	AccessLevel level(a) default AccessLevel.NONE;
	boolean makeFinal(a) default false;
}
Copy the code

If makeFinal is true, then every instance field (except those modified by the @nonFinal annotation) will be modified by the final modifier.

If the level attribute has a value, then each instance field that is privately accessed by the package (that is, not modified by the access modifier) and not modified by the @packageprivate annotation will have a modifier corresponding to the value of the attribute added.

  1. That is, @value marks the POJO class as immutable, and all its member variables that are not decorated by the @NonFinal annotation will be
  2. At this point, I still don’t know where the problem is (poor Java foundation). Keep looking for a solution. Google search found this question:

Lombok @Wither, @Value, @NoArgsConstructor, @AllArgsConstructor do not work together

The answer includes a description of Java Final:

A final variable can only be initialized once, either via an initializer or an assignment statement. It does not need to be initialized at the point of declaration: this is called a “blank final” variable. A blank final instance variable of a class must be definitely assigned in every constructor of the class in which it is declared; similarly, a blank final static variable must be definitely assigned in a static initializer of the class in which it is declared; otherwise, a compile-time error occurs in both cases.

The translation is as follows:

A final-modified variable can be initialized only once by an initializer or assignment statement. It does not need to be initialized at the declaration: this is called a “blank final” variable. The blank final instance variable of a class must be assigned in each constructor of the class that declares it; Similarly, a blank final static variable must be explicitly assigned in the static initializer of the class that declares it; Otherwise, a compilation error will occur in both cases.

  1. It turns out that the new field was not initialized in the original constructor. At this point, the problem is solved.