9

Given the following classes with the Lombok annotations @Data and @SuperBuilder

@Data
@SuperBuilder
public abstract class Parent {

    protected final String userId;
    protected final Instant requestingTime;
}

@Data
@SuperBuilder
public class Child extends Parent {

    private final Instant beginningDate;
    private final Instant endingDate;
    private final Collection<String> fields;
}

I am getting the following error appearing over the @Data annotation in the Child class:

Implicit super constructor Parent() is undefined. Must explicitly invoke another constructor.

Is there a way to configure a non-default constructor on the Child class's @Data annotation in order to have all final fields on both the Child and Parent classes initialized when invoking the Builder?

I have tried a few different combinations of the @Data, @Getter, @Setter annotations with the @SuperBuilder annotation on both the child and parent classes, but haven't found a working solution yet. I am using Lombok 1.18.10.

For reference, this question is related

EDIT

This is effectively the constructor that Lombok should be constructing and invoking on the SuperBuilder.build() operation.

public Child(
    final String userId,
    final Instant requestingTime,
    final Instant beginningDate,
    final Instant endingDate,
    final Collection<String> fields) {

    super(userId, requestingTime);
    this.beginningDate = beginningDate;
    this.endingDate = endingDate;
    this.fields= fields;
}

As requested, this is how I would expect to invoke the builder on the Child object.

final Child child = Child.Builder()
                         .userId(<value>)
                         .requestingTime(<value>)
                         .beginningDate(<value>)
                         .endingDate(<value>)
                         .fields(<value>)
                         .build();
burtmacklin16
  • 715
  • 2
  • 13
  • 31

2 Answers2

5

AFAIK, @Data generates a @NoArgsConstructor, which is just wrong. Actually, @Data is wrong per se, as it's meant for mutable classes; @Value would be better, but it can't deal with the super constructor either.

So remove @Data, add @Getter, @EqualsAndHashCode, @ToString and whatever you need. Don't forget to add callSuper=true in the subclass.


This is effectively the constructor that Lombok should be constructing and invoking on the SuperBuilder.build() operation.

public Child(
    final String userId,
    final Instant requestingTime,
    final Instant beginningDate,
    final Instant endingDate,
    final Collection<String> fields) {

    super(userId, requestingTime);
    this.beginningDate = beginningDate;
    this.endingDate = endingDate;
    this.fields= fields;
}

No, that's not how SuperBuilder works. This is actually Lombok can't do as it can't see the super fields. Instead, the builder uses something like

public Child(ChildBuilder b) {    
    super(b);
    this.beginningDate = b.beginningDate;
    this.endingDate = b.endingDate;
    this.fields= b.fields;
}

You can believe what Jan Rieke says, he wrote it.

Jan Rieke
  • 7,027
  • 2
  • 20
  • 30
maaartinus
  • 44,714
  • 32
  • 161
  • 320
  • Thanks for the suggestion. Removing @Data now causes a compilation error because the ```final``` fields are not being initialized. Adding a ```@RequiredArgsConstructor``` to both the ```Child``` and ```Parent``` classes results in an issue in the ```Child``` class stating the ```Parent()``` super constructor is not defined. – burtmacklin16 Feb 20 '20 at 18:51
  • I can implement the correct constructor explicitly in the ```Child``` class - it needs to take the arguments for ```Child``` as well as ```Parent``` and then invoke the ```Parent```'s @RequiredArgsConstructor. Ideally Lombok would be doing this automatically. – burtmacklin16 Feb 20 '20 at 18:58
  • 1
    Why do you want an additional constructor at all if you instantiate via builder? – Jan Rieke Feb 20 '20 at 20:19
  • The additional constructor is not necessary for how I want to instantiate the object, it seems necessary in order for the code to compile. All of the fields in both the ```Parent``` and ```Child``` class are marked ```final```, so without it, the code doesn't compile - unless I am missing something with how ```SuperBuilder``` is designed to work. – burtmacklin16 Feb 20 '20 at 20:44
  • 2
    `@SuperBuilder` uses its own special constructor, which just takes a builder instance as argument. No need to define anything else. I just verified that your code compiles just fine once you remove the `@Data`. – Jan Rieke Feb 20 '20 at 22:23
  • 1
    @burtmacklin16 Could you create a full project (e.g., on github) demonstrating your problem? You may have found a bug, but your usage of `SuperBuilder` after the removal of `@Data` is pretty basic and for sure works for many Lombok users, so there must be something special with your setup. Are you using IDEA? – maaartinus Feb 21 '20 at 01:25
  • I am using Eclipse 2018-12. – burtmacklin16 Feb 21 '20 at 14:40
0

@Data annotation implicitly generate code for below mentioned functionalities:


  • setter
  • getter
  • toString
  • equallAndHashCode
  • constructor(for required arguments only)

It means constructor declaration of loombok will generate code for Parent class will be as mentioned below:

Person(String userId, Instant requestingTime)

Similarly for Child class:

Child(Instant beginningDate, Instant endingDate, Collection fields)


Now as your program is throwing exception that

Parent() is undefined in parent class.

Please annotate your class with :

@NoArgsConstructor

This will generate required default constructor.

Atul Kumar
  • 99
  • 8
  • If Lombok attempts to use the NoArgsConstructor on the ```Parent``` class through the ```Child``` class's RequiredArgsConstructor, how would it be possible to set the fields in the ```Parent``` class that are marked ```final```? – burtmacklin16 Feb 20 '20 at 19:10
  • @burtmacklin16 As you are using SuperBuilder here, Please try creating objects with builder. Here SuperBuilder will generate the builder for both parent and child. You will be able to set value of parent class fields with child class builder object. Let me know if you feel that sample code may be more helpful. – Atul Kumar Feb 20 '20 at 19:27
  • Unfortunately adding the @NoArgsConstructor isn't an option because the final fields on the abstract ```Parent``` class will not be initialized. – burtmacklin16 Feb 20 '20 at 19:32
  • You are initializing child class via Constructor? If yes, can you please share the use case for SuperBuilder annotation here. – Atul Kumar Feb 20 '20 at 19:34
  • Ideally it would be done through the ```SuperBuilder``` but without the explicit constructor in place that I mentioned in my edit, the code will not even compile. – burtmacklin16 Feb 20 '20 at 19:37