无法在注解处理器中加载资源(不在类路径上)

20

我有一个注解处理器,它将生成一个枚举,该枚举的键由接口的getter方法定义。

接口位于

MyProject / src / main / java / my.package.MyInterfaces.java。

我想验证驻留在MyProject / src / main / resources / META-INF / resource-bundle / 中的属性文件是否包含生成的枚举中定义的键。

我的问题是,属性文件无法通过处理器或Filer.getResource(...)的类加载器获得。

  • 如何使此项目的源或类路径可用于处理器,以便可以加载属性文件?

  • 现在,我只有处理器所在的jar中可用的资源。 我尝试通过eclipse Project / Properties / Java compiler / Annotation processing / Processor options定义-classpath和/或-sourcepath,但这没有成功。

有人遇到过这样的问题吗?能否给我一些线索,以便我可以使资源对处理器可用?

我有maven结构,但由于应用程序中存在旧的依赖项,因此我不使用maven。所以现在maven对我来说不是选择。

Eclipse 3.6 Helios 看起来Filer#getResource()中没有实现StandardLocation.SOURCE_PATH和StandardLocation.CLASS_PATH,因此似乎不可能将生成的源或类文件写入SOURCE_PATH或CLASS_PATH,也无法访问任何位于SOURCE_PATH和CLASS_PATH上的文件*

谢谢。


是的,看起来它还没有被实现。有人有解决方法吗? - Arne Deutsch
1
你解决过这个问题吗?我有一个类似的问题:https://dev59.com/y4nda4cB1Zd3GeqPDLkr - Jurgen Vinju
比源代码位置更重要的是输出文件夹中的位置。你检查过文件是否也在output/META-INF/resource-bundle中吗?你是如何构建的?你的输出文件夹是什么,加载bundle时指定了哪个路径? - Jürgen
为什么不使用 MyProject/src/main/java/my/package/MyInterfaces.java 呢? - Thorbjørn Ravn Andersen
3个回答

2
问题在于当调用Processor#process时,绑定到当前线程(Thread.currentThread().getContextClassLoader())的ClassLoader不是URLClassLoader。它似乎是一个受限制的ClassLoader,不允许加载资源。这会发生在javac、eclipse编译器、maven编译器等工具中。
幸运的是,您的processor类将有适当的ClassLoader与之绑定(即getClass().getClassLoader())。
问题是大多数实用程序都希望将正确的ClassLoader绑定到线程上(尤其是ServiceLoader和ResourceBundles)。
因此有一个解决方法。当您的Processor执行时,您可以重新绑定ClassLoader到当前线程:
@Override
public boolean process(
        Set<? extends TypeElement> annotations,
        RoundEnvironment roundEnv) {

    Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
    //...
}

编辑:

我感觉很多人都遇到了使用注解处理器Filer时,Eclipse无法加载位于src/main/resources中的资源的问题(会抛出异常)。

事实上,众所周知,Eclipse不会加载target/classes中的资源。我上面展示的类路径黑客方法可能有效,也可能无效,并且更多是为其他库所用(例如它们已经编译了资源)。

解决方案(如果可以称之为解决方案)是像普通文件一样加载文件。这需要猜测项目结构并进行某些技巧性操作

或者

您可以告诉Eclipse用户将资源放在src/main/java中。


我现在在Eclipse中遇到了这个处理器的问题。我尝试了你的解决方法,但它仍然找不到资源。你有其他的选择吗? - Cristiano
@Cristiano 让我猜猜,你正在尝试访问通常在 src/main/resources 中的资源?Eclipse注释处理器对此有问题,请参见https://stackoverflow.com/questions/49631221/how-to-get-resouce-in-eclipse-jdt-apt-environment。 - Adam Gent

0

作为一种解决方法,您可以尝试通过命令行参数-Xboothclasspath/a:path添加所需使用的类路径,/a将把path中的值附加到引导类路径中。您需要将其作为命令行选项添加到实际的注释处理运行中,因此在Eclipse中,您需要右键单击项目,选择属性,Java编译器,注释处理,在表格中单击“新建”,添加键-Xbootclasspath/a和要添加的路径作为值。我很抱歉我没有尝试过这种注释处理方法,但是这值得一试!


-1
我的问题是处理器的类加载器或Filer.getResource(...)都无法访问属性文件。
我不确定我是否理解了您的问题。但也许这里的某些内容可以帮助您。
如何使此项目的源或类路径可供处理器使用,以便我可以加载属性文件?
您需要在Eclipse中将src/main/resources添加为“源文件夹”。首先,在Java项目上选择Eclipse中的Configure Build Path。然后选择Source选项卡,单击Add Folder。您应该能够选择src/main/resources文件夹并单击Ok。现在,您应该在源文件夹列表中看到src/main/resources
如果您查看target/classes目录,您应该会看到所有来自资源目录的文件,这表明它们已正确复制到类路径中。
# files in the src main resources
> ls src/main/resources/x/y/z
jgroups_udp.xml
# should compile into target/classes
> ls target/classes/x/y/z
jgroups_udp.xml org
# and should show up in the jar
> -tvf target/project.jar 
   0 Thu Nov 03 18:50:00 EDT 2016 META-INF/
 135 Thu Nov 03 18:49:58 EDT 2016 META-INF/MANIFEST.MF
 ...
3036 Thu Nov 03 18:49:36 EDT 2016 x/y/z/jgroups_udp.xml

然后在您的代码中,您可以通过以下方式引用该文件。这将从类路径的顶部加载文件。如果它在子目录中,则需要使用以下命令:

InputStream stream =
    getClass().getClassLoader().getResourceAsStream("x/y/z/jgroups_udp.xml");

顺便说一句,如果你正在使用Maven,你需要在你的pom.xml文件中添加类似以下的内容:
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
        </resource>
    </resources>
</build>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接