I have project with Spring configuration in XML file. I added below aspect with pointcut.
<aop:aspectj-autoproxy/>
<aop:config proxy-target-class="true">
<aop:aspect id="customAuditAspect" ref="customAudit">
<aop:pointcut id="customAuditPointcut"
expression="#target(lombok.NoArgsConstructor)"/>
<aop:before pointcut-ref="customAuditPointcut" method="customAuditUpdate"/>
</aop:aspect>
</aop:config>
And this is a bean, which abovementioned pointcut refers to:
<bean id="customAudit" class="com.socha.modules.inspektr.aspect.AuditCustomUpdateAspect"/>
This is class:
#Slf4j
#NoArgsConstructor
public class AuditCustomUpdateAspect {
#Autowired
JdbcTemplate jdbcTemplate;*
public void customAuditUpdate() {
log.warn("here I am");
}
}
When i deploy Web app with this feature, it complains in following way:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'dataSourceAudit'
defined in ServletContext resource [/WEB-INF/spring-context/portlet-application-context.xml]:
Unsatisfied dependency expressed through constructor parameter 0:
Could not convert argument value of type [com.sun.proxy.$Proxy1719]
to required type [com.zaxxer.hikari.HikariConfig]:
Failed to convert value of type 'com.sun.proxy.$Proxy1719
implementing org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised,org.springframework.cglib.proxy.Factory,com.zaxxer.hikari.HikariConfigMXBean,org.springframework.core.DecoratingProxy'
to required type 'com.zaxxer.hikari.HikariConfig';
nested exception is java.lang.IllegalStateException:
Cannot convert value of type 'com.sun.proxy.$Proxy1719
implementing org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised,org.springframework.cglib.proxy.Factory,com.zaxxer.hikari.HikariConfigMXBean,org.springframework.core.DecoratingProxy'
to required type 'com.zaxxer.hikari.HikariConfig':
no matching editors or conversion strategy found
Below I am attaching this bean with all its dependent beans:
<bean id="inspektrTransactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate"
p:transactionManager-ref="txManagerAudit" p:isolationLevelName="ISOLATION_READ_COMMITTED"
p:propagationBehaviorName="PROPAGATION_REQUIRED"/>
<bean id="auditHikariCPConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="poolName" value="auditHikariCP"/>
</bean>
<bean id="dataSourceAudit" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="auditHikariCPConfig"/>
</bean>
I understand more or less how is AOP in Spring working. Class HikariDataSource of bean dataSourceAudit implements some interfaces and by default it applies JDK proxying. In above snippet I am trying to apply proxy-target-class=true, but it still fails. I see when I add this setting, that implemented interfaces changes a bit - org.springframework.cglib.proxy.Factory appears, but content of error is still the same. Maybe I am eventually failing to apply this setting on HikariDataSource bean and that's why it is not working?
Thank you in advance for any hints
This particular problem was solved by narrowing scope of the classes to be adviced , as R.G and Kriegaex suggested. Errors stopped occuring
Thank you
Related
I need to add OAuth client to a Spring 3 project. I need to use xml based configuration. And I want to know the xml equivalent of the following bean configuration I found in another Spring project. Note that there is an input parameter in the bean definition where an object of type OAuth2ClientContext is being passed (OAuth2ClientContext is an Interface) and is named clientContext. But no bean definition is written anywhere for clientContext. What does this mean? And how would you write this in xml?
#Bean
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext clientContext){
return new OAuth2RestTemplate(oauth2Resource(), clientContext);
}
The configuration should be like this
<bean id="client" class="package.OAuth2ClientContext" />
<bean id="resource" class="package.Oauth2Resource" />
<bean id="restTemplate" class="package.Oauth2Resource">
<property name="nameOfPropertyResource" ref="resource" />
<property name="nameOfPropertyClient" ref="client" />
</bean>
are you sure that the bean client is not declared? Maybe it’s declared in some jar? If yes you should find it’s name and use the name in the ref
I am trying to use AOP for logging all method calls while entering and leaving a method, using the below bean and aop declaration in my beans xml,
<aop:config>
<aop:pointcut id="componentAnnotatedClass" expression="execution(* com.test.*.*.*(..))" />
<aop:advisor advice-ref="loggingAdvisor" pointcut-ref="componentAnnotatedClass" />
</aop:config>
<bean id="loggingAdvisor" class="org.springframework.aop.interceptor.CustomizableTraceInterceptor">
<property name="enterMessage" value="Entering $[targetClassShortName].$[methodName]($[arguments])" />
<property name="exitMessage" value="Leaving $[targetClassShortName].$[methodName](): $[returnValue], Total Execution Time : $[invocationTime]ms" />
</bean>
But when i use this i am getting an exception like below,
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.test.dao.BCommonDataAccessor]: 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
When i browsed through this, i got to know that cglib requries a default consructor, but in my app i have a parametrized constructor to inject my data source. I cannot have a default constructor in my data accessor. Is there any workaroud to over come this issue.
Note: I am using spring3.2 vesion
Problem:
I'm integrating with a library written by the other team. This library provides a set of classes that I'm using in my Spring-driven application. Every bean in my application is in singleton scope.
Also 99% of the classes from that library uses constructor injection.
I'm using XML and my configuration looks very similar to the following:
<bean id="lib.service1" class="lib.Service1"/>
<bean id="lib.service2" class="lib.Service2">
<constructor-arg ref="lib.service1"/>
</bean>
<bean id="lib.service3" class="lib.Service3">
<constructor-arg ref="lib.service1"/>
</bean>
<bean id="lib.service4" class="lib.Service3">
<constructor-arg ref="lib.service2"/>
<constructor-arg ref="lib.service3"/>
</bean>
<!-- other bean definitions -->
<bean id="lib.serviceN" class="lib.ServiceN">
<constructor-arg ref="lib.serviceX"/>
<constructor-arg ref="lib.serviceY"/>
<constructor-arg ref="lib.serviceZ"/>
<constructor-arg ref="lib.serviceK"/>
</bean>
<!-- other bean definitions -->
What I want:
I want to simplify my configuration to not to use bean IDs and ask spring to do constructor injection for me based on the type of arguments in the bean constructors. I can also ask library implementers to add #Inject annotation to the class constructors (the 99% of the classes have just one public constructor), but this is all that I can ask wrt refactoring of their library.
And eventually I want to have just following in my spring config (doesn't work, but illustrates the idea):
<bean class="lib.Service1"/>
<bean class="lib.Service2"/>
<bean class="lib.Service3"/>
<!-- ... -->
<bean class="lib.ServiceN"/>
Here I'm expecting Spring to figure out that I want to use constructor injection for all those beans and infer bean instances based on the constructor argument types.
Note that I cannot use component scan - they have one package (lib. in the example given above) and some classes in that package are useless for my application and too expensive to be needlessly created. Plus some classes that I'm not using are experimental and can be changed/renamed/removed without prior notice.
Add autowire="constructor", assuming these bean types only have one constructor and that the corresponding parameters match single beans.
<bean class="lib.Service1" autowire="constructor"/>
From the documentation
"constructor"
Analogous to "byType" for constructor arguments. If there
is not exactly one bean of the constructor argument type in the
bean factory, a fatal error is raised. Note that explicit
dependencies, i.e. "property" and "constructor-arg" elements, always
override autowiring. Note: This attribute will not be inherited by
child bean definitions. Hence, it needs to be specified per concrete
bean definition.
In all the examples of autowiring that I have found, the example is about one <bean> autowire attribute which is set for example to byName, and the has only one property value which is supposed to be set through autowiring.
My question is what if a <bean> has multiple properties that you want to set through autowiring? No one seems to explain that situation. Can someone explain if I can or if I should use autowire to set multiple properties in a bean? The following is an example of such a situation where I want to set the account and credit properties of the customer bean by autowiring:
<beans>
<bean name="customer" class="ultratech.com.Customer" autowire="byName">
<bean name="account"/>
<bean name="credit>
</beam>
<bean name="account" class="ultratech.com.Account"/>
<bean name="credit" class="ultratech.com.Credit"/>
</beans>
Also, please correct me if I'm wrong, but if I were to use annotation (#Autowire), then my problem is easily solved, since I would be able to add #Autowire to any property of a bean separately.
[EDIT: edited to reflect on updated question]
Your question is much more clear right now. You seem to think (if I follow your thinking properly), that in the autowire="byName" you are supposed to provide a bean name instead of byName value.
That is not correct. The autowire attribute can take a few possible values and byName is one of those. When you set autowire to byName like here:
<bean name="someBean" class="foo.bar.Baz" autowire="byName />
then Spring will look at all the fields in someBean (foo.bar.Baz class) and attempt to wire all fields of this object on a per name basis. That is, (in your case) if a Customer class has a field account, Spring will look in its context and try to find a bean with name account to inject into the Customer bean.
If you define two such beans:
<bean name="customer" class="ultratech.com.Customer" autowire="byName" />
<bean name="account" class="ultratech.com.Account" />
then you are good to, if Customer is a class along this lines:
public class Customer {
(...)
private Account account;
(...)
}
Here is what your XML code snippet should look like, assuming that your Customer class has fields named account and credit:
<beans>
<bean name="customer" class="ultratech.com.Customer" autowire="byName" />
<bean name="account" class="ultratech.com.Account" />
<bean name="credit" class="ultratech.com.Credit" />
</beans>
Apart from "byName" autowiring, you can autowire:
no - default - no autowiring
byType - looks for a bean of the property type - be wary, though - only one bean of this type is allowed for autowiring byType; if there is more then one an exception is raised
constructor - works just like byType, but looks for constructor parameters only; all of constructor parameters have to be satisfied with exactly one bean of each respective type
See Spring reference for more info:
http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-factory-autowire
I have the following bean defined:
<bean id="myBean" class="com.me.myapp.Widget">
<constructor-arg name="fizz" value="null"/>
<constructor-arg name="buzz" ref="someOtherBean" />
</bean>
When I run my app, Spring throws a bean config exception:
[java] Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myBean' defined in class path resource [spring-config.xml]:
Unsatisfied dependency expressed through constructor argument with index 0
of type [com.me.myapp.Widget]: Could not convert constructor argument value of
type [java.lang.String] to required type [com.me.myapp.Widget]: Failed to
convert value of type 'java.lang.String' to required type
'com.me.myapp.Widget'; nested exception is java.lang.IllegalStateException:
Cannot convert value of type [java.lang.String] to required
type [com.me.myapp.Widget]: no matching editors or conversion strategy found
I just want to create a Widget like I would if I wrote the following Java:
Widget w = new Widget(null, someOtherBean);
How can I do this? Thanks in advance!
You can use Spring's <null> tag:
<bean id="myBean" class="com.me.myapp.Widget">
<constructor-arg name="fizz">
<null />
</constructor-arg>
<constructor-arg name="buzz" ref="someOtherBean" />
</bean>
At times spring fails to inject the values in the ordered you have mentioned into a constructor. It's better if you try with explicit ordering, i.e.
<constructor-arg index="0" name="fizz"><null/></constructor-arg>
<constructor-arg index="1" name="buzz"><ref bean="someOtherBean"/></constructor-arg>
this was, actually, not working for me,
so what I've done is, not passing the object through spring,
but asking "if the object is null", and create New object and assign it to it,
it is also done once (similar to spring),
the difference is that, it is not the best practice, and the creation point of the object is in the flow of the class, and not in early stage.