Я столкнулся с проблемами, пытаясь заставить 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 в автоматических сборках?




Проблема, скорее всего, в следующем:
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);, чтобы предоставить больше контекста. В противном случае он может укусить вас при переходе на модульный код в будущем.