Unable to apply aspects to String class - java

I was experimenting with AspectJ. I tried to apply aspect on String class. I created Spring configuration file as:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<!-- Enable #AspectJ annotation support -->
<aop:aspectj-autoproxy />
<!-- Employee manager -->
<bean id="employeeManager" class="com.test.advice.EmployeeManager" />
<!-- Logging Aspect -->
<bean id="loggingAspect" class="com.test.advice.LoggingAspect" />
<bean id="bean1" class="java.lang.String">
<constructor-arg value="abx" />
</bean>
</beans>
Then an Aspect class like,
package com.test.advice;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class LoggingAspect
{
#Around("execution(* java.lang.String.*(..))")
public void logAroundGetEmployee(ProceedingJoinPoint joinPoint) throws Throwable
{
System.out.println("works");
}
}
After that created a class with a main method like:
package com.test.advice;
package com.test.advice;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AspectJAutoProxyTest
{
public static void main(String[] args)
{
ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Customer.xml");
String pqr = (String) context.getBean("bean1");
pqr.trim();
}
}
On running it should output "works" to console. But it fails saying,
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy5 cannot be cast to java.lang.String
at com.test.advice.AspectJAutoProxyTest.main(AspectJAutoProxyTest.java:13)
What is the issue? Can't we apply proxy to java.lang objects? Please help.

To use a proxy object as a replacement for the real object, the proxy object must be of a subclass of the real object. String being final, the JVM does not permit creating such a subclass.
(Note that spring has two proxy modes; one creates an actual subclass and the other just implements all public interfaces. You're probably using the latter, but if you changed to the former, you'd see an exception at proxy creation time)

Related

Spring AOP aspect does not intercept annotated method

i want to use the #before ,#after and #AfterThrowing in my function.
If other function use the annotation like #MyAspectTest, it should run beforeAction(), afterAction() and afterExcept() at related time.
But, it seems doesn't work.
i have already input the dependency and modified the beans.
package com.service.metrics;
import com.mgr.CMPMgr;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.AfterThrowing;
import java.lang.reflect.Method;
#Aspect
public class CMPAspect {
#Before(value="#annotation(com.mgr.CMPMgr)")
public void beforeAction(JoinPoint joinPoint) throws ClassNotFoundException {
testcode
}
#After(value="#annotation(com.mgr.CMPMgr)")
public void afterAction(){
testcode
}
#AfterThrowing(value="#annotation(com.mgr.CMPMgr)")
public void afterExcept(){
testcode
}
}
package com.mgr;
public #interface CMPMgr {
String name() default "";
long startTime = System.currentTimeMillis();
}
#CMPMgr(name = "vipGet")
#GET
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
#Path("/{lbId}")
public Response get(#PathParam("lbId")String lbId,
#HeaderParam("Authorization") String basicAuthData,
#HeaderParam("UserID") String behalf) {
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.0</version>
</dependency>
<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:jpa="http://www.springframework.org/schema/data/jpa" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:aspectj-autoproxy />
<!-- enabling annotation driven configuration / -->
<context:annotation-config />
<context:component-scan />
<!-- responsible for registering the necessary Spring components that power
annotation-driven transaction management; such as when #Transactional methods
are invoked -->
<tx:annotation-driven />
it should get into the Aspect functions. But i don't find it work in debug mode. Why?
Some things come to mind:
Your annotation needs runtime retention, but I do not see #Retention(RetentionPolicy.RUNTIME) in your code.
Your aspect should be a #Component, but I do not see the corresponding annotation either.
The target class containing method public Response get(..) also has to be a Spring bean/component. Because you only show incoherent snippets instead of full class definitions, I have no idea which package that class resides in, if it is a Spring component and whether or not it is picked up by component scan.

Spring AOP Advice is being executed twice

I am using Spring AOP to create an Aspect. The Aspect that I defined is being executed twice. I can't seem to figure out why. I'd appreciate any inputs anyone has on this issue.
Thanks!
// Spring Configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
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"
default-autowire="no"
default-lazy-init="true">
<bean id="loggingAdvice" class="com.xyz.aop.LoggingAdvice" />
<aop:config>
<aop:aspect id="loggingAspect" ref="loggingAdvice">
<aop:pointcut id="loggingPointcut"
expression="execution(* com.xyz.FooServiceImpl.foo(..))"/>
<aop:around pointcut-ref="loggingPointcut" method="log" />
</aop:aspect>
</aop:config>
<context:component-scan base-package="com.xyz.controllers" />
</beans>
// Advice
package com.xyz.aop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
public class LoggingAdvice {
public Object log(final ProceedingJoinPoint pjp) throws Throwable {
log.info("Started!");
try {
return pjp.proceed();
} finally {
log.info("Ended!");
}
}
}
// Advised Method
package com.xyz;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class FooServiceImpl implements FooService {
private static final Log log = LogFactory.getLog(FooServiceImpl.class);
#Override
public void foo() {
log.info("Foo!");
}
}
}
// Output
Started!
Started!
Foo!
Ended!
Ended!
// EDIT 1: Added more spring configuration info. Not using any Spring AOP annotations at all. I attached a debugger and saw that the aspect/log statements were being executed twice as well. So I doubt that it has anything to do with log statement printing the string twice.
Well, it seems like this is actually an issue with the logger. Same problem I encountered long time back and found that everything is being logged twice. When I replaced logger calls with regular sysout calls, everything worked fine.
Because the <aop:around...> is telling this to do work both before and after the method. You could use <aop:before...> or <aop:after...> instead for running only once.

Load Time Weaving not working in domain object

I have a scenario where I need to access spring managed beans in my domain object(i.e. object created with new operator). I searched a lot and found that it can be done using Load Time Weaving provided by aspectJ. I've done all configurations for the above to the best of my knowledge. I'm new to aspectJ. Following are my code and the configuration files.
Domain class,
package test.components;
import hibSERVICES.NounHeader.NounHeaderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
#Configurable
public class TestLoadTimeWeaving {
#Autowired
private NounHeaderService nounHeaderService;
public void hello(){
nounHeaderService.findByPrimaryKey(0L);
}
}
Controller,
package test.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping(value = "/testController.do")
public class TestController{
#RequestMapping(params = "todo=onLoad", method = {RequestMethod.POST, RequestMethod.GET})
public void onLoad(HttpServletRequest request, HttpServletResponse response){
TestLoadTimeWeaving testLoadTimeWeaving = new TestLoadTimeWeaving();
testLoadTimeWeaving.hello();
}
}
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"
xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.directwebremoting.org/schema/spring-dwr
http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:spring-configured />
<context:annotation-config />
<context:component-scan base-package="test" />
<context:load-time-weaver aspectj-weaving="on"/>
<bean lass="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect" factory-method="aspectOf"/>
aop.xml,
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN"
"http://www.aspectj.org/dtd/aspectj_1_5_0.dtd">
<aspectj>
<weaver>
<exclude within="*..*CGLIB*" />
</weaver>
</aspectj>
I've written -javaagent:c:\spring-agent-2.5.6.jar as the VM argument
Using following jars to support LTW and aspectJ,
aspectjrt-1.5.4.jar
spring-agent-2.5.6.jar
spring-aspect.jar
aspectjWeaver-1.5.4.jar
spring-2.5.6.jar
All other spring dependencies are working fine, only the dependencies which are injected in the domain objects( i.e. object created with new operator) are not working i.e. I'm getting null for those depedencies.
Kindly help. Thanks in advance.

spring sample application in netbeans

This is my code. I have gotten some errors. Can anyone help me solve the problem? I get some casting errors, like cast ClassPathResource to Resource and resource object r to resource.
package firstspring;
import javax.annotation.Resource;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
public class test {
public static void main(String[] args){
Resource r =new ClassPathResource("applicationContext.xml");
BeanFactory bf=new XmlBeanFactory(r);
Student stud=(Student)bf.getBean("first");
stud.display();
}
}
This is my XML file;
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="first" class="Student">
<property name="name" value="sneha"></property>
</bean>
</beans>
You are using both the resources like javax.annotation.Resource and org.springframework.core.io.Resource, which has resulted in a conflict.
You need to use them like this
org.springframework.core.io.Resource r = new ClassPathResource("applicationContext.xml");
then program will execute.
Instead of importing
javax.annotation.Resource
use,
org.springframework.core.io.Resource

Spring NoClassDefFoundError org.springframework.beans.FatalBeanException when adding <context:component-scan ...> in the config

I'm writing a simple Spring 3.1 test, I'm getting an exception when adding the following line in my config:
<context:component-scan base-package="com.software.shared" />
Here's the exception:
INFO: Loading XML bean definitions from class path resource [spring-config.xml]
Exception in thread "main" java.lang.NoClassDefFoundError: org.springframework.beans.FatalBeanException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:997)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:943)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.software.shared.PersonBeanTest.<init>(PersonBeanTest.java:15)
at com.software.shared.PersonBeanTest.main(PersonBeanTest.java:31)
I don't get what's going on. If I remove the line, the exception dissappears, but Autowiring doesn't work.
I have all the jars in the spring 3.1 RELEASE distribution, on my class path, including org.springframework.beans-3.1.0.RELEASE.jar and I checked that it contains that file.
This is the code in the main method:
package com.software.shared;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
#Service
public class PersonBeanTest {
public PersonBeanTest() {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//System.out.println("Name=" + ((PersonBean) (context.getBean("personBean"))).getName());
}
private PersonBean myBean;
public PersonBean getMyBean() {
return myBean;
}
#Autowired
public void setMyBean(PersonBean myBean) {
this.myBean = myBean;
}
public static void main(String[] args) {
PersonBeanTest test = new PersonBeanTest();
System.out.println("Name=" + test.getMyBean().getName());
}
}
Here's the Spring config:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
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-2.5.xsd"
default-autowire="byName">
<!-- <context:component-scan base-package="com.software" /> -->
<!-- Register Annotation-based Post Processing Beans -->
<context:annotation-config />
<!-- Scan context package for any eligible annotation configured beans. -->
<context:component-scan base-package="com.software.shared" />
<bean id="personBean" class="com.software.shared.PersonBean">
<property name="name" value="MyName" />
</bean>
</beans>
I start the app by right clicking on this class and clicking "Run As -> Java Application".
Any ideas on why I get the exception?
you are trying to make spring scan class PersonBeanTest in package com.software.shared, but meanwhile you are creating the same application context in the constructor of PersonBeanTest, I guess this is the root cause of the exception.
try to scan some other package:
<context:component-scan base-package="some.other.package" />
and test it with the following code snippet to see if it works
public class PersonBeanTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
assertNotNull(context.getBean(PersonBean.class));
}
}
In my case, this happened because of a StackOverflowError. In some Spring catch block, the FatalBeanException subclass initialization failed again because of the current very long stack, leading to a NoClassDefFoundError
I think When your ApplicationContext loads at startup it tries to instantiate the Bean PersonBeanTest using its default constructor inside which you are creating another ApplicationContext which will again try to instantiate the same bean.This process goes on for infinite time finally throwing an Exception.
I've had the same problem under different circumstances. I'm not sure why this happens, but you should be able to find the original exception by putting a breakpoint inside AbstractAutowireCapableBeanFactory where the BeanCreationException is being thrown.
Please make sure your spring-config.xml into the classpath.

Categories