Spring bean set values taken from properties file - spring

I have a spring bean defined like
<util:set id="siteLanguages" value-type="java.util.Locale" set-class="java.util.LinkedHashSet">
<value>#{T(java.util.Locale).GERMAN}</value>
<value>#{T(java.util.Locale).ITALIAN}</value>
<value>#{T(java.util.Locale).ENGLISH}</value>
</util:set>
I'm wondering how can I pass the value list definitions to the bean as a properties list value.
<util:set id="siteLanguages" value-type="java.util.Locale" set-class="java.util.LinkedHashSet">
???
</util:set>
I would like to have in my properties file something like
site.languages=#{T(java.util.Locale).GERMAN},#{T(java.util.Locale).ITALIAN},#{T(java.util.Locale).ENGLISH}
or even better
site.languages=GERMAN,ITALIAN,ENGLISH
and pass this in to the bean

The main problem is that you cannot express multivalue data structures (arrays, lists etc) in plain java property files by using the java standard api.
You can do it easily though with Apache commons configuration library.
http://commons.apache.org/proper/commons-configuration/

Related

Spring dynamic properties name

I'm wondering if I can use dynamic properties name (for instance, using environment variables).
I want to use #ConfigurationProperties for injecting keys and values to HashMap. I tried it this way, but it didn't work.
application.yaml:
my-properties:
${my-env-variable-1}: env-1-value
${my-env-variable-2}: env-2-value

Spring boot yaml property binding: collection types

I find Spring Boot's (or spring in general) handling of yaml collections to be a bit peculiar. Collections according to yaml specs should be written in .yaml files as:
myCollection: ['foo', 'bar']
or
myCollection:
- foo
- bar
But neither #Value("${myCollection}") annotation or Environment.getProperty("myCollection", String[].class) (also tried List.class) can read collection properties (returns null). The only method I know of that works is to use #ConfigurationProperties annotation described in spring boot docs.
The problem with #ConfigurationProperties annotation is that (a) it is too verbose if all I want is a single property and (b) it rely on bean injection to get an instance of the #ConfigurationProperties class. Under some circumstances, bean injection is not available and all we have is a reference to Environment (e.g: thru ApplicationContext).
In my particular case, I want to read some properties during ApplicationEnvironmentPreparedEvent event, since it happens before context is built, the listener has to be manually registered and therefore, no bean injection. Via the event argument, I can get a reference to Environment. So, I can read other properties but cannot read collections.
A couple of "solutions" I noted (quoted because I don't find them very satisfactory):
Specify collections in .yaml file as myCollection: foo, bar. But this is not ideal because, the format isn't really yaml anymore.
Read individual elements using an index, for example Environment.getProperty("myCollection[0]", String.class). Will require some not-so-elegant utility methods to read and put all elements into a List.
So, my questions is - What is a good way to read collection-type properties if I cannot use #ConfigurationProperties? Also curious why comma-separated format works but not yaml-style collections.
EDIT: corrected some typos
Quite Frankly Spring boot application.properties and application.yaml or application.yml is meant to load configuration properties.
The #ConfigurationProperties annotation is designed as an abstraction to hide the implementations of configuration properties and support both .properties and .yaml/.yml.
For yaml/yml however Spring uses org.yaml.snakeyaml.Yaml library underneath to parse the file and load it to a Properties object inside org.springframework.boot.env.YamlPropertySourceLoader and a Collection is mapped as a Set not an array or List. So you try doing the following;
Environment.getProperty("myCollection", Set.class)

Specifing part of Spring context properties from JUnit test files

I have multiple mock implementations of a bean, that bean is referenced as beanA. Mock's reference names is let say: beanAMock1, beanAMock2... beanAMockN.
In context file I am aliasing beanA reference according to context placeholder beanAImplementation:
<alias name="${beanAImplementation}" alias="beanA"/>
Also there other beans (beanB, beanC...) that have mock implementations like this. And I have a number test suits that utilizing theirs specific sets of beanA, beanB... implementations.
All beans have default values for theirs switching placeholders that is specified in property file included from context.
I am looking for a ways to change part of bean's implementations per test suit.
I know three ways to do this:
1) create additional context file for each test suit that will load required properties from separate property files - this way requires creation of two additional files per test suite (context, property).
2) create profile for each test suite with aliases definitions. As I understand this requires providing aliases for each bean within per each profile - while I am having a default set of beans implementations.
3) create context within test suite manually and override required properties - with this I need to write many of the code within test suite.
Is there another ways? (may be like #3 but working with SpringJUnit4ClassRunner or its subclasses and if it will be possible just to provide required properties within annotations - it seems to be a best approach)
I've solved this problem by subclassing SpringJUnit4ClassRunner and overriding its
TestContextManager createTestContextManager(Class clazz) method. This method accepts Class object of test suite and is called before context creation. So it is possible to read additional annotations from test suite class and set system properties that will substitute corresponding placeholders during context creation.

Reading all spring beans from a particular context file

I have a spring context file with several beans of type defined.
If the input to my program is "help" then I would like to display the bean names from the context file, so that the user can pick a particular bean and give it as input. The program would instantiate the bean with that name and perform some logic.
I am not able to query the list of bean names from a particular context file.
I don't want to use a properties file to store the bean names as I am already using spring context files. Is there a better way to do this ?
Spring's BeanFactory has got a method called String[] getBeanDefinitionNames(). See Javadoc here. You can iterate through the returned list and show them to the user. then you can do a getBean call on the chosen bean name to run the logic.

Overriding the bean defined in parent context in a child context

Our app has a requirement to support multi-tenancy. Each of the boarded customer might potentially override 1 or more beans or some properties of a bean defined at the core platform level (common code/definitions). I am wondering what is the best way to handle this.
Spring allows you to redefine the same bean name multiple times, and takes the last bean definition processed for a given name to be the one that wins. So for example, your could have an XML file defining your core beans, and import that in a client-specific XML file, which also redefines some of those beans. It's a bit fragile, though, since there's no mechanism to specifically say "this bean definition is an override".
I've found that the cleanest way to handle this is using the new #Bean-syntax introduced in Spring 3. Rather than defining beans as XML, you define them in Java. So your core beans would be defined in one #Bean-annotated class, and your client configs would subclass that, and override the appropriate beans. This allows you to use standard java #Override annotations, explicitly indicating that a given bean definition is being overridden.

Resources