Доступ к файлу свойств в приложении JSF программно

Я пытаюсь получить доступ к файлу свойств i18n, который я использую в своем приложении JSF в коде. (Идея состоит в том, чтобы иметь страницу, отображающую ее ключи и значения в качестве таблицы на самом деле.)

Проект является проектом maven и в папке src/resources/localization и развернут в военном файле в WEB-INF\classes\localization\

java.util.Properties prop = new java.util.Properties();
String path = "localization/stat_codes.properties";
InputStream foo = prop.getClass().getResourceAsStream(path);

Но переменная foo оказывается нулевой, независимо от того, как я устанавливаю переменную пути, /WEB -INF/classes/localization/stat_codes.properties, "localization.stat_codes.properties" и т.д. Аналогичный вопрос: здесь, но там нет полезного ответа.

Ответ 1

Class#getResourceAsStream() может принимать путь, который находится относительно местоположения Class, который вы используете там как отправную точку. Например, если класс находится в пакете com.example и вы запрашиваете путь foo/filename.properties, то он фактически загрузит файл com/example/foo/filename.properties. Но если вы используете /foo/filename.properties, то он фактически загрузит foo/filename.properties из корня classpath.

Итак, ваш код

java.util.Properties prop = new java.util.Properties();
String path = "localization/stat_codes.properties";
InputStream foo = prop.getClass().getResourceAsStream(path);

будет искать файл java/util/localization/stat_codes.properties.

Но в приложениях с сложной иерархией многоуровневого загрузчика один загрузчик классов не является другим. Классный загрузчик, который загружал основные классы Java, не обязательно знает о файлах, которые находятся в webapp /WEB-INF/classes. Поэтому префикс пути с / не обязательно будет решением, он все равно вернет null.

Если вы можете гарантировать, что текущий класс будет виден тем же загрузчиком классов, что и файлы свойств (поскольку они находятся в одном и том же под-корневом пути пути к классам, например /WEB-INF/classes, тогда вы действительно должны использовать

String path = "/localization/stat_codes.properties";
InputStream foo = this.getClass().getResourceAsStream(path);

Но если в какой-то момент файлы свойств будут экстернализированы из-за более легкого обслуживания/редактирования во время выполнения, так что вам не нужно перестраивать/повторно развертывать/перезапускать webapp, когда вы хотите редактировать файлы, то приведенное выше строка кода, скорее всего, не удастся. Внешнее местоположение будет доступно только другому загрузчику классов. Каноническое решение заключается в том, чтобы вместо этого использовать загрузчик классов контекста потока как отправную точку, он имеет доступ ко всем ресурсам в пути к классам.

String path = "localization/stat_codes.properties";
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream foo = loader.getResourceAsStream(path);

(обратите внимание, что этот путь не может принимать путь, начинающийся с /, он всегда относится к общему корню)

См. также:

Ответ 2

Кажется, что виновником является объект prop, я предположил, что любой объект будет работать, но он должен быть текущим объектом (this), на который вызывается метод getClass(). Кроме того, путь должен начинаться с /, так как каталог localization находится в WEB-INF/classes.

String path = "localization/stat_codes.properties";
InputStream foo = this.getClass().getResourceAsStream(path);