How load set of properties and then access it using spring framework - spring

I have a spring web application. Let's say it is managing an animals zoo.
In my property file I am writing how much animals there are and for each animal its type and name as following :
animal.number = 2
animal.1.type= tall
animal.1.name= Simba
animal.2.type= small
animal.2.name= Pumba
Now i would like to use this property in my application using spring way. In my config.xml i could write something like following.
<bean id="animal" class="com.zoo.animalsManaging">
<property name="animalNumber" value="${animal.number}" />
<property name="animal1Name" value="${animal.1.name}" />
<property name="animal1Type" value="${ animal.1.type}" />
<property name="animal2Name" value="${animal.2.name}" />
<property name="animal2Type" value="${ animal.2.type}" />
</bean>
The problem is that animalNumber will always change. I am wondering if there is a spring way to get the entire animal property and then access to sub property by let's say animal.1.type.

As guided here you can use the util:properties
Animal properties
animal.1.type= tall
animal.1.name= Simba
animal.2.type= small
animal.2.name= Pumba
animal.number= 2
application.xml configuration
<context:property-placeholder location="classpath:animal.properties"/>
<bean name="zoo" class="com.stack.Zoo" init-method="init">
<property name="animalProperties">
<!-- not sure if location has to be customizable here; set it directly if needed -->
<util:properties location="${classpath:animal.properties}"/>
</property>
<property name="numberOfAnimals" value="${animal.number}" />
</bean>
Zoo is class Hold list of animals from Properties.
public class Zoo {
Properties animalProperties;
private Integer numberOfAnimals;
List<Animal> animals;
public void init() {
animals = new ArrayList<Animal>();
if (numberOfAnimals > 0) {
StringBuffer key = new StringBuffer();
for (int i = 1; i <= numberOfAnimals; i++) {
key.setLength(0);
key.append("animal.").append(i).append(".type");
String type = this.animalProperties.getProperty(key.toString());
key.setLength(0);
key.append("animal.").append(i).append(".name");
String name = this.animalProperties.getProperty(key.toString());
animals.add(new Animal(name,type));
System.out.println("Animals Added");
}
}
}
// Setter and getter Methods
}
In Post Construct , we are reading the properties and creating the Animal Instances.
numberOfAnimals value injected by Spring.

Related

Circular dependency (with inner bean) without duplication - is is possible?

Take the following configuration:
<beans>
<bean name="myToyota" class="Car">
<property name="contents">
<list>
<bean class="Wheel">
<property name="designation"><value>front-left</value></property>
<property name="parent"><ref bean="myToyota"/></property>
</bean>
<bean class="Wheel">
<property name="designation"><value>front-right</value></property>
<property name="parent"><ref bean="myToyota"/></property>
</bean>
</list>
</property>
</bean>
</beans>
Is it possible to build this graph without directly referencing myToyota from the Wheel beans? (Maybe using SpEL).
My concern is that I can not copy-paste the description of the Wheels to an other Car bean without introducing the possibility of broken references (that's me forgetting to adjust the parent property by hand).
In other words: is there a way an inner bean can referece it's containing bean without knowing its name?
What if you do something like the following:
public class Car {
private List contents;
public List getContents() {
return contents;
}
public void setContents(List contents) {
this.contents = contents;
for (Iterator iterator = contents.iterator(); iterator.hasNext();) {
Wheel object = (Wheel) iterator.next();
object.setParent(this);
}
}
}

How to assign a constructor-arg value of a property in a spring bean based on the enum constant

I have an enum ContentType and it has a method like ContentType.getName() which can evaluate to regText OR session. So, how do I do the below where I can instantiate the bean based on the return value of this method. Also, I only want to do this in XML config and not annotations.
<property name="contentCaptureRegEx" ref="${ContentType.getName()}">
</property>
<bean id="regText" class="java.util.regex.Pattern" factory-method="compile" lazy-init="true">
<constructor-arg value="xyz" /></bean>
<bean id="session" class="java.util.regex.Pattern" factory-method="compile" lazy-init="true">
<constructor-arg value="abc" /></bean>
I would suggest a static factory method since the pattern regexes are already using that pattern. Just eliminate them and add:
package com.mine;
public class MyFactory {
public static Pattern newContentCaptureRegEx() {
String patternString;
if ("regText".equals(ContentType.getName())) {
patternString = "xyz";
} else if ("session".equals(ContentType.getName())) {
patternString = "abc";
} else {
throw new IllegalStateException("ContentType must be regText or session");
}
Pattern.compile(patternString);
}
}
which you can wire as:
<bean id="ContentCaptureRegEx" class="com.mine.MyFactory"
factory-method="newContentCaptureRegEx" />
And then you can ref that bean anywhere as:
<property name="contentCaptureRegEx" ref="ContentCaptureRegEx" />

Does order matter while injecting properties in ProxyFactoryBean

I am trying to inject the aspects in a service. For this service I am creating a proxied object using classic way.
I have written a bean- baseProxy of type (ProxyFactoryBean) which contains a list of all the required advices.
<bean id="baseProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<list>
<value>methodInvocationAdvice</value>
</list>
</property>
</bean>
I am creating a proxy for the service like this :
<bean id="singproxy" parent="baseProxy">
<property name="target" ref="singtarget" />
<property name="targetClass" value="com.spring.learning.SingingService"></property>
</bean>
Which doesn't work but when I revert these two properties and write like this :
<bean id="singproxy" parent="baseProxy">
<property name="targetClass" value="com.spring.learning.SingingService"></property>
<property name="target" ref="singtarget" />
</bean>
To my surprise it works fine. In spring does it matter on the order for bean ? Or its a special case with ProxyFactoryBean?
I tried with Spring 3.0 I am not sure same behavior exists with previous versions.
Concerning target and targetClass, It's one or the other, but not both. Here's the relevant source (from org.springframework.aop.framework.AdvisedSupport), a parent class of ProxyFactoryBean:
public void setTarget(Object target) {
setTargetSource(new SingletonTargetSource(target));
}
public void setTargetSource(TargetSource targetSource) {
this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
}
public void setTargetClass(Class targetClass) {
this.targetSource = EmptyTargetSource.forClass(targetClass);
}
As you can see, both setTarget() and setTargetClass() write to the same field, so the last assignment wins.

Spring's overriding bean

Can we have duplicate names for the same bean id that is mentioned in the XML?
If not, then how do we override the bean in Spring?
Any given Spring context can only have one bean for any given id or name. In the case of the XML id attribute, this is enforced by the schema validation. In the case of the name attribute, this is enforced by Spring's logic.
However, if a context is constructed from two different XML descriptor files, and an id is used by both files, then one will "override" the other. The exact behaviour depends on the ordering of the files when they get loaded by the context.
So while it's possible, it's not recommended. It's error-prone and fragile, and you'll get no help from Spring if you change the ID of one but not the other.
I will add that if your need is just to override a property used by your bean, the id approach works too like skaffman explained :
In your first called XML configuration file :
<bean id="myBeanId" class="com.blabla">
<property name="myList" ref="myList"/>
</bean>
<util:list id="myList">
<value>3</value>
<value>4</value>
</util:list>
In your second called XML configuration file :
<util:list id="myList">
<value>6</value>
</util:list>
Then your bean "myBeanId" will be instantiated with a "myList" property of one element which is 6.
Not sure if that's exactly what you need, but we are using profiles to define the environment we are running at and specific bean for each environment, so it's something like that:
<bean name="myBean" class="myClass">
<constructor-arg name="name" value="originalValue" />
</bean>
<beans profile="DEV, default">
<!-- Specific DEV configurations, also default if no profile defined -->
<bean name="myBean" class="myClass">
<constructor-arg name="name" value="overrideValue" />
</bean>
</beans>
<beans profile="CI, UAT">
<!-- Specific CI / UAT configurations -->
</beans>
<beans profile="PROD">
<!-- Specific PROD configurations -->
</beans>
So in this case, if I don't define a profile or if I define it as "DEV" myBean will get "overrideValue" for it's name argument. But if I set the profile to "CI", "UAT" or "PROD" it will get "originalValue" as the value.
An example from official spring manual:
<bean id="inheritedTestBean" abstract="true"
class="org.springframework.beans.TestBean">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithDifferentClass"
class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBean" init-method="initialize">
<property name="name" value="override"/>
<!-- the age property value of 1 will be inherited from parent -->
</bean>
Is that what you was looking for?
Updated link
Since Spring 3.0 you can use #Primary annotation. As per documentation:
Indicates that a bean should be given preference when multiple
candidates are qualified to autowire a single-valued dependency. If
exactly one 'primary' bean exists among the candidates, it will be the
autowired value. This annotation is semantically equivalent to the
element's primary attribute in Spring XML.
You should use it on Bean definition like this:
#Bean
#Primary
public ExampleBean exampleBean(#Autowired EntityManager em) {
return new ExampleBeanImpl(em);
}
or like this:
#Primary
#Service
public class ExampleService implements BaseServive {
}
Another good approach not mentioned in other posts is to use PropertyOverrideConfigurer in case you just want to override properties of some beans.
For example if you want to override the datasource for testing (i.e. use an in-memory database) in another xml config, you just need to use <context:property-override ..."/> in new config and a .properties file containing key-values taking the format beanName.property=newvalue overriding the main props.
application-mainConfig.xml:
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
p:driverClassName="org.postgresql.Driver"
p:url="jdbc:postgresql://localhost:5432/MyAppDB"
p:username="myusername"
p:password="mypassword"
destroy-method="close" />
application-testConfig.xml:
<import resource="classpath:path/to/file/application-mainConfig.xml"/>
<!-- override bean props -->
<context:property-override location="classpath:path/to/file/beanOverride.properties"/>
beanOverride.properties:
dataSource.driverClassName=org.h2.Driver
dataSource.url=jdbc:h2:mem:MyTestDB
Whether can we declare the same bean id in other xml for other reference e.x.
Servlet-Initialize.xml
<bean id="inheritedTestBean" class="org.springframework.beans.TestBean">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
Other xml (Document.xml)
<bean id="inheritedTestBean" class="org.springframework.beans.Document">
<property name="name" value="document"/>
<property name="age" value="1"/>
</bean>
Question was more about XML but as annotation are more popular nowadays and it works similarly I'll show by example.
Let's create class Foo:
public class Foo {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and two Configuration files (you can't create one):
#Configuration
public class Configuration1 {
#Bean
public Foo foo() {
Foo foo = new Foo();
foo.setName("configuration1");
return foo;
}
}
and
#Configuration
public class Configuration2 {
#Bean
public Foo foo() {
Foo foo = new Foo();
foo.setName("configuration2");
return foo;
}
}
and let's see what happens when calling foo.getName():
#SpringBootApplication
public class OverridingBeanDefinitionsApplication {
public static void main(String[] args) {
SpringApplication.run(OverridingBeanDefinitionsApplication.class, args);
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(
Configuration1.class, Configuration2.class);
Foo foo = applicationContext.getBean(Foo.class);
System.out.println(foo.getName());
}
}
in this example result is: configuration2.
The Spring Container gets all configuration metadata sources and merges bean definitions in those sources. In this example there are two #Beans. Order in which they are fed into ApplicationContext decide. You can flip new AnnotationConfigApplicationContext(Configuration2.class, Configuration1.class); and result will be configuration1.

Reading a list from a file .properties using Spring properties place holder

I want to fill a bean list property using Spring properties place holder.
Context file
<bean name="XXX" class="XX.YY.Z">
<property name="urlList">
<value>${prop.list}</value>
</property>
</bean>
Properties File
prop.list.one=foo
prop.list.two=bar
Any help would be much appreciated
Use a util:properties element to load your properties. You can use PropertyPlaceholderConfigurer to specify the path to your file:
<bean name="XXX" class="XX.YY.Z">
<property name="urlList">
<util:properties location="${path.to.properties.file}"/>
</property>
</bean>
Update I've misunderstood the question; you only want to return properties where key starts with specific string. The easiest way to achieve that would be to do so within setter method of your bean. You'll have to pass the string to your bean as a separate property. Extending the above declaration:
<bean name="XXX" class="XX.YY.Z" init-method="init">
<property name="propertiesHolder">
<!-- not sure if location has to be customizable here; set it directly if needed -->
<util:properties location="${path.to.properties.file}"/>
</property>
<property name="propertyFilter" value="${property.filter}" />
</bean>
In your XX.YY.Z bean:
private String propertyFilter;
private Properties propertiesHolder;
private List<String> urlList;
// add setter methods for propertyFilter / propertiesHolder
// initialization callback
public void init() {
urlList = new ArrayList<String>();
for (Enumeration en = this.propertiesHolder.keys(); en.hasMoreElements(); ) {
String key = (String) en.nextElement();
if (key.startsWith(this.propertyFilter + ".") { // or whatever condition you want to check
this.urlList.add(this.propertiesHolder.getProperty(key));
}
} // for
}
If you need to do this in many different places you can wrap the above functionality into a FactoryBean.
A simpler solution:
class Z {
private List<String> urlList;
// add setters and getters
}
your bean definition
<bean name="XXX" class="XX.YY.Z">
<property name="urlList" value="#{'${prop.list}'.split(',')}"/>
</bean>
Then in your property file:
prop.list=a,b,c,d
<bean id="cpaContextSource" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="urls">
<bean class="org.springframework.util.CollectionUtils" factory-method="arrayToList">
<constructor-arg type="java.lang.Object">
<bean class="org.springframework.util.StringUtils" factory-method="tokenizeToStringArray">
<constructor-arg type="java.lang.String" value="${myList}"/>
<constructor-arg type="java.lang.String" value=" "/>
</bean>
</constructor-arg>
</bean>
</property>
where:
myList=http://aaa http://bbb http://ccc
The only way i see here is, implement the interface 'MessageSourceAware' to get the messageResource, and then manually populate your list.
class MyMessageSourceAwareClass implemets MessageSourceAware{
public static MessageSource messageSource = null;
public void setMessageSource(MessageSource _messageSource) {
messageSource = _messageSource;
}
public static String getMessage( String code){
return messageSource.getMessage(code, null, null );
}
}
--- Properties File ---
prop.list=foo;bar;one more
Populate your list like this
String strlist = MyMessageSourceAwareClass.getMessage ( "prop.list" );
if ( StringUtilities.isNotEmptyString ( strlist ) ){
String[] arrStr = strList.split(";");
myBean.setList ( Arrays.asList ( arrStr ) );
}
Just add the following Bean definition
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:myprops.properties</value>
</list>
</property>
</bean>
To use it like so please note port is defined in myprops.properties
<bean id="mybean" class="com.mycompany.Class" init-method="start">
<property name="portNumber" value="${port}"/>
</bean>
There are several ways , one of them is below.
XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));
cfg.postProcessBeanFactory(factory);

Resources