Spring Social GitHub: revisiting GitHub integration

Tags

, , ,

In my last post, Calling the GitHub API using Spring’s RestTemplate, I explained how to call a public endpoint that retrieves a repository’s watchers on the GitHub API using Spring’s RestTemplate.

I was happy to receive a comment by Craig Walls pointing out that Spring Social has a GitHub binding, which came with an invitation to contribute code to that binding. Sounded great–I forked the project on GitHub and dug in. I discovered two factoids:

  1. The project is Gradle-based. Excellent, because I’d been wanting to try it out for a couple of years since Craig first recommended it to me in at Spring One 2GX. I just never got around to it.
  2. The Spring Social GitHub binding is nascent. (Understandably, Facebook, Twitter and LinkedIn get the lion’s share of development attention.) Outstanding, because I could implement whatever I wanted.

I ended up writing a handful of public endpoints for Spring Social GitHub. I focused on the public ones instead of the personal ones requiring OAuth (GitHub supports OAuth2 among others) since the Skybase app I’m building probably doesn’t need any of the personal endpoints. I’ll show you some of what I did since it’s fairly straightforward and since some of you might be interested in contributing further code. The Spring Social documentation has a chapter on how to create or elaborate a binding, and there are existing bindings for Facebook, Twitter and LinkedIn that provide good guidance as to how to structure things. The GitHub site has useful information on the mechanics as well. I was a little bit lazy and just shot Craig a few questions. He was good-natured about it, and pointed me to the right examples.

Implementing support for repository watching in Spring Social GitHub

Implementing a user class. In the last post I implemented a User class and then just called the GitHub URL with the RestTemplate, deserializing the JSON into my User. As it turns out, this isn’t that different than what I added to Spring Social GitHub. In fact, the revised version is almost exactly the same:

package org.springframework.social.github.api;

import java.io.Serializable;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;

@SuppressWarnings("serial")
@JsonIgnoreProperties(ignoreUnknown = true)
public class GitHubUser implements Serializable {
    private Long id;
    private String url;
    private String login;
    private String avatarUrl;
    private String gravatarId;

    public Long getId() { return id; }

    public void setId(Long id) { this.id = id; }

    public String getUrl() { return url; }

    public void setUrl(String url) { this.url = url; }

    public String getLogin() { return login; }

    public void setLogin(String login) { this.login = login; }

    @JsonProperty("avatar_url")
    public String getAvatarUrl() { return avatarUrl; }

    public void setAvatarUrl(String avatarUrl) { this.avatarUrl = avatarUrl; }

    @JsonProperty("gravatar_id")
    public String getGravatarId() { return gravatarId; }

    public void setGravatarId(String gravatarId) { this.gravatarId = gravatarId; }
}

I added the @JsonIgnoreProperties annotation to try to future-proof the class a little, and I renamed it to GitHubUser since that was more in line with the Spring Social convention around naming data transfer objects.

Creating the client interfaces. Spring Social basically wraps RestTemplate with provider-specific methods and support for OAuth authorization. So instead of passing https://api.github.com/repos/williewheeler/skybase to RestTemplate.getForObject(), we call a getWatchers() method on the Spring Social GitHub API.

The general pattern is for there to be a top-level Java client interface, which is called Facebook, or Twitter, or LinkedIn, or GitHub, and then for this interface to have smaller sub-APIs to group related operations. This avoids having a monster interface with dozens and dozens of methods. Here, for example, is what the GitHub interface looks like so far:

package org.springframework.social.github.api;

import org.springframework.social.ApiBinding;
import org.springframework.social.github.api.impl.GitHubTemplate;

public interface GitHub extends ApiBinding {

    RepoOperations repoOperations();

    UserOperations userOperations();
}

GitHub has a lot more sets of operations than that (e.g. gists, issues, orgs, pull requests, etc.), but I was just getting my feet wet and so I only created a couple of XxxOperations interfaces here.

Here’s what RepoOperations looks like so far:

package org.springframework.social.github.api;

import java.util.List;

public interface RepoOperations {
    List getCollaborators(String user, String repo);
    List getCommits(String user, String repo);
    List getWatchers(String user, String repo);
}

(As I mentioned, I implemented a few things beyond getWatchers().)

Filling in the client implementations. With the interfaces in place, it was time to write their implementations. This looked pretty close to the code from my previous article, but a little more industrial-strength to handle API modularity and also personal endpoints. Here for instance is the RepoTemplate.

package org.springframework.social.github.api.impl;

import static java.util.Arrays.asList;

import java.util.List;
import org.springframework.social.github.api.GitHubCommit;
import org.springframework.social.github.api.GitHubUser;
import org.springframework.social.github.api.RepoOperations;
import org.springframework.web.client.RestTemplate;

public class RepoTemplate extends AbstractGitHubOperations
    implements RepoOperations {

    private final RestTemplate restTemplate;

    public RepoTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser) {
        super(isAuthorizedForUser);
        this.restTemplate = restTemplate;
    }

    public List getCollaborators(String user, String repo) {
        return asList(restTemplate.getForObject(
            buildRepoUri("/collaborators"), GitHubUser[].class, user, repo));
    }

    public List getCommits(String user, String repo) {
        return asList(restTemplate.getForObject(
            buildRepoUri("/commits"), GitHubCommit[].class, user, repo));
    }

    public List getWatchers(String user, String repo) {
        return asList(restTemplate.getForObject(
            buildRepoUri("/watchers"), GitHubUser[].class, user, repo));
    }

    private String buildRepoUri(String path) {
        return buildUri("repos/{user}/{repo}" + path);
    }
}

Test cases. I wrote some test cases as well, using the test framework that the Spring guys put together. It is basically a mock server that serves up JSON files so you don’t have to hit the real GitHub and put your rate limit in danger.

Using Spring Social GitHub

With all that in place, I was excited to try out my new code. Spring Social GitHub hasn’t had an actual release yet (Spring Social Core has, but not the GitHub binding), so you’ll need to hit a snapshot repository to get it:

<repository>
    <id>spring-snapshot</id>
    <name>Spring Maven Snapshot Repository</name>
    <url>http://maven.springframework.org/snapshot</url>
</repository>

...

<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-core</artifactId>
    <version>1.0.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-github</artifactId>
    <version>1.0.0.BUILD-SNAPSHOT</version>
</dependency>

Here’s the actual Java code:

import org.springframework.social.github.api.GitHub;
import org.springframework.social.github.api.GitHubUser;

...

GitHub gitHub = ... injected or whatever ...
List<GitHubUser> watchers =
    gitHub.repoOperations().getWatchers("williewheeler", "skybase");

Couldn’t be much easier.

Here are some Skybase screenshots that show what sort of information I’m pulling down from GitHub using Spring Social GitHub:

Calling the GitHub API using Spring’s RestTemplate

Tags

, , , ,

GitHub has an RESTful JSON API that we can call from our apps. In this post I’ll show how I’m grabbing a GitHub repo’s watchers and pull them into my own app using Spring’s RestTemplate.

Meet the GitHub API

First, take a quick look at the GitHub Repo Watching API. It’s pretty simple, and it doesn’t require credentials to call. The URL for my Skybase project, for example, is https://api.github.com/repos/williewheeler/skybase/watchers.

Go ahead and click the watcher link above. You’ll see that the response is a JSON array of watcher objects.

Note that since the GitHub API is HTTPS-based, you will need to download the GitHub API certificate (using, e.g., openssl) and then import it into your Java keystore (using keytool) so your Java programs can call the API without running into certificate errors.

Create a User class for object/JSON mapping

We’re going to use Jackson to map the GitHub JSON to Java objects. We’ll need a User class for that. Here it is:

package org.skydingo.skybase.integrations.github.model;

import org.codehaus.jackson.annotate.JsonProperty;

public class User {
    private Long id;
    private String url, login, avatarUrl, gravatarId;

    public Long getId() { return id; }

    public void setId(Long id) { this.id = id; }

    public String getUrl() { return url; }

    public void setUrl(String url) { this.url = url; }

    public String getLogin() { return login; }

    public void setLogin(String login) { this.login = login; }

    @JsonProperty("avatar_url")
    public String getAvatarUrl() { return avatarUrl; }

    public void setAvatarUrl(String avatarUrl) { this.avatarUrl = avatarUrl; }

    @JsonProperty("gravatar_id")
    public String getGravatarId() { return gravatarId; }

    public void setGravatarId(String gravatarId) { this.gravatarId = gravatarId; }
}

Nothing too amazing here. Note that I’m using @JsonProperty to clarify the mapping from the avatar_url and gravatar_id JSON fields to the avatarUrl and gravatarId Java properties, since Jackson doesn’t automatically handle underscores or anything like that.

The Maven dependency for the @JsonProperty annotation is

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.3</version>
</dependency>

Get the data using RestTemplate

Now that we have User, all we need to do is grab the data using RestTemplate. Easy:

package org.skydingo.skybase.service;

import javax.inject.Inject;
import org.skydingo.skybase.integrations.github.model.User;
import org.skydingo.skybase.model.Application;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class ApplicationService {
    private static final String GITHUB_WATCHER_URI =
        "https://api.github.com/repos/{user}/{repo}/watchers";

    @Inject private RestTemplate restTemplate;

    public User[] getGithubRepoWatchers(String user, String repo) {
        return restTemplate.getForObject(GITHUB_WATCHER_URI, User[].class, user, repo);
    }
}

Recall that GitHub returns an array of watchers. That’s why we’re using User[].class in the call. RestTemplate substitutes the user and repo values into the GITHUB_WATCHER_URI string for us.

Spring configuration

All we need to do is put a RestTemplate instance on the app context:

<bean class="org.springframework.web.client.RestTemplate" />

Success!

After a little hacking at the UI:

Skybase SCM page

[See my post Skybase/GitHub integration on the Skydingo blog for more context as to why we'd want to integrate our CMDB with GitHub.]

Making <form:select> work nicely using Spring 3 Formatters

Tags

,

When you’re creating a web form, it’s often the case that you want to give the user a way to connect one entity up to another entity. This post explains how to do this in a nice, clean way using Spring Formatters.

A real-life example

To make things concrete, let’s use a real-life example. I’m working on an open source CMDB called Skybase that has entities such as farms, environments and data centers. When the user creates or edits a farm, he needs to specify the environment in which the farm lives (e.g., Development, Test, Production, etc.) and also the data center (e.g., US West DC 1, US West DC 2, etc.). We want the user to select an environment and a data center using dropdowns, like so:

For edits, we obviously want the dropdowns to be preset to their current values. We want validation: in our example, all three fields are required. For both edits and creates, when the user submits an invalid farm (e.g., missing name), we want the environment and data center to be preset to whatever value the user just submitted. Standard stuff.

Let’s look at three different approaches to solving this in Spring. The first two are ugly and the last one is clean. (If you’re impatient, feel free to skip right to the third approach.)

Approach #1 (ugly): ad hoc ID fields

One approach is to create special fields on the Farm entity to hold the environment and data center IDs, and then write custom code in the controller to map these to Environment and DataCenter instances. Here’s how such a Farm might look:

public class Farm {
    private Long id;
    private String name;
    private Environment environment;
    private DataCenter dataCenter;
    private Long environmentId;
    private Long dataCenterId;

    ... getters and setters for id, name, environment and dataCenter ...

    @NotNull
    @Transient
    @XmlTransient
    public Long getEnvironmentId() { return environmentId; }

    public void setEnvironmentId(Long id) { this.environmentId = id; }

    @NotNull
    @Transient
    @XmlTransient
    public Long getDataCenterId() { return dataCenterId; }

    public void setDataCenterId(Long id) { this.dataCenterId = id; }
}

And the form code looks something like this (I’m suppressing some details just for clarity’s sake):

<form:select path="environmentId">
    <form:option value="" label="-- Choose one--" />
    <form:options items="${environmentList}" itemValue="id" itemLabel="name" />
</form:select>
<form:errors path="environmentId">
    <span class="help-inline"><form:errors path="environmentId" /></span>
</form:errors>

The approach works, but it’s stinky for at least a couple of reasons:

  • It dirties up the Farm entity. We already have Environment and DataCenter properties, and each of those has an ID, so it’s redundant and annoying to have to include extra getters and setters to handle the IDs. If we’re doing ORM or OXM, it becomes very clear from the @Transient and @XmlTransient annotations that these extra ID properties aren’t really part of the entity at all; they’re purely supporting data transfer.
  • It forces us to write custom code in the controller to map the IDs to an Environment and a DataCenter so we can, e.g., save it in the database using Hibernate or whatever.

Now let’s see a closely related approach that’s a step in the right direction, but still stinky.

Approach #2 (still ugly): use the referenced entities’ ID properties

Instead of using redundant ID properties, we can just leave the Farm alone (meaning it has an ID, a name, an environment and a data center, and no extra ID properties) and just point the form at the environment’s and data center’s IDs:

<form:select path="environment.id">
    <form:option value="" label="-- Choose one--" />
    <form:options items="${environmentList}" itemValue="id" itemLabel="name" />
</form:select>
<form:errors path="environment.id">
    <span class="help-inline"><form:errors path="environment.id" /></span>
</form:errors>

Spring is fine with complex properties like this. And so this almost works. But there are once again a couple of issues:

  • Stylistically, it’s a bit inelegant to treat reference-backed properties in a special way. It would be cleaner to deal with environment and dataCenter instead of environment.id and dataCenter.id. Minor issue, but still worth considering.
  • More seriously, validation (at least JSR-303 validation) doesn’t work properly anymore. Referencing environment.id in the form causes Spring to create an Environment instance automatically, even if the user picks “– Choose one –” with ID = “”. So the environment and dataCenter properties won’t ever be null. And we can’t put @NotNull on the environment and data center IDs, because they’re allowed (indeed, expected) to be null when creating new ones. So you end up having to write custom code to make sure that the IDs are whatever you want to see. Blech.

OK, those are some approaches that aren’t very clean. Fortunately Spring 3 has some features that clean things up.

Approach #3 (good approach): use Formatters

The best practice approach in Spring 3 is to use so-called Formatters. As this blog post is already pretty long, let’s just jump right into the code. If you want to see more code details, check out the actual code at the Skybase Github site.

First, our entities don’t have any ad hoc ID properties like we saw in approach #1 above. But you do need to implement equals() for your entities, or else form prepopulation won’t happen.

Next, here’s what the form looks like:

<form:select path="environment">
    <form:option value="" label="-- Choose one--" />
    <form:options items="${environmentList}" itemValue="id" itemLabel="name" />
</form:select>
<form:errors path="environment">
    <span class="help-inline"><form:errors path="environment" /></span>
</form:errors>

(Same thing for the dataCenter property.) Notice that we’re not messing around with IDs at all, other than where we’re telling the <form:options> tag which property to use for the option value, which is perfectly fine and legitimate.

Next we need to look at the controller. In earlier versions of Spring we would have had to register some JavaBeans PropertyEditors in an @InitBinder method, but we don’t have to do that anymore. All we have to do is make sure we’re prepared to accept a Farm in our handler method, that we annotate it with @Valid, etc.:

@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public String putEditForm(
        @PathVariable Long id,
        @ModelAttribute("formData") @Valid Farm formData,
        BindingResult result,
        Model model) {

    ...
}

The method body doesn’t matter so much for our current purpose–we can check for validity using result.hasErrors(), save the data if it’s valid, return the invalid form if it’s not, or whatever. The main thing is that the Farm will come populated with an Environment and a DataCenter (both having the right IDs set) if the user chose them, and they’ll be null if the user didn’t:

To make the magic work, we need to implement Formatters to convert our environments and data centers back and forth to IDs. Regarding Formatters, I’ll let you read about them in the Spring Reference Documentation; here I’ll give some code examples. Here’s the EnvironmentFormatter:

package org.skydingo.skybase.formatter;

import java.text.ParseException;
import java.util.Locale;
import org.skydingo.skybase.model.Environment;
import org.springframework.format.Formatter;
import org.springframework.stereotype.Component;

@Component
public class EnvironmentFormatter implements Formatter {

    @Override
    public String print(Environment environment, Locale locale) {
        return environment.getId().toString();
    }

    @Override
    public Environment parse(String id, Locale locale) throws ParseException {
        Environment environment = new Environment();
        environment.setId(Long.parseLong(id));
        return environment;
    }
}

One more thing we have to do is configure the formatters in our Spring configuration. Here’s what that looks like (Spring 3.0.6+; I’m suppressing the namespace declarations):

<context:component-scan base-package="org.skydingo.skybase.formatter" />

<bean id="conversionService"
    class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="formatters">
        <set>
            <ref bean="dataCenterFormatter" />
            <ref bean="environmentFormatter" />
        </set>
    </property>
</bean>

<mvc:annotation-driven conversion-service="conversionService" />

This tells Spring Web MVC to use the conversion service both when rendering the form and when processing submitted form data. We won’t go into all the gory details here since they’re not necessarily important to making the whole thing work, but the formatter’s print() method is the one that handles form rendering, and the formatter’s parse() method handles turning the IDs in the HTML into entities in the Java controller.

Quick tip regarding Firefox. Before I close, I wanted to offer a quick tip. When you’re implementing and troubleshooting this stuff, be aware that Firefox has a feature where it remembers your most recently submitted form values when you hit the refresh button instead of resetting the form to its default settings. The feature helps users avoid data loss, but for developers it’s a pain because you have to reload the page from the actual address bar (click in there and hit Enter) instead of refreshing the page. I didn’t know this and the form was not responding to my code changes in the way I expected.

ClasspathScanningJaxb2Marshaller

Tags

, ,

By default, Spring’s <oxm:jaxb2-marshaller> tag uses the Jaxb2Marshaller class. It’s painful to use, though, if you have a lot of classes, because you have to enumerate them all individually. There are a couple of options here:

  • You can use one of the JAXB2 mechanisms (an ObjectFactory or an jaxb.index file; see JAXBContext).
  • You can use the marshaller’s classesToBeBound property.

Both of these options require more work than they ought to. Here, for example, is what the classesToBeBound approach looks like:

<oxm:jaxb2-marshaller id="marshaller">
    <oxm:class-to-be-bound name="org.skydingo.skybase.model.Database" />
    <oxm:class-to-be-bound name="org.skydingo.skybase.model.DataCenter" />
    <oxm:class-to-be-bound name="org.skydingo.skybase.model.Environment" />
    <oxm:class-to-be-bound name="org.skydingo.skybase.model.Farm" />
    <oxm:class-to-be-bound name="org.skydingo.skybase.model.Instance" />
    <oxm:class-to-be-bound name="org.skydingo.skybase.model.Package" />
    <oxm:class-to-be-bound name="org.skydingo.skybase.model.Package$MyListWrapper" />
    <oxm:class-to-be-bound name="org.skydingo.skybase.model.Person" />
    <oxm:class-to-be-bound name="org.skydingo.skybase.model.Project" />
    <oxm:class-to-be-bound name="org.skydingo.skybase.model.Region" />
    <oxm:class-to-be-bound name="org.skydingo.skybase.model.relationship.ProjectMembership" />
    <oxm:class-to-be-bound name="org.skydingo.skybase.web.jit.JitNode" />

    ... and so forth ...

</oxm:jaxb2-marshaller>

Every time we add a new entity to the system, we have to go back to the list and add a corresponding entry. Blech.

About a year back I discovered a gem by Jarno Walgemoed called ClasspathScanningJaxb2Marshaller. Actually, I don’t remember if that’s its exact name, because his blog post no longer exists, but that’s pretty close if not exactly it. At any rate, it uses Spring’s classpath scanning mechanism (you know, the one that finds @Component and @Repository and so forth) to find classes annotated with @XmlRootElement, and then JAXB-binds them.

[EDIT: I found the original blog post after all. -- WLW]

Here’s a slightly modified version of Jarno’s class, reposted with his kind permission. (Thanks Jarno!) I’ve used it on multiple projects and it works great.

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.xml.bind.annotation.XmlRootElement;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;

public class ClasspathScanningJaxb2Marshaller extends Jaxb2Marshaller {
    private static final Logger log = LoggerFactory.getLogger(ClasspathScanningJaxb2Marshaller.class);

    private List basePackages;

    public List getBasePackages() { return basePackages; }

    public void setBasePackages(List basePackages) { this.basePackages = basePackages; }

    @PostConstruct
    public void init() throws Exception {
        setClassesToBeBound(getXmlRootElementClasses());
    }

    private Class[] getXmlRootElementClasses() throws Exception {
        ClassPathScanningCandidateComponentProvider scanner =
            new ClassPathScanningCandidateComponentProvider(false);
        scanner.addIncludeFilter(new AnnotationTypeFilter(XmlRootElement.class));

        List<Class> classes = new ArrayList<Class>();
        for (String basePackage : basePackages) {
            Set definitions = scanner.findCandidateComponents(basePackage);
            for (BeanDefinition definition : definitions) {
                String className = definition.getBeanClassName();
                log.info("Found class: {}", className);
                classes.add(Class.forName(className));
            }
        }

        return classes.toArray(new Class[0]);
    }
}

Initializing lazy-loaded collections with Spring Data Neo4j

Tags

, ,

Spring Data Neo4j has been around for about a year now, but the so-called “simple mapping” strategy (the one that doesn’t use AspectJ) is new. So it doesn’t have some of the bells and whistles that you might expect to see if you’re coming from, say, Hibernate. In particular, it doesn’t (as of Spring Data Neo4j 2.0.0.RELEASE) use proxies for collections.

The question of how to initialize lazily loaded collections came up on StackOverflow. Michael Hunger (Spring Data Neo4j lead) explained that you can use the Neo4jTemplate’s fetch() method to perform the initialization. Here’s some code showing how to do it:

package org.skydingo.skybase.service.impl;

import java.util.Set;
import javax.inject.Inject;
import org.skydingo.skybase.model.Person;
import org.skydingo.skybase.repository.PersonRepository;
import org.skydingo.skybase.service.PersonService;
import org.springframework.data.neo4j.support.Neo4jTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class PersonServiceImpl implements PersonService {
    @Inject private Neo4jTemplate template;
    @Inject private PersonRepository personRepo;

    @Override
    public Person findPersonDetails(Long id) {
        Person person = personRepo.findOne(id);
        Set reports = person.getDirectReports();
        for (Person report : reports) { template.fetch(report); }
        return person;
    }

    ... other methods ...
}

Have fun.

Configuring Jackson to use JAXB2 annotations with Spring

Tags

, , , , , , ,

If you want to generate both XML and JSON views of some object, one option is to use JAXB2 annotations for the XML mapping and Jackson annotations for the JSON mapping. But that’s a little bit of a nuisance, because you have to declare the what are essentially the same mappings twice. It turns out that it’s possible to configure Jackson to use the JAXB2 annotations.

Maven configuration

First, make sure you have the jackson-xc dependency (in addition to the other Jackson dependencies) declared. This is the Maven dependency that supports using JAXB2 annotations:

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-xc</artifactId>
    <version>1.9.2</version>
</dependency>

Spring configuration

Next, you’ll need a bit of Spring configuration:

<oxm:jaxb2-marshaller id="marshaller">
    <oxm:class-to-be-bound name="org.skydingo.skybase.model.Person" />
    <oxm:class-to-be-bound name="org.skydingo.skybase.model.Project" />
</oxm:jaxb2-marshaller>

<bean id="jaxbAnnIntrospector"
    class="org.codehaus.jackson.xc.JaxbAnnotationIntrospector" />
<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper">
    <property name="serializationConfig.annotationIntrospector"
        ref="jaxbAnnIntrospector" />
    <property name="deserializationConfig.annotationIntrospector"
        ref="jaxbAnnIntrospector" />
</bean>

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="mediaTypes">
        <map>
            <entry key="html" value="text/html" />
            <entry key="json" value="application/json" />
            <entry key="xml" value="application/xml" />
        </map>
    </property>
    <property name="viewResolvers">
        <list>
            <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
                p:prefix="/WEB-INF/jsp/"
                p:suffix=".jsp" />
        </list>
    </property>
    <property name="defaultViews">
        <list>
            <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"
                p:objectMapper-ref="jacksonObjectMapper">
                <property name="renderedAttributes">
                    <set>
                        <value>person</value>
                        <value>project</value>
                    </set>
                </property>
            </bean>
            <bean class="org.springframework.web.servlet.view.xml.MarshallingView"
                p:marshaller-ref="marshaller" />
        </list>
    </property>
</bean>

Note the use of the compound property names when injecting into the Jackson ObjectMapper. That’s a little-known but useful technique for performing injections in cases where constructor and simple property injection aren’t options.

See also

SpringOne 2GX takeaways

Tags

, , , , , , , , , ,

SpringOne 2GX logo

I attended SpringOne 2GX in Chicago last week and had a good time. Great sessions and keynotes, and I got to see some people I hadn’t seen in a while, and meet some new people too.

Here are some of the things that I found most interesting. This is just my own personal list obviously, and there’s a huge list of things happening in the Spring world.

Code2Cloud. This will be cloud-based application lifecycle management (ALM), like source control, issue tracking and continuous integration. One feature that looked particularly interesting was that the ALM system will execute the committed code and complain about code performance issues by creating an issue in the issue tracking system, complete with contextual information surrounding the performance issue in question.

Gradle. From what I gather, this is like Maven, but Groovy-based instead of XML-based, and much more aggressive about making assumptions about your project. The end result is that the build file is much smaller than a Maven POM file. I suspect that I’m not doing Gradle justice with this description but even with that description I’m interested because I like Maven’s approach, but I wouldn’t mind build files that are more compact.

Spring support for NoSQL data stores. NoSQL (“not only SQL”) is a pretty important topic and Spring is jumping into this space with support for multiple providers. One thing that was neat was that you can have POJOs that are partially backed by traditional RDBMS databases (say for metadata) and partially backed by a NoSQL store, all using annotations as you might guess.

Spring Social. It allows developers to create apps that interact with the major social networks. Part of what’s involved includes expanded RestTemplates for making the web service calls. The other part is that it handles the OAuth authorization behind the scenes so developers don’t have to mess around with what can be a complicated undertaking.

Spring Mobile. This allows Spring developers to develop apps for mobile platforms like the iPhone and the Droid.

Support for HTML 5. Saw some pretty nice demos of HTML 5 apps. I’m not sure at this point exactly what this support entails, but it looks like this is one of several areas of effort.

Cache API and support for distributed caches. Spring has included a preliminary cache API for several years now, but with the uptick in distributed caching they’re building this out and will include it in Spring 3.1 I think they said.

Support for environments. Also a Spring 3.1 feature, there will be support for creating environment-specific beans (e.g. beans for dev, functional test, staging, prod, etc.).

Gemfire data fabric. I sat in on a session here and there was quite a bit to take in, so I’d need to hear the talk again to report on exactly what the offer is here. But the basic idea is highly available, low latency, horizontally scalable data that doesn’t sacrifice consistency. I know a lot of organizations could use something like that so I’ll be keeping an eye on this.

Those were the things that stood out for me. Any fears that Java and/or Spring aren’t keeping with the times would appear to be unfounded.

Quick tip: Spring Security role-based authorization and permissions

Tags

, , , ,

The problem: hardcoded role-based authorization

One of the challenges around using Spring Security is that the examples—both in the documentation and on the web—tend to promote an overly-simple approach to role-based authorization, hardcoding roles in the source in a non-configurable fashion. For example:

@PreAuthorize("hasRole('facultyMember')")
public Newsletter getFacultyNews() { ... }

(Assume for the sake of example that ACL-based authorization is overkill for the method in question. The user either has permission to read faculty newsletters or not.)

The problem is that when we decide to make a change—for example, maybe teaching assistants should be allowed to read the faculty newsletters too—we have to go into the code to make a change:

@PreAuthorize("hasRole('facultyMember') or hasRole('teachingAssistant')")
public Newsletter getFacultyNews() { ... }

For domain object security there’s no problem because the permissions are cleanly separated from roles. We can map associate individual permissions on domain objects with users and roles as we wish. So the code contains annotations like

@PreAuthorize("hasPermission(#message, write)")
public void editMessage(Message message) { ... }

and all is good. We probably won’t need to change the relationship between the permission and the method itself; we’ll only need to change who (which users/roles) actually has the write permission on the message in question, and we can do that in the database. So that is nice, and we want the same thing for role-based authorization.

Solution: use granted authorities to model permissions, not roles

Here we assume an authentication source that models the desired relationship between users, roles and permissions. The typical relationship would be a many-many relationship between users and roles, and a many-many relationship between roles and permissions. For example:

Sample custom user schema

It would be possible to have a direct relationship between users and permissions too (say to allow for the assignment of fine-grained permissions to specific users in addition to assigning roles), if that were desired.

The schema can be part of some standard authentication source or it can be a custom UserDetailsService; it doesn’t matter.

At the end of the day we need to transform our user representation into a UserDetails, and the trick is to map permissions—not roles—to GrantedAuthority objects to support the getAuthorities() contract on the UserDetails interface. We still have roles, but they matter only insofar as they help to bundle permissions up into convenient packages. The UserDetails implementation will probably expose the roles, but the UserDetails interface simply exposes the permissions (not the roles) via the getAuthorities() method.

It’s really that simple, and the final result is that we can avoid hardcoding roles in the code:

@PreAuthorize("hasRole('PERM_READ_FACULTY_NEWS')")
public Newsletter getFacultyNews() { ... }

As an aside, the predicate name hasRole rather than hasAuthority is a minor annoyance since permissions aren’t roles. The backing check is against a GrantedAuthority and so hasRole() seems to reflect either the intended or the typical use of GrantedAuthority.

Quick tip: avoid rule duplication when using security:authorize

Tags

, ,

Spring Security features a tag that allows us to show or hide JSP content based on access rules we can define. Here’s an example:

<security:authorize access="hasRole('admin')">
    <a href="/main/admin.html">Admin</a>
<security:authorize>

This is probably the most common way to use the tag. The problem with this approach, though, is that it leads to rule duplication, because the same hasRole('admin') rule is defined in the security application context.

A better approach is to bind the display of the tag body to the user’s actual access to the URL in question. Suppose for example that we have the following definition in the app context:

<intercept-url pattern="/main/admin.html" method="GET"
    access="hasRole('admin')" />

Then we can simply replace the old JSP tag definition with a new one like this:

<security:authorize url="/main/admin.html" method="GET">
    <a href="/main/admin.html">Admin</a>
<security:authorize>

Now we’ve successfully eliminated the duplicate rule definition. If we were to decide to change the rule to hasRole('administrator'), or to anything else for that matter, we’d be able to do that in a single location.

Quick tip: upgrade a legacy password storage scheme

Tags

, , , ,

This one’s a Spring Security quick tip that I wanted to share. Suppose that you have a password storage scheme that stores passwords as plaintext, and you want to upgrade that to storing hashes. No problem; simply replace the plaintext passwords with hashed versions (e.g., SHA-256).

But what if your legacy scheme is to store hashed passwords, and you want to upgrade that to store salted, hashed passwords? Here you don’t have the original passwords, so you can’t construct salted, hashed versions of the originals, at least not without resorting to reversing the passwords, which we generally don’t want to do. How do we proceed?

It’s easy. Just use multiple authentication providers pointing at the same source: one for hashed passwords, and one for salted, hashed passwords. Here’s how it looks in Spring Security 3:

<authentication-manager>

    <!-- For legacy passwords -->
    <authentication-provider user-service-ref="userDetailsService" />

    <!-- Salted, hashed passwords -->
    <authentication-provider user-service-ref="userDetailsService">
        <password-encoder ref="passwordEncoder">
            <salt-source ref="saltSource" />
        </password-encoder>
    </authentication-provider>
</authentication-manager>

The first provider handles the legacy simple hash-based scheme, and the second handles the new scheme.

Follow

Get every new post delivered to your Inbox.