ClassLoader не находит файлы ресурсов после сборки

Я столкнулся с проблемами, пытаясь заставить Java ClassLoader извлекать файлы JSON из каталога test/resources после развертывания.

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 в автоматических сборках?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
867
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема, скорее всего, в следующем:

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

Метод getFile () класса URL не возвращает допустимое имя файла. Он просто возвращает часть пути 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);, чтобы предоставить больше контекста. В противном случае он может укусить вас при переходе на модульный код в будущем.

Holger 28.09.2018 13:19

Другие вопросы по теме