I am trying to learn AOP with Spring Framework, but there is one exception that keeps on getting invoked.
Error : Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy13 cannot be cast to com.controller.Triangle
Shape.java
package com.controller; public interface Shape { public void draw(); }
Triangle.java
package com.controller; import org.springframework.stereotype.Component; @Component public class Triangle implements Shape { public void draw() { System.out.println("this draw method of triangle"), } }
myCustomAspect.java
package com.AOP; import org.aspectj.lang.annotation.After; @EnableAspectJAutoProxy @Component @Aspect public class myCustomAspect { @Pointcut("execution(* *.draw())") private void pop(){} @Before("pop()") private void beforeMeth(){ System.out.println("this is before draw"); } }
inside main method
ApplicationContext ssp = new ClassPathXmlApplicationContext("/Spring.xml"); Shape tr=(Triangle)ssp.getBean("triangle"); tr.draw();
Spring.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" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop = "http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> <context:annotation-config></context:annotation-config> <context:component-scan base-package="com.controller,com.AOP"></context:component-scan> </beans>
Please any one help.
Thanks for the MCVE, now it was easy to recreate your problem and verify the fix. Just reading the code and not being able to run it did not make me spot the problem.
It is very simple: Your advice beforeMeth()
must be public. Then everything works like a charm.
Update:
Okay, I think I know what is missing on your part. You are casting the created bean to Triangle
, but that is not an interface but a class, thus it cannot be proxied by Spring AOP without further configuration. So you have two options here:
Either you just change the code to Shape tr = (Shape) appContext.getBean("triangle");
so as to cast to the interface that is automatically used by Spring in order to create the JDK dynamic proxy.
Or you enable class proxying with CBLIB via <aop:aspectj-autoproxy proxy-target-class="true"/>
. You can also use @EnableAspectJAutoProxy(proxyTargetClass = true)
instead, of course.
Now here is a solution showing both approaches in parallel. You can switch by changing the value of XML_CONFIG
.
BTW, I also corrected your package name com.AOP
to com.aop
(lower-case characters are the default for packages) and your Aspect name from myCustomAspect
to MyCustomAspect
(Java classes should start with an upper-case character). I also renamed Spring.xml
to spring.xml
. And in tnterfaces you do not need public
for method declarations because all interface methods are by definition public. But all of this is just cosmetics, the real fix is the one above.
So here is your improved code:
package com.controller; public interface Shape { void draw(); }
package com.controller; import org.springframework.stereotype.Component; @Component public class Triangle implements Shape { public void draw() { System.out.println("this draw method of triangle"); } }
package com.aop; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.stereotype.Component; @Component @Aspect public class MyCustomAspect { @Pointcut("execution(* *.draw())") private void pop() {} @Before("pop()") public void beforeMeth() { System.out.println("this is before draw"); } }
package de.scrum_master.app; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.controller.Shape; import com.controller.Triangle; @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) @ComponentScan(basePackages = { "com.controller", "com.aop" }) public class Application { private static final boolean XML_CONFIG = true; public static void main(String[] args) { ApplicationContext appContext = XML_CONFIG ? new ClassPathXmlApplicationContext("/spring.xml") : new AnnotationConfigApplicationContext(Application.class); Shape tr = (Triangle) appContext.getBean("triangle"); tr.draw(); } }
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> <context:component-scan base-package="com.controller,com.aop"></context:component-scan> <aop:aspectj-autoproxy proxy-target-class="true"/> </beans>