Announcement Announcement Module
Collapse
No announcement yet.
How-to configure Spring Social via XML Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How-to configure Spring Social via XML

    I spend a few hours trying to get Twitter integration to work with Spring Social using the XML configuration approach. All the examples I could find on the web (and on stackoverflow) always use the
    Code:
    @Config
    approach as shown in the samples

    For whatever reason the bean definition to get an instance to the twitter API throws an AOP exception:

    Code:
    Caused by: java.lang.IllegalStateException: Cannot create scoped proxy for bean 'scopedTarget.twitter': Target type could not be determined at the time of proxy creation.
    	at org.springframework.aop.scope.ScopedProxyFactoryBean.setBeanFactory(ScopedProxyFactoryBean.java:94)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1475)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.access$0(AbstractAutowireCapableBeanFactory.java:1466)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$5.run(AbstractAutowireCapableBeanFactory.java:1437)
    	at java.security.AccessController.doPrivileged(Native Method)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1435)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
    	... 47 more|
    Here's the complete config file I have:

    Code:
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:jaxrs="http://cxf.apache.org/jaxrs"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:util="http://www.springframework.org/schema/util" 
        xmlns:cxf="http://cxf.apache.org/core"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:jee="http://www.springframework.org/schema/jee"
        xmlns:mvc="http://www.springframework.org/schema/mvc" 
        xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
        xsi:schemaLocation="
           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
           http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
           http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
           http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
           http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd">
    
        <import resource="classpath:META-INF/cxf/cxf.xml" />
        <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
    
        <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/DefaultDB" />
    
        <!-- initialize DB required to store user auth tokens -->
        <jdbc:initialize-database data-source="dataSource" ignore-failures="ALL">
          <jdbc:script location="classpath:/org/springframework/social/connect/jdbc/JdbcUsersConnectionRepository.sql"/>
        </jdbc:initialize-database>
    
        <bean id="connectionFactoryLocator"
            class="org.springframework.social.connect.support.ConnectionFactoryRegistry">
            <property name="connectionFactories">
                <list>
                    <ref bean="twitterConnectFactory" />
                </list>
            </property>
        </bean>
    
        <bean id="twitterConnectFactory" class="org.springframework.social.twitter.connect.TwitterConnectionFactory">
            <constructor-arg value="xyz" />
            <constructor-arg value="xzy" />
        </bean>
    
        <bean id="usersConnectionRepository"
            class="org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository">
            <constructor-arg ref="dataSource" />
            <constructor-arg ref="connectionFactoryLocator" />
            <constructor-arg ref="textEncryptor" />
        </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>
    
        <bean id="twitter" factory-method="findPrimaryConnection"
            factory-bean="connectionRepository" scope="request" depends-on="connectionRepository">
            <constructor-arg value="org.springframework.social.twitter.api.Twitter" />
            <aop:scoped-proxy proxy-target-class="false" />
        </bean>
    
    
        <bean id="textEncryptor" class="org.springframework.security.crypto.encrypt.Encryptors"
            factory-method="noOpText" />
    
        <bean id="connectController" class="org.springframework.social.connect.web.ConnectController">
            <constructor-arg ref="connectionFactoryLocator"/>
            <constructor-arg ref="connectionRepository"/>
            <property name="applicationUrl" value="https://socialscn.int.netweaver.ondemand.com/socialspringdemo" />
        </bean>
    
        <bean id="signInAdapter" class="com.sap.netweaver.cloud.demo.social.SimpleSignInAdapter" />
    
    </beans>
    What puzzles me is that the connectionRepositoryinstantiation works perfectly fine (I commented-out the twitter bean and tested the code!) ?!? It uses the same features: request scope and interface AOP proxy and works, but the twitter bean instantiation fails ?!?

    The spring social config code looks as follows (I can not see any differences, can you?):

    Code:
    @Configuration
    public class SocialConfig {
    
        @Inject
        private Environment environment;
    
        @Inject
        private DataSource dataSource;
    
        @Bean
        @Scope(value="singleton", proxyMode=ScopedProxyMode.INTERFACES) 
        public ConnectionFactoryLocator connectionFactoryLocator() {
            ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
            registry.addConnectionFactory(new TwitterConnectionFactory(environment.getProperty("twitter.consumerKey"),
                    environment.getProperty("twitter.consumerSecret")));
            return registry;
        }
    
        @Bean
        @Scope(value="singleton", proxyMode=ScopedProxyMode.INTERFACES) 
        public UsersConnectionRepository usersConnectionRepository() {
            return new JdbcUsersConnectionRepository(dataSource, connectionFactoryLocator(), Encryptors.noOpText());
        }
    
        @Bean
        @Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)   
        public ConnectionRepository connectionRepository() {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication == null) {
                throw new IllegalStateException("Unable to get a ConnectionRepository: no user signed in");
            }
            return usersConnectionRepository().createConnectionRepository(authentication.getName());
        }
    
        @Bean
        @Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)   
        public Twitter twitter() {
            Connection<Twitter> twitter = connectionRepository().findPrimaryConnection(Twitter.class);
            return twitter != null ? twitter.getApi() : new TwitterTemplate();
        }
    
        @Bean
        public ConnectController connectController() {
            ConnectController connectController = new ConnectController(connectionFactoryLocator(), connectionRepository());
            connectController.addInterceptor(new PostToWallAfterConnectInterceptor());
            connectController.addInterceptor(new TweetAfterConnectInterceptor());
            return connectController;
        }
    
        @Bean
        public ProviderSignInController providerSignInController(RequestCache requestCache) {
            return new ProviderSignInController(connectionFactoryLocator(), usersConnectionRepository(), new SimpleSignInAdapter(requestCache));
        }
    }
    Any help/pointers would be appreciated!!!

    Cheers, Matthias

  • #2
    Yes, XML configuration of Spring Social can be tricky. A couple of bits of help for you, though:

    1. Have you looked at the Twitter4j? It uses XML-based configuration. Although it doesn't use TwitterTemplate (it's main purpose is to demonstrate that Spring Social can also work with 3rd party API bindings), it does use XML config for the connection repositories and the connection factory locator. It might be a good source to look at to try to see if you've configured those beans properly.

    2. Going forward in Spring Social 1.1.0, I've added a simplified XML configuration with a set of Spring Social XML namespaces (core, plus one for each provider module). You can see an example of its usage at https://github.com/SpringSource/spri...l-showcase-xml. This is still in 1.1.0 snapshots and not released yet (and therefore, subject to change), but I think it's very promising and greatly simplifies Spring Social configuration.

    That said, I'll try to sort out your problem, but may not have a chance to review your work right away...perhaps later today or tomorrow if that's okay. Also, it'd be a huge help if there were a project I could pull from GitHub or in a zip file somewhere to try out what you've done...so that I don't have to attempt to recreate it on my end.

    Please do keep me posted if you make any progress.

    Comment


    • #3
      Thanks habuma for the prompt reply! Today is a national holiday in Germany anyway hence I got limited time on my end as well...

      I wish I could point you to a Github repo right away, yet as I have compiled the code as part of my job I yet have to wait till the outbound Open Source process is dealt with (corporate policies ) - I'd happily share the code with you via email in the meanwhile though. So, may I ask you to contact me at: matthias.steiner [at] inscope.net and I'll send you the (maven) project?

      Oh, and one more thing I noticed irt to the design of the spring social connect package: unfortunately "JdbcConnectionRepository" is on package visibility and its "addConnection" method uses the "COALESCE" JDBC statement. Unfortunately that is not supported by our target DB. Hence I was forced to sub-class both "JdbcConnectionRepository" and "JdbcUserConnectionRepository" respectively in order to change that method. Maybe that is something to consider for 1.1 as well.

      In the meanwhile I worked around the problem with "TwitterTemplate" by simply injecting "ConnectionRepository" and obtaining the TwitterTemplate manually as below:

      Code:
      protected Twitter getTwitter()
      {
      	Connection<Twitter> twitter = connectionRepository.findPrimaryConnection(Twitter.class);
      	return twitter != null ? twitter.getApi() : new TwitterTemplate();
      }
      I'll have a look at the sample code and the simplifications you mention later this week. Would really like to stick to TwitterTemplate as it's a unified approach for all social media APIs. (I did use twitter4J previously, but as most my projects use spring anyway - I do like the idea of keeping the overall dependencies to a minimum.)

      Cheers,
      Matthias

      Comment


      • #4
        FWIW, I tried recreating your problem, with limited success (and by that I mean, I was successful in getting things to work). The only thing that stuck out to me is that your JdbcUsersConnectionRepository bean, although a single (which is correct) isn't given an <aop:scoped-proxy> element as is the case in the XML config in the Twitter4j example. I'm not sure if that's the whole problem or if there's more to it...but that's something to look at.

        And, I'm not recommending that you switch to using Twitter4j; that's just what that particular sample shows. I just pointed at that example for it's XML configuration. Unfortunately, I don't think I have any other XML-based configuration examples that aren't using the new configuration namespace. (Truthfully, without the namespace support, the Java-based configuration is just so much easier than the XML configuration...which makes me wonder if there's a reason you can't/won't use Java config?)

        As for the coalesce statement...good thing to point out. Could you open a Bug issue at https://jira.springsource.org/browse/SOCIAL for that? Thanks

        Comment

        Working...
        X