Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.
See all our reports

What you can build for free in 2 hours with Spring Boot, Twitter and Facebook

If someone told me 10 years ago that people would be using Spring to tweet their Facebook status, I’d probably say, “What the hell is a tweet?!?” OK, 5 years ago, I’d say, “Hmmm, that’s interesting, I bet it took you the best part of 2 months to get the integrations working and another 6 months to draw up the XML”.

If I told you that, just today, I did the same thing in less than two hours of combined time with annotations, Injection, free bootstrapping with Spring Boot and development with instantly visible code changes and no restarts using JRebel, it would be a little more interesting. Plus, the gem… I didn’t use a single line of XML :)

XMLEndorse

Why am I doing all of this? Well, I’m a developer advocate so it’s important to be social, right! I use Facebook in my private life, but I use Twitter, LinkedIn and other social networks heavily with my work. What kind of advocate/evangelist would I be if I didn’t?

Anyway, I wanted to play with Spring Social, which is a grouping of nice integrations that Spring provides to let you easily set up integrations with social sites. There is a bit of fuss on the social networking sites when it comes to providing third-party access to apps/accounts, but we’ll visit that later.

Spring Social has integrations for Twitter (really good), Facebook (limited to Facebook’s restrictive app permissions approvals, per app), LinkedIn (reasonable) and a bunch of other third-party implementations available for almost all other networking sites.

In this post, I’ll show how I put my application together, including the guides I used along the way to prevent the need to make any living sacrifices to the XML gods…for anyone who wants a bit of a giggle, check out this JSONx specification from IBM, which threatens to revolutionise the JSON industry by… turning it into XML. Naturally.

Create your Spring app without XML!

First, let’s grab some code that gives us a head start. We’ll need some code from the sample application described in the Spring quickstart guides, which by the way, I’m liking more and more these days.

The first step is to actually create an app on the Facebook developer site that will provide you with the door to access posts, timelines and general information about a user. I wanted to actually post on behalf of a user, but the permissions are so restrictive that I believe I have to request the ability (from a human) to post on behalf of users. Since this can take up to 7 days to get approved, I opted to tweet my Facebook status instead. If you know how to get around this, let me know!

Once you create your application, give it a name and a description, then you’ll be given a key and a secret code. These are needed by your client application to gain access to the user data upon login, so keep them nearby.

I promised no XML, instead going for annotations and injection. My gradle build file grabs the Facebook dependency that provides us with the helper and component types we need to be awesome. Here’s a snippet (Oh and thanks to Adam Brodziak for converting my maven XML to gradle!):

dependencies {
    compile("org.springframework.boot:spring-boot-starter-thymeleaf")
    compile("org.springframework.social:spring-social-facebook")
}

Adding the Facebook Controller

Next, I’m going to create a Controller that has Facebook-like mapping, /fb, and a constructor, which Spring uses to kindly initialize a very useful Facebook class that gives us all the necessary operations to snoop around feeds and check out timelines.

@Controller
@RequestMapping("/fb")
public class HelloFBController {

    private Facebook facebook;
    
    @Inject
    public HelloFBController(Facebook facebook) {
        this.facebook = facebook;
    }
[.....]
}

Getting the Facebook feed

Next up, we’ll add a method called on a GET operation, which will firstly authenticate us as a third party so that we can access all that dirty data–you know, that annoying screen that’s actually important to read so an app doesn’t start sending your vital information to all your friends! Once you’re logged in, we’ll grab the user’s authenticated feed and add it to the model parameter that we’ll represent later.

@RequestMapping(method=RequestMethod.GET)
public String helloFacebook(Model model) {
    if (!facebook.isAuthorized()) {
        return "redirect:/connect/facebook";
    }
        
    model.addAttribute("feed", facebook.feedOperations().getFeed());
    
    return "hellofb";
}

Formatting the response

We return the String “hellofb” which represents the HTML file we want to forward to next. Interesting parts of the HTML file, shown below, creates a form, which forwards over to the Twitter controller, which we’ll see later. It uses Thymeleaf, which is a neat tool quite similar to JSPs, in terms to the ability to drop data into your view layer, but it does it in less of a code-drop way and more of an element attribute way.

<h4>Here are your posts:</h4>
  <form action="/twitter">
    <th:block th:each="status:${feed}">
      <input type="radio" name="tweet" th:attr="value=${status.getDescription()}" th:if="${status.getDescription()} != null" th:text="${status.getDescription()}">Post</input>
      <br th:if="${status.getDescription()} != null"/>
    </th:block>
    
<button type="submit">Tweet Post!</button>
  </form>

We take the feed element and loop over it taking each Status object which our controller created for us and adding a radio box for each valid Facebook status. I think many of these statuses are protected by their visibility and so were actually returned blank. I used the Thymeleaf th:if syntax to eliminate empty results.

But does it work?

Let’s take a look now at the application running and what actually happens. First of all, we need a container to run this all in, but rather than waste time putting together a container and package up an application, I’m just going to use Spring Boot. Yeh, you may have seen the giveaway in my pom above…10 points to you! I just need to create an Application class which I can run as a Java application:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
} 

When we run this as a Java Application, we get some of the most amazing ascii art the world has ever seen:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.9.RELEASE)

Even more, we also get an embedded Tomcat environment that runs our freshly-baked code. When we hit out /fb endpoint, we’re prompted to press a button that asks us to authenticate.

connected-to-fb

Oh wait, we didn’t do that bit yet! Quick, let’s create an application.properties file and add the following two lines:

spring.social.facebook.appId=157xxxxxxxxxx902
spring.social.facebook.appSecret=3cbxxxxxxxxxxxxxxxxxxxxxxxx06b

OK, I added some x’s in there, since I don’t want everyone seeing my really interesting facebook posts, now do I? Go back to our browser and let’s click the button and see what happens:

connected-to-fb

Yay, we passed the appId and appSecret values (which should never be given out by the way) that verify that we are who we say we are. We can now go back to our fb URL. By the way, these last two screens are pieces of HTML that come with the sample app. Now we see the following:

fb-posts

Pushing Posts to Twitter

Now I know what you’re thinking, and you’re right to be envious of my exciting Facebook life! There would be a bunch more if my posts were public, I’m pretty sure.

These are two posts that were articles and I added them to my timeline using widgets, so I’m guessing they use different privacy rules. Anyway, I’m going to take the first status and not just because the second one is greater than 140 chars in length, but because I happened to write that blog a day before this one that is literally about Spring Boot, JRebel and RESTful endpoints.

Next, I’m gonna click “Tweet Post!” but first, I guess we should implement that bit. First, let’s change our gradle build file so that we add the dependency for Twitter integration:

dependencies {
    compile("org.springframework.boot:spring-boot-starter-thymeleaf")
    compile("org.springframework.social:spring-social-facebook")
    compile("org.springframework.social:spring-social-twitter")
}

After pulling that dependency in and refreshing our Spring Boot environment, we need to go over the same steps we did previously in Facebook to allow third-party access to our personal information. This time, we’re going to visit the Twitter development site.

While the Spring documentation suggests you don’t need to fill in the Callback textbox yet, I found that unless you want a 406 error, it was pretty essential and in fact the most important option to fill in. Once you’ve completed the form with your information, you’ll get another key and secret passcode which you’ll need to keep close to hand. Actually, let’s just fill in the application.properties file again with that information so we don’t forget:

spring.social.twitter.appId=Fjxxxxxxxxxxxxxxxxxxxxxxxxxf9
spring.social.twitter.appSecret=iPiRyMbJ5xxxxxxxxxxxxxxxxxxxxxxxxxxx55HNuapduV5

So now, we should have access to Twitter, we just need to make use of the value passed to us by the radio boxes on the last page. Yeh, that’s a bit hacky and not gonna work with all tweets, but it works in this small sample that isn’t being deployed into production any time soon. So who cares!

Now let’s create our new Controller, as shown here:

@Controller
@RequestMapping("/twitter")
public class HelloTwitterController {

    private Twitter twitter;
    private ConnectionRepository connectionRepository;

    @Inject
    public HelloTwitterController(Twitter twitter, ConnectionRepository connectionRepository) {
        this.twitter = twitter;
        this.connectionRepository = connectionRepository;
    }
[...]
}

We’ve added a new URL mapping and with our constructor, which takes Twitter and ConnectionRepository types that magically get injected at runtime for us to use. We’re going to use the @ModelAttribute annotation to grab the text we want to tweet on the request, and implement a method to handle our request coming in.

First time round, we need to authenticate with Twitter using our special appId and appSecret details and then we’ll call updateStatus on the TimelineOperations interface that we can get from our pre-injected Twitter object. This is an incredibly small amount of neat code! We’re going to grab the timeline for the Twitter user and add that as an attribute to the model which we’ll then extract in the HTML later on.

@RequestMapping(method=RequestMethod.GET)
public String helloTwitter(Model model, @ModelAttribute("tweet") String tweet) {
    if (connectionRepository.findPrimaryConnection(Twitter.class) == null) {
        return "redirect:/connect/twitter";
    }
        
    twitter.timelineOperations().updateStatus(tweet);
    model.addAttribute("tweets", twitter.timelineOperations().getHomeTimeline());
        
    return "hellotwitter";
}

Once again, the String we return, “hellotwitter”, refers to the HTML which we’re deferring to in the view layer. The interesting HTML is below.

<ul>
    <li th:each="tweet:${tweets}" th:text="${tweet.getText()}">Tweet</li>
</ul>

We iterate through the tweets, output the text of the tweet, and present it as an unordered list. It’s an understatement to say that this bit of code looks nice with Thymeleaf. Let’s go back to the runtime and see what breaks! :) After clicking the “Tweet Post!” button, we get the twitter authorisation page, as expected:

authorize-twitter-app

Once we authorise the application to pretty much do anything it wants to, we get back to our application and can make the invocation again.

connected-to-twitter

The second time we make the invocation, we notice from our Twitter application that the tweet has indeed been sent! Everyone’s a winner!

twitter-integration-works

What follows is a list of tweets from my Twitter timeline, i.e. tweets from people I follow as well as myself. You can see from the list below that my tweet is at the top, having only just tweeted it and also Burton Albion just scored to go 1-0 up against Wycombe Wanderers away. Very interesting indeed.

recent-tweets

What’s the message?

As a social guy both personally and professionally, I really enjoy being able to have and share an interesting coding experience using these tools and technologies mentioned above. Using Spring Social really lowers the barrier in terms of the amount of code you need to write and the set up required to engage with social networks.

But it’s not all gravy yet–one of the current bottlenecks in my opinion is actually getting the social networking sites to enable third-party tools that expose their status, but I guess this is for security and other important things like that. Spring Social integrations only require you to add one or two lines of code to make something happen and everything else is kind of done for you with annotations- and injection-based development. Nice and clear. To end with a pun, I’d say that Spring Boot really kicks it up a notch (get it?!), especially when you pair it up with JRebel for seeing all your code changes instantly. Altogether, a really productive pair!

  • Thai

    Do you happen to have the code of this app anywhere? I’d like to write a similar app using JEE 6 and running on tomee 1.7 (of which the tomee-maven-plugin, I think, can make a standalone jar that we can run as in the case of Spring Boot).

  • Skini

    Can you show please the code for connecting to the social network ? (when you redirect to connect/facebook for example ) This is like the most important part and we can`t see it.

    Thanks

  • dima

    Hi, Simon! Can you please, show the code? I didn’t find your github profile.

  • Lucky

    Guys, as mentioned in the article, refer the sample spring facebook application https://github.com/spring-guides/gs-accessing-facebook guide.