Lombok: Wish: makeFinal parameter for Getter/Setter annotations

Created on 14 Aug 2017  Â·  20Comments  Â·  Source: projectlombok/lombok

Add boolean makeFinal() default false to Getter and Setter.

Though it's already discussed here (discusstion start is here) and will, probably, be "won't fix" anyway — but I consider it useful in some rare cases when getter and/or setter is needed to be explicitly final (not for marking most of getters/setters as final).

As I haven't found this wish in this issue-tracker, I took the liberty to repost it here (at least: to group all requests in one place) — please, feel free to close it immediately, if it's still a no-way.

parked

Most helpful comment

makeFinal will be a useful attribute, because sometimes I need to create final getter/setter to exclude overriding.

All 20 comments

What would be the added value to final getters/setters over public members ?

@grimly The obvious ones: 1. They (can't be overridden but they) still can override a method. 2. They are methods (my rule is: no non-private non-constant fields).

@grimly, do you mean: over the public fields?

Well:

  1. Consistent (unbroken) API.

    Right now you have properties getX/setX and getY/setY backed directly into the fields x and y. Then you add calculated getPhi/setPhi and getRho/setRho properties. Then you decide that it's better to store getPhi/setPhi and getRho/setRho as phi and rho fields, with making getX/setX and getY/setY calculated instead.

  2. Don't forget that nobody forces you to use both lombok.Getter and lombok.Setter at once. You can use trivial (lombok-generated) getter with more complex setter (e.g. this.value = value; repaint()). Or a trivial (lombok-generated) getter with more complex getter (e.g. return this.value != null ? this.value : parent.value). Or only trivial getter with no setter; or trivial getter with other ways to set (like T getValue() + void setValue(T value, String changeReason)).

I think you misunderstood my comment. I asked what would be the added value from final getter and setter over a public field (as I wrote member, my bad).

If you mark your getter and setter final and they are as the dummy ones, they are no differents to public fields

I personally forbid myself the use of final modifier from the countless errors I encountered with container environments (jee, spring), and overriding might be useful at times, so I can't see the use of it but since the discussion is open I want to know what would be your use of it.

@grimly:

I asked what would be the added value from final getter and setter over a public field (as I wrote member, my bad).

I answered exactly that question. Do I write clear enough in 1 and 2 — or should I describe in more details?

Hmmmm. Fine to me. I thought there was more.
We have not the same problems or solutions in mind to solve them.
I see locked APIs as an issue since you may not extend them.

Nevertheless , to be able to generate final getters and setters do not alter current usages of lombok. If the cost is low, what do we lose ?

I see locked APIs as an issue since you may not extend them.

Locked only for incompatible changes. E.g. you can add new method, but not turn method into field or field into method.

Nevertheless , to be able to generate final getters and setters do not alter current usages of lombok. If the cost is low, what do we lose ?

Sorry, I haven't got the question. What do we lose from what?

makeFinal will be a useful attribute, because sometimes I need to create final getter/setter to exclude overriding.

I stumbled upon this one myself today. Had to refactor a non-Lombok project to use Lombok but it has simple getter/setter which are final.

I can try and implement this myself if I can get some agreement that it would be useful/doable. I've browsed the source code for Lombok and I believe adding a boolean makeFinal() default false; to the Getterand Setterclasses plus handling the method generation in the Getter and Setter handlers should suffice (for both javac and eclipse compilers). Am I correct? Are there any complications I'm not aware of?

No plans on supporting creating final getters/setters by Lombok?

Can someone please explain why having a final getX() is better than just getX() ?

I'm looking for an actual use-case, not a "because I want to have sub-classes, but they are not allowed to override my getter/setter."

I'm looking for an actual use-case, not a "because I want to have sub-classes, but they are not allowed to override my getter/setter."

@rspilker, sorry, maybe I ask something stupid, but why don't you consider "I want to have sub-classes, but they are not allowed to override my getter/setter" to be an actual use case? (What do you mean by actual use case then?)

Can you describe a common, real world (non-hypothetical) scenario where the class in not final, but the getters and setter must be final, and that that's the best solution for the problem.

In my experience, lots of code bases are favoring composition over inheritance. Most data classes don't have sub-classes. And if they do, there is no requirement that the getters/setters need to be final. I mean, that invariants are fundamentally broken.

One could always argue that it help reasoning about the code in case you want to execute a refactoring. But that alone is not good enough to add additional parameters and complications to @Getter and @Setter.

We're really interested. Maybe there is a good reason we don't know about. But so far, we haven't heard compelling arguments. The best argument so far was "It speeds up introducing Lombok in legacy code bases". And, although compelling, that alone not good enough.

@rspilker, for me "I want to have sub-classes, but they are not allowed to override my getter/setter" is a real-world every-day (every day when I use Java) scenario.

In my experience, lots of code bases are favoring composition over inheritance.

Exactly. That's why I tend to have things final by default. Usually I make the whole class final (therefore making all members implicitly final).

But in some cases we allow class to be inherited. In that cases usually _specific_ methods are allowed to be overridden but not _all_ methods. I.e. in such classes I by default mark all methods as final and then unmark those of them that are allowed to be overridden by design.

I.e. almost every class that I allow to be inherited has at least some final methods (though for most of the classes I forbid inheritance at all). And if such (non-final) class has some trivial getter and/or setter methods, they're most certainly final — because they're usually not the part of the stuff that is by design allowed to be overridden.

Maybe it matters that I use Java not for my work but for my hobby projects. Never-the-less for me it's a usual thing: I make everything final by default and then consciously "unfinalize" some small parts. Getters and setters almost never get "unfinallized". (If I were a Lombok designer, I'd made getter and setters final by default, but I understand that now it might be too incompatible change.)

@o-pikozh This sounds pretty convincing. Actually, this is just like what I always do concerning visibility (everything is as much private as possible). I don't do this w.r.t. finality as I never really thought about it, but I'd love when it was the default in Java - I mean everything is final unless marked as non-final (or there's a corresponding annotation on the whole class). But that train has sailed years ago.

I'm rather sure that being restrictive is a (very) good thing, but I'm unsure if in this particular case it's good enough to warrant the effort. If there was a lombok.config option for making all etters final, I'd surely switch it on. Unfortunately, such an option requires a possibility to override it, which means an additional annotation parameter or a new annotation or alike... even more effort (implementation, maintenance and learning curve).

Disclaimer: I'm not a lombok team member.

Consider abstract base classes (for e.g. database objects => my use-case) as a real-world scenario.

We also had that use case (database mapping classes for JCR). JCR also has a (very special) notion of inheritance. Thus, it becomes even more important to design the inheritance in Java well, especially as we allow plugins with customer-specific database sub-classes (i.e. code that we do not control).

Joshua Bloch also says "Design for inheritance or else prohibit it" (Effective Java). Getter and setters are a typical example where you do not want any subclass to mess around with. Imagine a subclass overriding the getter for the unique ID.

Agreed. Whenever possible, all methods should be either abstract or final.

I'm just moving some fields up in the hierarchy. By making the getters final, I could ensure that there'll be no leftovers.

Can someone please explain why having a final getX() is better than just getX() ?

I'm looking for an actual use-case, not a "because I want to have sub-classes, but they are not allowed to override my getter/setter."

"because I want to have sub-classes, but they are not allowed to override my getter/setter" it's an actual use-case. Just because you don't think so doesn't make it less important.

I agree that a final getter that simply returns the property seems useless. And I agree with the concept of composition over inheritance.
But this doesn't mean that inheritance is useless or should not be used.
So many times I start writing some classes and then I realize that all those classes share something that is better expressed with inheritance and not composition.
In those cases, I refactor my classes extracting a base abstract one, and at that moment I often realized that those commons behaviours must not be overridden. So I need to add the final keyword on base class methods.
And sometimes those base class methods are just simple getters... And all is good, because the important thing is that this method, regarding its complexity, it's something that subclasses should not be able to override, so I want to enforce this behaviour.

The final keyword in simple getter often appears in my value objects. Those value object often have a value and I want to be sure that value object subclasses don't return whatever they want. I want they initialize the value calling super(value), maybe adding some validation logic, but I don't want they change what the value object return as the value. So I need the final keyword in my getter method.

You can argue that I can simply declare my field public final and all works fine.
Not at all. I want to be open to change how the value is provided through the getter in my base class, so to avoid a "huge" refactor in my codebase I always use a getter method instead of letting access the raw property.

Everything would be better if Java had properties like Kotlin, and getters and setters for those properties.
But Java doesn't have class properties, so I need the final keyword in my getter

Can you describe a common, real world (non-hypothetical) scenario where the class in not final, but the getters and setter must be final, and that that's the best solution for the problem.

In my experience, lots of code bases are favoring composition over inheritance. Most data classes don't have sub-classes. And if they do, there is no requirement that the getters/setters need to be final. I mean, that invariants are fundamentally broken.

One could always argue that it help reasoning about the code in case you want to execute a refactoring. But that alone is not good enough to add additional parameters and complications to @Getter and @Setter.

We're really interested. Maybe there is a good reason we don't know about. But so far, we haven't heard compelling arguments. The best argument so far was "It speeds up introducing Lombok in legacy code bases". And, although compelling, that alone not good enough.

Real use-case for you:
Mockito will mock all methods of an object if they're not final.
So I have a custom mock class which e.g. counts something and I'm incrementing a counter, I say @Getter long x; but at runtime I get org.mockito.exceptions.verification.NoInteractionsWanted, why? because the non-final getX() was mocked. I google and end up here.

Was this page helpful?
0 / 5 - 0 ratings