Expose field annotations in getter/setter/constructor?

171 views
Skip to first unread message

Tillmann Gaida

unread,
Nov 15, 2014, 5:01:07 AM11/15/14
to project...@googlegroups.com
I make heavy use of JSR 305 annotations and it leads to these annotation stacks:

@SomeAnnotation
@Getter(onMethod = @__(@
SomeAnnotation))
@Setter(onParam = @__(@
SomeAnnotation))
SomeType field;


Furthermore, I then need to manually write a constructor. I'd love to see JSR 305 annotations exposed on getters, setters and constructors (I always have to write those manually). The question is how this can be generalized to all annotations, since an exception for JSR 305 seems silly. Off the top of my head:

@Expose(@__(@SomeAnnotation))
SomeType field;

creates

@SomeAnnotation
SomeType field;

@SomeAnnotation
public SomeType getField() {
  return field;
}

public void setField(@SomeAnnotation field) {
  this.field = field;
}

(if getter/setter are constructed) and also puts @SomeAnnotation on the corresponding argument of any generated constructor.

Alternatively, @Getter, @Setter, @Data, @Value, @AllArgsConstructor, @RequiredArgsConstructor, ... could get an exposeFieldAnnotations flag or something.

I suspect that one could come up with better solutions. For now the question is if this issue is too specific for lombok or if it can be discussed.

Reinier Zwitserloot

unread,
Nov 18, 2014, 8:21:29 AM11/18/14
to project-lombok
Not all annotations are legal on both fields and methods, but using resolution to try to figure this out is too expensive and complicated.

We did come up with the 'text file' tech (a text file listing a bunch of types, to which we can easily accept new commits, this sounds acceptable to us for storing 'domain knowledge' on such topics as: Which annotations like to be copied over to where), that might apply here: List the JSR 305 annotations so that lombok knows specifically to copy these to the params of methods and the generated getters.

So, let's get going on this. We need the FQN of each and every annotation type that is relevant, and we need to know a few things about it. Specifically:

* Should an annotation on the field copy to the param on the setter, and the param on the constructor (and the param on the builder, if present, and on the wither)?
* Should an annotation on the field copy to the getter?
* Should the annotation then be removed from the field? This may never work right (I'm afraid javac will just abort right off the bat without ever invoking lombok if you put an annotation that is explicitly defined not to be legal on fields, on a field).
* What does it 'mean'? Specifically, is there behaviour that should influence lombok? For example, right now any annotation called NonNull, no matter the package, imparts the null check behaviour onto lombok, but for the generate-nullcheck-in-any-method feature (where lombok inject if (x == null) throw new NPE("x") on the first line of a method if the param is annotated with lombok's own NonNull). We don't look at NotNull because JPA uses that, and NotNull in JPA land means something completely different. We can use the text file tech to the same purpose here: Have a listing of which annotations actually mean: Ensure that this field is never null, throw exceptions if that would ever happen.

Something like:

annotations.txt:

lombok.NonNull = NULL-PARAM-CHECK NULL-PROPERTY-CHECK COPY-TO-PARAM COPY-TO-GETTER
javax.annotation.Nonnull = NULL-PROPERTY-CHECK COPY-TO-PARAM COPY-TO-GETTER
javax.annotation.Nullable = COPY-TO-PARAM COPY-TO-GETTER
javax.annotation.RegEx = COPY-TO-PARAM COPY-TO-GETTER
javax.annotation.Inject = COPY-TO-PARAM REMOVE

Here PROPERTY-CHECK means that lombok generates nullcheckers in the builder, constructor, and setter, and PARAM-CHECK means lombok will interpret the presence of this annotation on any parameter anywhere as indicating the need to generate an if (x == null) line at the top of that method / constructor.

The COPY string identifies that this annotation needs to be copied over. (COPY-PARAM is copy to builder, constructor, setter, and wither, and COPY-GETTER means to copy to getter). REMOVE means to remove it from fields, though, as I said, that may not actually ever work.

We don't use JSR305 that much (though I know Roel finds this stuff interesting and has looked at it before, and the same goes for me), so preferably someone more familiar with the framework thinks this through and contributes the text file defining the appropriate definitions for all the JSR305 (and any others you can think of).

We can resolve types, kind of, in a cheap fashion. Our type resolver can answer questions of the form:

"This reference to Nonnull here, is that shorthand for javax.annotation.Nonnull?", and lombok can answer that question without resolution (by analysing the import and package statements in the source file), only getting it wrong when you have a star import on javax.annotation and a package-local type named Nonnull (lombok would say that is javax.annotation.Nonnull, but under those conditions, it isn't). Thus, we can 'find' the named annotations without resolution, if we have a text file that lists complete names.



 --Reinier Zwitserloot

--
You received this message because you are subscribed to the Google Groups "Project Lombok" group.
To unsubscribe from this group and stop receiving emails from it, send an email to project-lombo...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Martin Grajcar

unread,
Nov 18, 2014, 9:08:49 PM11/18/14
to project...@googlegroups.com
On Tue, Nov 18, 2014 at 2:20 PM, Reinier Zwitserloot <rei...@zwitserloot.com> wrote:
lombok.NonNull = NULL-PARAM-CHECK NULL-PROPERTY-CHECK COPY-TO-PARAM COPY-TO-GETTER

I guess, I'd prefer slightly shorter names. It's no problem to write this as there are not so many interesting annotations, but when trying to read it, I get soon lost among all those similar-looking words shouting on me.
 
REMOVE means to remove it from fields, though, as I said, that may not actually ever work.

The second best choice would be probably
@Expose(@__(@SomeAnnotation))
as proposed by the OP. It's still way better than thinking about what Lombok annotation should be polluted and how again and again.

I'm not sure how much this is related to the proposed feature allowing to create own annotations as shortcuts. I could imagine a similar file defining things like

lombok.customized.InjectingConstructor = @RequiredArgsConstructor(onConstructor=@__(@Inject))

Unlike with your file, this one should be user-specific (like lombok.configuration), though some common patterns will surely emerge.
 
"This reference to Nonnull here, is that shorthand for javax.annotation.Nonnull?", and lombok can answer that question without resolution (by analysing the import and package statements in the source file), only getting it wrong when you have a star import on javax.annotation and a package-local type named Nonnull (lombok would say that is javax.annotation.Nonnull, but under those conditions, it isn't). Thus, we can 'find' the named annotations without resolution, if we have a text file that lists complete names.

As I did not use any star import for years and never defined anything called Nonnull, I guess, that's more than good enough. Star imports are frown upon and useless as the IDE takes care about imports. Reusing names already occurring in the project is a good way to confuse oneself, so they should be avoided, too.

Reply all
Reply to author
Forward
0 new messages