48

I have this simple code:

@Data
@Builder
public class RegistrationInfo {

    private String mail;
    private String password;

    public RegistrationInfo(RegistrationInfo registrationInfo) {
        this.mail = registrationInfo.mail;
        this.password = registrationInfo.password;
    }
}

First I was using only the @Builder Lombok annotation and everything was fine. But I added the constructor and the code does not compile any more. The error is:

Error:(2, 1) java: constructor RegistrationInfo in class com.user.RegistrationInfo cannot be applied to given types;
  required: com.user.RegistrationInfo
  found: java.lang.String,java.lang.String
  reason: actual and formal argument lists differ in length  

So I have two questions:

  1. Why is Lombok @Builder not compatible with this constructor?
  2. How do I make the code compile taking into account that I need both the builder and the constructor?
Boann
  • 48,794
  • 16
  • 117
  • 146
IKo
  • 4,998
  • 8
  • 34
  • 54
  • From the error, i assume that 1) incorrect number of parameters in the constructor 2) incorrect parameters type is passed to the constructor – Marios Nikolaou Jul 01 '18 at 10:25
  • Does that happen for all constructors or for that particular one? Do you get an error even if you change parameters of constructor? – wdc Jul 01 '18 at 10:25
  • @wdc I have only one constructors (which is mentioned in the code). I need constructor with this parameter to be able to copy the object. – IKo Jul 01 '18 at 10:30
  • 1
    Did you check `@Builder(toBuilder = true)` ? This suppose to give you functionality of copy constructor. `Foo copy = original.toBuilder().build()` – wdc Jul 01 '18 at 10:37
  • @wdc just tried your solution. It's even better then with the constructor. Thanks! – IKo Jul 01 '18 at 10:55

3 Answers3

62

You can either add an @AllArgsConstructor annotation, because

@Builder generates an all-args constructor if there are no other constructors defined.

(Quoting @Andrew Tobilko)

Or set an attribute to @Builder : @Builder(toBuilder = true) This give you the functionality of a copy constructor.

@Builder(toBuilder = true)
class Foo {
    // fields, etc
}

Foo foo = getReferenceToFooInstance();
Foo copy = foo.toBuilder().build();
RubioRic
  • 2,442
  • 4
  • 28
  • 35
wdc
  • 2,623
  • 1
  • 28
  • 41
  • though it is a more concise way and [is backed up by the author](https://stackoverflow.com/a/47093799/4922375), it is also counter-intuitive and involves the creation of an unnecessary instance (`foo.toBuilder()` here) – Andrew Tobilko Jul 01 '18 at 11:36
33

When you provide your own constructor then Lombok doesn't create a constructor with all args that @Builder is using. So you should just add annotation @AllArgsConstructor to your class:

@Data //try to avoid as it's an anti-pattern
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RegistrationInfo {
    //...
}
jumping_monkey
  • 5,941
  • 2
  • 43
  • 58
Cepr0
  • 28,144
  • 8
  • 75
  • 101
13

Presumably, @Builder generates an all-args constructor if there are no other constructors defined.

@Data
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
class RegistrationInfo {

    private String mail;
    private String password;

    private RegistrationInfo(RegistrationInfo registrationInfo) {
        this(registrationInfo.mail, registrationInfo.password);
    }
}
rjdkolb
  • 10,377
  • 11
  • 69
  • 89
Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • 2
    In my case, I use the default constructor so I was forced to also add this annotation `@NoArgsConstructor` – Bludwarf Apr 10 '19 at 10:20