I am just starting up with Spring and trying autowiring byName
here is my code
Address class:
package org.springinaction;
public class Address {
private String addressline;
public String getAddressline() {
return addressline;
}
public void setAddressline(String addressline) {
this.addressline = addressline;
}
}
Customer class:
package org.springinaction;
public class Customer {
private Address address;
public Address getN() {
return address;
}
public void setN(Address n) {
this.address = n;
}
}
Spring cofiguration:
<beans>
<bean id="customer" class="org.springinaction.Customer" autowire="byName" />
<bean id="address" class="org.springinaction.Address">
<property name="addressline" value="bangalore" />
</bean>
</beans>
CustomerTest.java
package org.springinaction;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class CustomerTest {
public static void main(String[] args) {
ApplicationContext context =new ClassPathXmlApplicationContext("SpringInAction.xml");
Customer cust=(Customer)context.getBean("customer");
System.out.println(cust.getN());
}
}
When I am trying to do autowring by name which states thats if name of property matches with name of name it will get autowired.however in my case its not happening.
its giving me null with this...can anyone help me this this so that it be autowired correctly
The "name" that auto wiring looks for is the name of the JavaBean property as derived from the name of the setter method, therefore your Customer class has a property named n (from the setN method), the fact that the private field is named address is irrelevant.
You either need to define a suitable bean with id n or change the getter and setter in Customer to getAddress and setAddress in order to match the name of the existing address bean.
Change your getter and setter to this:
public Address getAddress() {
return address;
}
public void setAddress(Address n) {
this.address = n;
}
According to Java beans convention your getter and setter must have name get (or set) + name of property with first letter capitalized.
If you just want your Customer bean to be injected with your Address bean, then simply use the #Autowired annotation, no need for setters/getters then:
<context:annotation-config /> // EDIT - think this required for autowiring
<bean id="customer" class="org.springinaction.Customer"/>
<bean id="address" class="org.springinaction.Address">
<property name="addressline" value="bangalore" />
</bean>
public class Customer {
#Autowired
Address address;
....
Have more than 1 address bean? Then use the #Qualifier as well:
<bean id="customer" class="org.springinaction.Customer"/>
<bean id="work-address" class="org.springinaction.Address">
<property name="addressline" value="bangalore" />
</bean>
<bean id="home-address" class="org.springinaction.Address">
<property name="addressline" value="bangalore" />
</bean>
public class Customer {
#Autowired
#Qualifier ( value = "work-address" )
Address workAddress;
#Autowired
#Qualifier ( value = "home-address" )
Address homeAddress;
....
Related
i have requirement to replace private method of spring bean, can i achieve through spring replace.
My Code :
Replacer Class :
public class PrivateCarRep extends Car implements MethodReplacer{
#Override
public Object reimplement(Object obj, Method method, Object[] args) throws
Throwable {
// new property of Car.breaks() method.
System.out.println("New privateBreaksIs Done from Shiv");
return obj;
}
}
Car.java
package org.websparrow.beans;
public class Car {
private void privateBreaks() {
System.out.println("Old car break. privateBreaks");
}
}
My Spring Configuration:
<bean id="PrivateCarRep" class="org.websparrow.beans.PrivateCarRep"/>
<bean id="car" class="org.websparrow.beans.Car">
<replaced-method name="privateBreaks" replacer="PrivateCarRep" />
</bean>
Dear All,
i already know that i can't replace private method through spring replacer but is there any workaround for this in spring..
You need to define PrivateCarRep as a bean:
<bean id="privateCarReplacer" class="com.xx.yy.zz.PrivateCarRep" />
<bean id="car" class="org.websparrow.beans.Car">
<replaced-method name="privateBreaks" replacer="privateCarReplacer" />
</bean>
I'm afraid you can't do that,I thing the method should be be protected or public.
I need to instantiate a bean ( EmployeeSaver) with in a method with parameter coming in dynamically. I can't use constructor setter for these values are not populated at config time.
Sample code:
class MyEmployeeBean{
public void saveEmployeeDetail (Employee employee , EmployeeHistory hist ){
EmployeeDetail detail = hist.getDetail();
EmployeeSaver eSave = new EmployeeSaver(employee, detail)
saver.saveEmployee();
}
}
class EmployeeSaver {
private Employee empl;
private EmployeeDetail detail;
public EmployeeSaver(Employee emp, EmployeeDetail det){
empl = emp;
detail = det;
}
public void saveEmployee(){
// code to same the guy...
}
}
As MyEmployeeSaver class don't have default constructor so it's throwing runtime exception. I am unsable to use following config as employeeDetail is not know until I do hist.getDetail() !
<bean id="mySaverBean" class="come.saver.EmployeeSaver">
<constructor-arg name="empl" ref="employee" />
<constructor-arg name="hist" ref = "employeeHistory" />
</bean>
How to instantiate employeeSaverBean with constructor arguments?
You can't do this directly with Spring configuration, but using ApplicationContext.getBean(String beanName,Object...args) like described in this question.
MyEmployeeBean must implements ApplicationContextAware to access Spring's context
class MyEmployeeBean implements ApplicationContextAware {
ApplicationContext applicationContext;
void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void saveEmployeeDetail (Employee employee , EmployeeHistory hist ){
EmployeeDetail detail = hist.getDetail();
EmployeeSaver eSave = (EmployeeSaver)this.applicationContextnew.getBean("mySaverBean", employee, detail);
saver.saveEmployee();
}
}
and in beans.xml
<bean id="mySaverBean" class="come.saver.EmployeeSaver" scope="prototype" />
Remeber to addo scope="prototype" to let Spring create a new instance at every request.
How can we switch between different Implementations in Spring Context XML with an Boolean?
for example:
<bean id="detailsController" class="com.something.detailsController" >
if true then
<property name="dao" ref="firstDao"/>
else
<property name="dao" ref="secoundDao"/>
I know in Spring3 we can work with profiles
You could do that by modifying your Java code and use Spring EL together with ApplicationAware and InitializingBean.
public class DetailsController implements ApplicationContextAware, InitializingBean {
private DetailsControllerDAO dao;
private String daoName;
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void afterPropertiesSet() {
dao = applicationContext.getBean(daoName);
}
public void setDaoName(String daoName) {
this.daoName = daoName;
}
}
In XML:
<bean id="detailsController" class="com.something.detailsController">
<property name="daoName" value="#{myCondition ? 'firstDao' : 'secondDao'}" />
</bean>
Of course, this solution has the disadvantage to add dependency to Spring code in your controller. To avoid that, you could move that code in a proxy class, as described by Guillaume Darmont.
I dont think this can be done at the XML level.
Spring really cannot do that. See the bean lifecycle. Been classes are created, than properties are injected and than afterPropertiesSet() or #PostConstructor methods are invoked. Of course when I omit lazy initialized beans.
But if you want for testing etc. and so you need just the firstDao or the secondDao in your application at the sametime that depends just on your settings, you can use a bean factory. The bean factory creates your bean as you want. I also use it for to split development environment, test environment and production environment.
package com.dummyexample.config;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Factory bean to create real or test dao.
* The result depends on realDaoEnabled configuration parameter.
*
* #author Martin Strejc
*/
#Configuration
public class DaoBeanFactory {
// mapping to servlet context configuration
#Resource(mappedName = "realDaoEnabled")
private Boolean realDaoEnabled = true;
// TestDao extends or implements Dao
#Autowired
private TestDao testDao;
// ProdDao extends or implements Dao
#Autowired
private ProdDao prodDao;
public DaoBeanFactory() {
}
#Bean(name="dao")
public Dao getDao() {
if(realDaoEnabled) {
return prodDao;
}
return testDao;
}
}
Since your DAOs are exchangeable, they inherits the same type (abstract class or interface). Thus you can write a RoutingDetailsControllerDAO.
Let's say that your common interface is named DetailsControllerDAO, with two methods getDetails and getMoreDetails inside, the code would be :
public class RoutingDetailsControllerDAO implements DetailsControllerDAO {
private DetailsControllerDAO firstDAO;
private DetailsControllerDAO secondDAO;
protected DetailsControllerDAO getDAOToUse() {
return YOUR_BOOLEAN_CONDITION ? firstDAO : secondDAO;
}
#Override
public Details getDetails() {
return getDAOToUse().getDetails();
}
#Override
public Details getMoreDetails() {
return getDAOToUse().getMoreDetails();
}
// Insert firstDAO and secondDAO setters below
...
}
Your Spring XML config is now :
<bean id="detailsController" class="com.something.detailsController" >
<property name="dao" ref="routingDetailsControllerDAO"/>
</bean>
<bean id="routingDetailsControllerDAO" class="com.something.RoutingDetailsControllerDAO">
<property name="firstDao" ref="firstDao"/>
<property name="secondDao" ref="secondDao"/>
</bean>
Few possibilities:
You can either use profiles (<beans profiles="profileOne">).
You can use FactoryBean to create the correct DAO
You can use SPeL
The last one is the easiest:
<bean id="detailsController" class="com.something.detailsController">
<property name="dao" ref="#{condition ? 'firstDao' : 'secondDao'}" />
</bean>
Of course you can load bean name from properties file via property configurer:
<bean id="detailsController" class="com.something.detailsController">
<property name="dao" ref="${bean.name.from.properties.file}" />
</bean>
I'm trying to run a simple application with jmx-exported method. I do it like (spring-context and cglib for "#Configuration" are in classpath):
package com.sopovs.moradanen.jmx;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jmx.export.MBeanExporter;
import org.springframework.stereotype.Component;
#Component
#Configuration
public class SpringJmxTest {
public static void main(String[] args) {
new AnnotationConfigApplicationContext("com.sopovs.moradanen.jmx");
while (true) {
Thread.yield();
}
}
#Bean
public MBeanExporter createJmxExporter() {
return new MBeanExporter();
}
public interface FooBarMBean {
public String hello();
}
#Component
public static class FooBar implements FooBarMBean {
#Override
public String hello() {
return "Hello";
}
}
}
However when I run it I get:javax.management.MalformedObjectNameException: Key properties cannot be empty. I tried to debug and solved it with:
#Component
public static class FooBar implements FooBarMBean, SelfNaming {
#Override
public String hello() {
return "Hello";
}
#Override
public ObjectName getObjectName() throws MalformedObjectNameException {
return new ObjectName("fooBar:name=" + getClass().getName());
}
}
But is there a better way to supply a name for MBean?
You can use the descriptions annotations provided by Spring Context #Managed* :
To do this, you must NOT implements the interface with "MBean" or "MXBean" suffix, neither SelfNaming.
Then, the bean will be detected as a standard spring "managed bean" when MBeanExporter will registerBeanInstance(..), and will be converted to a ModelMBean using all spring annotations, including descriptions of attributes, operations, parameters, etc..
As a requirement, you should declare in your spring context the MBeanExporter with AnnotationJmxAttributeSource, MetadataNamingStrategy, and MetadataMBeanInfoAssembler attributes, which can be simplified like this (as described here):
<bean id="mbeanExporter"
class="org.springframework.jmx.export.annotation.AnnotationMBeanExporter" />
or:
<context:mbean-export />
or, using programmatic approach:
#Configuration
#EnableMBeanExport
public class AppConfig {
}
And your managed bean should look like this :
#Component("myManagedBean")
#ManagedResource(objectName="your.domain.jmx:name=MyMBean",
description="My MBean goal")
public class AnnotationTestBean {
private int age;
#ManagedAttribute(description="The age attribute", currencyTimeLimit=15)
public int getAge() {
return age;
}
#ManagedOperation(description = "Check permissions for the given activity")
#ManagedOperationParameters( {
#ManagedOperationParameter(name = "activity",
description = "The activity to check")
})
public boolean isAllowedTo(final String activity) {
// impl
}
}
Remember to not implements an MBean interface, which would be a StandardMBean, and SelfNaming interface, which would bypass Spring naming management !
You can use KeyNamingStrategy to define all JMX-related properties inside XML configuration without adding any compile-time dependencies to Spring into the source code of your MBean:
<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="namingStrategy" ref="namingStrategy"/>
</bean>
<bean id="namingStrategy"
class="org.springframework.jmx.export.naming.KeyNamingStrategy">
<property name="mappings">
<props>
<prop key="someSpringBean">desired.packageName:name=desiredBeanName</prop>
</props>
</property>
</bean>
If you can live with somewhat arbitrary object names, then you can use the IdentityNamingStrategy as a naming strategy for MBeanExporter and minimize the XML configuration event further:
<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="namingStrategy" ref="namingStrategy"/>
</bean>
<bean id="namingStrategy"
class="org.springframework.jmx.export.naming.IdentityNamingStrategy"/>
Check spring documentation: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/jmx.html section 22.3.2 explains the JDK 5.0 annotations that are available.
Section 22.4 explains mechanisms available for object naming.
I have some problems wth autowire annotation. My app looks like this:
Here is controller:
#Controller
public class MyController {
#Autowired
#Qualifier("someService")
private SomeService someService;
....
}
It's a service layer:
public interface SomeService {
...
}
#Service
public class SomeServiceImpl implements SomeService{
#Autowired
#Qualifier("myDAO")
private MyDAO myDAO;
....
}
And DAO layer:
public interface MyDAO{
....
}
#Repository
public class JDBCDAOImpl implements MyDAO {
#Autowired
#Qualifier("dataSource")
private DataSource dataSource;
....
}
This is a app-service.xml file:
....
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="/WEB-INF/jdbc.properties" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"/>
<bean id="SomeService" class="com.service.SomeServiceImpl" />
<bean id="myDAO" class="com.db.JDBCDAOImpl" />
So... When I'm launching a web-app, MyController Autowires correctly (the someService field correctly injected by SomeServiceImpl class object), but myDAO feild of someService has null value (not injected properly).
Could you help me to find a problem?
P.S. Its interesting, but when I'm changing a "bean id" from myDAO to some another (e.g. myDAO2), system gives me an error, that injecting could not be done, because bean myDAO doesn't exist. So, Spring make an injection, but where it is? And why it's not work correctly?
I found the solution. As Javi said (thanks a lot for you, Javi), I have to annotate DAO and Service layer classes with #Repository and #Service annotation. Now I've tried to write like this:
#Service("someService")
public class SomeServiceImpl implements SomeService{
#Autowired
#Qualifier("myDAO")
private MyDAO myDAO;
....
}
and
#Repository("myDAO")
public class JDBCDAOImpl implements MyDAO {
#Autowired
#Qualifier("dataSource")
private DataSource dataSource;
....
}
and all works fine!!!
But I still not found an answer for this quesion: if application will be more complex, and will have more complex structure, where #Repositore and #Service annotation are not preferred for some classes, how to inject correctly beans, which located in lower levels (in a fields of classes, or in a field of fields of classes) (with #Autowire annotation, of course)?
I guess you need <context:annotation-config />.
You can use
<context:component-scan base-package="PATH OF THE BASE PACKAGE"/>
entry in your configuration .xml file. This entry will scan/read all the stated type and annotations from the java classes.
Important points:
Sometimes, #Component may leads to a problem where it might say no default constructor found.
The class which is defined as a #Component annotation, it must have a default constructor.
Suppose, we have applied #Autowired annotation at field which is a user defined class reference.
Now, if we also apply #Component to that class then it will always be initialized with null.
So, a field with #Autowired should not have #Component at its class definition.
By default #Autowired is byType.
Address bean is autowired at Student class.
Let’s see what happens if we apply #Component at Address.java.
CollegeApp.java:
package com.myTest
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.bean.Address;
import com.bean.Student;
//Component scanning will for only those classes
//which is defined as #Component. But, all the class should not use
//#Component always even if the class is enabled with auto
//component scanning, specially the class which is Autowired
//Or which is a property of another class
#Configuration
#ComponentScan(basePackages={"com.bean"})
public class CollegeApp {
#Bean
public Address getAddress(){
return new Address("Elgin street");
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(CollegeApp.class);
Student student=context.getBean(Student.class);
System.out.println(student.toString());
context.close();
}
}
We want Elgin street to be autowired with Student address.
Address.java:
package com.bean;
import org.springframework.stereotype.Component;
#Component
public class Address {
private String street;
public Address()
{
}
public Address(String theStreet)
{
street=theStreet;
}
public String toString()
{
return (" Address:"+street);
}
}
Student.java:
package com.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class Student {
private String name;
private int age;
private Address address;
public Student()
{
}
public Student(String theName,int theAge)
{
name=theName;age=theAge;
}
#Autowired
public void setAddress(Address address) {
this.address = address;
}
public String toString()
{
return ("Name:"+name+" Age:"+age+ " "+address);
}
}
Output: - Name:null Age:0 Address:null //Address not Autowired here.
To resolve the issue, only change the Address.java as below:
Address.java:
package com.bean;
public class Address {
private String street;
public Address(String theStreet)
{
street=theStreet;
}
public String toString()
{
return (" Address:"+street);
}
}
Output:-
Name:null Age:0 Address:Elgin street
You should include this section of XML code in spring-config.xml :
<context:component-scan base-package="Fully.Qualified.Package.Name" />
but you should know the difference between <context:annotation-config> vs <context:component-scan> as most people are suggesting these two :
1) First big difference between both tags is that <context:annotation-config> is used to activate applied annotations in already registered beans in application context. Note that it simply does not matter whether bean was registered by which mechanism e.g. using <context:component-scan> or it was defined in application-context.xml file itself.
2) Second difference is driven from first difference itself. It does register the beans in context + it also scans the annotations inside beans and activate them. So <context:component-scan>; does what <context:annotation-config> does, but additionally it scan the packages and register the beans in application context.
There can be two reasons for this.
When you have not annotated the injected object or say service with proper #Service/#Component/#Repository annotations.
Once you have made sure of point 1 ,next check for whether the class package of your annotated service class is included in the class-path for your spring boot application in the main class.You can configure this using the following annotation.
#SpringBootApplication(scanBasePackages = {
"com.ie.efgh.somepackage","com.ie.abcd.someotherpackage" })
Doing this you tell spring to look into the packages for the classes during class loading.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Specifying base package of the Components like Controller, Service,
DAO -->
<context:component-scan base-package="com.jwt" />
<!-- Getting Database properties -->
<context:property-placeholder location="classpath:application.properties" />
<!-- DataSource -->
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource"
id="dataSource">
<property name="driverClassName" value="${database.driver}"></property>
<property name="url" value="${database.url}"></property>
<property name="username" value="${database.user}"></property>
<property name="password" value="${database.password}"></property>
</bean>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
</bean>
</beans>