Lombok 扩展方法:Prevalence/priority?
Lombok extension methods: Prevalence/priority?
首先:我非常喜欢龙目岛计划。很棒的工具!这个 'compile time' 库有很多优秀的方面。
喜欢@ExtensionMethod
s,我已经点击'feature'几次了,所以现在是时候问这个问题了:
假设我有以下 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);
}
}
输出:
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
- 这是为什么?
- 为什么
message(String)
在第一个示例中没有被调用,即使它的方法签名比 message(Object)
更好?
- 为什么
@ExtensionMethod
取决于参数的顺序?
这是我盲目假设的:
- 在解析 ExtensionMethods 时,Lombok 将从左到右处理注释值
-
- 对于
Run_Object_String
这意味着:首先 AObject
,然后 AString
-
- 对于
Run_String_Object
这意味着:首先 AString
,然后 AObject
- Object-String: 将
AObject
修补成class Run_Object_String
时,会添加message(Object)
方法。而在AString
中用message(String)
方式打补丁时,则不会添加。
大概是因为message(Object)
也匹配了对message(String)
的调用,所以不会添加message(String)
。
- String-Object: 将
AString
修补成class Run_String_Object
时,会添加message(String)
方法。
当用 message(Object)
修补 AObject
class 时,旧的和现在的 message(String)
方法将不接受调用 message(Object)
,因此方法 message(Object)
将被添加。
那么,除了注意添加 @UtilityClass
引用的顺序外,还有其他解决方案吗?
- 是否可以扩展 Lombok 预处理器并使其在添加扩展方法时更加明智?
- 你们对此有什么建议,或者对实际发生的事情的解释(与我的假设相反)
这是我不知道的 Lombok 的一个有趣用法。我认为您可以深入寻找答案的最佳位置是源代码本身,因为关于这项实验性工作的文档看起来很轻松,可以理解。
查看 git 此处:HandleExtensionMethod。
我根据以下逻辑猜测,有效“适合”注释中正确方法的区域如下所示。
它似乎没有尝试“最佳”匹配,而是以“第一次”匹配为目标。
也就是说,它似乎迭代了 List<Extension> extensions
。由于它是一个 Java 列表,我们假设顺序保留在原始注释中指定扩展名的顺序。
它似乎只是按照列表的顺序工作,return
只要某些东西匹配正确的方法和类型形状。
Types types = Types.instance(annotationNode.getContext());
for (Extension extension : extensions) {
TypeSymbol extensionProvider = extension.extensionProvider;
if (surroundingTypeSymbol == extensionProvider) continue;
for (MethodSymbol extensionMethod : extension.extensionMethods) {
if (!methodName.equals(extensionMethod.name.toString())) continue;
Type extensionMethodType = extensionMethod.type;
if (!MethodType.class.isInstance(extensionMethodType) && !ForAll.class.isInstance(extensionMethodType)) continue;
Type firstArgType = types.erasure(extensionMethodType.asMethodType().argtypes.get(0));
if (!types.isAssignable(receiverType, firstArgType)) continue;
methodCall.args = methodCall.args.prepend(receiver);
methodCall.meth = chainDotsString(annotationNode, extensionProvider.toString() + "." + methodName);
recursiveSetGeneratedBy(methodCall.meth, methodCallNode);
return;
}
}
您可以查看其余代码以获得其他见解,因为那里似乎没有太多内容(即行数)可供查看,但不可否认,这是一项令人印象深刻的壮举space.
首先:我非常喜欢龙目岛计划。很棒的工具!这个 'compile time' 库有很多优秀的方面。
喜欢@ExtensionMethod
s,我已经点击'feature'几次了,所以现在是时候问这个问题了:
假设我有以下 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);
}
}
输出:
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
- 这是为什么?
- 为什么
message(String)
在第一个示例中没有被调用,即使它的方法签名比message(Object)
更好? - 为什么
@ExtensionMethod
取决于参数的顺序?
这是我盲目假设的:
- 在解析 ExtensionMethods 时,Lombok 将从左到右处理注释值
-
- 对于
Run_Object_String
这意味着:首先AObject
,然后AString
- 对于
-
- 对于
Run_String_Object
这意味着:首先AString
,然后AObject
- 对于
- Object-String: 将
AObject
修补成classRun_Object_String
时,会添加message(Object)
方法。而在AString
中用message(String)
方式打补丁时,则不会添加。 大概是因为message(Object)
也匹配了对message(String)
的调用,所以不会添加message(String)
。 - String-Object: 将
AString
修补成classRun_String_Object
时,会添加message(String)
方法。 当用message(Object)
修补AObject
class 时,旧的和现在的message(String)
方法将不接受调用message(Object)
,因此方法message(Object)
将被添加。
那么,除了注意添加 @UtilityClass
引用的顺序外,还有其他解决方案吗?
- 是否可以扩展 Lombok 预处理器并使其在添加扩展方法时更加明智?
- 你们对此有什么建议,或者对实际发生的事情的解释(与我的假设相反)
这是我不知道的 Lombok 的一个有趣用法。我认为您可以深入寻找答案的最佳位置是源代码本身,因为关于这项实验性工作的文档看起来很轻松,可以理解。
查看 git 此处:HandleExtensionMethod。
我根据以下逻辑猜测,有效“适合”注释中正确方法的区域如下所示。
它似乎没有尝试“最佳”匹配,而是以“第一次”匹配为目标。
也就是说,它似乎迭代了 List<Extension> extensions
。由于它是一个 Java 列表,我们假设顺序保留在原始注释中指定扩展名的顺序。
它似乎只是按照列表的顺序工作,return
只要某些东西匹配正确的方法和类型形状。
Types types = Types.instance(annotationNode.getContext());
for (Extension extension : extensions) {
TypeSymbol extensionProvider = extension.extensionProvider;
if (surroundingTypeSymbol == extensionProvider) continue;
for (MethodSymbol extensionMethod : extension.extensionMethods) {
if (!methodName.equals(extensionMethod.name.toString())) continue;
Type extensionMethodType = extensionMethod.type;
if (!MethodType.class.isInstance(extensionMethodType) && !ForAll.class.isInstance(extensionMethodType)) continue;
Type firstArgType = types.erasure(extensionMethodType.asMethodType().argtypes.get(0));
if (!types.isAssignable(receiverType, firstArgType)) continue;
methodCall.args = methodCall.args.prepend(receiver);
methodCall.meth = chainDotsString(annotationNode, extensionProvider.toString() + "." + methodName);
recursiveSetGeneratedBy(methodCall.meth, methodCallNode);
return;
}
}
您可以查看其余代码以获得其他见解,因为那里似乎没有太多内容(即行数)可供查看,但不可否认,这是一项令人印象深刻的壮举space.