The Hidden JavaEE 7 Gem - Lambdas With JDK 1.7
EL 3.0 (Expression Language 3.0) JSR-341 is part of JSF, JSP and so a JavaEE 7 and comes with amazing capabilities. You can pass objects to the ELProcessor to access the properties, define collection literals or perform computations:
import java.util.Map;
import java.util.Set;
import javax.el.ELProcessor;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import org.junit.Before;
import org.junit.Test;
public class ELTest {
private ELProcessor cut;
@Before
public void init() {
this.cut = new ELProcessor();
}
@Test
public void formula() {
Long result = (Long) this.cut.eval("2*2");
assertThat(result, is(4l));
}
@Test
public void bean() {
Workshop workshop = new Workshop("javaee airhacks");
this.cut.defineBean("workshop", workshop);
String title = (String) this.cut.eval("workshop.title");
assertThat(title, is(workshop.getTitle()));
}
@Test
public void listLiteral() {
String listLiteral = "{1,2,3}";
Set list = (Set) this.cut.eval(listLiteral);
assertFalse(list.isEmpty());
System.out.println("List: " + list);
}
@Test
public void mapLiteral() {
String listLiteral = "{\"one\":1,\"two\":2,\"three\":3}";
Map map = (Map) this.cut.eval(listLiteral);
assertFalse(map.isEmpty());
System.out.println("Map: " + map);
}
}
Also EL 3.0 allows you to declare and execute lambdas …on Java 7:
@Test
public void lambda(){
Object result = this.cut.eval("[1,2,3,4,5,6,7,8].stream().
filter(i->i%2 == 0).map(i->i*10).toList()");
assertNotNull(result);
System.out.println("Result: " + result);
result = this.cut.eval("[1,5,3,7,4,2,8].stream().sorted((i,j)->j-i).toList()");
System.out.println("Result: " + result);
}
ELProcessor can be started outside the application server within JavaSE environment. You only need a single maven dependency:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.0</version>
</dependency>
The code above is an example used during the airhacks.com.
See you at Java EE Workshops at MUC Airport!
In formula(), you're asserting that 2*2 = 41
Posted by Robert J Saulnier on September 13, 2013 at 05:32 PM CEST #
Yes, this is indeed a gem. I'd say an undocumented gem.
In JSF, you can do some crazy stuff with this. Expanding on your example, look at this:
<h:form prependId="false">
<p><h:inputText id="index" value="#{requestScope.i}" /></p>
<!--
#{xx = (null != requestScope.i) ? requestScope.i : 0}
-->
<p id="output"><h:outputText value="#{[1,2,3,4,5,6,7,8].stream().
filter(i->i%2 == 0).map(i->i*10).toArray()[xx]}" /></p>
<h:commandButton value="submit" />
</h:form>
Now, it would be better to put that "xx" assignment in an <h:outputText rendered="false"> so it doesn't show up in the page, but, hey, putting it in a comment reminds us of the bad old days of scriptlets.
Posted by Ed Burns on September 14, 2013 at 03:47 PM CEST #
The only Problem i got is:
Strings, Strings, Strings
That's why i'm not the biggest Fan of ExpressionLanguage - It's all just a String, no Type-Safety at Compile-Time, poor Refactoring-Support etc.
Posted by Gustav on September 16, 2013 at 11:38 AM CEST #
@Robert,
"In formula(), you're asserting that 2*2 = 41"
This would be a hidden miracle, not a gem :-)
I'm asserting a long. So it is 4 + the l character and not the one number.
Thanks for scanning the code!,
adam
Posted by Adam Bien on September 16, 2013 at 03:31 PM CEST #
@Gustav,
it is not type safe, what makes it usable for an entire new set of use cases. It is another option for the "Fluid Logic" pattern:
http://www.adam-bien.com/roller/abien/entry/restful_calculator_with_javascript_and
With Java you would have to implement a custom DSL with e.g. ANTLR to achieve similar effect.
thanks for your opinion!,
adam
Posted by Adam Bien on September 16, 2013 at 03:33 PM CEST #
WTF! Collection literals and lambda expressions in EL! And available in Java 7 too!!!
I wonder if collection literals will make into Java 9, since it's weird to have them en EL and not in Java itself. I would love to write
[1,2,3,4,5,6,7,8].stream().filter(i->i%2 == 0).map(i->i*10).toList();
in Java!
Does anybody here has the power to make it happen? :-)
Posted by ikk on September 28, 2013 at 06:04 AM CEST #