New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FEATURE] Placeholder type THIS to be replaced in derived classes. #2432
Comments
Sounds like a straightforward variant of
https://github.com/rzwitserloot/lombok/wiki/LOMBOK-CONCEPT:-Resolution
.. which means lombok probably can't solve this problem, sorry.
..
…On Sat, Apr 18, 2020, 09:28 TreffnonX ***@***.***> wrote:
Java does not have a generic placeholder to represent the actual current
class, as opposed to the declaring class of any field, method, and thelike.
This would be tremendously helpful e.g. with methods that are supposed to
return the object which's method is called, similar to a builder-pattern:
MySubclass myObject= ...;
myObject.refresh().doSomethingElse();
While the above will work, if doSomething is defined on or above the same
type as refresh, this is - more often than not - not the case, especially
if MySubclass is derived from a type declaring many standard functions for
it's derivates. Assuming that refresh returns the called upon instance,
it could be the same type as myObject, assuming at the time of
invokation, I knew that type.
To achieve this, and handle similar issues, a placeholder annotation type
could be introduced, similar to the var and val types, which is then
replaced in the declaring class (and all compilation units marked with a
certain annotation). Consider the following example:
@...public class MySupertype {
// will become signature:
// public MySupertype refresh();
public THIS refresh() {
//...
return this;
}
}
@Redeclarepublic class MySubtype extends MySupertype {
// will redeclare all fields and methods with 'THIS':
// public MySubtype refresh() {
// return super.refresh();
// }
// this implicitly declares the refresh method again, with the more specific return type of this class.
}
In this example, both MySupertype and MySubtype declare a refresh method,
but with different return types. The only issue I see is that the
compilation units are separate. However, since MyDerivedType is a subtype
of MyHibernateType it should theoretically be possible to leave some
trace in the supertype, which could then be used in the subtype to save the
day.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#2432>, or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABIERPLYUKFVWUKUJ4YIZDRNFJDRANCNFSM4MLHZKUA>
.
|
Except... you do it the |
Well, if anyone has the expertise to implement something like that it's you
;)
…On Sat, Apr 18, 2020, 12:17 Jan Rieke ***@***.***> wrote:
Except... you do it the @SuperBuilder way: Create a static inner class
ThisTypeHelper (with fancy type params), which you could use as return
type. That class provides a get() method, which has the correct return
type (with the help of the type params).
I've not tested this, so I'm not sure that this really works. Similar to
@SuperBuilder, you'd need it on every class in the hierarchy, and you'd
have to call the get() method instead of just using the returned value.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#2432 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABIERKULU4XZS6O65STCELRNF42NANCNFSM4MLHZKUA>
.
|
I thought again and tried around with this. I'm pretty sure this will only work if we put the type param directly on the annotated class. Generating a parameterized inner helper class will not work. So in the end the code will look like this:
It works, but the price is too high in my opinion, because you need those seemingly useless type params everywhere you use that class. Furthermore, you have to suppress a warning, which is also not so nice (although you can extract that to an extra method so you won't have to suppress warnings in the affected this-returning methods). |
Thank you for trying though, it seemed simpler when I thought about it. But I understand that - more often than not - the restraints lombok must function under prevent such things. Hopefully, one day there will be a solution to this, but for now it seems we have to stick with the verbose redeclaraton. |
Let's wait what the Lombok maintainers say. Maybe they have another idea. |
There is a possible solution that works without those type params:
However, there is a technical problem: lombok does not generate new compilation units, it just modifies existing ones. As the JLS does not allow more than one |
On the opposite, it's a feature. You need threes type per class, which is a lot and making them all top-level makes it even worse. When you want to extend them in a different package, you need to make the abstract scaffold public, too. So I'd go for classes nested in an interface which would be IMHO much nicer as the interface is what's needed most of the time (actually, all the time; see below). It could look like
The nesting and the use of strange name helps to prevent mistakes like
or something like this. No generics, no references to either I may be missing something.... |
So users of the annotated class should only work with the interface? Then you need the type params on the interface, otherwise you won't have the actual return type. And then the problem with the unnecessary |
@janrieke I wanted to hide all generics in the generated code, but I may be completely wrong.... It should go as follows: The user defines the classes using e.g.,
and Lombok creates the nested
with no generics at all. What obviously can't work ideally, is using |
Java does not have a generic placeholder to represent the actual current class, as opposed to the declaring class of any field, method, and thelike. This would be tremendously helpful e.g. with methods that are supposed to return the object which's method is called, similar to a builder-pattern:
While the above will work, if
doSomething
is defined on or above the same type asrefresh
, this is - more often than not - not the case, especially if MySubclass is derived from a type declaring many standard functions for it's derivates. Assuming thatrefresh
returns the called upon instance, it could be the same type asmyObject
, assuming at the time of invokation, I knew that type.To achieve this, and handle similar issues, a placeholder annotation type could be introduced, similar to the var and val types, which is then replaced in the declaring class (and all compilation units marked with a certain annotation). Consider the following example:
In this example, both
MySupertype
andMySubtype
declare arefresh
method, but with different return types. The only issue I see is that the compilation units are separate. However, sinceMySubtype
is a subtype ofMySupertype
it should theoretically be possible to leave some trace in the supertype, which could then be used in the subtype to save the day.The text was updated successfully, but these errors were encountered: