Announcement Announcement Module
Collapse
No announcement yet.
Spring Social getting Facebook friends not working Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring Social getting Facebook friends not working

    I'm using Spring Social to connect to Facebook and Twitter. The connection part works fine, but when I try to get Facebook friends, it throws error:

    Code:
    The server encountered an internal error () that prevented it from fulfilling this request.
    But fetching Twitter friends works fine.
    My configuration file is as follows:

    Code:
    <bean id="connectionFactoryLocator"
            class="org.springframework.social.connect.support.ConnectionFactoryRegistry">
            <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}" />
                        <constructor-arg value="${facebook.appNamespace}" />
                    </bean>
                </list>
            </property>
        </bean>
    
        <bean id="textEncryptor" class="org.springframework.security.crypto.encrypt.Encryptors"
            factory-method="noOpText" />
    
        <bean id="usersConnectionRepository"
            class="org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository">
            <constructor-arg ref="jpaDataSource" />
            <constructor-arg ref="connectionFactoryLocator" />
            <constructor-arg ref="textEncryptor" />
            <property name="connectionSignUp" ref="accountConnectionSignUp" />
        </bean>
    
        <bean id="accountConnectionSignUp" class="com.joinups.controller.AccountConnectionSignUp" />
    
        <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 class="org.springframework.social.connect.web.ProviderSignInController">
            <property name="applicationUrl" value="${application.url}" />
        </bean>
    
        <bean class="com.joinups.config.SocialApiConfig" />
    The SocialApiConfig is as follows:

    Code:
    @Configuration
    public class SocialApiConfig {
    
        @Bean
        @Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)   
        public Facebook facebook(ConnectionRepository connectionRepository) {
            Connection<Facebook> facebook = connectionRepository.findPrimaryConnection(Facebook.class);
            return facebook != null ? facebook.getApi() : new FacebookTemplate();
        }
    
        @Bean
        @Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)   
        public Twitter twitter(ConnectionRepository connectionRepository) {
            Connection<Twitter> twitter = connectionRepository.findPrimaryConnection(Twitter.class);
            return twitter != null ? twitter.getApi() : new TwitterTemplate();
        }
    }
    And my controller to get the friends is as follows:
    Code:
    @Controller
    public class SocialController {
    
        private final Twitter twitter;
        private final Facebook facebook;
    
        @Inject
        public SocialController(Twitter twitter, Facebook facebook) {
            this.twitter = twitter;
            this.facebook = facebook;
        }
    
        @RequestMapping(value="/social/facebook/friends")
        public @ResponseBody JSONObject facebookFriends(Model model) {
            model.addAttribute("facebookProfiles", facebook.friendOperations().getFriendProfiles());
            return JSONObject.fromObject(model);
        }
    
        @RequestMapping(value="/social/twitter/friends")
        public @ResponseBody JSONObject twitterFriends(Model model) {
            model.addAttribute("twitterProfiles", twitter.friendOperations().getFriends());
            return JSONObject.fromObject(model);
        }
    
    }
    While the Twitter part works perfectly fine, the Facebook part throws error: Please help. Am I missing something.
    p.s. I also have a CustomConnectController controller that extends ConnectController. Just FYI.

  • #2
    Hi,

    I stumbled upon this question which seems similar: http://stackoverflow.com/questions/1...-500-exception

    Where the OP solved the problem by downgrading the Jackson to 1.8.5 version.

    My current version is 1.9.9. Can that be the problem? Anyone?

    I feel so lonely in this Spring Social forum!

    Comment


    • #3
      I'm not sure if that's the problem. Switching back to 1.8.5 might coincidentally fix it, but I've got working code (some small tests as well as the Spring Social Showcase) that fetch a user's friends and use Jackson 1.9.9 and they both work fine. Of course, both of these bits of working code are using the current Spring Social codebase.

      It might be helpful to know which version of Spring Social and Spring Social Facebook you're using. Actually, since Spring Social doesn't do much directly with Jackson in its binding to that portion of the API, it's even more interesting to know which version of the core Spring Framework that you're using. And, of course, if you have any stack trace in the logs, that would be helpful.

      Comment


      • #4
        Originally posted by habuma View Post
        I'm not sure if that's the problem. Switching back to 1.8.5 might coincidentally fix it, but I've got working code (some small tests as well as the Spring Social Showcase) that fetch a user's friends and use Jackson 1.9.9 and they both work fine. Of course, both of these bits of working code are using the current Spring Social codebase.

        It might be helpful to know which version of Spring Social and Spring Social Facebook you're using. Actually, since Spring Social doesn't do much directly with Jackson in its binding to that portion of the API, it's even more interesting to know which version of the core Spring Framework that you're using. And, of course, if you have any stack trace in the logs, that would be helpful.
        Hi habuma,
        Thanks for your insight.
        I'm using
        Spring Social version: 1.1.0.BUILD-SNAPSHOT
        SS Facebook version: 1.1.0.BUILD-SNAPSHOT
        Spring Core: 3.1.0.RELEASE

        Let me try to revert Jackson to 1.8.5 and check if it works. I don't have any log. All it shows is that server encountered an error. How can I print the stacktrace?

        EDIT
        ----

        I tried changing it to 1.8.5, but it still doesn't work. Kindly help.
        Last edited by deathfrag; Nov 2nd, 2012, 09:35 AM.

        Comment


        • #5
          I tried the following:

          I changed the request to a GET on an anchor, and it works.
          So the problem is that while returning JSONObject.fromObject(model).

          So I changed the code from:
          Code:
          @RequestMapping(value="/social/facebook/friends")
          	public @ResponseBody JSONObject facebookFriends(Model model) {
          		model.addAttribute("facebookProfiles", facebook.friendOperations().getFriendProfiles());
          		return JSONObject.fromObject(model);
          	}
          to

          Code:
          @RequestMapping(value="/social/facebook/friends")
          	public String facebookFriends(Model model) {
          		model.addAttribute("facebookProfiles",facebook.friendOperations().getFriendProfiles().get(0).getFirstName());
          		return "testing";
          	}
          And it works perfectly giving me the first name. So why does it fail when I try to make JSONObject.
          Btw, JSONObject is net.sf.json.JSONObject from

          Code:
          <dependency>
          			<groupId>net.sf.json-lib</groupId>
          			<artifactId>json-lib-ext-spring</artifactId>
          			<version>1.0.2</version>
          		</dependency>
          Please help.

          Comment


          • #6
            Ah...This is failing when you return the Model as a @ResponeBody-annotated controller method...not in Spring Social. I'll bet that if you were to call facebook.friendOperations().getFriendProfiles() and assign in to a List<Profile>, that line would work...but it would still fail when Spring Social attempts to convert a Model into a JSON object.

            In short...Spring Social is working, but the problem is in your code.

            What's going on here is that you're mixing two different approaches to Spring MVC. When working with human-facing Spring MVC applications (that is, those that take model data and bind them to a view...such as a JSP) then the Model class makes perfect sense. It also makes sense if you're relying on ContentNegotiatingViewResolver to convert that model to JSON for a REST API.

            But when you annotate a handler method with @ResponseBody, there's a different thing going on. Technically, there is no model or view in that scenario, so populating the model is pointless. And attempting to convert it to a JSON object is...well...just weird. I can't say for sure what would happen there, but it appears that it just doesn't work. :-)

            My guess is that you would want your handler method to look something like this instead:

            Code:
            @RequestMapping(value="/social/facebook/friends")
            public @ResponseBody List<Profile> facebookFriends() {
            	return facebook.friendOperations().getFriendProfiles());
            }
            Or, if you want to return a JSON object with the list as a property:

            Code:
            @RequestMapping(value="/social/facebook/friends")
            public @ResponseBody Map<String, ?> facebookFriends() {
            	Map<String, ?> response = new HashMap<String, ?>();
            	response.put("facebookProfiles", facebook.friendOperations().getFriendProfiles());
            	return response;
            }
            (Note that I just hacked these code snippets into the forum post and haven't actually tried them...so there could be errors in there.)

            The point is that if you're using a @ResonseBody-annotated controller method, you just return the thing that you want converted to JSON...Spring takes care of it from there. There's no need for a Model.

            Comment


            • #7
              BTW, if you take a look at https://github.com/SpringSource/spri...ontroller.java, you'll see that I'm doing roughly what you're doing. The only difference is that I'm actually returning the list of friend profiles in the model so that it can be rendered in the JSP view.

              In your case, there is no view and no model...the @ResponseBody says to convert whatever is being returned into JSON.

              Of course, I'm assuming that's what you're trying to do. If, in fact, what you really want is to return the list of profiles in the model to be rendered in a view (JSP or otherwise), then you could just remove the @ResponseBody annotation...and you probably also don't want to mess with converting it to a JSONObject. Something like this:

              Code:
              @RequestMapping(value="/social/facebook/friends")
              public String facebookFriends(Model model) {
              	model.addAttribute("facebookProfiles", facebook.friendOperations().getFriendProfiles());
              	return "friends"; // the logical view name
              }

              Comment


              • #8
                Originally posted by habuma View Post
                Ah...This is failing when you return the Model as a @ResponeBody-annotated controller method...not in Spring Social. I'll bet that if you were to call facebook.friendOperations().getFriendProfiles() and assign in to a List<Profile>, that line would work...but it would still fail when Spring Social attempts to convert a Model into a JSON object.

                In short...Spring Social is working, but the problem is in your code.

                What's going on here is that you're mixing two different approaches to Spring MVC. When working with human-facing Spring MVC applications (that is, those that take model data and bind them to a view...such as a JSP) then the Model class makes perfect sense. It also makes sense if you're relying on ContentNegotiatingViewResolver to convert that model to JSON for a REST API.

                But when you annotate a handler method with @ResponseBody, there's a different thing going on. Technically, there is no model or view in that scenario, so populating the model is pointless. And attempting to convert it to a JSON object is...well...just weird. I can't say for sure what would happen there, but it appears that it just doesn't work. :-)

                My guess is that you would want your handler method to look something like this instead:

                Code:
                @RequestMapping(value="/social/facebook/friends")
                public @ResponseBody List<Profile> facebookFriends() {
                	return facebook.friendOperations().getFriendProfiles());
                }
                Or, if you want to return a JSON object with the list as a property:

                Code:
                @RequestMapping(value="/social/facebook/friends")
                public @ResponseBody Map<String, ?> facebookFriends() {
                	Map<String, ?> response = new HashMap<String, ?>();
                	response.put("facebookProfiles", facebook.friendOperations().getFriendProfiles());
                	return response;
                }
                (Note that I just hacked these code snippets into the forum post and haven't actually tried them...so there could be errors in there.)

                The point is that if you're using a @ResonseBody-annotated controller method, you just return the thing that you want converted to JSON...Spring takes care of it from there. There's no need for a Model.
                Thanks a ton, Habuma. The answer is two fold.
                Firstly I learnt something new & realized that I was doing something stupid.
                Secondly, it solved my problem & I am a better programmer now.

                All thanks to you!!

                I changed the code to
                Code:
                @RequestMapping(value="/social/facebook/friends")
                	public @ResponseBody Map<String, List<FacebookProfile>> facebookFriends(Model model) {
                		Map<String, List<FacebookProfile>> response = new HashMap<String, List<FacebookProfile>>();
                		response.put("facebookProfiles", facebook.friendOperations().getFriendProfiles());
                		return response;
                	}
                as suggested by you. And it works perfectly!
                Thanks for the help. Faith in Spring Social restored! Faith in strangers helping strangers restored! Thanks mate!

                Comment

                Working...
                X