MarioC
MarioC

Reputation: 3228

SPRING - Create MessageSources programmatically and use them as beans

I have to create different messageSources programmatically and put them in a Bean in order to use the correct one when needed.

The application must have a messageSource for each of our Customers, so i created a Configuration class

@Configuration
public class MessageSourceConfig implements BeanFactoryAware {

    private BeanFactory beanFactory;

    @Autowired
    private ICompanyService service;

    private Map<Company, MessageSource> messageSourceMap = new HashMap<Company, MessageSource>();

    // default messageSource
    @Bean
    @Primary
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("classpath:messages");
        messageSource.setUseCodeAsDefaultMessage(true);
        messageSource.setCacheSeconds(5);
        messageSource.setDefaultEncoding("UTF-8");

        return messageSource;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;

    }

    @PostConstruct
    public void onPostConstruct() {
        ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;

        Iterable<Company> companies = service.findAll();
        for(Company c : companies) {
             String beanName= c.getSlug()+"_messageSource";
             MessageSource bean = getCompanyMessageSource(c);        
             configurableBeanFactory.registerSingleton(beanName, bean);

             messageSourceMap.put(c, bean);
        }


     }


    private MessageSource getCompanyMessageSource(Company company) {
        ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource();
        ms.setBasename("classpath:" + company.getSlug() + "/messages");
        ms.setUseCodeAsDefaultMessage(true);
        ms.setCacheSeconds(5);
        ms.setDefaultEncoding("UTF-8");

        return ms;
    }


    public MessageSource companyMessageSource(Company company) {
        return messageSourceMap.get(company);
    }

In this way we have a default messageSource and one specific messageSource for each Company. The idea was to put this specific messageSources into a Map and then accessing the correct one from the map when we need it. The problem is that companyMessageSource should be a bean, but i cannot pass a parameter to the bean, how can i access dynamically the correct source?

Upvotes: 1

Views: 1230

Answers (2)

Emirhan Naneli
Emirhan Naneli

Reputation: 66

My goal was to inject the messages I set as default via gist and I solved it this way

You can update it according to your needs.

@Configuration  
open class I18nConfig : InitializingBean {  
  
    @Bean  
 open fun messageSource(): ResourceBundleMessageSource {  
        val source = ResourceBundleMessageSource()  
        source.setBasename("i18n/messages")  
        source.setDefaultEncoding(StandardCharsets.UTF_8.name())  
        source.setCacheMillis(Duration.ofHours(2).toMillis())  
        source.setFallbackToSystemLocale(false)  
        source.setUseCodeAsDefaultMessage(true)  
  
        return source  
  }  
  
    override fun afterPropertiesSet() {  
        val files = ClassPathResource("i18n").file.listFiles() ?: return  
  files.forEach { file ->  
  val locale = file.nameWithoutExtension.split("_").last()  
            val properties = loadBaseTranslations(locale)  
  
            file?.let {  
 it.inputStream().use { stream ->  
  val reader = InputStreamReader(stream, StandardCharsets.UTF_8)  
                    properties.load(reader)  
                }  
 }  
  file?.let { it.outputStream().use { stream -> properties.store(stream, null) } }  
 }  }  
  
    private fun loadBaseTranslations(locale: String): Properties {  
        val url = URI  
  .create("https://gist.githubusercontent.com/emirhannaneli/.../global-messages:$locale")  
            .toURL()  
        val connection = url.openConnection()  
        connection.connect()  
        val inputStream = connection.getInputStream()  
        val reader = InputStreamReader(inputStream, StandardCharsets.UTF_8)  
        val properties = Properties()  
        properties.load(reader)  
        return properties  
  }  
}

Upvotes: 0

Turbut Alin
Turbut Alin

Reputation: 2676

I am not entirely sure I understand how you want to use the created beans, but one way to get the registered singletons of MessageSource is to get them programmatically something like this:

@Service
public class CompanyService {

    @Autowired
    private ApplicationContext applicationContext;

    public void useCompanySpecificMessageSource(Company c) {
        MessageSource ms = applicationContext.getBean(c.getSlug() + "_messageSource");
        log.debug(ms.getMessage("code", null, new Locale("en", "GB"));
    }
}

Hope this helps.

Upvotes: 1

Related Questions