How to Instantiate spring bean with in a method with runtime constructor arguments? - spring

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.

Related

Replace Private Method of Spring Bean

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.

Spring AOP : Can we access bean object by getBean("beanName") method after applying ProxyFactoryBean on that Bean?

I have applied a 'BeforeAdvice' through 'ProxyFactoryBean' on a Bean of type "MyXMLApplication" now I am not able to access the Bean object directly{by getBean(MyXMLApplication.class)}, it is giving error :-
by setter dependency injection myxml
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.journaldev.spring.di.consumer.MyXMLApplication] is defined: expected single matching bean but found 2: MyXMLApp,proxy
However I am able to get the bean object by "proxy" bean object{(MyXMLApplication)context.getBean("proxy")}. Now my question is after applying proxy on any bean is there any way to access it directly without proxy bean.
My code is:
********Before Advisor*********
public class MyBeforeAdvisor implements MethodBeforeAdvice{
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
// TODO Auto-generated method stub
System.out.println("before advice run");
}
}
*********applicationContext.xml********
<bean id="twitter" class="com.journaldev.spring.di.services.TwitterService"></bean>
<bean id="MyXMLApp" class="com.journaldev.spring.di.consumer.MyXMLApplication" autowire="byType"/>
<bean id="beforeAdvice" class="com.journaldev.spring.aop.advisor.MyBeforeAdvisor"></bean>
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="MyXMLApp"></property>
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>
</list>
</property>
</bean>
**********Main Bean Class************
public class MyXMLApplication {
private MessageService service;
public void setService(MessageService svc){
System.out.println("by setter dependency injection myxml");
this.service=svc;
}
public boolean processMessage(String msg, String rec) {
return this.service.sendMessage(msg, rec);
}
}
**********Autowired Bean Interface *******
public interface MessageService {
boolean sendMessage(String msg, String rec);
}
**********Autowired Bean Impl*********
public class TwitterService implements MessageService {
public boolean sendMessage(String msg, String rec) {
System.out.println("Twitter message Sent to "+rec+ " with Message="+msg);
return true;
}
}
************* Main function**********
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
MyXMLApplication app = context.getBean(MyXMLApplication.class); --> Not Working
//MyXMLApplication app = (MyXMLApplication)context.getBean("proxy"); -->working
app.processMessage("Hi", "abc#abc.com");
context.close();
}
Sorry guys, the error was coming because I was calling getBean(MyXMLApplication.class) [by type] that is why it founds two beans "proxy" and "MyXMLApp" of type MyXMLApplication.class and giving the error.
It is not something like we can not call the 'getBean'method on bean directly after applying any proxy on that.

How to set EasyMock expectations after #Autowired injection?

I'm trying to get to grips with EasyMock in order to run some server side integration tests on a spring-ws web service. I have a DAO which I want to mock for my integration testing, I've managed to autowire it successfully, but I can't figure out how to set the expectations post autowire.
I have the following in my spring context xml:
<bean id="accountServiceDao" class="org.easymock.EasyMock" factory-method="createMock">
<constructor-arg value="com.xxx.account.dao.AccountServiceDao" />
</bean>
<bean id="notMockedDao" class="com.xxx.account.dao.AccountServiceDaoImpl"/>
<context:component-scan base-package="com.xxx.account" />
<context:property-placeholder location="classpath:accountDetailService_test.properties" />
<sws:annotation-driven />
<jdbc:embedded-database id="dataSource" type="HSQL">
<jdbc:script location="classpath:sql/db_schema.sql" />
<jdbc:script location="classpath:sql/test_data.sql" />
</jdbc:embedded-database>
My dummy test is as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/applicationContext_test.xml" })
public class AccountDetailServiceMockIntergrationTest {
#Autowired
private ApplicationContext applicationContext;
private MockWebServiceClient mockClient;
#Before
public void createClient() {
mockClient = MockWebServiceClient.createClient(applicationContext);
/* Set the expectations for the autowired mock dao here */
}
#Test
public void customerEndpoint() throws Exception {
Source requestPayload = new StringSource(TestData.requestXML);
Source responsePayload = new StringSource(TestData.responseXML);
mockClient.sendRequest(withPayload(requestPayload)).andExpect(
payload(responsePayload));
}
}
The endpoint which is hit is below:
#Autowired
private AccountService accountService;
#PayloadRoot(localPart = "AccountSearchRequest", namespace = TARGET_NAMESPACE)
public #ResponsePayload
AccountSearchResponse getAccountDetails(
#RequestPayload AccountSearchRequest request) {
logger.info("Received request | debtornum - " + request.getDebtornum());
AccountSearchResponse accountSearchResponse = objectFactory.createAccountSearchResponse();
AccountDetailsType accountDetails = accountService.getAccountDetails(request.getDebtornum());
accountSearchResponse.setAccountDetails(accountDetails);
logger.info("Returned response | status - " + accountSearchResponse.getAccountDetails().getDebtorStatus().value());
return accountSearchResponse;
}
And here's the service class which contains the DAO which is being mocked
#Service
public class AccountServiceImpl implements AccountService {
//Autowired on a setter
private AccountServiceDao accountServiceDao;
Logger logger = LoggerFactory.getLogger(AccountServiceImpl.class);
#Override
public AccountDetailsType getAccountDetails(BigInteger accountNumber) {
........................
Via debug I can see that the mock DAO is getting injected correctly, but I don't know how to set the behavior on the mock object.
For my unit tests I was able to do the following:
accountDao = EasyMock.createMock(AccountServiceDao.class);
EasyMock.expect(accountDao.checkAccountExists(new BigInteger("12345678"))).andReturn(new Account(new BigInteger("12345678"),"Y",1,0,0,0,"ROI","ROI","DO","10012054082","POST","DD","John Doe","a#a.com","123456"));
EasyMock.replay(accountDao);
testSvc.setAccountServiceDao(accountDao);
I'm not sure how to do the same configuration when the mock is autowired via spring xml config. I'm probably missing something obvious or misunderstanding EasyMock, but any help or guidance would be appreciated.
Thanks
As per Dan's comment above, I've set my expectations as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/applicationContext_test.xml" })
public class AccountDetailServiceMockIntergrationTest {
#Autowired
private ApplicationContext applicationContext;
private MockWebServiceClient mockClient;
#Before
public void createClient() {
mockClient = MockWebServiceClient.createClient(applicationContext);
//get the mocked bean from the applicationContext
AccountServiceDao svcDao = (AccountServiceDao)applicationContext.getBean("accountServiceDao");
//reset just in case
EasyMock.reset();
//set expectations on the mock
EasyMock.expect(svcDao.checkAccountExists(new BigInteger("12345678"))).andReturn(new Account(new BigInteger("12345678"),"Y",1,0,0,0,"ROI","ROI","DO","10012054082","POST","DD","John Doe","a#a.com","123456"));
EasyMock.replay(svcDao);
}
#Test
public void customerEndpoint() throws Exception {
Source requestPayload = new StringSource(TestData.requestXML);
Source responsePayload = new StringSource(TestData.responseXML);
mockClient.sendRequest(withPayload(requestPayload)).andExpect(
payload(responsePayload));
}
}
Works fine.

Accessing spring bean from logging appender class

I have log4j DailyRollingFileAppender class in which setFile() method I need to check database value to decide which file to used for logging.
DailyRollingFileAppender class
public void setFileName()
{
isLoginEnabled = authenticationManager.checkLoginLogging();
}
Here 'authenticationManager' is object of class used to make database call using spring dependency injection feature.
spring-beans.xml
<bean id="dailyRollingFileAppender" class="com.common.util.DailyRollingFileAppender">
<property name="authenticationManager">
<ref bean="authenticationManager"/>
</property>
</bean>
<bean id="authenticationManager" class="com.security.impl.AuthenticationManagerImpl">
<property name="userService">
<ref bean="userService"/>
</property>
</bean>
Now when I start my application log4j gets initiated first and since spring-beans is yet to invoked it throws NullPointerException in method setFileName().
So is there a way I can make call to 'authenticationManager.checkLoginLogging();' from DailyFileAppender class so that when log4j loads it should able to get database value?
A few years late, but I hope this is of help to someone.
I was after similar functionality - I have a custom appender, and i wanted to use an autowired bean to perform some logging using a service we'd built. By making the appender implement the ApplicationContextAware interface, and making the field that i'd normally autowire static, i'm able to inject the spring-controlled bean into the instance of the appender that log4j has instantiated.
#Component
public class SslErrorSecurityAppender extends AppenderSkeleton implements ApplicationContextAware {
private static SecurityLogger securityLogger;
#Override
protected void append(LoggingEvent event) {
securityLogger.log(new SslExceptionSecurityEvent(SecurityEventType.AUTHENTICATION_FAILED, event.getThrowableInformation().getThrowable(), "Unexpected SSL error"));
}
#Override
public boolean requiresLayout() {
return false;
}
#Override
public synchronized void close() {
this.closed = true;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) {
if (applicationContext.getAutowireCapableBeanFactory().getBean("securityLogger") != null) {
securityLogger = (SecurityLogger) applicationContext.getAutowireCapableBeanFactory().getBean("securityLogger");
}
}
}

Why do the protected fields of type String not get Autowired, while other beans do

I am trying to set value of protected String field in a annotation configured bean using property-override mechanism. It throws following exception unless I add a setter for the field in the bean.
org.springframework.beans.NotWritablePropertyException: Invalid property 'cookie' of bean class [com.test.TestBean]: Bean property 'cookie' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
To compare I also have another protected field which is of type of another class. Bean of the other class is defined in XML. This field gets properly autowired.
Here's the first bean
#Component("testBean")
public class TestBean {
protected #Autowired(required=false) String cookie;
protected #Autowired InnerBean innerBean;
public String getCookie() {
return cookie;
}
public void setCookie(String cookie) {
this.cookie = cookie;
}
public InnerBean getInnerBean() {
return innerBean;
}
}
Here's InnerBean
public class InnerBean {
private String value;
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
Spring configuration file - only interesting bits
<context:property-override location="beans.properties"/>
<context:component-scan base-package="com.test"></context:component-scan>
<context:annotation-config></context:annotation-config>
<bean id="innerBean" class="com.test.InnerBean">
<property name="value">
<value>Inner bean</value>
</property>
</bean>
beans.properties
testBean.cookie=Hello Injected World
Main
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
TestBean bean = context.getBean(TestBean.class);
System.out.println("Cookie : " + bean.getCookie());
System.out.println("Inner bean value : " + bean.getInnerBean().getValue());
}
Output
Cookie : Hello Injected World
Inner bean value : Inner bean
If I just comment out the setter for cookie in TestBean, I get the mentioned NotWritablePropertyException exception. Is there a difference between autowiring a bean and autowiring a property?
#Autowired should only be used when you want to wire up a Spring bean to another bean.
Properties are set by PropertyOverrideConfigurer which is a different process to autowiring, and doesn't use the #Autowired annotation. That #Autowired annotation on the cookie property is unnecessary and probably confusing Spring's bean factory. I expect that simply removing the annotation should fix the problem for you, ie:
protected String cookie;
protected #Autowired InnerBean innerBean;
Spring is capable of setting properties even if they are private or protected.

Resources