Проблема с @PropertySource и привязкой карты

#spring #spring-boot #configuration

#весна #весна-загрузка #конфигурация

Вопрос:

У меня есть эта конкретная проблема с моим файлом конфигурации yml. У меня есть многомодульный проект maven следующим образом:

 app
 |-- core
 |-- web
 |-- app
  

У меня есть этот файл конфигурации в core проекте

 @Configuration
@PropertySource("core-properties.yml")
public class CoreConfig {

}
  

И это отображение:

 @Component
@ConfigurationProperties(prefix = "some.key.providers.by")
@Getter
@Setter
public class ProvidersByMarket {

  private Map<String, List<String>> market;

}
  

Вот мои core-properties.yml

 some.key.providers:
  p1: 'NAME1'
  p2: 'NAME2'

some.key.providers.by.market:
  de:
    - ${some.key.providers.p1}
    - ${some.key.providers.p2}
  gb:
    - ${some.key.providers.p1}
  

Например, когда я загружаю файл через активацию профиля, переименуйте файл в application-core-properties.yml , и тогда -Dspring.profiles.active=core-properties это сработает, однако, если при попытке загрузить файл через @PropertySource("core-properties.yml") это не получается, и я получаю следующую ошибку:

 Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-03-27 10:07:36.397 -ERROR 13474|| --- [  restartedMain] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to bind properties under 'some.key.providers.by.market' to java.util.Map<java.lang.String, java.util.List<java.lang.String>>:

    Reason: No converter found capable of converting from type [java.lang.String] to type [java.util.Map<java.lang.String, java.util.List<java.lang.String>>]

Action:

Update your application's configuration


Process finished with exit code 1
  

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

1. Вы не можете загружать файлы YAML с помощью @PropertySource (см. mdeinum.github.io/2018-07-04-PropertySource-with-yaml-files ). Используйте механизмы загрузки spring по умолчанию для загрузки дополнительных конфигурационных файлов вместо @PropertySource .

Ответ №1:

Возможно, у вас нет эквивалентной структуры свойств, например

 spring:
    profiles: test
name: test-YAML
environment: test
servers: 
    - www.abc.test.com
    - www.xyz.test.com

---
spring:
    profiles: prod
name: prod-YAML
environment: production
servers: 
    - www.abc.com
    - www.xyz.com
  

И класс конфигурации должен быть

 @Configuration
@EnableConfigurationProperties
@ConfigurationProperties
public class YAMLConfig {

    private String name;
    private String environment;
    private List<String> servers = new ArrayList<>();

    // standard getters and setters
  

Ответ №2:

Я решил проблему, реализовав следующее, PropertySourceFactory подробно описанное в here

 import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import org.springframework.lang.Nullable;

public class YamlPropertySourceFactory implements PropertySourceFactory {

    @Override
    public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
        Properties propertiesFromYaml = loadYamlIntoProperties(resource);
        String sourceName = name != null ? name : resource.getResource().getFilename();
        return new PropertiesPropertySource(sourceName, propertiesFromYaml);
    }

    private Properties loadYamlIntoProperties(EncodedResource resource) throws FileNotFoundException {
        try {
            YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
            factory.setResources(resource.getResource());
            factory.afterPropertiesSet();
            return factory.getObject();
        } catch (IllegalStateException e) {
            // for ignoreResourceNotFound
            Throwable cause = e.getCause();
            if (cause instanceof FileNotFoundException)
                throw (FileNotFoundException) e.getCause();
            throw e;
        }
    }
}
  

Ответ №3:

У меня была похожая проблема, и я нашел обходной путь, подобный этому:

 diacritic:
  isEnabled: true
  chars: -> I wanted this to be parsed to map but it didn't work
    ą: a
    ł: l
    ę: e
  

И мое решение до сих пор:

 diacritic:
  isEnabled: true
  chars[ą]: a           -> these ones could be parsed to Map<String, String>
  chars[ł]: l           
  chars[ę]: e