I've been using Lombok with IntelliJ for a while now. I have installed newest (v. 0.28) Lombok plugin, enabled annotation processing and added a Lombok dependency (v. 1.18.10) in pom.xml. It all worked well until today, when I wanted to implement the experimental #SuperBuilder.
I have a simple hierarchy:
#SuperBuilder
public class User {
private String a;
}
#SuperBuilder
public class Employee extends User {
private int b;
}
#SuperBuilder
public class Employer extends User {
private double c;
}
I wanted to set the fields from parent's class in child's builder, e.g.:
Employee.builder().a("Positive").b(1).build();
Employer.builder().a("Negative").c(-2.1).build();
At the first glance it all seems to work - there are no errors displayed when the file is open and the builder is fine. However after mvn clean compile I get the following result on every #SuperBuilder line (i.e. in each of those 3 classes):
Error:(20) java: cannot find symbol
What am I missing here? I tried updating Lombok plugin version and reinstalling it, but without any success.
I've faced same issue and adding #SuperBuilder to the all "base" classes solved the issue.
Before:
abstract class Parent {
...
}
#SuperBuilder
class Child extends Parent {
...
}
After:
#SuperBuilder // <- addded
abstract class Parent {
...
}
#SuperBuilder
class Child extends Parent {
...
}
Ok, I found it. I missed that the User class was extending a basic class every entity in our application extends. It seemed so obvious and yet I didn't notice...
Anyway, I found out only by running the mvn clean install in terminal - the output was much more verbose that the one in IntelliJ and it pointed out this class. After adding #SuperBuilder annotation on top of it compilation was successful.
But #SuperBuilder(toBuilder=true) is the right way of using it.
Related
We are using Immutables with MapStruct and ran into a problem while converting an entity to dto.
#Value.Immutable
public interface ProjectDto {
String getId();
String getName();
//ProjectStatisticsDto getStatistics();
}
#Value.Immutable
public interface ProjectStatisticsDto {
Long getCount();
}
#Immutable
public interface Project extends Serializable {
#JsonProperty("_id")
String getId();
String getName();
//ProjectStatistics getStatistics();
}
#Immutable
public interface ProjectStatistics extends Serializable {
Long getCount();
}
The mapper class
#Mapper
public interface ProjectMapper {
ProjectMapper INSTANCE = Mappers.getMapper(ProjectMapper.class);
ImmProjectDto toDto(ImmProject project); // This works only when the inner model of project statistics is commented.
//ProjectDto toDto(Project project); THIS DOES NOT WORK (Error 1)
// ImmProjectDto toDto(ImmProject project); After I uncomment the inner class of project statistics then even this does not work (Error 2)
In the cases of error, the issue is exactly the same
Error 1: No implementation was created for ProjectMapper due to having a problem in the erroneous element com.xyz.ProjectDto.
Error 2: No implementation was created for ProjectMapper due to having a problem in the erroneous element com.xyz.ProjectStatisticsDto.
I checked the tests for mapstruct with immutables and there is nothing different I see https://github.com/mapstruct/mapstruct/blob/master/integrationtest/src/test/resources/immutablesBuilderTest/mapper/src/main/java/org/mapstruct/itest/immutables/Person.java.
I tried removing serialization statements but no luck. I added some verbose statements which say
Note: MapStruct: Immutables found on classpath
Note: MapStruct: Using accessor naming strategy: org.mapstruct.ap.spi.ImmutablesAccessorNamingStrategy
Note: MapStruct: Using builder provider: org.mapstruct.ap.spi.ImmutablesBuilderProvider
Note: MapStruct: Using enum naming strategy: org.mapstruct.ap.spi.DefaultEnumMappingStrategy
And this looks absolutely correct
Looking at the title of the question "Inner immutable class with mapStruct" I guess that your immutable classes are inside another class.
This is a known problem for MapStruct (see mapstruct/mapstruct#2198) that already has a PR for it and it will be fixed in the next non patch release.
In the meantime you will have to make your Immutable classes top level classes.
According to the documentation, Lombok has 3 annotations for constructor generation:
#NoArgsConstructor - generates an empty constructor;
#AllArgsConstructor - generates a constructor that initializes all
fields;
#RequiredArgsConstructor - generates a constructor that
initializes only final fields.
They all have an onConstructor property that allows you to specify the annotations with which the generated constructor should be marked.
According to the Javadoc, the syntax for this feature depends on JDK version (nothing we can do about that; it's to work around javac bugs).
Up to JDK7:
#NoArgsConstructor(onConstructor=#__({#AnnotationsGoHere}))
From JDK8:
#NoArgsConstructor(onConstructor_={#AnnotationsGohere}) // note the underscore after onConstructor
I am working on JDK8. However, only the JDK7 variant works for me, while the JDK8 variant does not work (a constructor without annotations is generated).
I checked on JDK11 - same result.
I check with Refactor -> Delombok -> #Constructors.
For example, like this:
#AllArgsConstructor(onConstructor = #__(#Deprecated))
public class SomeClass {
}
the following code is generated:
public class SomeClass {
#Deprecated
public SomeClass() {
}
}
But like so:
#AllArgsConstructor(onConstructor_ = #Deprecated)
public class SomeClass {
}
code like this is generated:
public class SomeClass {
public SomeClass() {
}
}
I noticed that the documentation on the Lombok site only contains a JDK7 style example.
The Javadoc is incorrect or am I doing something wrong?
I found, that it's not the Lombok's bug, it's Lombok IntelliJ plugin bug.
Constructor annotations add in compiled code.
Delombok tool of Lombok IntelliJ plugin incorrect convert Lombok's annotations to vanilla Java code.
I have added Lombok's JAR file in STS (eclipse).
I am using Lombok to create object using builder(). But, I am facing issue in inheritance.
If I am using Lombok's builder pattern to create objects it's working in workspace & in executable JAR file.
But, If I am using Lombok's builder pattern to create objects which inherit another object, then it's not working.
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
class BaseEmp {
private int a;
private int b;
}
#Data
#NoArgsConstructor
#Builder
class Emp extends BaseEmp implements Serializable {
private static final long serialVersionUID = 1L;
#Builder
public Emp(int a, int b) {
super(a, b);
}
}
Emp emp = Emp.builder.a(ipA).b(ipB).build();
In this one when I am printing object, a and b values are null in JAR and working in STS.
But, when I converted to normal object creation in workspace and JAR, in both places it is working.
Means, upon compile, Lombok processor somehow misses inheritance class field.
If you extend another class, you should really think about using #SuperBuilder. Although it is still experimental, the Lombok maintainers made clear that this is mainly because it is a very young, extremely complex feature that will not receive support/bugfixes as fast as the core features. It is unlikely that #SuperBuilder will be redesigned or dropped in the future.
However, if you want to stick with #Builder, you must not have #Builder annotations on both the class and the constructor. Just put it on the constructor and it should work.
Furthermore, your superclass should also not have #Builder, otherwise you'll get a name clash on the builder() method. (You can work around that by renaming it using the parameter builderMethodName.)
I've read other questions regarding lombok's builder and inheritance but none of the solutions have worked. Using Lombok version 1.18.4 and Java 11.
I'm trying to inherit the parent builder while also satisfying an interface, using only immutable fields. This is my class structure:
The Code
public interface FooInterface {
String getFoo();
}
The getFoo logic is very common across all implementations, so I decided to make an Abstract helper to avoid copy-pasting the same code everywhere.
#Data
#SuperBuilder
public abstract class AbstractFoo implements FooInterface {
#Builder.Default
private final String foo = "foo";
}
And the actual Foo implementation:
#Data
#SuperBuilder
public class FooTest extends AbstractFoo {
private final String bar;
}
'Win Condition'
I would like Lombok to
Recognize fields required by the parent class.
Include those fields in the generated Builders of child classes.
In code:
final FooInterface fooTest = FooTest.builder.foo("string").bar("string").build();
assertThat("string").equals(fooTest.getFoo());
assertThat("string").equals(fooTest.getBar());
Attempted Solutions
The problem is, IntelliJ highlights the #Data annotation with this error:
Lombok needs a default constructor in the base class.
If I remove #Data from FooTest I get this error:
There is no default constructor available in base class.
So I removed the #SuperBuilder from AbstractFoo and added a manually-created constructor with all the arguments. The error persists. I've tried other things and annotation combinations, but none have worked.
I also tried -in vain- to set all AbstractFoo fields to protected final, and declare Foo implementations final themselves, which would be consistent with my business rules.
#SuperBuilder isn't supported by current version of IntelliJ IDEA plugin yet.
There's an open issue on project's Github tracker - https://github.com/mplushnikov/lombok-intellij-plugin/issues/513
Although it's targeted for 0.25 release which has been released just a few days ago -
https://github.com/mplushnikov/lombok-intellij-plugin/releases/tag/releasebuild_0.25
Issue still seems to be open and not yet implemented.
I'd suggest to just try version 0.25 and wait for the next release if it won't work.
I have the following code:
import lombok.Builder;
import lombok.Getter;
#Getter
#Builder
public class NameParserResponse {
private boolean match;
}
public class Main {
public static void main(String[] args) {
NameParserResponse nameParserResponse = NameParserResponse.builder().build();
nameParserResponse.isMatch();
}
}
When trying to reference isMatch(), I get:
Ambiguous method call. Both
isMatch () in Response and
isMatch () in Response match
I have also tried removing the #Builder annotation, but this doesn't help.
It looks like I had the Hrisey Intellij plugin installed in addition to the Project Lombok plugin. I must have accidentally installed this when I was looking for the Project Lombok plugin.
After disabling this plugin, the issue was no longer present.
IntelliJ has a refactoring to "de-Lombok" the code, which will expand the Lombok magic out into the more lengthy code it auto-generates behind the scenes. When I've encountered oddities like this before, looking at the actual produced code, instead of just guessing about it, has helped make the problem clearer. YMMV.
Good luck.