Re: Generate constructor with all but one field

10,070 views
Skip to first unread message

Reinier Zwitserloot

unread,
Nov 12, 2012, 4:27:52 PM11/12/12
to project...@googlegroups.com
Hmm, adding an 'exclude' option to @AllArgsConstructor seems like a workable angle.

Anyone else have thoughts on this idea? Putting an 'include' on @AllArgsConstructor seems really weird. Do we need a @SomeArgsConstructor where you must explicitly supply either an include or an exclude? We have a number of ways we can design a feature to give Jammy what he needs, and it seems worth doing. Any suggestions?



On Monday, November 12, 2012 6:12:50 PM UTC+1, Jammy wrote:
Hey guys, finally got round to trying out lombok and I love it! Can't believe I waited so long, brilliant stuff, can't wait to see what else comes out of it.

I've got a question regarding the three constructor annotations, I'm just going through lombokking up (is that a word) my hibernate entities and the only thing that I couldn't tidy up were the constructors. In some cases the entities have over 15 fields, and I want to have a constructor for all of these except the id field. The only way I can see to do this is to annotate all these fields with @NonNull which I am loath to do, firstly because that's a bit messy compared to one @Data annotation, and secondly because it's a little confusing mixing lomboks @NonNull in with entities and the idea that this might represent nullable database fields. What I'm really looking for is a constructor annotation which has an exclude member. Is such a thing available?

Thanks.

Daniel López

unread,
Nov 13, 2012, 3:42:22 AM11/13/12
to project...@googlegroups.com
From a user POV, I think I'd find it clearer to have @ArgsConstructor accepting either an exclude "xor" an include list. I agree that adding parameters to @AllArgsConstructor would be counterintuitive. One could consider also replacing @AllArgsConstructor with @ArgsConstructor with some kind of flag (All?) as another option in order not to have different anotations for similar things... but I'm not sure it would be worth breaking backwards compatibility.

My 2ec,
D.

2012/11/12 Reinier Zwitserloot <rein...@gmail.com>
--
 
 

Jammy

unread,
Nov 13, 2012, 4:22:55 AM11/13/12
to project...@googlegroups.com
Wow, thanks guys you got back super fast! So it's not currently possible? Guess I'll roll my own until an update, still saving masses of boilerplate stuff :).

As for design, I agree that @AllArgsConstructor is pretty definitive, and adding include confuses its meaning. Exclude makes sense however, to me anyway ;).

Roel Spilker

unread,
Nov 13, 2012, 7:20:18 AM11/13/12
to project...@googlegroups.com
How about @Constructor?
--
 
 

Reinier Zwitserloot

unread,
Nov 13, 2012, 7:34:09 AM11/13/12
to project...@googlegroups.com
Do we want:

@Constructor(allArgs=true)

@Constructor(noArgs=true)

@Constructor (this is the default - and is the current @RequiredArgsConstructor)

@Constructor(includes={"field1", "field2"})

@Constructor(excludes={"field1", "field2"})

With all these options being mutually exclusive, or do we want to keep the current 3 annotations and add a 4th with the includes/excludes?

For all this include/exclude stuff (it's also part of @ToString etc), it feels bad that these are stringly typed. We could move to unique excludes annotations that exist inside @ToString etc, so then it would look like:

@Constructor
public class Test {
    @Constructor.Exclude private int unid;
    private String name, address, description, comment;
    private int age;
}

note that, annoyingly, eclipse's auto-fix imports will turn this into just @Exclude along with an "import lombok.Constructor.Exclude;" statement, not really what we're looking for.

Daniel López

unread,
Nov 13, 2012, 8:52:29 AM11/13/12
to project...@googlegroups.com
Would @Constructor(noArgs=true) really be necessary? That would only seem to be needed when the default constructor would add some fields that are required... which means they are final, so a constructor not initialising them would not make sense... right?

I might have missed some corner case as I usually just use the default one :D.
S!
D.

PD: I'm all for compile time checking things instead of "stringly typed" parameters, but I thought you were not fond of class annotations overriden by field annotations... hence the proposed mechanism similar to the current @toString. 

2012/11/13 Reinier Zwitserloot <rein...@gmail.com>
--
 
 

Maaartin G

unread,
Nov 13, 2012, 9:24:10 AM11/13/12
to project...@googlegroups.com
On Tuesday, November 13, 2012 2:52:31 PM UTC+1, GreenEyed wrote:
Would @Constructor(noArgs=true) really be necessary? That would only seem to be needed when the default constructor would add some fields that are required... which means they are final, so a constructor not initialising them would not make sense... right?

I might have missed some corner case as I usually just use the default one :D.

You have (as I nearly have when writing this). "required" means required due to `final` or due to `@NonNull` and ignoring the latter makes sense.

On Tuesday, November 13, 2012 1:34:09 PM UTC+1, Reinier Zwitserloot wrote:
Do we want:
@Constructor(allArgs=true)
@Constructor(noArgs=true)
@Constructor (this is the default - and is the current @RequiredArgsConstructor)
@Constructor(includes={"field1", "field2"})
@Constructor(excludes={"field1", "field2"})
With all these options being mutually exclusive,

I'd say the first two are just like `@Constructor(includes={})` and `@Constructor(excludes={})`, respectively. It's not really obvious to exclude nothing if you want them all, but I could get used to it. There could be a problem with the default annotation values, however, it's something you can solve IIRC. Still, it's ugly, so I'm not really proposing it.

Obviously, the base for `excludes` should be "all". But what should be the base for `includes`? You must include all final fields, so you don't want to mention them explicitly, do you? Should be @NonNull non-final fields be included by default, too? If so, you may want to *both* exclude and include:

@Constructor(include="a", exclude="b")
class C {
int a; // was included explicitly
@NonNull int b; // was excluded explicitly
@NonNull int c; // is included by default (assuming the base is "all required")
final int d; // is always in and can't be excluded
}

This is quite ugly, I know.

or do we want to keep the current 3 annotations and add a 4th with the includes/excludes?

The 5 above options are exclusive, but you might need multiple constructors. The easiest way is probably to stick with multiple annotations. I could propose an ugly alternative:

@Constructor(excludes={"field1", "field2"}, allArgs=true, noArgs=true)

which would be a compact way to define 3 constructors. However, this leaves no place for defining `accessLevel`, `staticName`, or annotations (which we all hope will come again), unless you want them the same for all generated constructors. But you surely  *do not* want to place `@Inject` on multiple constructors.

For all this include/exclude stuff (it's also part of @ToString etc), it feels bad that these are stringly typed. We could move to unique excludes annotations that exist inside @ToString etc, so then it would look like:
@Constructor
public class Test {
    @Constructor.Exclude private int unid;
    private String name, address, description, comment;
    private int age;
}

This looks much nicer, but what if you need multiple constructors? Assuming the `@Constructor.Exclude` annotation works with the new `@Constructor` only and the three old constructor annotation are still available, it should suffice.

note that, annoyingly, eclipse's auto-fix imports will turn this into just @Exclude along with an "import lombok.Constructor.Exclude;" statement, not really what we're looking for.

Eclipse loves to import nested classes although it's rarely a good idea. Calling it `@lombok.Exclude.Constructor` could help here, but it feels a bit strange (OTOH "exclude something" is correct English, not the other way round).

Roel Spilker

unread,
Nov 13, 2012, 10:02:35 AM11/13/12
to project...@googlegroups.com
Yes, one of the reasons we now have distinct annotations is that currently you can only use a specific annotation only once at any location. That will change in java8 though. But I prefer to be able to use lombok in java6 for a while.

Alternatively you can currently create an annotation called @Constructors with a value of type @Constructor[]. But that really sucks. So I prefer to keep using the @XxxArgsConstructors.

If we would use @Constructor to specify fields, we still need the ugly @Constructors annotation if a user wants to generate multiple constructors.

We could also have a load of annotations: @Constructor1, @Constructor2 etc. to work around that problem, but I don't think that that's a better solution.

So I suggest keeping the current annotations and add both @Constructor and @Constructors for specifying fields explicitly.

Roel
--
 
 

Reply all
Reply to author
Forward
0 new messages