如何从注释处理器内部检查包是否存在(在编译时)?
How to check if the package exists from inside the annotation processor (in compile-time)?
我正在为 Android 构建一个注释处理器(为了以后的解释,我们称它为 TestProcessor
)。
处理器的计划是在两种模式下运行:
Mode 1
:生成代码A
Mode 2
:生成代码A
和B
Mode 2
只有在处理器生成代码的环境中存在附加(可选)包时才应选择。
有没有办法在注释处理器的process
方法中找出是否存在可选包?
编辑 1:
关于“(可选)包”的小说明。我所说的附加包是指 可能 但不一定存在于项目(使用处理器)中的 java 包。例如,可选包可以表示外部库的内容。外部库可以但不必包含在项目中。
举个小例子:
- 假设我们有一个(单模块)项目
Sample
。
Sample
正在使用我的 TestProcessor
.
- 我们以
Square's
Picasso
为例,使用外部库
- 如果
Sample
具有 Square's
Picasso
作为其依赖项之一,则 TestProcessor
在 Mode 2
中运行并生成代码 A
和 B
。换句话说:如果您可以从 com.square.picasso
(在 Sample
中)使用 类 而没有任何问题,那么处理器应该在 Mode 2
[=106= 中运行].
- 如果
Sample's
依赖中没有Square's
Picasso
,TestProcessor
在Mode 1
中运行,并且仅生成代码 A
.
编辑 2:
我想到了两个解决这个问题的方法:
- 对两个
processor
Modes
使用两种注解(例子:@DoStuffModeOne
,@DoStuffModeTwo
)
- 使用第二种类型的注释(应该在
Application
上使用)触发 Mode 2
的使用(示例:@TriggerModeTwo
)
对于我的情况,第二种解决方法更可取,但仍然 比 TestProcessor
本身可以决定哪个 更糟糕 ]Mode
选择。
您可以检查应用程序类路径中的 ButterKnife
类 之一。然后根据检查的结果执行你的逻辑。
Class butterKnifeClass = null;
try {
butterKnifeClass = Class.forName("butterknife.ButterKnife");
} catch (ClassNotFoundException e) {
// no butterknife present
}
if (butterKnifeClass != null) {
// blah... stuff with butterknife
}
您可以使用此代码查明注释处理环境中是否存在 class。
TypeElement typeElement = processingEnvironment.getElementUtils().
getTypeElement("com.squareup.picasso.Picasso");
我没有成功使用 Elements.getPackageElement()
方法,因为它成功返回 non-existent 包(至少在 Eclipse 下),运行 PackageElement.getEnclosedElements()
方法即使对于 non-empty 个包,这样创建的包上也是空的。我建议您像我之前的示例一样在您感兴趣的包中选择特定的 class,因为它对现有类型元素按预期工作并为 non-existing 类型返回 null
。
我目前没有找到基于Annotation Processing API的方法来判断以这种方式找到的类型元素是否基于源代码文件项目的源路径或编译 class 路径上的 二进制 class 文件 。可能有一种涉及 processingEnvironment.getFiler().getResource(StandardLocation.SOURCE_PATH, ...)
的方法,但不幸的是它不可移植,因为 Eclipse 不支持 StandardLocation.SOURCE_PATH
。
希望对您有所帮助。
除了JBirdVegas建议的解决方案;此函数可用于在运行时检查包是否存在于外部库中。
public static boolean packageExists(String packagePath) {
return Thread.currentThread().getContextClassLoader().getResource(packagePath) != null;
}
用法:
packageExists("apackage/innerpackage")
我正在为 Android 构建一个注释处理器(为了以后的解释,我们称它为 TestProcessor
)。
处理器的计划是在两种模式下运行:
Mode 1
:生成代码A
Mode 2
:生成代码A
和B
Mode 2
只有在处理器生成代码的环境中存在附加(可选)包时才应选择。
有没有办法在注释处理器的process
方法中找出是否存在可选包?
编辑 1:
关于“(可选)包”的小说明。我所说的附加包是指 可能 但不一定存在于项目(使用处理器)中的 java 包。例如,可选包可以表示外部库的内容。外部库可以但不必包含在项目中。
举个小例子:
- 假设我们有一个(单模块)项目
Sample
。 Sample
正在使用我的TestProcessor
.- 我们以
Square's
Picasso
为例,使用外部库 - 如果
Sample
具有Square's
Picasso
作为其依赖项之一,则TestProcessor
在Mode 2
中运行并生成代码A
和B
。换句话说:如果您可以从com.square.picasso
(在Sample
中)使用 类 而没有任何问题,那么处理器应该在Mode 2
[=106= 中运行]. - 如果
Sample's
依赖中没有Square's
Picasso
,TestProcessor
在Mode 1
中运行,并且仅生成代码A
.
编辑 2:
我想到了两个解决这个问题的方法:
- 对两个
processor
Modes
使用两种注解(例子:@DoStuffModeOne
,@DoStuffModeTwo
) - 使用第二种类型的注释(应该在
Application
上使用)触发Mode 2
的使用(示例:@TriggerModeTwo
)
对于我的情况,第二种解决方法更可取,但仍然 比 TestProcessor
本身可以决定哪个 更糟糕 ]Mode
选择。
您可以检查应用程序类路径中的 ButterKnife
类 之一。然后根据检查的结果执行你的逻辑。
Class butterKnifeClass = null;
try {
butterKnifeClass = Class.forName("butterknife.ButterKnife");
} catch (ClassNotFoundException e) {
// no butterknife present
}
if (butterKnifeClass != null) {
// blah... stuff with butterknife
}
您可以使用此代码查明注释处理环境中是否存在 class。
TypeElement typeElement = processingEnvironment.getElementUtils().
getTypeElement("com.squareup.picasso.Picasso");
我没有成功使用 Elements.getPackageElement()
方法,因为它成功返回 non-existent 包(至少在 Eclipse 下),运行 PackageElement.getEnclosedElements()
方法即使对于 non-empty 个包,这样创建的包上也是空的。我建议您像我之前的示例一样在您感兴趣的包中选择特定的 class,因为它对现有类型元素按预期工作并为 non-existing 类型返回 null
。
我目前没有找到基于Annotation Processing API的方法来判断以这种方式找到的类型元素是否基于源代码文件项目的源路径或编译 class 路径上的 二进制 class 文件 。可能有一种涉及 processingEnvironment.getFiler().getResource(StandardLocation.SOURCE_PATH, ...)
的方法,但不幸的是它不可移植,因为 Eclipse 不支持 StandardLocation.SOURCE_PATH
。
希望对您有所帮助。
除了JBirdVegas建议的解决方案;此函数可用于在运行时检查包是否存在于外部库中。
public static boolean packageExists(String packagePath) {
return Thread.currentThread().getContextClassLoader().getResource(packagePath) != null;
}
用法:
packageExists("apackage/innerpackage")