Category Archives: spring

Eclipse AJDT intertypes and Push-In refactoring

In the wake of the recent 1.0.0 release of Spring Roo, while going through Ben Alex’s captivating three part tutorial (1,2,3) on the tool, I experienced one of those moments that are normally few and far between when you know you’ve come across something new – something rare and revolutionary for the space of technology that it’s acting within that would never have occurred to you – something lateral in nature (no pun intended as we’ll see later on). Meet Eclipse ADJT, intertypes and Push-In refactoring.

Let’s take the Spring Roo project in the above tutorial as an example.

Spring Roo Project

Spring Roo Project

Imagine the following pojo.

package name.dhruba.wedding.domain;

import javax.persistence.Entity;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;
import org.springframework.roo.addon.entity.RooEntity;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Date;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.springframework.format.annotation.DateTimeFormat;

@Entity
@RooJavaBean
@RooToString
@RooEntity(finders = { "findRsvpsByCodeEquals" })
public class Rsvp {

    @NotNull
    @Size(min = 1, max = 30)
    private String code;

    @Size(max = 30)
    private String email;

    private Integer attending;

    @Size(max = 100)
    private String specialRequests;

    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(style = "S-")
    private Date confirmed;
    
    
}

It has no methods of any kind. Now imagine a separate compilation unit that provides these methods.

package name.dhruba.wedding.domain;

import java.lang.Integer;
import java.lang.Long;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PersistenceContext;
import javax.persistence.Version;
import name.dhruba.wedding.domain.Rsvp;
import org.springframework.transaction.annotation.Transactional;

privileged aspect Rsvp_Roo_Entity {
    
    @PersistenceContext    
    transient EntityManager Rsvp.entityManager;    
    
    @Id    
    @GeneratedValue(strategy = GenerationType.AUTO)    
    @Column(name = "id")    
    private Long Rsvp.id;    
    
    @Version    
    @Column(name = "version")    
    private Integer Rsvp.version;    
    
    public Long Rsvp.getId() {    
        return this.id;        
    }    
    
    public void Rsvp.setId(Long id) {    
        this.id = id;        
    }    
    
    public Integer Rsvp.getVersion() {    
        return this.version;        
    }    
    
    public void Rsvp.setVersion(Integer version) {    
        this.version = version;        
    }    
    
    @Transactional    
    public void Rsvp.persist() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        this.entityManager.persist(this);        
    }    
    
    @Transactional    
    public void Rsvp.remove() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        if (this.entityManager.contains(this)) {        
            this.entityManager.remove(this);            
        } else {        
            Rsvp attached = this.entityManager.find(Rsvp.class, this.id);            
            this.entityManager.remove(attached);            
        }        
    }    
    
    @Transactional    
    public void Rsvp.flush() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        this.entityManager.flush();        
    }    
    
    @Transactional    
    public void Rsvp.merge() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        Rsvp merged = this.entityManager.merge(this);        
        this.entityManager.flush();        
        this.id = merged.getId();        
    }    
    
    public static final EntityManager Rsvp.entityManager() {    
        EntityManager em = new Rsvp().entityManager;        
        if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");        
        return em;        
    }    
    
    public static long Rsvp.countRsvps() {    
        return (Long) entityManager().createQuery("select count(o) from Rsvp o").getSingleResult();        
    }    
    
    public static List Rsvp.findAllRsvps() {    
        return entityManager().createQuery("select o from Rsvp o").getResultList();        
    }    
    
    public static Rsvp Rsvp.findRsvp(Long id) {    
        if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Rsvp");        
        return entityManager().find(Rsvp.class, id);        
    }    
    
    public static List Rsvp.findRsvpEntries(int firstResult, int maxResults) {    
        return entityManager().createQuery("select o from Rsvp o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();        
    }    
    
}

Imagine that your editor handles the separation seamlessly and merges the two for you to work with the API at compile time.

    @RequestMapping(method = RequestMethod.POST)
    public String post(@ModelAttribute("rsvp") Rsvp rsvp, ModelMap modelMap) {
        rsvp.setConfirmed(new Date());
        if (rsvp.getId() == null) {
            rsvp.persist();
        } else {
            rsvp.merge();
        }
        if (rsvp.getEmail().length() > 0) {
            sendMessage("Ben Alex ", "RSVP to our wedding", rsvp.getEmail(),
                    "Your RSVP has been saved: " + rsvp.toString());
        }
        modelMap.put("rsvp", rsvp);
        return "thanks";
    }

This allows Spring Roo to achieve a true separation of concerns as well a multitude of other compelling benefits.

Now imagine you want to merge such duality into one, project wide, once your initial project harness is ready. You can.

Right click the project » Refactor » Push-In.

Eclipse AJDT Push-In Menu

Eclipse AJDT Push-In Menu

Check pending actions.

Push-In pending actions

Push-In pending actions

Preview the action.

Preview Push-In Refactoring

Preview Push-In Refactoring

Apply and you can get the following outcome.

package name.dhruba.wedding.domain;

import javax.persistence.Entity;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;
import org.springframework.roo.addon.entity.RooEntity;
import org.springframework.transaction.annotation.Transactional;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Version;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.format.annotation.DateTimeFormat;

@Configurable
@Entity
@RooJavaBean
@RooToString
@RooEntity(finders = { "findRsvpsByCodeEquals" })
public class Rsvp {

    @NotNull
    @Size(min = 1, max = 30)
    private String code;

    @Size(max = 30)
    private String email;

    private Integer attending;

    @Size(max = 100)
    private String specialRequests;

    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(style = "S-")
    private Date confirmed;
    
    

	public String toString() {    
        StringBuilder sb = new StringBuilder();        
        sb.append("Id: ").append(getId()).append(", ");        
        sb.append("Version: ").append(getVersion()).append(", ");        
        sb.append("Code: ").append(getCode()).append(", ");        
        sb.append("Email: ").append(getEmail()).append(", ");        
        sb.append("Attending: ").append(getAttending()).append(", ");        
        sb.append("SpecialRequests: ").append(getSpecialRequests()).append(", ");        
        sb.append("Confirmed: ").append(getConfirmed());        
        return sb.toString();        
    }

	@PersistenceContext    
    transient EntityManager entityManager;

	@Id    
    @GeneratedValue(strategy = GenerationType.AUTO)    
    @Column(name = "id")    
    private Long id;

	@Version    
    @Column(name = "version")    
    private Integer version;

	public Long getId() {    
        return this.id;        
    }

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

	public Integer getVersion() {    
        return this.version;        
    }

	public void setVersion(Integer version) {    
        this.version = version;        
    }

	@Transactional    
    public void persist() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        this.entityManager.persist(this);        
    }

	@Transactional    
    public void remove() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        if (this.entityManager.contains(this)) {        
            this.entityManager.remove(this);            
        } else {        
            Rsvp attached = this.entityManager.find(Rsvp.class, this.id);            
            this.entityManager.remove(attached);            
        }        
    }

	@Transactional    
    public void flush() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        this.entityManager.flush();        
    }

	@Transactional    
    public void merge() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        Rsvp merged = this.entityManager.merge(this);        
        this.entityManager.flush();        
        this.id = merged.getId();        
    }

	public static final EntityManager entityManager() {    
        EntityManager em = new Rsvp().entityManager;        
        if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");        
        return em;        
    }

	public static long countRsvps() {    
        return (Long) entityManager().createQuery("select count(o) from Rsvp o").getSingleResult();        
    }

	public static List findAllRsvps() {    
        return entityManager().createQuery("select o from Rsvp o").getResultList();        
    }

	public static Rsvp findRsvp(Long id) {    
        if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Rsvp");        
        return entityManager().find(Rsvp.class, id);        
    }

	public static List findRsvpEntries(int firstResult, int maxResults) {    
        return entityManager().createQuery("select o from Rsvp o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();        
    }

	public String getCode() {    
        return this.code;        
    }

	public void setCode(String code) {    
        this.code = code;        
    }

	public String getEmail() {    
        return this.email;        
    }

	public void setEmail(String email) {    
        this.email = email;        
    }

	public Integer getAttending() {    
        return this.attending;        
    }

	public void setAttending(Integer attending) {    
        this.attending = attending;        
    }

	public String getSpecialRequests() {    
        return this.specialRequests;        
    }

	public void setSpecialRequests(String specialRequests) {    
        this.specialRequests = specialRequests;        
    }

	public Date getConfirmed() {    
        return this.confirmed;        
    }

	public void setConfirmed(Date confirmed) {    
        this.confirmed = confirmed;        
    }

	public static Query findRsvpsByCodeEquals(String code) {    
        if (code == null || code.length() == 0) throw new IllegalArgumentException("The code argument is required");        
        EntityManager em = Rsvp.entityManager();        
        Query q = em.createQuery("SELECT Rsvp FROM Rsvp AS rsvp WHERE rsvp.code = :code");        
        q.setParameter("code", code);        
        return q;        
    }
}

If we look at the difference in the number of files before and after you can clearly see the intertypes have been deleted.

$ find wedding.original/ | wc -l
     211
$ find wedding/ | wc -l
     191

Simply genius.

Support is upcoming for the opposite: Pull-Out.

Note that in order for the above to work you must either have STS which comes with the AJDT plugin or Eclipse with the AJDT plugin installed. Also you must either have the AspectJ nature or AJDT weaving enabled or both.

Spring Roo 1.0.0, EclipseLink 2.0.0 and JPA2 incompatible

Recently Spring Roo 1.0.0 was released. However for those interested in using Roo with EclipseLink (in other words for those with a fervent disdain of Hibernate) please note that this is not yet supported. The related online discussion is on the forum and there is an open JIRA for integrating it which you can vote on and watch. Apparently EclipseLink 2.0.0 has a dependency on JPA2 API which is causing issues. It’s a real shame that EclipseLink isn’t supported yet as it would have been useful on one of our projects going forward but this integration can always be done by hand.

Spring Expression Language (SpEL) Primer

Spring Expression Language, abbreviated SpEL, is a powerful expression language, in the newly released Spring 3, that supports a plethora of ways of interacting with object graphs at runtime. It is intended to be a fully featured expression language for reuse across all products in the Spring Portfolio. This article explores all the various features of SpEL by example.

There will be the smallest possible prerequisite object model to minimise the learning curve prior to getting into the examples. Each example will be fully self contained with the exception of those that make use of the object model defined at the outset. The examples themselves have been constructed as unit tests to be able to easily visualise the outcome of executing the code and also so that they can be taken away and easily run as standalone tests. Finally, as always, as has been proven to be popular, the entire code will be made available for download (as an eclipse maven project).

The article and the examples grew while learning SpEL from the official documentation which is excellent. However it is hoped that this offers some value in terms of complete self contained and varied examples for reference over the official content. It also features as a modest test suite for the API which in itself has highlighted one or two issues relating to one possible bug (collection selection of last entry matching a predicate) and certain API questions all of which have already been raised on the forums and are awaiting answers.

Model

The model simply consists of the following User object.

package spring.examples.spel.model;

public class User {
    private String name;

    public User(String user) {
        this.name = user;
    }

    public String getName() {
        return name;
    }

    public void setName(String user) {
        this.name = user;
    }
}

The User only has one property called name which obeys the javabean naming convention. The examples which don’t use the model use the JDK classes to minimise the learning curve.

Fundamentals

Parser

The spel parser is thread safe and reusable and as such can be created once and cached as follows.

package spring.examples.spel;

import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class TestParser {

    public final static ExpressionParser PARSER = new SpelExpressionParser();

}

The parser can then used to parse any given expression at runtime. An expression can also be accompanied by a ParserContext which determines the prefix and suffix of an expression and an EvaluationContext which can hold state in terms of root objects, variables and functions that are relevant to the expressions to be subsequently parsed. In the following examples the parser instance will be referred as the static variable PARSER.

Strings

    @Test
    public void testStringLiteral() {
        Expression exp = PARSER.parseExpression("'foo'");
        String value = exp.getValue(String.class);
        assertEquals("foo", value);
    }

The above example shows the equivalent of a hello world example. The PARSER instance has been constructed as previously mentioned. The parser then parses an expression and from the expression instance we can extract the end result. Here in the expression is provided a string literal enclosed in single quotes. Note the generic getValue() methods that allow you to retrieve strongly typed objects without the need to cast.

Primitives

Primitive literals are supported as expected. Watch out for primitive literal junit oddities though.

    @Test
    public void testPrimitives() {
        assertTrue(0 == PARSER.parseExpression("0").getValue(byte.class));
        assertTrue(0 == PARSER.parseExpression("0").getValue(short.class));
        assertTrue(0 == PARSER.parseExpression("0").getValue(int.class));
        assertTrue(0L == PARSER.parseExpression("0L").getValue(long.class));
        assertTrue(0.1F == PARSER.parseExpression("0.1F").getValue(float.class));
        assertTrue(0.1D == PARSER.parseExpression("0.1D").getValue(double.class));
        assertTrue(PARSER.parseExpression("true").getValue(boolean.class));
        assertTrue('c' == PARSER.parseExpression("'c'").getValue(char.class));
    }

State and behaviour registration

The evaluation context can be provided with state or behaviour to take into account when the parser parses the expression.

Variable registration

Here a variable is registered with the evaluation context and is referred to in the expression with a hash prefix.

    @Test
    public void testStateRegistration() {
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setVariable("foo", "bar");
        String bar = PARSER.parseExpression("#foo").getValue(context, String.class);
        assertEquals("bar", bar);
    }

Note that this is not the only way to supply state to the context. One can register a root variable either as a constructor argument to the context or by calling the public void setRootObject(Object rootObject) method. It is also possible to refer to intermediate local variables during iteration when performing a ‘Collection selection’ which is illustrated later.

Function registration

Similarly here a function is registered with the context and referred to in the same way.

    @Test
    public void testBehaviourRegistration() throws SecurityException, NoSuchMethodException {
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setVariable("foo", "bar");
        context.registerFunction("quote", StringUtils.class.getDeclaredMethod("quote", String.class));
        String bar = PARSER.parseExpression("#quote(#foo)").getValue(context, String.class);
        assertEquals("'bar'", bar);
    }

Admittedly requiring the use of reflection here as an argument to the public API is less than ideal and questionable. An alternative would be to require the client code to implement an interface (which would of course couple the client code to SpEL). In due time it would be interesting to register closures/lambda expressions in jdk7.

Function registration 2

Here follows a slightly different application of function registration where one of the classes of the JDK is registered with SpEL.

    @Test
    public void testRegisterFunction2() throws SecurityException, NoSuchMethodException {
        List<Integer> list = new ArrayList<Integer>(Arrays.asList(0, 1));
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.registerFunction("max", Collections.class.getDeclaredMethod("max", new Class[] { Collection.class }));
        context.setRootObject(list);
        Integer max = PARSER.parseExpression("#max(#root)").getValue(context, Integer.class);
        assertSame(1, max);
    }

The use of a root object is also demonstrated above and when a root object is used there is no need to pass any variable within the getValue() call although one can do so if the root object is changing over time.

Behaviour invocation

Behaviour invocation allows interaction with an object graph in virtually every way you’d expect from the java language itself. Constructors, instance methods, static methods, javabean properties and nested properties are all supported. Each of the examples below are expected to be self explanatory and are therefore not necessarily elaborated upon.

Constructor invocation

    @Test
    public void testConstructorInvocation() {
        Expression exp = PARSER.parseExpression("new String('foo')");
        String value = exp.getValue(String.class);
        assertEquals("foo", value);
    }

Method invocation

    @Test
    public void testMethodInvocation() {
        Expression exp = PARSER.parseExpression("'foo'.concat('!')");
        String value = exp.getValue(String.class);
        assertEquals("foo!", value);
    }

Static invocation

Static invocations are slightly different. The T qualifier is necessary to tell the parser that a static Class instance is required there. Here T(Math) is resolved to Math.class and the static method is invoked on it.

    @Test
    public void testStaticInvocation() {
        Expression exp = PARSER.parseExpression("T(Math).random() * 100.0");
        double value = exp.getValue(double.class);
        assertNotNull(value);
    }

Note that since the Math class is in the java.lang package there is no need to fully qualify it’s name. SpEL just like Java has an understanding of this default package.

Javabean property

Java bean properties are automatically supported in a scripting like style which is nice.

    @Test
    public void testJavaBeanProperty() {
        Expression exp = PARSER.parseExpression("'foo'.bytes");
        byte[] bytes = exp.getValue(byte[].class);
        assertTrue(Arrays.equals("foo".getBytes(), bytes));
    }

Nested property

Nested property support is analogous to method changing in Java and works as you’d expected. The example below accesses initially one java bean property but then chains to a public variable.

    @Test
    public void testNestedProperties() {
        Expression exp = PARSER.parseExpression("'foo'.bytes.length");
        int length = exp.getValue(int.class);
        assertSame("foo".getBytes().length, length);
    }

Unchanging root object

When using the parser with an object one has the option of either supplying that object as the root object to the context or to register it as variable or to supply it on every invocation of the parseExpression method. Here the first of those is demonstrated.

    @Test
    public void testQueryUnchangingRootObjectProperty() {
        Expression exp = PARSER.parseExpression("name");
        EvaluationContext context = new StandardEvaluationContext(new User("foo"));
        String name = exp.getValue(context, String.class);
        assertEquals("foo", name);
    }

In the above usage the root object is not changing with every invocation of the parser so it can be supplied once and parsing of expressions can be performed multiple times.

Changing root object

In the opposite scenario if the root object is expected to be changing between expression parse invocations then it can be supplied to the parser when parsing the expression itself. This is the concurrent option.

    @Test
    public void testQueryChangingRootObjectProperty() {
        Expression exp = PARSER.parseExpression("name");
        String name = exp.getValue(new User("foo"), String.class);
        assertEquals("foo", name);
    }

Changing root object with cached context

The need for caching the evaluation context arises from the fact that the construction of the context is actually quite expensive. As a result here the context is created only once with a root object and is reused for parsing various expressions.

    @Test
    public void testQueryChangingRootObjectPropertyWithCachedContext() {
        Expression exp = PARSER.parseExpression("name");
        EvaluationContext context = new StandardEvaluationContext(new User("foo"));
        assertEquals("foo", exp.getValue(context, String.class));
        String bar = exp.getValue(context, new User("bar"), String.class);
        String baz = exp.getValue(context, new User("baz"), String.class);
        assertEquals("bar", bar);
        assertEquals("baz", baz);
    }

Note however that although in the first value extraction we make use of the root object in the context with name ‘foo’ – in the latter two value extractions we override the root object with new ones named ‘bar’ and ‘baz’ respectively. Note also that when we override the root objects we still reuse the evaluation context since it is already constructed negating the need for SpEL to create one itself.

Mutations

There are a number of ways of mutating properties illustrated below.

Mutate typed property

Here a list element is flipped from true to false.

    @Test
    public void mutateTypedProperty() {
        List<Boolean> list = new ArrayList<Boolean>(Arrays.asList(true));
        EvaluationContext context = new StandardEvaluationContext(list);
        PARSER.parseExpression("#root[0]").setValue(context, "false");
        assertFalse(list.iterator().next());
    }

Note that false is recognised as a boolean and converted as such by SpEL and also that array/list elements can be accessed using indices just like in the language itself.

Assignment on root object

The parser provides mutative methods that can be used to set specific properties of a root object to designated values.

    @Test
    public void testAssignmentOnRootObjectDirectly() {
        Calendar calendar = Calendar.getInstance();
        PARSER.parseExpression("timeInMillis").setValue(calendar, 0);
        assertTrue(0 == calendar.getTimeInMillis());
    }

Above a calendar property is set directly without using an evaluation context.

Assignment on evaluation context

Alternatively an evaluation context can be constructed with the calendar as the root object and then the property mutated.

    @Test
    public void testAssignmentOnContext() {
        Calendar calendar = Calendar.getInstance();
        EvaluationContext context = new StandardEvaluationContext(calendar);
        PARSER.parseExpression("timeInMillis").setValue(context, 0);
        assertTrue(0 == calendar.getTimeInMillis());
    }

Assignment within expression

Mutations can also be done via accessor methods within the expression itself.

    @Test
    public void testAssignmentInExpression() {
        Calendar calendar = Calendar.getInstance();
        long value = PARSER.parseExpression("timeInMillis = 0").getValue(calendar, long.class);
        assertTrue(0 == value);
    }

The assignment operator above works exactly as in the language itself.

Operators

SpEL supports the basic relational, logical and mathematical operators that one would expect. However in addition it also supports conditional operators in the form of ternary, elvis and safe navigation operators discussed below.

Relational operators

    @Test
    public void testRelationalOperators() {
        assertTrue(PARSER.parseExpression("2==2").getValue(boolean.class));
        assertTrue(PARSER.parseExpression("2<3").getValue(boolean.class));
        assertTrue(PARSER.parseExpression("3>2").getValue(boolean.class));
        assertTrue(PARSER.parseExpression("0!=1").getValue(boolean.class));
    }

Logical operators

    @Test
    public void testLogicalOperators() {
        assertTrue(PARSER.parseExpression("true and true").getValue(boolean.class));
        assertTrue(PARSER.parseExpression("true or true").getValue(boolean.class));
        assertTrue(PARSER.parseExpression("!false").getValue(boolean.class));
        assertTrue(PARSER.parseExpression("not false").getValue(boolean.class));
        assertTrue(PARSER.parseExpression("true and not false").getValue(boolean.class));
    }

Mathematical operators

    @Test
    public void testMathematicalOperators() {
        assertSame(2, PARSER.parseExpression("1+1").getValue(int.class));
        assertSame(0, PARSER.parseExpression("1-1").getValue(int.class));
        assertSame(1, PARSER.parseExpression("1/1").getValue(int.class));
        assertSame(1, PARSER.parseExpression("1*1").getValue(int.class));
        assertSame(1, PARSER.parseExpression("1^1").getValue(int.class));
        assertTrue(1D == PARSER.parseExpression("1e0").getValue(double.class));
        assertEquals("foobar", PARSER.parseExpression("'foo'+'bar'").getValue(String.class));
    }

Ternary, Elvis and Safe Navigation operators

The ternary operator will be familiar to all from Java. However the elvis and safe navigation operator are powerful yet succinct additions to the SpEL language as demonstrated below.

    @Test
    public void testTernaryElvisAndSafeNavigationOperators() {
        assertEquals("foo", PARSER.parseExpression("true ? 'foo' : 'bar'").getValue(String.class));
        assertEquals("null", PARSER.parseExpression("null?:'null'").getValue(String.class));
        assertEquals(null, PARSER.parseExpression("null?.foo").getValue(String.class));
    }

The Elvis operator is a more succinct form of the ternary operator requiring only one half of the statement to be specified. The safe navigation operator performs a safe null dereference by returning null rather than throwing a NullPointerException.

Utilities

A few utility applications of SpEL lie below.

System properties

System property access is reported to be supported in SpEL. In the tests written it was noted that it’s not supported in programmatic usage of SpEL. One can only assume that it is only supported when using SpEL through the application context. Below is a weak emulation of using system properties in conjunction with SpEL although the author accedes this would be of no practical use whatsoever.

    @Test
    public void testGetSystemProperty() {
        System.setProperty("foo", "bar");
        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("systemProperties", System.getProperties());
        Expression exp = PARSER.parseExpression("#systemProperties['foo']");
        String value = exp.getValue(context, String.class);
        assertEquals("bar", value);
    }

Date parsing

SpEL has an understanding of dates and is able to add dates together as well using the ‘+’ operator.

    @Test
    public void testDateParsing() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(2010, 11, 25, 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        assertEquals(calendar.getTime(), PARSER.parseExpression("'2010/12/25'").getValue(Date.class));
    }

Instanceof

The instanceof ‘keyword’ is supported exactly as in Java but the right hand side argument must be provided as an instance of Class by using the T() qualification.

    @Test
    public void testInstanceOfCheck() {
        assertTrue(PARSER.parseExpression("0 instanceof T(Integer)").getValue(boolean.class));
    }

Matches

The ‘matches’ keyword supports regular expression matching but in a far more terse way than Java itself which is nice.

    @Test
    public void testRegularExpressionMatch() {
        assertTrue(PARSER.parseExpression("-0.1e-4 matches '^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$'").getValue(
                boolean.class));
    }

Expression templating

SpEL supports String templating. However to do this, rather oddly in the author’s opinion, the client code must supply a ParserContext implementation which contains the expression prefix and suffix. It’s odd because there isn’t such an implementation provided by SpEL already and also because a more succinct way of specifying prefix and suffix isn’t available.

    @Test
    public void testExpressionTemplating() {
        String fooBarBaz = PARSER.parseExpression("foo ${'foobar'.substring(3)} ${'barbaz'.substring(3)}",
                new ParserContext() {
                    public String getExpressionPrefix() {
                        return "${";
                    }

                    public String getExpressionSuffix() {
                        return "}";
                    }

                    public boolean isTemplate() {
                        return true;
                    }
                }).getValue(String.class);
        System.out.println(fooBarBaz);
        assertEquals("foo bar baz", fooBarBaz);
    }

Predicate based extractions

Predicate based extractions are by far the most interesting feature area in SpEL. With merely a few characters one is able to do predicate based selection and projection similar to that in functional programming languages. Magic variables exist that allow the expression access to intermediate stack variables just as you would have in a for loop.

Collection selection

List selection

The example below selects all integer elements in the given list that are even.

    @Test
    public void testListSelection() {
        List<Integer> list = new ArrayList<Integer>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("list", list);
        List<?> evenNumberList = PARSER.parseExpression("#list.?[#this%2==0]").getValue(context, List.class);
        assertEquals(Arrays.asList(0, 2, 4, 6, 8), evenNumberList);
    }

Note that the variable named #this refers to the current list element accessible within that particular iteration over the list.

Simple map selection

Similarly map values can be accessed in the same way that you would access an array or list element in SpEL – that is by providing a key within square brackets.

    @Test
    public void testMapSelectionSimple() {
        Map<String, String> map = new HashMap<String, String>();
        map.put("foo", "bar");
        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("map", map);
        Expression exp = PARSER.parseExpression("#map['foo']");
        String value = exp.getValue(context, String.class);
        assertEquals("bar", value);
    }

Advanced predicate based map selection

In the slightly more involved three step example of map selection the first expression selects all map entries with value less than three. The second and third expressions select the first and last map entry with value less than three respectively.

    @Test
    @SuppressWarnings("unchecked")
    public void testSelectionFromMapAdvanced() {
        Map<Integer, Integer> map = new TreeMap<Integer, Integer>();
        map.put(1, 1);
        map.put(2, 2);
        map.put(3, 3);
        /*
         * NOTE: select all map entries with value less than 3
         */
        Map<Integer, Integer> all = (Map<Integer, Integer>) PARSER.parseExpression("#root.?[value<3]").getValue(map);
        assertTrue(all.size() == 2);
        Iterator<Integer> iterator = all.keySet().iterator();
        assertTrue(iterator.next() == 1);
        assertTrue(iterator.next() == 2);
        /*
         * NOTE: select first entry with value less than 3
         */
        Map<Integer, Integer> first = (Map<Integer, Integer>) PARSER.parseExpression("#root.^[value<3]").getValue(map);
        assertTrue(first.keySet().iterator().next() == 1);
        /*
         * NOTE: select last entry with value less than 3
         */
        Map<Integer, Integer> last = (Map<Integer, Integer>) PARSER.parseExpression("#root.$[value<3]").getValue(map);
        // assertTrue(last.keySet().iterator().next() == 2);
        assertTrue(last.size() == 1);
    }

Note that the final assertion isn’t like those that precede it. It has been simplified considerably. This is because the commented out assertion above it actually fails. It isn’t clear why this fails to work as the others do and this issue has been raised by the author on the forums. Update: It seems there is a bug open on this issue already.

Collection projection

Collection projection is a fascinating feature of SpEL. It essentially takes as input objects and returns a cross section of those objects in the form of their properties after having operated on their properties.

    @Test
    @SuppressWarnings("unchecked")
    public void testCollectionProjection() {
        List<User> list = new ArrayList<User>(Arrays.asList(new User("foo"), new User("bar"), new User("baz")));
        List<String> names = (List<String>) PARSER.parseExpression("#root.![name]").getValue(list);
        assertEquals(Arrays.asList("foo", "bar", "baz"), names);
    }

Above the parser is provided three User objects and is instructed to extract the name property from all those objects. Admittedly this is a very simple case but it illustrates the use of projection.

Application context

The vast majority of the use of SpEL is likely to be as part of the Spring application context either through its use in xml or within annotations.

XML based configuration

Here are examples of how SpEL may be used in XML.

<property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/<
<property name="defaultLocale" value="#{ systemProperties['user.region'] }"/<
<property name="myOtherBeanProperty" value="#{ myOtherBean.property }"/>

Annotation based configuration

Alternatively expressions can be used within the @Value annotation.

@Value("#{ systemProperties['userName'] }")

Conclusion

For the author the Spring Expression Language has proved to be by far the most interesting feature addition to Spring 3. The expression language is incredibly terse and incredibly powerful inspired often by the Groovy scripting grammar. What’s also incredibly gratifying is that it incorporates certain syntax that was proposed for Java but failed to be incorporated. Overall it is an excellent feature addition and it will be interesting to see how SpEL is used over time within Spring and in other Spring portfolio projects for which it was intended.

There are already reports of Spring Integration being enhanced greatly with the addition of SpEL which will manifest in version 2. It would be nice to see SpEL becoming more pervasive in Spring and associated portfolio projects than simply being used to look up configuration within the application context. Naturally there will be the consideration of the expressions becoming unwieldy and perhaps unmaintainable over time in any given code base but the considerations of misuse and complexity apply to any language.

SpringSource Hyperic HQ slides available

A month back I attended a presentation on SpringSource Hyperic HQ. They’ve finally made the slides available which are obviously missing the demonstrations that took place during the presentation. All in all my verdict at the time was that SpringSource Hyperic HQ was very good at what it was intended to do originally which was to generically monitor and manage processes and applications. However what I was looking for when I went to this presentation was a much more specialised developer level introspection into Spring based applications and that it currently doesn’t offer. There are rumours however that there exists a plugin for Spring TC server that currently offers such introspection and that this plugin will also be made available in the community edition of Hyperic HQ by the end of the year. I’ll be curious to see what metrics that offers in due time.

VMWare acquires SpringSource

After the recent purchase of Sun by Oracle the company behind the most prevalent IoC container and component model in Java has now also been acquired. VMWare and SpringSource have signed an agreement for SpringSource to be taken over by VMWare in Q3 this year. Over the years the community has witnessed a progression in SpringSource from catering for building applications using the Spring Framework and associated projects and tooling to deploying applications using dmServer and tcServer to finally monitoring and managing applications using SpringSource Hyperic in the current day. With this latest move SpringSource are putting forward the idea of the platform as a service (PAAS) by investing their worth in virtualisation and elastic computing.

The purported justifications are theoretically compelling. The operating system layer is now a secondary concern with several layers of mature abstraction over it and deploying to and managing an elastic medium allows rapid startup and relatively easy scaling of resources. Going forward the full stack package of development frameworks, virtualisation and elastic computing along with associated tooling and introspection appears, on the face of it, to offer everything that one could possibly need. So what’s the catch? I’d like to ask the following fleeting questions.

Is the common consumer ready for this? And is this a completely different architectural paradigm to how we currently develop? How will external heterogenous points of contention such as databases, data warehouses and event driven systems respond to being scaled on an elastic medium along with homogenous request-reply systems? Will we see EAI, EIP, CEP and ESB systems playing a much more prominent role in platform architecture for mediation of events across the cloud? Will data fabrics, data protocols and canonical data model design evolve for effective and low latency communication within cloud architectures? Going forward will we design to be cloud ready the first time around for an added dimension to portability? And finally will all this be brought to us in a single cohesive and coherent development model?

Along with the consideration of fine grained parallelism on one hand, that being the multi-core problem, this will be the much broader consideration of how we can design at the platform level to leverage such concepts and scale uniformly. Needless to say this will be an exciting evolution to watch over time and I welcome any movement that accelerates its delivery to the mainstream masses.

Upcoming SpringSource London events

There are a couple of SpringSource events coming up in London on Wednesday July 29 2009.

Both sound very interesting but unfortunately they are both on a weekday in the daytime.

Update: On a tangent there is also an OSGi event on July 15th – OSGi(TM) Users’ Forum UK: Peter Kriens presents OSGi, The Next Enterprise Release.

Spring Integration Series – Getting started

In the past few months I’ve had the good fortune of getting familiar in depth with Spring Integration and being responsible for adopting it for use within a major investment bank. I’ve learnt a lot through many different channels, met in person with people from SpringSource and those directly contributing to Spring Integration and provided my own feedback through all these channels derived from my experiences in using it to fulfil my commercial use-cases.

During all this time I’ve been dying to blog about Spring Integration and particularly my use of it but haven’t been able to due to lack of time and energy outside of work. Going forward, however, my hope is that I’ll write a series of articles, one at a time, each exploring a different perspective on Spring Integration.

Here we begin by looking at how to get started with Spring Integration and how to get close to the source of the project using Eclipse IDE. The value of this will be felt most when browsing the org.springframework.integration.samples project which contains numerous fully working examples of how to use Spring Integration in different ways.

Getting started

My approach to learning any new subject is to put theory first. Here’s what I did to get started.

  1. Read the manual (yes the entire ~100 pages).
  2. Set up the source (as in the next section of this article).
  3. Review the sample applications (once you’ve set up the source).

If you prefer a more pragmatic approach from the start you can dive straight into the sample applications and start to write your own by referring to the manual as and when needed but this approach has the danger of leaving gaps in your knowledge as you start to write code.

Getting close to the source

The tools that you’ll need to work with the source are as follows.

Here’s how to set up the Spring Integration source in Eclipse.

  1. Check out the source.
    svn co https://src.springframework.org/svn/spring-integration/trunk/ si
  2. Increase max perm size available to Ant.
    export ANT_OPTS="-XX:MaxPermSize=512m"
  3. Build the project. This will take approximately ten minutes while it downloads all dependencies using Ivy.

    cd si/build-spring-integration/

    ant

    If you are running on Ubuntu and at this point you get UnknownHostException error messages then see recommended fix.

  4. Import the project into eclipse.

    • File > Import > Existing projects into workspace
    • Select root directory > Browse > Select the si/ folder
    • Deselect the project with no name and click Finish
  5. Create an ivy cache variable as follows.

    • Right click on any of the projects you imported above.
    • Properties > Java Build Path > Libraries
    • Add Variable > Configure Variables > New
    • Enter variable name as ‘IVY_CACHE’ and value as something similar to /home/dhruba/sources/si/ivy-cache/repository
    • Confirm all the dialogue boxes. The projects should automatically rebuild.

At this point you should have all the Spring Integration projects imported into Eclipse with no fatal errors and at the time of writing 94 warnings. Common guys we can reduce that to zero 😉 Now you should be able to open up the org.springframework.integration.samples project and browse through and run the sample applications provided for you.

With any luck a number of further articles on Spring Integration should follow. I have a lot that I want to convey but it is, as always, finding the time and the energy to write not only the articles but fully working illustrative showcase applications.

Thanks to Jonas Partner, Spring Integration committer, for providing the instructions.

Jonas Partner’s Spring Integration video available

The video of Jonas Partner’s talk on Spring Integration (one of my favourite software products) at the last Spring User Group is now available. It was very interesting indeed as was the informal Q&A afterwards. I very much like the fact that you can meet such key people in person and that they have time for your questions. On a related note the next Spring User Group meeting called ‘Spring Along‘ is on 12 March at 7pm in The Old Star. Interestingly, not only are Rod Johnson and Graeme Rocher going to be there but this venue is literally two steps away from my flat! See you there.

Upcoming London Spring related events

The previous Spring user group meeting featured Rick Evans (ex-SpringSource) providing a sneak preview of Spring 3.0 M1 and it was an excellent talk. The next meeting has the following agenda and all talks look also to be very interesting indeed.

The next and very impressive Spring User Group event for 2009 is on Wednesday 11 February at the offices of Skills Matter in Farringdon. This is a packed out agenda with two important speakers and the regular update on activities at SpringSource. This will be a very exciting evening event.

18:00 Registration
18:20 Introduction and SpringSource update
18:25 Darren Davison of UPCO – A real world experience
19:15 Jonas Partner of SpringSource – The power of Spring Integration

After the previous Spring user group meeting when we were all having an informal chat we were asked what more could be done to make the user group more appealing so that it would attract larger numbers. The answer to me was obvious which I clearly stated at the time – accounts of real world commercial use-cases and their solutions. It’s great to see that this feedback from more than one of us was taken onboard.

At December’s meeting there was a strong demand for more real-life experience, so you have it with Darren Davison relating the good, bad and ugly of a major financial services project.

The talk I’m looking forward to the most is the one by Jonas Partner on Spring Integration. Recently I started looking into Spring Integration as an EAI+EIP implementation for one of our major projects at work and I was just blown away by the quality of the product and how powerful and easy to use it was. No doubt by the time I attend this talk I’ll have plenty of questions.

Spring Integration provides an extension of the Spring programming model to support the well-known Enterprise Integration Patterns while building on the Spring Framework’s existing support for enterprise integration. It enables simple messaging within Spring-based applications and integrates with external systems via simple adaptors The project committer in the UK is Jonas Partner who has massive experience in this field.

Here are links to the next few talks.

I’ll be going to the first and third of the above however not to Spring Exchange as it is on a weekday full day. It’s a shame really – it was a really great event last year but then it was on a Saturday. It’s just not possible for me to attend on a weekday. I look forward to the rest.

Implementing single and multiple file multipart uploads using Spring 2.5

Overview

This article has two objectives. Firstly it aims to compare and contrast the means necessary to enable single file uploads as opposed to multiple file multipart uploads. And, secondly, it shows that multiple file uploads cannot be implemented in exactly the same way as single file uploads (when using Spring 2.5) and then proceeds to outline a number of alternative solutions. The article covers only Commons Fileupload support as that is not only the only library now supported in Spring 2.5 but also it is a very good api.

Example code from a complete example project will be used in the article and the example project is made available as a compressed file at the end. It can be used as a skeletal implementation and as a test harness. There’s nothing revolutionary or difficult here but hopefully this will serve as an informative and more complete resource that I wish I had when I was trying to implement multiple file uploads using Spring.

Table of contents

  • Introduction
  • Single file upload
    • Create an html form to test uploads
    • Create a form backing object bean
    • Create a file upload controller
    • Define Spring configuration
  • Multiple file upload
    • Solution 1 – Modify form backing object to accept multiple files
    • Solution 2 – Use the raw http servlet request
    • Solution 3 – Disable Spring support and use commons fileupload directly
    • Solution 4 – Using a cross cut to disable spring support conditionally
  • Conclusion
  • Example project
  • Related Spring Jira Issues

The reader is encouraged to have a look at the open Spring jira issues related to this article and add his/her vote to those issues.

Continue reading