Further Design by Contract annotations

101 views
Skip to first unread message

Sebastian Dietrich

unread,
Dec 11, 2021, 4:02:42 PM12/11/21
to Project Lombok
Are there any plans to provide further annotations that can be used for design by contract purposes like @NonNull
e.g. myMethod(@NonEmpty @Length(max=32) String name, @Min(0) int age)

Reinier Zwitserloot

unread,
Jan 2, 2022, 8:16:23 PM1/2/22
to Project Lombok
No, and aggressively so (in that any PRs that add it will be denied unless they come with an explanation of why our concerns are either wrong or adequately addressed, which will take some convincing as we currently think it is impossible to do so. We'd love to be proven wrong, but the keyword there is 'proven'. A PR would have to come with said proof).

Here's the basic gist of why we think this is a bad idea / impossible to deliver in a fashion that fits what lombok is for:

`@NonNull` is about the reference itself, whereas anything else you care to think about isn't about the thing the reference is pointing at.

And therein lies the rub. Whatever does `@NonEmpty` mean? I guess you could make a list. Perhaps:

* If on a `java.lang.String`, then it means the string's length is more than 0.
* If on a `java.lang.Collection`, then it means: its `.size()` returns non-zero.
* If on anything else, it's a compile-time error.

OR perhaps:

* Whatever if it is, it must have an `isEmpty()` method, it will be checked, and it must return `false`.

OR perhaps:

* If on a `java.lang.String`, then it means the string's length __after trimming__ is more than 0. The string "     " also fails the test.
* If on a `java.lang.Iterable`, make an iterator and invoke its `hasNext()` method. It must not be false.

Now, reading all that, tell me: Have you even considered that the first and third option are in any universe the wrong answer, because we forgot about `java.util.Map` which is neither Iterable nor a Collection and yet is obviously something one would consider eligible for a `@NonEmpty` annotation? I bet many wouldn't have, which goes some way to prove that it is actually far more complicated than you think this is. What about `java.nio.file.Path` or `java.io.File` objects and what it should mean for those, or perhaps Stream, InputStream, or Reader? One might expect something there, but it is not possible to non-destructively check for emptiness on these.

Should it be an extensible system where you can register 'handlers' for types and such annotations? How would one go about registering these?

Read up on resolution ( https://github.com/projectlombok/lombok/wiki/LOMBOK-CONCEPT:-Resolution ) - that explains this maxim: Lombok doesn't actually know what `String` might be, at least, not easily. At best you can ask: Is this node `String` in this sourcecode highly likely to be `java.lang.String`? - This thoroughly complicates any attempt at an extensible design.

So, none of these have a clear meaning (e.g. does `@NonEmpty` apply to files? What about all-whitespace strings?) - and even if you accept that significant downside, the system is either non-extensible or requires a sizable manual to read first. None of this is good for lombok.

Sebastian Dietrich

unread,
Jan 4, 2022, 1:56:07 PM1/4/22
to Project Lombok
You name two reasons. The second - that it is probably impossible/complicated/slow - is of course a valid reason, and I am with you that this will be hard to implement properly. But the first and lengthly stated reason is IMHO not valid:

Of course @NonEmpty has - when examined thoroughly - an ambiguous meaning. But that is true for every name and annotation. Just have an equally thoroughly look at @NonNull:
Stating that something is "non null" does not explicitely imply that it is about the reference itself:
* what if it references a weak/soft/phantom reference? Shouldn't it (like with strong references) consider only such references to be null if they reference a null-object?
* what if it references a (dynamic) proxy? Shouldn't it consider only proxies to be null, if they reference a null-object?
* what if it references an Optional? Shouldn't it consider only those optionals to be null, if their isPresent() method returns false?
And besides of that - it needs clarification, why it was named @NonNull and not @NotNull

Lombok has never considered these and has only implicitely ("null-check") documented that @NonNull is just about the reference itself. Nevertheless these are valid use-cases for @NonNull - as valid as your examples above for @NonEmpty.

So as with other frameworks that provide such checks (see e.g. https://javaee.github.io/javaee-spec/javadocs/javax/validation/constraints/NotEmpty.html) it needs documentation to make it 100% clear, what is ment by these. But that is equally true for @NonNull and all other annotations.

Michael Ernst

unread,
Feb 5, 2022, 2:00:45 PM2/5/22
to project...@googlegroups.com
Although Lombok does not contain the annotations you requested, some other frameworks do.

For example, if you use the Checker Framework, then your `@NonEmpty @Length(max=32)` can be stated as `@ArrayLenRange(from=1, to=32)`, and your `@Min(0)` can be stated as `@IntRange(from=0)`.
When using the Checker Framework annotation processor, these annotations are verified at compile time.

See here for notes about using Lombok and the Checker Framework together.

-Mike

On Sat, Dec 11, 2021 at 1:02 PM Sebastian Dietrich <Sebastian...@e-movimento.com> wrote:
Are there any plans to provide further annotations that can be used for design by contract purposes like @NonNull
e.g. myMethod(@NonEmpty @Length(max=32) String name, @Min(0) int age)

--
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/project-lombok/72f5aa2c-9467-4677-aa54-97d20192ed00n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages