First off: I absolutely LOVE Project Lombok. Awesome tool! There's so many excellent aspects to this 'compile time' library.
Loving the @ExtensionMethod
s, I have already hit this 'feature' a few times, so now it's time for me to ask this question:
Suppose I have the following classes:
@UtilityClass
public class AObject {
static public String message(final Object pObject) {
return "AObject = " + (pObject != null);
}
}
@UtilityClass
public class AString {
static public String message(final String pObject) {
return "AString = " + (pObject != null);
}
}
@ExtensionMethod({ AObject.class, AString.class })
public class Run_Object_String {
public static void main(final String[] args) {
System.out.println("\nRun_Object_String.main()");
final String s = "Bier!";
final Object o = new Object();
System.out.println("Testing s: " + s.message());
System.out.println("Testing o: " + o.message());
System.out.println("Testing s: " + s.message());
}
}
@ExtensionMethod({ AString.class, AObject.class })
public class Run_String_Object {
public static void main(final String[] args) {
System.out.println("\nRun_String_Object.main()");
final String s = "Bier!";
final Object o = new Object();
System.out.println("Testing s: " + s.message());
System.out.println("Testing o: " + o.message());
System.out.println("Testing s: " + s.message());
}
}
public class ClassPrevalenceTest {
public static void main(final String[] args) {
Run_Object_String.main(args);
Run_String_Object.main(args);
}
}
With the output:
Run_Object_String.main()
Testing s: AObject = true
Testing o: AObject = true
Testing s: AObject = true
Run_String_Object.main()
Testing s: AString = true
Testing o: AObject = true
Testing s: AString = true
- Why is this?
- Why is the
message(String)
not called in the first example, even though it has a better method signature fit thanmessage(Object)
? - Why is
@ExtensionMethod
dependent on sequence of the arguments?
Here's what I blindly assume:
- when parsing for ExtensionMethods, Lombok will process annotation values from left to right
-
- For
Run_Object_String
that means: firstAObject
, thenAString
- For
-
- For
Run_String_Object
that means: firstAString
, thenAObject
- For
- Object-String: When patching
AObject
into classRun_Object_String
, themessage(Object)
method will be added. And when patching inAString
with themessage(String)
method, it will not be added. Presumably because themessage(Object)
also matches a call tomessage(String)
, somessage(String)
will not be added. - String-Object: When patching
AString
into classRun_String_Object
, themessage(String)
method will be added. When patching inAObject
class withmessage(Object)
, the old and presentmessage(String)
method will NOT accept the callmessage(Object)
, thus the methodmessage(Object)
will be added.
So, apart from taking great care of what order I add the @UtilityClass
references, are there any other solutions to this?
- Can the Lombok preprocessor be extended and made more sensible when adding in extension methods?
- Do you guys have any suggestions regarding this, or an explanation of what is really happening (as opposed to my assumptions)