Reputation: 65
I am writing a small application to check the functionality of "AfterAdvice" concept in spring-AOP but i am getting an exception related to xml file (I think) please help me how to solve the exception
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean id="pinCheck" class="com.nt.advice.AtmPinVerifierAdvice" />
<bean id="targetBean" class="com.nt.service.AtmPinGenerator" />
<bean id="pfb" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="targetBean" />
<property name="interceptorNames">
<list>
<value>pinCheck</value>
</list>
</property>
</bean>
</beans>
ClientApp.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import com.nt.service.AtmPinGenerator;
public class ClientApp {
public static void main(String[] args) {
//activate IOC container
ApplicationContext ctx = new FileSystemXmlApplicationContext("src/com/nt/cfgs/applicationContext.xml");
//get proxy obj
AtmPinGenerator gen = ctx.getBean("pfb",AtmPinGenerator.class);
//call b.method
gen.pinGenerator();
}
}
AtmPinGenerator.java
import java.util.Random;
public class AtmPinGenerator extends Random {
//generating pin
public int pinGenerator(){
//creat java.util.Random object
Random rad = new Random();
//use nextInt() to generate random pin of 4 digits
int pin = rad.nextInt(9999);
return pin;
}//pinGenerator
}
AtmPinVerifierAdvice.java
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class AtmPinVerifierAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object retValue, Method method, Object[] args,
Object target) throws Throwable {
System.out.println(retValue);
Integer pin = (Integer)retValue;
//if generated pin is less than four digit throw an exception
if(pin<=999)
throw new IllegalArgumentException("invalid pin");
}//afterReturning
}//AtmPinVerifierAdvice
If I run the above application I am getting this Exception
Output
Aug 17, 2015 2:03:57 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.FileSystemXmlApplicationContext@3ff14318: startup date [Mon Aug 17 14:03:57 IST 2015]; root of context hierarchy
Aug 17, 2015 2:03:57 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from file [G:\java\Frameworks\SpringAOP\AOPProj6(After advice - pin verifier decl)\src\com\nt\cfgs\applicationContext.xml]
Exception in thread "main" org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'pfb' must be of type [com.nt.service.AtmPinGenerator], but was actually of type [com.sun.proxy.$Proxy2]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(Abstract BeanFactory.java:375)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBe anFactory.java:199)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractA pplicationContext.java:962)
at test.ClientApp.main(ClientApp.java:14)
I don't why I am getting Exception. please any one help me why this exception is raising?
Upvotes: 4
Views: 8951
Reputation: 125292
Spring by default uses JDK Dynamic proxies, which are interface based, for applying AOP.
Your AtmPinGenerator
extends Random
which implements Serializable
. Spring sees the interface and uses interface based proxies. You will get a proxy implementing only the Serializable
interface.
You have 3 options to solve it
ProxyFactoryBean
Random
.The last option would be the easiest simply don't extend Random
, this will force the use of class-based proxies.
public class AtmPinGenerator {
public int pinGenerator(){
Random rad = new Random();
return rad.nextInt(9999);
}
}
You could also set the proxyTargetClass
property of the ProxyFactoryBean
to true
and then you don't need to change your class.
<property name="proxyTargetClass" value="true" />
The last option is to introduce an interface and simply expose the pinGenerator()
method on it and let your AtmPinGenerator
implement that interface.
public interface PinGenerator {
int pinGenerator();
}
public class AtmPinGenerator implements PinGenerator { ... }
This way you are using interface based proxied. In your main
method now use the PinGenerator
interface instead of the AtmPinGenerator
.
Upvotes: 5