Skip to main content

Adding EL support on your projects

Posted by felipeal on October 26, 2008 at 11:07 PM PDT

A few years ago, JSTL introduced the concept of EL (Expression Language) to the Java standards. Since then, the technology have been slowing climbing the JCP ladder, first becoming part of JSP 2.0, then having its own API (javax.el).



Although there is a lot of documentation out there on how to use EL in places that support it (like the aforementioned JSTL and JSP technologies), there is a lack of resources on how to support EL on *your* application.



First of all, why would you want to use EL on your application? Well, there is a couple of use cases. Basically, if you need some templating in your application, you could use EL (sure, you could use other projects like Velocity or even OGNL, but that's not the point). I used it myself in 4 opportunities: in a mailing application I worked on a few years ago, in the test cases of a project, in a project that generate alerts from templates, and in the upcoming JUnit in Action 2nd edition. As the first three cases are kind of private, let's use the book example as our use case scenario.



Chapter 17 of the book is about DbUnit, and one of the topics uses EL on DbUnit datasets. Roughly speaking, you could have an XML file like:




<?xml version="1.0"?>
<dataset>
  <users id="${id}" username="ElDuderino" first_name="Jeffrey" last_name="Lebowsky" />
</dataset>



And then the EL engine would replace ${id} by the proper value.



Even though I like this trick (and I think it should be adopted by other prjects, like Unitils) and explained its benefits in that chapter, it was out of the scope of book to detail how it was implemented. And to my surprise, nothing in this area seems to be available elsewhere (it took me a lot of hacking back in 2006 to implement it for the first time, but I thought that by now there would be more tutorials on the subject).



Programatically speaking, you would like something like this:



String elText = "Dude, where is my ${car}?";
SomeSortOfContext context = new SomeSortOfContext();
context.bind( "car", "EL tutorial" );
String convertedText = doSomeMagic( context, elText );
// convertedText is "Dude, where is my EL tutorial?"



Anyway, without further ado, here is my quick howto (which is not necessarily the right approach, but it's better than nothing :-):

  1. First, get the el-api.jar. Where? Another of life's obscure mysteries, but long story short, try https://maven-repository.dev.java.net/repository/javax.el/jars
  2. Then you need to define SomeContext. The EL API defines an ELContext (javax.el.ELContext), but that is an abstract class - you need to extend it and implement the getELResolver(), getFunctionMapper(), and getVariableMapper() methods.
  3. For getELResolver(), you can just return a new BeanELResolver() (that class is part of the EL api). Similarly, you are not interested on getFunctionMapper() (unless you need to support EL functions), so you can create an inner class implementation that does nothing (don't panic, I will show the whole code below).
  4. Now comes the first real trick, implementing getVariableMapper(). For this dude, you also create your own implementation, which simply uses a Map to store the variables you want to bind. And as a courtesy to your fellow programmers, you add the bind() method shown in the above example.
  5. Next step is to get a javax.el.ExpressionFactory implementation. If you guessed that el-api.jar does not provide any implementation, congratulations, you read my mind! But in this case you don't need to create your own, you can get an existing implementation, such as Tomcat's (again, the shorcut is to download jasper-el.jar from http://mirrors.ibiblio.org/pub/mirrors/maven2/org/apache/tomcat/jasper-e...)
  6. That leave us with the final step, the doSomeMagic() method, which is simply return factory.createValueExpression(context, elText, Object.class ).getValue(context);!



Confused? Welcome to the club :-).



Jokes aside, the test case below contains the whole code:

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.el.BeanELResolver;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.el.FunctionMapper;
import javax.el.ValueExpression;
import javax.el.VariableMapper;

import org.apache.el.ValueExpressionLiteral;
import static org.junit.Assert;
import org.junit.Test;

public class BlogTest {
 
  @Test
  public void doIt() {
    String elText = "Dude, where is my ${car}?";
    SomeContext context = new SomeContext();
    context.bind( "car", "EL tutorial" );
    Object convertedText = doSomeMagic( context, elText );
    assertEquals( "Dude, where is my EL tutorial?", convertedText );
  }

  private Object doSomeMagic(SomeContext context, String elText) {
    if ( factory == null ) {
      throw new RuntimeException( "could not get instance of factory class " + factoryClass );
    }
    ValueExpression converted = factory.createValueExpression(context, elText, Object.class );
    return converted.getValue(context);
  }
 
  private static final String factoryClass = "org.apache.el.ExpressionFactoryImpl";
  private static final ExpressionFactory factory;
 
  static {
    System.setProperty("javax.el.ExpressionFactory", factoryClass);
    ExpressionFactory tmpFactory = null;
    try {
      tmpFactory = ExpressionFactory.newInstance();   
    } catch ( RuntimeException e ) {
      System.err.println("D'OH!");
    }
    factory = tmpFactory;
  }
 
  public class SomeContext extends ELContext {

    private final BeanELResolver resolver = new BeanELResolver();
    private final FunctionMapper functionMapper = new NoopFunctionMapper();
    private final VariableMapper variableMapper = new VariableMapperImpl();
    private final Map variables =  new HashMap();

    @Override
    public ELResolver getELResolver() {
      return resolver;
    }

    @Override
    public FunctionMapper getFunctionMapper() {
      return functionMapper;
    }

    @Override
    public VariableMapper getVariableMapper() {
      return variableMapper;
    }
   
    public void bind( String variable, Object obj ) {
      variables.put( variable, new ValueExpressionLiteral(obj,Object.class) );
    }
   
    private class VariableMapperImpl extends VariableMapper {
      public ValueExpression resolveVariable(String s) {
        return variables.get(s);
      }
      public ValueExpression setVariable(String s, ValueExpression valueExpression) {
        return (variables.put(s, valueExpression));
      }
    }

    private class NoopFunctionMapper extends FunctionMapper {
      public Method resolveFunction(String s, String s1) {
        return null;
      }
    }

  }
 
}

Have ${fun}!.

Related Topics >>

Comments

Nice, but, still a bit complicated, and as ljnelson mentioned the BeansBinding ELProperty class, I just tried it. Here is the sample code: Person mom = new Person("Ann", null); Person son = new Person("Dave", mom); Dog dog = new Dog("Foxy"); ELProperty el = ELProperty .create("${name}'s mom is ${mother.name}"); System.out.println(el.getValue(son)); ELProperty mapEL = ELProperty .create("${mother.name}'s dog is ${dog.name}"); Map map = new HashMap(); map.put("mother", mom); map.put("dog", dog); System.out.println(mapEL.getValue(map));

> All this code for a little bit of find and replace magic on strings?

In the exact example show, it's just find and replace. But using EL in this case is more powerful than that - for instance, you could use ${id+1}, ${user.name}, etc.

>took an EL guru to point out the flaws in this 'toy' example that the OP still doesn't fully understand?

Did *you* understand the flaw? Maybe the "OP" is getting old and dumb, because I didn't even understand what "OP" means...

>It just doesn't seem worth it. This seems like a case of overengineering that Java is so often criticized for.

The motivation for this blog was to try to explain how to use the javax.el on your code, because it seems to be lacking documentation on how to do so. Maybe I wasn't clear (or was too ironic) that you missed the point, but I see a lot of 'flaws' in your comments:

1.The technology (or something similar) is useful in that context (no pun intended), it's not just a search-and-replace.
2.The 'toy' example was one of the simplest possible (everything in just one class), although still functional and showing the point.
3.In the past, I used OGNL for the same purpose, and it was much clear how to use this technology (I didn't need any guru to point my flaws; hopefully I didn't make any). But since EL is now part of the standards, I decided to use it.
4.I still don't think this code is flawed on the context it is used (but let's wait Jacob's opinion on this matter). I've been using it for months and everything worked fine.
5.Finally, regarding the 'overengineering', if you think using a expression language for a simple 'search and replace' is an overkill, you're wrong (because as I explained, it's not just that). Now, if you think the javax.el is an overkill on this case, maybe you're right. I used to think - or to naively believe - that the javax.el could be used by anyone, not only by web framework providers. If that was the case, it should be better documented (and probably simpler to use). But if the technology was not intended for that general-use purpose, it should be explicitly said so (maybe the lack of documentation is an implicit way of telling us to not use the way I did :-).

-- Felipe

I think you need to show another example. Something that shows off more then string replacement. For this use case StringTemplate [http://www.stringtemplate.org/] really shines. Exmaple: StringTemplate hello = new StringTemplate("Dude, where is my, $car$"); hello.setAttribute("car", "StringTemplate Tutorial"); System.out.println(hello.toString()); That said, what can EL do? Is EL a jsr 223 compatible scripting language? Is there an EL interpreter? Can you call methods on a java Object? Is it OO, procedural, functional? It's used in beansbindings right?

Very cool! Had I known it was so easy...

BTW, let me clarify some things about my reply to Jacob, as I my brain was very tired yesterday night (after a long working day and a sucky Heroes episode :-(. Before the 'unified' javax.el was created, JSP 2.0 and JSF 1.1 had their own EL implementations, and they were not compatible. That was blatant in some cases like mixing JSTL's with JSF tags, as pointed on Jacob's blog and on that famous article that stress the JSF/JSP incompatibilities (http://www.onjava.com/pub/a/onjava/2004/06/09/jsf.html). So, when Jacob points the flaw in the example, I believe he means that code would not handle this kind of dynamic binding, which is fine, as I don't need to support something as complex as loop statements. In fact, if I did, I would need to support tags as well, so it would be simpler to use Velocity in this case. So, that's what I meant by ", I guess I don't need that sort of late resolution capabilities". Second, let's say I needed that or I wanted to have a 'correct' example. I didn't understand what I should do, i.e., how would I replace the BealELResolver (which I think is what Jacob referred as VariableResolver). To use a CompositeELResolver, I would still need to add some ELResolvers to it, which I guess I would have to implement myself. The question then is, how would I implemented them? Anyway, I still thing that would be an ever bigger overkill in my use case scenario...

All this code for a little bit of find and replace magic on strings? And it took an EL guru to point out the flaws in this 'toy' example that the OP still doesn't fully understand? It just doesn't seem worth it. This seems like a case of overengineering that Java is so often criticized for.

Hi Jacob,

First of all, thanks for stopping by and give your 2 cents - it's nice to hear a "second opinion" from someone that really understand this stuff :-).

Anyways, I read your comment, your original blog, and even some Javadocs, and I still don't understand what's wrong with this example :-(. If I implement my own ELResolver, how would I bind my variables to it? Should I use a MapELResolver? I still think this example is fine, I guess I don't need that sort of late resolution capabilities...

[]s,

-- Felipe

Using the VariableResolver in this case is incorrect. You'd want to implement ELResolver as part of your CompositeELResolver which does a transient binding. Using the VariableResolver persists the binding with the expression which removes anything dynamic from the execution. For applications, you'd want to just no-op the VariableMapper like you did for FunctionMapper. see http://weblogs.java.net/blog/jhook/archive/2006/03/the_unified_el.html

Cool, I was not aware of that project. What I used in the first project was OGNL (which is very powerful, BTW).

But regardless of these side-projects, I still think there should be more 'official' documentation on how to use EL in your programs...

Another really easy way to do this is to use the (dormant, rotting, but nicely functional) BeansBinding project. You can use their ELProperty class to give you bean- and map-based EL resolution for free.