Enabling AOP breaks my dependency injection for a factory bean that takes a string - spring

Enabling AOP breaks my dependency injection for a factory bean that takes a string.
Here's the fragment from the context file:
<aop:aspectj-autoproxy/>
<bean id="foo"
class="FooFactory"
p:url-ref="url"/>
<bean id="url" class="java.lang.String">
<constructor-arg value="#{ 'localhost:50131'}"/>
</bean>
Here's the factory bean.
public class FooFactory extends AbstractFactoryBean<Foo> {
private String url;
public void setUrl(final String url) {
this.url = url;
}
#Override
public Class<?> getObjectType() {
return Foo.class;
}
#Override
protected Foo createInstance() throws Exception {
Validate.notNull(url, "null URL");
return new FooFactory().createFoo(new String[]{url});
}
}
Here is the only declared aspect:
#Component
#Aspect
public class ProfilerAspect {
#Around("#target(org.springframework.stereotype.Controller) && args(model,..)")
public Object profileController(final ProceedingJoinPoint proceedingJoinPoint, final Model model) throws Throwable {
return proceedingJoinPoint.proceed();
}
}
And this is the exception
java.lang.IllegalStateException: Cannot convert value of type [$Proxy13 implementing java.io.Serializable,java.lang.Comparable,java.lang.CharSequence,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [java.lang.String] for property 'url': no matching editors or conversion strategy found

It seems, that it has to do with the #target designator in the pointcut expression. I can reproduce the behaviour with a simple setup similar to yours (with only a custom annotation in the pointcut). It works fine with a simple execution() designator though.
Unfortunatly, I have no idea why this causes Spring to proxy the String object.

<aop:aspectj-autoproxy/> doesn't perform proxying without a reason. Perhaps you declared some aspect whose pointcut includes Strings, therefore it have been proxied.

Related

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.

#Autowired works but not #Inject

I have a Resource which injects the following class
#Component
public class CustomDozerBeanMapper implements Mapper {
private final DozerBeanMapper beanMapper;
public CustomDozerBeanMapper() {
this.beanMapper = new DozerBeanMapper();
BeanMappingBuilder builder = new BeanMappingBuilder() {
protected void configure() {
//some mapping stuff
}
};
beanMapper.addMapping(builder);
}
#Override
public <T> T map(Object o, Class<T> aClass) throws MappingException {
return beanMapper.map(o, aClass);
}
#Override
public void map(Object o, Object o1) throws MappingException {
beanMapper.map(o, o1);
}
#Override
public <T> T map(Object o, Class<T> aClass, String s) throws MappingException {
return beanMapper.map(o, aClass, s);
}
#Override
public void map(Object o, Object o1, String s) throws MappingException {
beanMapper.map(o, o1, s);
}
}
In my applicationContext.xml I have declared
<context:annotation-config/>
<context:component-scan base-package="foo.bar"/>
<bean id="customDozerMapper" class="foo.bar.CustomDozerBeanMapper" />
Then in our resource I inject it
class SomeResource {
#Inject CustomDozerMapper customDozerMapper;
//We have loads of other Injects which work just fine, only this class has problems
}
Caused by: A MultiException has 1 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=CustomDozerBeanMapper,parent=SomeResource,qualifiers={},position=-1,optional=false,self=false,unqualified=null,1098507248)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:75)
at org.jvnet.hk2.internal.Utilities.justInject(Utilities.java:947)
at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:975)
at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:965)
at org.glassfish.jersey.server.spring.SpringComponentProvider$SpringManagedBeanFactory.provide(SpringComponentProvider.java:191)
at org.jvnet.hk2.internal.FactoryCreator.create(FactoryCreator.java:153)
at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471)
at org.jvnet.hk2.internal.PerLookupContext.findOrCreate(PerLookupContext.java:70)
at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2072)
at org.jvnet.hk2.internal.ServiceLocatorImpl.internalGetService(ServiceLocatorImpl.java:761)
at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:700)
at org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:172)
at org.glassfish.jersey.server.model.MethodHandler$ClassBasedMethodHandler.getInstance(MethodHandler.java:284)
at org.glassfish.jersey.server.internal.routing.PushMethodHandlerRouter.apply(PushMethodHandlerRouter.java:74)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:109)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:112)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:112)
Now if I change and use #Autowired, it works fine
We are using Spring for dependency management, but for some reason h2k is being used, and I get the following exception
Can anyone please explain what the problem might be?
Why does it work with #Autowired and not #Inject
Why is h2k being used, and not Spring?
Probably, the problem may be because of 2 bean declarations (one in the XML configuration and the another one with #Component) and a DI container couldn't able to pick up one of them.
All solutions that are available here:
removing one of the bean definitions (I'd prefer the XML one)
specifying a bean by the #Qualifier or #Named annotation
The problem might also be due to the bean name in config file customDozerMapper and actual injection customerDozerMapper are not matching. If #inject does not find matching bean, it throws an exception. However, there is provision for #autowired wherein you can set attribute required=false and it injects null if it does not find matching bean.
Note: Configuration in config xml overrides the annotation
configuration.

Proxy cannot be cast to CLASS

I'm using Spring for wiring dependencies specifically for DAO classes that use Hibernate, but I'm getting an exception that has me puzzled:
$Proxy58 cannot be cast to UserDao
My DAO is configured as follows:
<bean id="userDao" class="com.domain.app.dao.UserDao">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
And I have an interface, abstract base class and a final implementation as follows.
Interface:
public interface Dao {
public void save(Object object);
public Object load(long id);
public void delete(Object object);
public void setSessionFactory(SessionFactory sessionFactory);
}
Abstract Base Class:
public abstract class BaseDao implements Dao {
private SessionFactory sessionFactory;
#Transactional
#Override
public void save(Object object) {
PersistentEntity obj = (PersistentEntity) object;
currentSession().saveOrUpdate(obj);
}
#Transactional
#Override
public abstract Object load(long id);
#Transactional
#Override
public void delete(Object object) {
// TODO: this method!
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session currentSession() {
return sessionFactory.getCurrentSession();
}
}
Implementation:
public class UserDao extends BaseDao implements Dao {
#Transactional(readOnly=true)
#Override
public Object load(long id) {
Object user = currentSession().get(User.class, id);
return user;
}
}
The following throws the exception mentioned above:
UserDao dao = (UserDao) context.getBean("userDao");
This, however, does not throw an exception:
Dao dao = (Dao) context.getBean("userDao");
If anyone can offer any assistance or guidance as to why this exception is happening, I would be very appreciative.
Spring uses JDK dynamic proxies by default ($Proxy58 is one of them), that can only proxy interfaces. This means that the dynamically created type $Proxy58 will implement one or more of the interfaces implemented by the wrapped/target class (UserDao), but it won't be an actual subclass of it. That's basically why you can cast the userDao bean to the Dao interface, but not to the UserDao class.
You can use <tx:annotation-driven proxy-target-class="true"/> to instruct Spring to use CGLIB proxies that are actual subclasses of the proxied class, but I think it's better practice to program against interfaces. If you need to access some methods from the proxied class which are not declared in one of it's interfaces, you should ask yourself first, why this is the case?
(Also, in your code above there are no new methods introduced in UserDao, so there is no point in casting the bean to this concrete implementation type anyway.)
See more about different proxying mechanisms in the official Spring reference.
I was writing unit tests and needed to be able to stub out the DAOs for some calls.
Per This guys post:
http://www.techper.net/2009/06/05/how-to-acess-target-object-behind-a-spring-proxy/
I used his method provided:
#SuppressWarnings({"unchecked"})
protected <T> T getTargetObject(Object proxy, Class<T> targetClass) throws Exception {
if (AopUtils.isJdkDynamicProxy(proxy)) {
return (T) ((Advised)proxy).getTargetSource().getTarget();
} else {
return (T) proxy; // expected to be cglib proxy then, which is simply a specialized class
}
}
Then you can easily call it with the proxy and get the object behind the proxy and manipulate the objects in it directly as needed.

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.

Problem instantiating generic class bean in Spring

I'm trying to instantiate a generic class in Spring, but I get following exception:
Initialization of bean failed; nested exception is
org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class football.dao.jpa.GenericJpaDAO]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given:
This is the XML configuration for Spring container:
<bean id="clubDAO" class="football.dao.jpa.GenericJpaDAO">
<constructor-arg type="EntityManagerFactory" ref="entityManagerFactory"/>
<constructor-arg type="Class" value="football.model.entities.ClubEntity"/>
<constructor-arg type="String" value="ClubEntity"/>
</bean>
This is the generic class:
public class GenericJpaDAO <T extends HavingID> {
private EntityManager em;
private Class entityClass;
private String entityName;
public GenericJpaDAO( Class entityClass, String entityName,
EntityManagerFactory emFactory ) {
this.entityClass = entityClass;
this.entityName = entityName;
em = emFactory.createEntityManager();
}
#Transactional
public void create( T entity ) {
em.persist( entity );
}
// more methods
}
I'm not really sure what could be causing this. I would appreciate any ideas.
This problem is not related to generics, it's a limitation of Spring AOP.
If aspects (including #Transactional aspect) are applied to the class using CGLIB proxy (this happens if target class doesn't implement any interfaces or if AOP is configured with proxy-target-class = "true"), no-argument constructor is required:
public class GenericJpaDAO <T extends HavingID> {
...
public GenericJpaDAO() {}
public GenericJpaDAO( Class entityClass, String entityName,
EntityManagerFactory emFactory ) { ... }
...
}
See also:
7.6 Proxying mechanisms

Resources