Lombok: combining @Data and @Builder remove the default constructor

Created on 15 Jul 2015  Â·  14Comments  Â·  Source: projectlombok/lombok

_Migrated from Google Code (issue 781)_

enhancement parked

Most helpful comment

:bust_in_silhouette: amine.bouhamidi   :clock8: Feb 06, 2015 at 03:03 UTC

It works if I add @ NoArgsConstructor @ AllArgsConstructor.

But I suggest that combining @ Data and @ Builder will add implicitly both NoArgsConstructor and AllArgsConstructor to keep the code pretty and clean.

All 14 comments

:bust_in_silhouette: amine.bouhamidi   :clock8: Feb 05, 2015 at 07:04 UTC

Please discuss feature requests first on
https://groups.google.com/forum/﹟!forum/project-lombok

What steps will reproduce the problem?

  1. Combining @ Data with @ Builder delete the default constructor without args
    @ Data
    @ Builder
    public class Foo {
    private String bar;
    public static void main (String[] args) {
    // I get compilation Error here
    Foo foo = new Foo();
    }
    }

What is the expected output? What do you see instead?
I expect to have the default constructor without args, because my objects used by Jackson Mapper so Jackson instantiate my Objects using the default constructor not the Builder.

What version of the product are you using? On what operating system?
I am using:

  • JDK 1.8
  • Lombok 1.16.0
  • eclipse juno
  • Ubuntu Desktop 14.04

:bust_in_silhouette: Maaartinus   :clock8: Feb 05, 2015 at 17:57 UTC

No idea about the exact rules, but in principle @ Data implies a @ NoArgsConstructor and @ Builder implies an @ AllArgsConstructor. In case a constructor already exists (possibly due to another annotation), this implication may or may not get omitted according to some subtle implementation details. In any case, I'd go for @ Data @ Builder @ NoArgsConstructor @ AllArgsConstructor to be sure as an explicit constructor annotation gets always honored.

:bust_in_silhouette: amine.bouhamidi   :clock8: Feb 06, 2015 at 03:03 UTC

It works if I add @ NoArgsConstructor @ AllArgsConstructor.

But I suggest that combining @ Data and @ Builder will add implicitly both NoArgsConstructor and AllArgsConstructor to keep the code pretty and clean.

_End of migration_

i ran into the same problem. this problem cause spring3+jersey failed without any error informations.

+1 - made worse by the fact that the IntelliJ plugin for Lombok handles it the "right" way (implying both) and then when compiling, throws an error

This is not a matter of 'just do the right thing', it's quite complicated.

The current behaviour of lombok is that this implies @AllArgsConstructor(access = AccessLevel.PRIVATE) (which is what @Builder implies) and that this removes the implied @RequiredArgsConstructor that @Data implies. This is sensible because the two constructors might overlap.

Let me say that again: "Just generate em all" does not work; what do we do when, for example, ALL fields are final, in which case the constructor @Data wants to make conflicts with the constructor @Builder wants to make. They aren't the same (one is public, the other private).

So, what do we do?

Talked with @rspilker about it and we came to this consensus. Would be nice if it matched your expectations:

  • If there is an explicit constructor already in the source file _OR_ there is at least one @XArgsConstructor on the class, that wins, and neither @Builder nor @Data do anything with constructors, at all.
  • If the 2 constructors to be generated conflict, then @Builder silently wins; the constructor will be generated private. This holds even if it's a no-arg constructor (that'd be some weirdo use of @Builder, but, hey legal).
  • If the @RequiredArgsConstructor would be empty, then, silently, both a public no-args constructor is generated (the one @Data wants to make), as well as the private all-args one (the one @Builder wants to make). __This is a breaking change to lombok API and thus we can't do this lightly!__
  • If the @RequiredArgsConstructor would NOT be empty, but different from what @Builder wants to make, well, that's really weird. In this case, we stick with the old behaviour (@Builder makes its private all-args version, @Data makes no constructor at all), but we emit a warning to explain that this is weird. To get rid of the warning, explicitly add @AllArgsConstructor(access = AccessLevel.PRIVATE), and if the public some-args constructor @Data would make is also desired, add @RequiredArgsConstructor on top of that.

Going to open this up for feedback. It's low priority in either case, and we need to make a call on whether it's worth making a behaviour break to non-experimental API to support this.

We'll gather feedback until at least april 17th, 2017 and make a decision then.

To me it's sounds too complicated. Maybe we could arrive at some simple rules (which may be even equivalent). I wonder what I'm missing.

Let me say that again: "Just generate em all" does not work

I sort of disagree. It may happen that both constructors are the same concerning their arguments. Then you obviously generate just one. The visibility should logically be the higher of the two as both annotations promise some features and by combining the annotations you should get the union of the features. Sure, there can be a good reason for the generated constructor to be private; I just can't see it.

My rules would be:

  • Generate them all (unless already coded manually), solve conflicts as follows:
  • An explicit constructor definition or @XArgsConstructor wins and defines the visibility.
  • Otherwise, take the higher visibility.

I'd stop here. It's a breaking change, but concerns only rare strange usage and it's easy to fix. I'd add a warning with an lengthy explanation in such a case. It could be disabled by avoiding this case (with an explicit constructor definition or annotation) or via configuration.

Simple rules would make live easier in the future, even for those hit by the breaking change. They'll also make merging future features simpler.

+1, it is still an issue in oct. 2017

I you want to show your support for an issue, please use the thumbs-up on the initial comment, instead of adding a +1 comment.

On-topic: We'll look into this. It does make sense, but is technically backwards incompatible, since recompiled current code will add the no-args constructor.

I also meet some issue. When I convert Json String to Java Object, it throws a exception: "default constructor not found". Even if I add "@NoArgsConstructor(access = AccessLevel.PACKAGE)" at my entity class, it still doesn't work. How to find the default constructor by using lombok jar?
I used lombok 1.16.18 version

If you have an allargs constructor or requiredargs constructor you can just
put this in lombok.config:

lombok.anyConstructor.addConstructorProperties = true

On Wed, Oct 24, 2018 at 1:32 PM Markus Oley notifications@github.com
wrote:

+1 from myside - wanted to have an entity be a builder at the same time
for sake of creating testdata easily

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/rzwitserloot/lombok/issues/816#issuecomment-432619580,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAKCRXCU72pgET5m3DQl0F7gLlWR2C5cks5uoE-5gaJpZM4GkWAq
.

--
"Don't only practice your art, but force your way into it's secrets, for it
and knowledge can raise men to the divine."
-- Ludwig von Beethoven

thank you, I will try

I use @NoArgsConstructor,@Builder,@Data at the same time, and the IDE(IDEA) said it needs a no-arg constructor, but finds an all-arg one, and the location of the error is on the line of @Builder.
Looks like the @Builder wins.
(JDK1.8)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

eximius313 picture eximius313  Â·  45Comments

arana198 picture arana198  Â·  53Comments

lex-em picture lex-em  Â·  61Comments

krzyk picture krzyk  Â·  88Comments

pgaschuetz picture pgaschuetz  Â·  42Comments