Spring — использование аннотации значения для чтения из локального файла конфигурации

#java #spring #spring-boot #configuration #nullpointerexception

#java #spring #spring-boot #конфигурация #исключение nullpointerexception

Вопрос:

Я пытаюсь использовать аннотацию значения в Spring для чтения из локального приложения.файл yaml я помещаю в тот же пакет, что и мой основной и модульный тестовый класс. У меня есть простой класс с методом, который получает значение конфигурации:

 public class EmailValidator {

    String getConfigValue(configurationProvider1 configurationReader, String configName) {
        String value = null;
        ConfigurationProvider reader;
        try {
            reader = configurationReader.configurationProvider();
            value = reader.getProperty(configName, String.class);
            //the `reader` above is null when I run the test, so I get Null Pointer Exception on this line
            if (value == null) {
                LOGGER.warn("The configuration for "   configName   " cannot be found.");
            }
        } catch (Exception e){
            e.printStackTrace();
        }

        return value;
    }
} 
  

И у меня есть класс поставщика конфигурации, который устанавливает средство чтения конфигурации, чтобы мой класс выше мог использовать его для чтения приложения.файл yaml:

 @Configuration
@AllArgsConstructor(access = AccessLevel.PACKAGE)
@NoArgsConstructor
@ComponentScan
public class configurationProvider1 {

        @Value("${configFilesPath:./domain/application.properties}")//Not really sure if this is the right way of locating my configuration file
        @Getter
        private String filePath;

        @Bean
        public ConfigurationProvider configurationProvider() throws FileNotFoundException {
            if (!Paths.get(this.filePath).toFile().exists()) {
                throw new FileNotFoundException("Configuration file doesn't exist: "   this.filePath);
            }

            ConfigFilesProvider configFilesProvider =
                    () -> Collections.singletonList(Paths.get(filePath).toAbsolutePath());
            ConfigurationSource source = new FilesConfigurationSource(configFilesProvider);
            Environment environment = new ImmutableEnvironment(this.filePath);

            return new ConfigurationProviderBuilder()
                    .withConfigurationSource(source)
                    .withEnvironment(environment)
                    .build();
        }
    } 
  

Как указано выше, я не уверен, @Value("${configFilesPath:./domain/application.properties}") правильно ли найти мой локальный файл application.properties (классы находятся в том же пакете, который называется domain , но файл конфигурации отсутствует в папке ресурсов, поскольку это уровень обслуживания. Так что это прямо под domain пакетом).

И когда я пытаюсь протестировать свой метод getConfigValue в своем первом классе, я получаю NPE (я предполагаю, что это потому, что configurationReader, который я передаю в качестве параметра методу getConfigValue, равен null):

 @RunWith(SpringRunner.class)
@SpringBootTest
public class EmailValidatorTest {

    @MockBean
    private configurationProvider1 configurationReader = mock(configurationProvider1.class);

    @Autowired
    private DefaultEmailValidator validator;//maybe I should inject the dependency somewhere?

    @Test
    public void simple(){
        String a = validator.getConfigValue(configurationReader,"mail.subject.max.length");
        System.out.println(a);
    } 
  

Я не уверен, действительно ли мой класс считывает значение конфигурации из файла конфигурации на данный момент. Любая помощь будет принята с благодарностью!

PS Код обновлен

Ответ №1:

@Значение

Аннотация Spring @Value предоставляет удобный способ ввода значений свойств в компоненты, а не для указания пути к файлу свойств

@PropertySource Используйте @PropertySource для этого документа

Аннотация, предоставляющая удобный и декларативный механизм для добавления PropertySource в среду Spring. Для использования в сочетании с @Configuration классами

Учитывая файл app.properties, содержащий пару ключ / значение testbean.name=myTestBean , следующий @Configuration класс использует @PropertySourc e для внесения вклада app.properties в набор PropertySources среды.

Пример

  @Configuration
 @PropertySource("classpath:/com/myco/app.properties")
 public class AppConfig {

 @Autowired
 Environment env;

 @Bean
 public TestBean testBean() {
     TestBean testBean = new TestBean();
     testBean.setName(env.getProperty("testbean.name"));
     return testBean;
   }
 }
  

24.7.4 Недостатки YAML

Файлы YAML не могут быть загружены с помощью @PropertySource аннотации. Итак, в случае, если вам нужно загружать значения таким образом, вам необходимо использовать файл свойств.

Переходя к тестовому варианту, вы не должны создавать новый экземпляр DefaultEmailValidator , который вам нужно использовать @SpringBootTest

Пример @SpringBootTest

@SpringBootTest Аннотацию можно использовать, когда нам нужно загрузить весь контейнер. Аннотация работает путем создания ApplicationContext, который будет использоваться в наших тестах.

RunWith(SpringRunner.class )

@RunWith (SpringRunner.class ) используется для обеспечения моста между функциями тестирования Spring Boot и JUnit. Всякий раз, когда мы используем какие-либо функции тестирования загрузки Spring в тестах JUnit, эта аннотация будет необходима.

@MockBean

Еще одна интересная вещь здесь — использование @MockBean . Это создает макет

EmailValidatorТест

  @RunWith(SpringRunner.class)
 @SpringBootTest
 public class EmailValidatorTest {

@MockBean
private configurationProvider1 configurationReader;

@Autowire
private DefaultEmailValidator validator

@Test
public void testGetConfigValue(){
    String a = validator.getConfigValue(configurationReader,"mail.subject.max.length");
    System.out.println(a);
} 
  

Комментарии:

1. извините за поздний ответ 🙂 Я попробовал выше и все еще получаю NPE для строки String a = validator.getConfigValue(configurationReader,"mail.subject.max.length"); . И я создал application.properties файл и поместил его в domain папку, а также поставил @Value("${configFilesPath:./domain/application.properties}") выше @Getter для пути к файлу. Я делаю что-то не так?

2. дайте мне знать, если вы хотите, чтобы я открыл еще один билет для NPE 🙂