【问题标题】:ClassLoader does not find resource files following buildClassLoader 在构建后找不到资源文件
【发布时间】:2018-09-27 20:54:48
【问题描述】:

我在尝试指示 Java 类加载器在部署后从 test/resources 目录中检索 JSON 文件时遇到了问题。

public class TestFileUtil {
    private static final ClassLoader classLoader = TestFileUtil.class.getClassLoader();

    public static Map<String, Object> getJsonFileAsMap(String fileLocation) {

        try {
            return new ObjectMapper().readValue(getTestFile(fileLocation), HashMap.class);
        } catch (IOException e) {
            throw new RuntimeException("Error converting JSON file to a Map", e);
        }
    }

    private static File getTestFile(String fileLocation) {

        return new File(classLoader.getResource(fileLocation).getFile());
    }
}

该实用程序在使用 Mockito 进行本地测试期间没有问题,如下所示:

public class LocalTest {

    @Before
    public void setUp() {
        Mockito.when(mockDataRetrievalService.getAssetJsonById(Mockito.any())).thenReturn(TestFileUtil.getJsonFileAsMap("test.json"));
    }
}

但是,在我们部署的环境中构建时,此行会引发 FileNotFound 异常。

当使用相对目录路径 "../../test.json" 时,我在两种环境中都看到 FileNotFound 异常。

本地目录结构:

test
| java
| |- project
| |  |- LocalTest
| |- util
| |  |- TestFileUtil.class
| resources
| |- test.json

部署后:

test
| com
| | project
| | | dao
| | | | LocalTest
| | other project
| | | | util
| | | | | TestFileUtil.class
| | | | | test.json

在自动构建中使用 ClassLoader 是否有任何特殊行为或所需的目录结构?

【问题讨论】:

    标签: java jenkins junit java-8 mockito


    【解决方案1】:

    问题很可能是这样的:

    new File(classLoader.getResource(fileLocation).getFile());
    

    URL 类的 getFile() 方法没有返回有效的文件名。它只返回 URL 的路径部分,不能保证是有效的文件名。 (当 URL 类作为 Java 1.0 的一部分引入时,方法名称是有意义的,因为几乎所有 URL 实际上都引用了物理文件,无论是在同一台机器上还是在不同的机器上。)

    ClassLoader.getResource 的参数不是文件名。它是一个相对 URL,其基础是 ClassLoader 类路径中的每个位置。如果您想读取与您的应用程序捆绑在一起的资源,请不要尝试将资源 URL 转换为文件。改为将 URL 读取为 URL:

    public class TestFileUtil {
        private static final ClassLoader classLoader = TestFileUtil.class.getClassLoader();
    
        public static Map<String, Object> getJsonFileAsMap(String fileLocation) {
    
            try {
                return new ObjectMapper().readValue(getTestFile(fileLocation), HashMap.class);
            } catch (IOException e) {
                throw new RuntimeException("Error converting JSON file to a Map", e);
            }
        }
    
        private static URL getTestFile(String fileLocation) {
    
            return classLoader.getResource(fileLocation);
        }
    }
    

    如果您想读取不属于您的应用程序的文件,请不要使用 getResource。只需创建一个 File 实例。

    【讨论】:

    • 但一般情况下,建议使用TestFileUtil.class.getResource("/"+fileLocation);,以提供更多上下文。否则,将来迁移到模块化代码时可能会咬到你。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-01
    • 1970-01-01
    • 2012-03-07
    • 1970-01-01
    • 2019-05-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多