gpt4 book ai didi

java - 如何验证Java VariableElement是否可以传递给ExecutableElement?

转载 作者:行者123 更新时间:2023-11-30 07:25:10 25 4
gpt4 key购买 nike

如果我有一个javax.lang.model.element.VariableElement表示一个List<SomeObject>类型的变量,一个javax.lang.model.element.ExecutableElement表示一个带有一个List<? extends SomeObject>类型参数的方法,那么如何验证我的变量类型可以传递给我的方法类型?

我开始尝试编写javax.lang.model.type.TypeVisitor来尝试比较忽略通配符类型的类型,但是我不确定是否有更简单的方法。

最佳答案

显而易见的解决方案,但无济于事:生成方法调用(我假设您正在这样做),等到上一次编译回合,并通过返回值RoundEnvironment#errorRaised()检查是否发生了错误。之后,您可能无法生成任何源。

如果您真的想对科学进行验证,请参阅下文。



正如您已经了解的那样,从技术上讲不可能将一个元素分配给另一个元素。您必须从元素转到类型(例如TypeMirror s)。这样做时要非常小心!


在继续操作之前,请始终检查源代码是否有错误。 ErrorType很疯狂:编译器将让它参与奇怪的任务,并且通常将其视为某些不可思议的“任何操作”通配符(不要与实际的WildcardType混淆)。我个人为此使用了Google Auto SuperficialValidaton的略微修改版本,您也应该这样做,除非其他人已经为您验证了所有元素。
永远不要假设某个元素具有某种特定类型的类型(例如DeclaredType)。如果这样做,您的代码将很难重构和适应新的语言功能。
一定要使用TypeMiror#getKind检查特定类型的类型,并强制转换为TypeMirror的特定子类型。访客范式可以使向前兼容变得容易,但是当您需要诸如DeclaredType之类的特定类型时,就不应该使用它。


由于您是在java.lang.model框架内编程的,因此我假设您了解实用程序类TypesElements以及如何获取它们的实例。我们将这些实例称为typeselements

将VariableElement和ExecutableElement都转换为TypeMirrors:

您尚未发布特定的代码,也没有告诉您方法和变量的来源以及它们的相似之处,因此这是可想象的最通用的方法:

VariableElement variable = ...
ExecutableElement method = ...

TypeMirror variableType = types.asMemberOf(c1, variable);
ExecutableType methodType = (ExecutableType) types.asMemberOf(c2, method);


上面代码中的 c1c2指的是最特定的类类型,它们将在运行时包含变量和方法。例如,您可能具有以下类c1和c2:

class c1Base<X extends Number> {
protected X variable;
}

interface c2Base<Y extends Number> {
void method(Y parameter);
}

class c1 extends c1Base<BigInteger> {}

abstract class c2 implements c2Base<Byte> {}


您得到c1和c2的类型:

// If you happen to know, that c1 and c2 have their own type arguments,
// and which type arguments may be used at run time, specify those here

DeclaredType c1 = types.getDeclaredType(elements.getTypeElement("co.exampl.c1"));

DeclaredType c2 = types.getDeclaredType(elements.getTypeElement("co.exampl.c2"));


变量和方法参数的类型将取值为 BigIntegerByte,就好像没有通用的参数开始!

自然,当细化类型参数没有意义时,您也可能碰巧处于这种情况:您通过调用 getEnclosedElements收到了方法和变量,却一无所知,在运行时可以使用哪种容器类型。在这种情况下,只需使用 asType

TypeMirror variableType = variable.asType();
ExecutableType methodType = (ExecutableType) method.asType();


检查是否可以将变量类型分配给参数类型

Javac是否允许将类型X的变量传递给参数类型Y的方法是基于两个因素的:


一般情况下,可以将X分配给Y吗?
很多类型推断魔术。


如果可以将X分配给Y而不涉及其他因素,则方法调用也肯定会成功:

TypeMirror methodParameterType = methodType.getParameterTypes().get(0);
if (types.isAssignable(variableType, methodParameterType)) {
// return early, the call will be allowed
}


但是如果不是这样,但是由于类型推断,调用仍然可能成功吗?不幸的是,从Java 8开始,似乎没有用于访问编译器类型推断的公共API,并且没有 java.lang.model类在后台使用它。您可以使用类型 List<? extends Date>和类似的方法:

<X extends Serializable> void foobar(List<X> parameter) throws RemoteException;


而且无论如何,如何检索TypeMirror, isAssignable都不会返回 true,尽管事实上可以使用此类参数来调用该方法。

Java规范的 part涉及类型推断,它庞大且使用许多功能,无法通过公共API(计算最小上限等)用于注释处理器。在主要语言版本中,它也有发生很大变化的趋势。自己实现相应的逻辑是非常不明智的。

如果您是我,我会放弃尝试预先执行确定性验证,而让Javac自己做一个决定。只是生成方法调用,如果用户在某处提供了错误的类型,就让它失败。您可以通过检查变量类型和方法参数类型是否均为 DECLARED且都没有任何类型参数来改善早期预测,但如果不是这种情况,则仍允许生成调用:

if (methodParameterType.getKind() == TypeKind.DECLARED
&& variableType.getKind() == TypeKind.DECLARED
&& types.isSameType(methodParameterType, types.erasure(methodParameterType))
&& types.isSameType(variableType, types.erasure(variableType))) {
// type inference is extremely unlikely to interfere
return types.isAssignable(variableType, methodParameterType);
}

// allowed the call ourselves, if compiler forbids it, it will emit
// a compilation error with descriptive message, so user should probably
// be able to figure things out

关于java - 如何验证Java VariableElement是否可以传递给ExecutableElement?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36905737/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com