Saturday, April 21, 2012

Spring Expression Langauge and Simple Bean References

In this post I'll demonstrate a simple use of Spring Expression Language (SpEL). First, I'll give a little background of the "problem" I used to solve, but feel free to skip ahead to the Spring configuration below.

The project in question was required to make two separate RESTful calls to the same service, for example:

  1. http://service.mycompany.com/business/record
  2. http://service.mycompany.com/business/order

The URLs contain the same base path, http://service.mycompany.com/business, and two separate paths, record and order. The URLs are to be looked up in a service directory, whose entries we have control of.

At first I considered placing both URLs in the directory to avoid having to deal with adding each path to the base URL in code. This sounded like a misuse of the directory however as each URL would not represent a separate service deployment. Then I remembered reading about SpEL and thought this could be help me add the paths to the URL in good ol' Spring configuration.

Here is a simplification of the defintion of the bean for the URL (java.net.URL) we will reference for defining the two service URLs:

    <bean id="serviceUrl" class="org.mycompany.service.entry.ServiceEntryProxy">
       <property name="serviceName" value="businessService"/>
       <property name="serviceDirectory" ref="serviceDirectory"/>
    </bean>

As we planned on using Spring's RestTemplate to invoke the remote service, we can convert the java.net.URL returned by the service lookup and translate them to Strings to be injected in the calling class.

    <bean id="recordServiceUrl" class="java.lang.String">
        <constructor-arg value="#{serviceUrl.toExternalForm()}/record"/>
    </bean>

    <bean id="orderServiceUrl" class="java.lang.String">
        <constructor-arg value="#{serviceUrl.toExternalForm()}/order"/>
    </bean>

We create the expressions above using #{...}, which is similar to syntax used to resolve properies in Spring, ${...}. Inside the expression, we can reference the serviceUrl bean defined earlier and call a method on it, #{serviceUrl.toExternalForm()}, which returns a String representation of the URL. From there we can add the remaining paths, /record and /order.

Given the following property signature of the class required to invoke the service:

    public class ServiceController {
        private RestTemplate restTemplate;

        private String recordUrl;
        private String orderUrl;

        // ...
    }

We can inject the URL string defined earlier:

    <bean id="serviceController" class="org.mycompany.service.business.ServiceController">
        <property name="restTemplate" ref="restTemplate"/>
        <property name="recordUrl" ref="recordUrl"/>
        <property name="orderUrl" ref="orderUrl"/>            
    </bean>

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

Admittedly, this is a very simple example of what we can do with SpEL. The feature overview in the documentation does a much better job of enumerating them than I could try to do. Hopefully, now that I've used in once, I'll look to SpEL again for other uses to help get out of some potentially tricky situations.