MvelCompileExpNullSafeTest.java
package org.mvel2.compiler;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import org.mvel2.MVEL;
import org.mvel2.compiler.CompiledExpression;
import org.mvel2.compiler.ExpressionCompiler;
import org.mvel2.integration.VariableResolver;
import org.mvel2.integration.impl.ImmutableDefaultFactory;
import org.mvel2.integration.impl.SimpleValueResolver;
import org.mvel2.tests.BaseMvelTest;
/**
* @author Viswa Ramamoorthy (viswaramamoorthy@yahoo.com)
*/
public class MvelCompileExpNullSafeTest extends BaseMvelTest
{
@Test
public void testMvelCompileNullSafeNullFirst() {
String expression = "((parentGroup != null) && ($.?child.firstName in parentGroup.parentList if $.?child.firstName != null).size() > 0)";
ExpressionCompiler compiler = new ExpressionCompiler(expression, true);
CompiledExpression compiledExpression = compiler.compile();
ParentGroup pGroup = new ParentGroup();
List<Parent> list = new ArrayList<Parent>();
Parent parent = new Parent();
parent.setChild(null);
list.add(parent);
pGroup.setParentList(list);
Boolean result = (Boolean)MVEL.executeExpression(compiledExpression, Collections.<String, Object>singletonMap("parentGroup", pGroup));
assert result == false;
Child child = new Child();
child.setFirstName("vlaa");
pGroup = new ParentGroup();
list = new ArrayList<Parent>();
parent = new Parent();
parent.setChild(child);
list.add(parent);
child = new Child();
child.setFirstName(null);
parent = new Parent();
parent.setChild(child);
list.add(parent);
pGroup.setParentList(list);
result = (Boolean)MVEL.executeExpression(compiledExpression, Collections.<String, Object>singletonMap("parentGroup", pGroup));
assert result == true;
}
@Test
public void testMvelCompileNullSafeNullSecond() {
String expression = "((parentGroup != null) && ($.?child.firstName in parentGroup.parentList if $.?child.firstName != null).size() > 0)";
ExpressionCompiler compiler = new ExpressionCompiler(expression, true);
CompiledExpression compiledExpression = compiler.compile();
Child child = new Child();
child.setFirstName("vlaa");
ParentGroup pGroup = new ParentGroup();
List<Parent> list = new ArrayList<Parent>();
Parent parent = new Parent();
parent.setChild(child);
list.add(parent);
child = new Child();
child.setFirstName(null);
parent = new Parent();
parent.setChild(child);
list.add(parent);
pGroup.setParentList(list);
Boolean result = (Boolean)MVEL.executeExpression(compiledExpression, Collections.<String, Object>singletonMap("parentGroup", pGroup));
assert result == true;
pGroup = new ParentGroup();
list = new ArrayList<Parent>();
parent = new Parent();
parent.setChild(null);
list.add(parent);
pGroup.setParentList(list);
result = (Boolean)MVEL.executeExpression(compiledExpression, Collections.<String, Object>singletonMap("parentGroup", pGroup));
assert result == false;
}
@Test
public void testCustomResolverFactory() {
String expression = "($ in mylist if $.firstName=='Etnya').size() > 0";
Child child = new Child();
child.setFirstName("Etnya");
List<Child> list = new ArrayList<Child>();
list.add(child);
Map<String, Object> map = new HashMap<String, Object>();
map.put("mylist", list);
Boolean result = (Boolean)MVEL.eval(expression, new MyResolverFactory(map));
assert result == true;
list.clear();
result = (Boolean)MVEL.eval(expression, new MyResolverFactory(map));
assert result == false;
child.setFirstName("Enjoy");
list.add(child);
result = (Boolean)MVEL.eval(expression, new MyResolverFactory(map));
assert result == false;
}
/**
* Tests NullSafe with a segment which shadows a variable.
*/
@Test
public void testNullSafeVariableOverlap() {
String expression = "foo.?bar.baz"; // "baz" shadows the variable named "baz".
final String expectedResult = "You got me!";
Map<String, Object> foo = new HashMap<>();
Map<String, Object> ctx = Collections.singletonMap("foo", foo);
Map<String, Object> bar = Collections.singletonMap("baz", expectedResult);
foo.put("bar", null); // start with null, as this will cause NullSafe to be added to the AST.
// This variable overlaps the segment to be resolved next after NullSafe.
Map<String, Object> vars = Collections.singletonMap("baz", "no, over here!");
Serializable compiledExpr = MVEL.compileExpression(expression);
Assert.assertNull(MVEL.executeExpression(compiledExpr, ctx, vars));
foo.put("bar", bar);
Assert.assertEquals(expectedResult, MVEL.executeExpression(compiledExpr, ctx, vars));
}
@Test
public void testNullSafeWithVariableAsMapKey() {
String expression = "foo.?bar[myvar]";
final String expectedResult = "You got me!";
Map<String, Object> foo = new HashMap<>();
Map<String, Object> ctx = Collections.singletonMap("foo", foo);
Map<String, Object> bar = Collections.singletonMap("baz", expectedResult);
foo.put("bar", null); // start with null, as this will cause NullSafe to be added to the AST.
Map<String, Object> vars = new HashMap<>();
vars.put("myvar", "baz");
Serializable compiledExpr = MVEL.compileExpression(expression);
Assert.assertNull(MVEL.executeExpression(compiledExpr, ctx, vars));
foo.put("bar", bar);
Assert.assertEquals(expectedResult, MVEL.executeExpression(compiledExpr, ctx, vars));
}
@Test
public void testNullSafeWithVariableAsMethodArg() {
String expression = "foo.?bar.convert(myvar)";
Map<String, Object> foo = new HashMap<>();
Map<String, Object> ctx = Collections.singletonMap("foo", foo);
foo.put("bar", null); // start with null, as this will cause NullSafe to be added to the AST.
Map<String, Object> vars = new HashMap<>();
vars.put("myvar", "hello");
Serializable compiledExpr = MVEL.compileExpression(expression);
Assert.assertNull(MVEL.executeExpression(compiledExpr, ctx, vars));
foo.put("bar", new StringConverter());
Assert.assertEquals("HELLO", MVEL.executeExpression(compiledExpr, ctx, vars));
}
public class StringConverter {
public String convert(String value) {
return value.toUpperCase();
}
}
public class Child {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
public class Parent {
private Child child;
public Child getChild() {
return child;
}
public void setChild(Child child) {
this.child = child;
}
}
public class ParentGroup {
private List<Parent> parentList;
public List<Parent> getParentList() {
return parentList;
}
public void setParentList(List<Parent> parentList) {
this.parentList = parentList;
}
}
public class MyResolverFactory extends ImmutableDefaultFactory {
private static final long serialVersionUID = 1L;
private Map<String, Object> tempVariables;
public MyResolverFactory(Map<String, Object> tempVariables) {
this.tempVariables = tempVariables;
}
public boolean isResolveable(String name) {
if (name instanceof String) {
boolean result = tempVariables.containsKey(name);
if (result) {
return result;
}
return super.isResolveable(name);
}
throw new IllegalArgumentException(
"MyResolverFactory can only resolve String variable names: " + name);
}
public VariableResolver getVariableResolver(String name) {
if (tempVariables.containsKey(name)) {
return new SimpleValueResolver(tempVariables.get(name));
}
return super.getVariableResolver(name);
}
}
}