【问题标题】:Getting the current working resource directory in java maven project在java maven项目中获取当前工作资源目录
【发布时间】:2012-08-13 21:44:40
【问题描述】:

我目前正在进行一项 JUnit 测试,该测试检查负责从/向某个文件加载/保存流程配置的功能。鉴于资源中存在特定的配置文件,该功能会从文件中加载参数。否则,该功能会尝试创建新的配置文件并保留类中编码的默认配置。现在我正在使用 .class.getResource() 方法来检查配置文件是否存在,并检索必要的信息。这种方法被证明在 maven 的“test-class”和“class”目录中都可以正常工作。但是,当文件不存在时,我在尝试保存默认配置时遇到问题,即 .class.getResource() 方法返回 null,因为资源尚不存在。这使我无法构建应保存文件的目标资源目录(取决于上下文)。

有没有办法对我的功能进行编码以评估特定对象是作为测试执行还是在生产中执行?更准确地说,我如何构建资源文件的相对路径以指向生产资源(../classes/...)或测试资源(../test-classes/..),具体取决于执行模式目前是哪个项目?

我的问题有点类似于下面的How should I discover test-resource files in a Maven-managed Java project?,但我认为它的不同足以保证新的线程。

【问题讨论】:

    标签: java maven junit


    【解决方案1】:

    如果我的理解正确,本质上你的问题是你有一个 Maven 项目,它读取一个特定的文件(通常在单元测试期间),它决定了应用程序的行为。如果该文件不存在,您的应用程序会创建它。

    ClassLoader.getSystemResource(...) 的问题在于它实际上并没有扫描单个目录。相反,它正在查看 Java 的类路径以确定该特定资源的位置。如果类路径上有多个目录,则文件可能位于多个区域。

    在某种意义上,.getSystemResource(...) 是一种方式。您可以查找文件的位置,但无法找到合适的位置来放置它。

    *那么什么时候需要把文件放到正确的位置呢?*

    您基本上有两个选择:

    1. 硬编码文件的位置:没有人喜欢这样做。
    2. 在类路径上扫描的位置被传递到类加载器中。例如,您可以使用第一个并在那里创建文件。

    第二个选项实际上并不坏。看看这个示例代码。

        final Enumeration<URL> urls = ClassLoader.getSystemClassLoader().getResources("");
        if(! urls.hasMoreElements()) {
            LOG.error("No entries exist on the class path!");
            System.exit(1);
        }
        final File configFile = new File(urls.nextElement().getFile(), "config.xml");
        configFile.createNewFile();
        LOG.info("Create a new configuration file: " + configFile.getPath());
        System.exit(0);
    

    这将配置文件解析到我的目标文件夹中:..\target\classes\config.xml

    做什么取决于你;如果您觉得需要更多提示和建议,我们很乐意提供更多提示和建议。

    【讨论】:

    • 如果您认为该答案解决了您的问题,请相应地标记它。 :)
    【解决方案2】:

    听起来您想要执行以下操作:

    当您的代码运行时,它会尝试加载配置文件。当找不到配置文件时,您要创建配置文件。转折点是

    • 如果您在“生产模式”下执行代码(我假设根据代码的性质使用类似 exec-maven-plugin 或 jetty-maven-plugin),您希望配置文件为放在 ${project.build.outputDirectory}

    • 如果您在“测试模式”下执行代码(例如,通过 surefire 或故障安全),您希望将配置文件放在 ${project.build.testOutputDirectory}

    我要做的是使用 ServiceLoader 模式。

    您创建一个负责存储配置的 ConfigFileStore 接口。

    ConfigFileStoreFactory 枚举所有实现该接口的服务(使用ServiceLoader API,通过获取所有 /META-INF/services/com.yourpackage.ConfigFileStore 资源并从中提取类名。如果没有注册实现然后它将实例化一个默认实现,该实现将文件存储在基于 getClass() 的路径中(即向后工作以到达 ${project.build.outputDirectory} 注意它应该处理将类捆绑到一个JAR,我认为在这种情况下配置文件可能会存储在 JAR 附近)

    注意:默认实现不会在/META-INF/services中注册

    然后在 src/test/java 中扩展默认实现并在 src/test/resources/META-INF/services/com.yourpackage.ConfigFileStore 中注册该扩展实现

    现在,当运行在类路径中包含测试代码的代码时,将找到测试版本,该版本将从 ${project.build.testOutputDirectory} 中获取类的 getClass(),因为它来自测试类路径的/META-INF/服务。

    当运行在类路径上没有测试代码的代码时,默认实现会从 ${project.build.outputDirectory} 中获取一个类的 getClass()

    应该做你想做的。

    【讨论】:

      猜你喜欢
      • 2011-06-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多