How to access data in another spring bean using current spring bean - java

I am new to Spring and I have a small requirement.
<bean name="triangle" class="com.thomson.learn.spring.triangle">
<property name="name" ref="dataSource" />
</bean>
<bean id="dataSource" class="java.lang.String">
<property name="name" value="easy" />
</bean>
I have written beans as shown above. I need to access the value easy from the bean with id="triangle", but when I try doing this I get a exception. Can someone please suggest how to overcome this problem?

Try the following:
<bean name="triangle" class="com.thomson.learn.spring.triangle">
<property name="name" ref="dataSource" />
</bean>
<bean id="dataSource" class="com.thomson.learn.spring.shape">
<property name="name" value="easy" />
</bean>
where com.thomson.learn.spring.triangle and com.thomson.learn.spring.shape must exist as classes in your project. your String class bean couldn't have worked because String has no name property (getName() method getter) to access.

If it is going to be String(s) that you want to inject into all of your beans you can refer properties from a property file and use <context:property-placeholder location="location to .properties"/>
or you can define properties in the configuration xml with <util:properties />
Example for property-placeholder
<bean id="appDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/> // Refered from property file
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<context:property-placeholder location="classpath:jdbc.properties"/>

A String does not have a property 'name', so you can't instantiate one the way you are trying to. Moreover, you don't need to, as you can use it directly as the value, e.g.:
<bean name="triangle" class="com.thomson.learn.spring.triangle">
<property name="name" value="easy" />
</bean>
Edit in reply to your comment:
If "name" is of type shape, then you need to inject a shape here...
<bean name="triangle" class="com.thomson.learn.spring.triangle">
<property name="name" ref="shape" />
</bean>
<bean name="shape" class="com.thomson.learn.spring.shape">
<!-- configure properties here -->
</bean>
The objects wired by Spring are supposed to be JavaBeans. What this means in practice is that they have a no-argument constructor and a set of properties, each of which has both a getter and a setter. When you write a definition such as above, Spring uses the setters to set properties you defined in the configuration file.
For instance if Shape was a class as such:
package com.thomson.learn.spring.Shape;
class Shape {
private String name;
public Shape() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Then you could wire it with the following:
<bean id="myShape" class="com.thomson.learn.spring.Shape">
<property name="name" value="blah" />
</bean>
Which really translates to Spring executing the following at runtime:
Shape myShape = new Shape();
shape.setName("blah");
That's all there is to it, except that properties can also be more complex instances of other classes of course, which is why you can use ref to refer to another bean for a property.
P.S.: Spring can use reflection to inject values in many cases, so it doesn't actually need a setter, but most people implement their beans this way for various reasons.

Related

Referencing a property of the current bean in Spring EL

I'd like to create a number of beans from a single class, all to be instantiated in the current application context, each based on prefixed properties in a properties file. I've given an example of what I'm trying to achieve. Any tips on how to do this without excessive code (e.g. without multiple classes, complicated factories, etc.) would be appreciated.
XML configuration:
<bean id="bean1" class="Mybean">
<property name="prefix" value="bean1"/>
</bean>
<bean id="bean2" class="Mybean">
<property name="prefix" value="bean2"/>
</bean>
<bean id="bean3" class="Mybean">
<property name="prefix" value="bean3"/>
</bean>
Properties File:
bean1.name=alfred
bean2.name=bobby
bean3.name=charlie
Class:
class Mybean {
#Value("${#{prefix}.name}")
String name;
}
Main Class:
public class Main {
#Autowired
List<MyBean> mybeans;
}
You can use PropertyPlaceholderConfigurer to set bean's name directly (instead of storing its prefix):
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="app.properties"/>
</bean>
<bean id="bean1" class="Mybean">
<property name="name" value="${bean1.name}"/>
</bean>
<bean id="bean2" class="Mybean">
<property name="name" value="${bean2.name}"/>
</bean>
<bean id="bean3" class="Mybean">
<property name="name" value="${bean3.name}"/>
</bean>

how to read properties file using spring and exposed to class

I am using spring 3.0.5 and trying to read properties files to make some kind of validation as well as datasource. But i am getting null when i use #Value ,below are my cfg.
in applicationContext.xml
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:database.properties"/>
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>// here It is perfectly establishing the data-source.
The Class where I want to exposed the values of properties file
#Component
public class PropertyReaderBean {
//#Value("#{propertyConfigurer1[dailyLimit]}")
//#Value("#{database['jdbc.driverClassName']}")
#Value("${jdbc.driverClassName}")// I tried all three but still getting null
private String limit;
public String getLimit()
{
System.out.println(" limit : "+limit);
return limit;
}
public void setLimit(String limit) {
System.out.println(" limit : "+this.limit);
this.limit = limit;
}
and finally the databse.properties file
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/imps
jdbc.username=root
jdbc.password=root
So whenever i am trying to access the values properties file using above configuration, i am getting null, please guide.
Update:
However the setter method of PropertyReaderBean is not working, i have checked the stacktrace, but when i add in xml like this then i can read the properties file values.
<bean id="propertyDao" class="com.alw.imps.validator.PropertyReaderBean">
<property name="limit" value="${jdbc.password}"></property>
</bean>
A likely cause is #Value doesn't work. Did you already declare < context:annotation-config /> in the application context?
You don't need property configurer, the definition of which in your code has syntax errors.
You can just do this and reference in code as you have :
<context:property-placeholder location="classpath:database.properties"/>
which relies on this
xmlns:context="http://www.springframework.org/schema/context"
and
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd

Common value configuration in Spring XML

I have several Spring beans in which one of the property value for all of them are same String value. Is there a way where I can define this String in XML at one place and refer it in all beans at property value settings?
<bean id="somebean" class="test.SomeBean">
<property name="property1" ref="someValue"></property>
<property name="commonProperty" value="commonValue"></property>
<bean id="nextBean" class="test.NextBean">
<property name="property2" ref="someValue"></property>
<property name="commonProperty" value="commonValue"></property>
How to set commonValue in a seperate place and refer it in both places?
Try like this.
<bean id="commonConfig" abstract="true">
<property name="commonField" value="CommonValue"></property>
</bean>
<bean id="class1" class="com.dataclass.Class1" parent="commonConfig">
<property name="field1" value="value1"></property>
</bean>
<bean id="class2" class="com.dataclass.Class2" parent="commonConfig">
<property name="field2" value="value2"></property>
</bean>
Class1 & Class2 having one common field name "commonField", parent attribute is use for this common purpose only.
In Spring this is called bean definition inheritance(this is not java class inheritance, above example Class1 & n Class not inheriting in their respective java file.)
For more detail, look at Spring doc's link.
I've never tried it before, but this should work
<bean id="commonProp" class="java.lang.String">
<constructor-arg name="original" value="yourString"></constructor-arg>
</bean>
Then, in every bean you need to reference it:
<bean id="somebean" class="test.SomeBean">
<property name="property1" ref="someValue"></property>
<property name="commonProperty" ref="commonProp"></property>
</bean>
You can define your string properties in some "init_constants.properties" file. Then you should load properties file in spring xml:
<bean id="properties"
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:db.properties</value>
<value>classpath:mail.properties</value>
<value>classpath:init_constants.properties</value>
</list>
</property>
</bean>
And after that you can inject this properties using xml:
<bean id="somebean" class="test.SomeBean">
<property name="property1" ref="{$prop1}"></property>
<property name="commonProperty" value="commonValue"></property>
</bean>
or in code using #Value annotation:
#Value(value="${prop1}")
private String property1;
Well If commonValue is string then you can put it in properties file and read it using #Value annotation.

How to inject a Spring bean id into another Spring Configured Bean?

I want to be able to pass a bean ID into another bean by reference. So if I have this:
<bean id="specialName" class="my.SpecialBean"/>
<bean id="referenceBean" class="my.ReferenceBean">
<property name="refId" value="<specialName.name>"/>
</bean>
public class ReferenceBean {
// The spring injected value of this should be 'specialName'
public String refId;
// getter & setter for refId
}
The reason I need this, it that ReferenceBean is actually a route builder in Camel and it directs messages to SpecialBean through the Spring Registry. I'm new to Spring and Camel, so if this is an ill conceived questions, my apologies.
You can use Spring-EL -
<bean id="specialName" class="my.SpecialBean"/>
<bean id="referenceBean" class="my.ReferenceBean">
<property name="refId" value="#{specialName.name}"/>
</bean>
Why not just put the id statically into refId there? It will not change later so why should you do something complicated here?
<bean id="specialName" class="my.SpecialBean"/>
<bean id="referenceBean" class="my.ReferenceBean">
<property name="refId" value="specialName"/>
</bean>
What about:
<bean id="specialName" class="my.SpecialBean" />
<bean id="referenceBean" class="my.ReferenceBean">
<property name="refId" ref="specialName" />
</bean>
This way your bean should be injected (provided you change the String attribute in my.SpecialBean.
Then you can get any attribute you want.
You could use the idref element (see Spring XML Beans Schema):
<bean id="specialName" class="my.SpecialBean"/>
<bean id="referenceBean" class="my.ReferenceBean">
<property name="refId">
<idref bean="specialName"/>
</property>
</bean>

Nested properties across property place holder configurers

I have multiple property files, a general one called application.properties and a more specific on called [HostName].properties
The Hostname.properties is set to higher priority than application.properties.
In application.properties I set the db.url:
db.url=jdbc:mysql://${db.host}:3306/${db.schema}?autoReconnect=true&sessionVariables=storage_engine=InnoDB;
I also set the db.host and db.schema values in this properties file.
db.schema=default
db.host=localhost
Then in [Hostname].properties I want to override the values for db.host and db.schema:
db.schema=specific
db.host=specific_hostname
However, it seems as if this nesting is not working.
The db.schema value resolves to "specific" but the db.url property resolves to the db.schema specified in the same file as the db.url is defined in.
Consider the following test snippet:
#Value("${db.url}")
private String dbUrl;
#Value("${db.schema}")
private String dbSchema;
#Test
public void testUrlTest() {
System.out.println(dbUrl);
System.out.println(dbSchema);
}
First value printed out is
jdbc:mysql://localhost:3306/default?autoReconnect=true&sessionVariables=storage_engine=InnoDB;
Second value is:
specific
Is this by design? I would love to be able to override nesting from one property configurer to the next.
Is there some way around this?
UPDATE:
The Property place holders are configured in the spring config xml as follows:
<context:property-placeholder order="10"
location="classpath:xxx.yyy/application.properties"
ignore-unresolvable="true" ignore-resource-not-found="false" />
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" ref="hostnameLookup" />
<property name="ignoreResourceNotFound" value="true" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="order" value="5" />
</bean>
<bean class="xxx.yyy.util.HostNameLookupFactory" id="hostnameLookup"
autowire-candidate="false">
<property name="prefix" value="classpath:xxx.yyy/" />
<property name="suffix" value=".properties" />
</bean>
The HostNameLookupFactory is a factory bean that provides the local host name.

Categories

Resources