Reputation: 132
I need to do the following Java line in XML:
usersConnectionRepository.setConnectionSignUp(new AccountConnectionSignUp());
So I did this:
<bean id="usersConnectionRepository"
class="org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository"
scope="singleton">
<constructor-arg ref="dataSource" />
<constructor-arg ref="connectionFactoryLocator" />
<constructor-arg ref="textEncryptor" />
<aop:scoped-proxy proxy-target-class="false" />
</bean>
<bean id="accountConnectionSignUp" class="edu.kit.tm.cm.ksc.config.AccountConnectionSignUp" />
<bean
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject">
<ref local="usersConnectionRepository" />
</property>
<property name="targetMethod">
<value>setConnectionSignUp</value>
</property>
<property name="arguments">
<list>
<ref local="accountConnectionSignUp" />
</list>
</property>
</bean>
The error occurs when the method is supposed to be called.
java.lang.NoSuchMethodException: com.sun.proxy.$Proxy12.setConnectionSignUp(edu.kit.tm.cm.ksc.config.AccountConnectionSignUp)
As you can see above, it's totally searching in the wrong package, and I have no idea why.
I have no idea how to debug this further. I'm inexperienced with Spring and it's XML-Notation. I hope someone can help me. Thank you.
As requested, the complete social.xml. Although, I do not think it is needed to solve this.
<?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:facebook="http://www.springframework.org/schema/social/facebook"
xmlns:twitter="http://www.springframework.org/schema/social/twitter"
xmlns:social="http://www.springframework.org/schema/social" xmlns:c="http://www.springframework.org/schema/c"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/social/facebook http://www.springframework.org/schema/social/spring-social-facebook.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/social/twitter http://www.springframework.org/schema/social/spring-social-twitter.xsd
http://www.springframework.org/schema/social http://www.springframework.org/schema/social/spring-social.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<context:property-placeholder
location="classpath:/edu/kit/tm/cm/ksc/config/application.properties" />
<bean id="connectionFactoryLocator"
class="org.springframework.social.connect.support.ConnectionFactoryRegistry"
scope="singleton">
<property name="connectionFactories">
<list>
<bean
class="org.springframework.social.twitter.connect.TwitterConnectionFactory">
<constructor-arg value="${twitter.consumerKey}" />
<constructor-arg value="${twitter.consumerSecret}" />
</bean>
<bean
class="org.springframework.social.facebook.connect.FacebookConnectionFactory">
<constructor-arg value="${facebook.clientId}" />
<constructor-arg value="${facebook.clientSecret}" />
</bean>
</list>
</property>
<aop:scoped-proxy proxy-target-class="false" />
</bean>
<bean id="usersConnectionRepository"
class="org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository"
scope="singleton">
<constructor-arg ref="dataSource" />
<constructor-arg ref="connectionFactoryLocator" />
<constructor-arg ref="textEncryptor" />
<aop:scoped-proxy proxy-target-class="false" />
</bean>
<bean id="accountConnectionSignUp" class="edu.kit.tm.cm.ksc.config.AccountConnectionSignUp" />
<bean
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject">
<ref local="usersConnectionRepository" />
</property>
<property name="targetMethod">
<value>setConnectionSignUp</value>
</property>
<property name="arguments">
<list>
<ref local="accountConnectionSignUp" />
</list>
</property>
</bean>
<bean id="connectionRepository" factory-method="createConnectionRepository"
factory-bean="usersConnectionRepository" scope="request">
<constructor-arg value="#{request.userPrincipal.name}" />
<aop:scoped-proxy proxy-target-class="false" />
</bean>
<mvc:annotation-driven />
<bean
class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />
<bean class="org.springframework.social.connect.web.ConnectController">
<!-- relies on by-type autowiring for the constructor-args -->
<!-- <constructor-arg ref="connectionFactoryLocator" /> -->
<!-- <constructor-arg ref="connectionRepository" /> -->
</bean>
<bean id="SimpleSignInAdapter" class="edu.kit.tm.cm.ksc.config.SimpleSignInAdapter" />
<bean class="org.springframework.social.connect.web.ProviderSignInController">
<!-- relies on by-type autowiring for the constructor-args -->
<constructor-arg ref="SimpleSignInAdapter" />
</bean>
We wrote the Java-examples of the Spring-Social-Documentation to XML. In this case for the ProviderSigninControllers dependencies. Unfortunately there are no XML examples given in this case.
Upvotes: 0
Views: 1887
Reputation: 280064
The simple solution is to change proxy-target-class
to true in your usersConnectionRepository
bean definition and add CGLIB to your class path.
If you don't need the proxying, remove it completely.
Explanation:
First, with this bean declaration
<bean id="usersConnectionRepository"
class="org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository"
scope="singleton">
<constructor-arg ref="dataSource" />
<constructor-arg ref="connectionFactoryLocator" />
<constructor-arg ref="textEncryptor" />
<aop:scoped-proxy proxy-target-class="false" />
</bean>
Spring is creating a bean of type JdbcUsersConnectionRepository
and wrapping it in a JDK proxy (since proxy-target-class
is false
). The serious shortcoming of JDK proxies, is that they only sub type interfaces.
In other words, Spring will see that the JdbcUsersConnectionRepository
class implements the UsersConnectionRepository
interface and use that when generating the Proxy. As the javadoc says
- A proxy class extends java.lang.reflect.Proxy.
- A proxy class implements exactly the interfaces specified at its creation, in the same order.
So the generated proxy will be of type Proxy
and UsersConnectionRepository
.
This won't be an issue for MethodInvokingFactoryBean
because it stores the reference in a field of type Object
. However, when MethodInvokingFactoryBean
tries to resolve the Method
to invoke, it uses the target object's Class
instance, ie. object.getClass()
. Since the target object is actually of type Proxy
, or com.sun.proxy.$Proxy12
to be exact, it does not have a JdbcUsersConnectionRepository#setConnectionSignUp
method and that causes a NoSuchMethodException
.
Upvotes: 2