Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

JAVA and MVEL

Introduction

MVEL is an Apache licensed powerful Expression Language (EL), written in Java for java based applications and hence its syntax is mostly similar to Java. In general, the regular expression language is used to match, find and replace the strings and numerals from large content using search patterns.

MVEL is similar to OGNL and it provides variety of expressions as given below:

  • Property Expressions
  • Boolean Expressions
  • Method invocations
  • Variable assignments
  • Functions definition

Why MVEL

  • When used as an Expression Language the operators directly support collection, array and string matching as well as regular expressions.
  • When used as a Templating Language, can be used for String construction and configuration.
  • MVEL performance is very faster compared to OGNL.

Use case

  • Usage of property expressions
  • Usage of Boolean expressions
  • Usage of functions definition
  • Collections usage in MVEL
  • Templating with MVEL

Pre-requisite

  • Setup JDK1.6+
  • MVEL jars

Basic Syntax

  • MVEL expression may be a simple statement or a complicated script.
  • The script will contain multiple statements separated by semicolon, denoting the statement termination and newline is not a substitute for the semicolon.
  • The expression execution is based on the operator precedence.
  • By default, the expression will return the value out of the last statement in the expression or script based on the last out value principle.

Usage of Property Expressions

Property expression is used to extract the property value out of the variable or from the model objects. Extracting from the property is always straight forward and known to the programmers.

The following example illustrates accessing the property using the MVEL expression:

Example

“Employee” is the java bean containing the firstName, lastName and age as properties.  The example code is used to extract the bean property using the MVEL expression:

//Here input to the MVEL expression is a map.
        Map<String, Object> input = new HashMap<String, Object>();
        Employee e = new Employee();
        e.setFirstName("john");
        e.setLastName("michale");
        input.put("employee", e);
        /*
         * Property Expression - Used to extract the property value out of the variable.
         */
	String lastName = MVEL.evalToString("employee.lastName",input); 
       System.out.println("Employee Last Name:"+lastName)

Usually developers access the object using its reference, actually this is not the case. In this example, the “Employee” object is passed with the employee key to the MVEL expression.  If we try to access the value using its reference “e”, then the following exception will be thrown.

Here, “input“ is the object context to the expression and MVEL maps the variable, finds the lastName property and extracts the value.

Usage of Boolean Expressions

Boolean expressions are used to validate a particular condition using the operators. MVEL has numerous operators to check the criteria. The following are the operators that are available in the MVEL:

  • Unary operators (>=, <=, ==, >, <, ! =)
  • Logical operators (&&, ||)
  • Bitwise operator (&, |, ^, -, /, *,  %)
  • contains, instance of, string concatenation (+), projections (in)

Example

MVEL.evalToBoolean("employee.lastName == \"john\"", input)
input.put("numeric", new Double(-0.253405));
System.out.println(MVEL.evalToBoolean("numeric > 0",input));

Usage of Functions Definition

Functions definition is a simple method calling. In MVEL, the function is defined using the keyword “def” or “function”. We can pass the parameters to this function and it returns the output value. It always returns a single output by the last statement.

Example

/*
* Function definitions
*/
System.out.println(MVEL.eval(new String(loadFromFile(new File("concat.mvel"))), new HashMap()));

concat.mvel

def stringcon(input){	
	return ($.firstName+$.lastName in input);	
}
stringcon(employeeList);
In the above example, the function is defined to concatenate the “firstName” and “lastName” of the employee bean and finally return the list of concatenated strings as output.

The following is the complete program:

MVELController.java

package com.main;

import static org.mvel2.util.ParseTools.loadFromFile;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.mvel2.MVEL;

import com.model.Employee;

/**
 * This class is responsible to show the different features possible by the MVEL.
 */
public class MVELController {
    public static List<Employee> employeeList = populateEmployee();

    public static void main(String args[]) throws IOException {
        // Here input to the MVEL expression is a map.
        Map<String, Object> input = new HashMap<String, Object>();
        Employee e = new Employee();
        e.setFirstName("john");
        e.setLastName("michale");
        input.put("employee", e);
        /*
         * Property Expression - Used to extract the property value out of the expression.
         */
        String lastName = MVEL.evalToString("employee.lastName", input);
        System.out.println("Employee Last Name:" + lastName);
        /*
         * Boolean Expression
         */
        System.out.println("Is employee name is John:" + MVEL.evalToBoolean("employee.lastName == \"john\"", input));
        input.put("numeric", new Double(-0.253405));
        System.out.println(MVEL.evalToBoolean("numeric > 0", input));
        input.put("input", employeeList);
        System.out.println(MVEL.eval("($ in input if $.firstName == \"john\")",input ));
        /*
         * Function definitions
         */
        System.out.println(MVEL.eval(new String(loadFromFile(new File("concat.mvel"))), new HashMap()));

    }

    private static List<Employee> populateEmployee() {
        List<Employee> employees = new ArrayList<Employee>();
        Employee e = new Employee();
        e.setFirstName("john");
        e.setLastName("michale");

        Employee e1 = new Employee();
        e1.setFirstName("merlin");
        e1.setLastName("michale");

        employees.add(e);
        employees.add(e1);
        return employees;
    }
}

Employee.java

package com.model;

public class Employee {
    private String firstName;
    private String lastName;
    private int    age;

    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 int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String toString(){
        return "First Name:"+firstName;
    }

    }

Output

Note: Method invocations are possible using the MVEL expression language.

Collections usage in MVEL

Comparing the collection

By using the MVEL expression we can compare two collections and can apply the operators (>, < and =) on the collection to find output.

Example

To find the numeric greater than constant from the numeric list:

String operator = ">";
List<Double> computedValue = new ArrayList<Double>();
computedValue.add(new Double(50.0));
computedValue.add(new Double(97.9));
computedValue.add(new Double(68.9));

Map<String, Object> input = new HashMap<String, Object>();
input.put("actual_value", new Double(55.9));
input.put("computed_value", computedValue);
List output = null;

if (operator.equals(">")) {
                output = (List) MVEL.eval("($ in computed_value if $ > actual_value)", input);
            } else {
                output = (List) MVEL.eval("($ in computed_value if $ < actual_value)", input);
            }

Templating with MVEL

Like other templating language MVEL also supports the following:

  • Binding dynamic values with the static HTML content.
  • Possible to call the static java method from the MVEL template to return the output.
  • Ability to use the java code in the MVEL template.
  • Binding dynamic values with static content is a general use case possible with other templating language. We have used MVEL templating for different use cases to generate the dynamic queries, to form the API calls, R script calls and many more.

Example

Here is the complete example explaining the different use cases for MVEL templating:

package com.main;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.mvel2.templates.CompiledTemplate;
import org.mvel2.templates.TemplateCompiler;
import org.mvel2.templates.TemplateRuntime;
import org.mvel2.util.ParseTools;

/**
 * Class is responsible to showcase MVEL template usage for different use case
 */
public class MVELTemplateController {
    public static void main(String args[]) {
        MVELTemplateController controller = new MVELTemplateController();

        // Usecase1: Injecting the dynamic property to the static HTML content.
        // MVEL supports the decision making tags to place the default values in case of the actual property value is null
        // Input map should contain the key name otherwise it will throw the exception
        System.out.println("***** Usecase1: Injecting the dynamic property Started *****");
        String message = "<html>Hello @if{userName!=null && userName!=''}@{userName}@else{}Guest@end{}! Welcome to MVEL tutorial<html>";
        System.out.println("Input Expression:" + message);
        Map<String, Object> inputMap = new HashMap<String, Object>();
        inputMap.put("userName", "Blog Visitor");
        System.out.println("InputMap:" + inputMap);
        String compliedMessage = controller.applyTemplate(message, inputMap);
        System.out.println("compliedMessage:" + compliedMessage);
        System.out.println("***** Usecase1: Injecting the dynamic property Ended  *****\n");

        // Usecase2: Loading the MVEL expression from the configuration or property file
        // MVEL library have build-in utility to load the expression from the file input.
        // Usually the mvel script,template will be save with .mvel extension
        try {
            String templateExpression = new String(ParseTools.loadFromFile(new File("input/declaretemplate.mvel")));
            System.out.println("templateExpression:" + templateExpression + "\n");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Usecase3: Accessing the java class methods from the MVEL template to return the output
        System.out.println("***** Usecase3: Accessing static method Started *****");
        String methodExpression = "@if{com.main.MVELTemplateController.validateInput(userName)}Valid Input@else{} Invalid Input@end{}";
        String validateExpression = controller.applyTemplate(methodExpression, inputMap);
        System.out.println("validateExpression:" + validateExpression);
        System.out.println("***** Usecase3: Accessing static method Ended *****\n");

        // Usecase4: Forming dynamic query by binding the dynamic values
        // We can build complex queries by using the decision making tags@if,@else and for loop tags @for
        // We can bind the values from the bean to expression
        System.out.println("***** Usecase4: Forming dynamic Query Started *****");
        String queryExpression = "select * from @{schemaName}.@{tableName} where @{condition}";
        Map<String, Object> queryInput = new HashMap<String, Object>();
        queryInput.put("schemaName", "testDB");
        queryInput.put("tableName", "employee");
        queryInput.put("condition", "age > 25 && age < 30");
        String query = controller.applyTemplate(queryExpression, queryInput);
        System.out.println("Dynamic Query:" + query);
        System.out.println("***** Usecase4: Forming dynamic Query Ended*****\n");

        // Usecase5: Forming dynamic API calls
        System.out.println("***** Usecase5: Forming dynamic API calls Started *****");
        String weatherAPI = "http://api.openweathermap.org/data/2.5/weather?lat=@{latitude}&lon=@{longitude}";
        Map<String, Object> apiInput = new HashMap<String, Object>();
        apiInput.put("latitude", "35");
        apiInput.put("longitude", "139");
        String weatherAPICall = controller.applyTemplate(weatherAPI, apiInput);
        System.out.println("weatherAPICall:" + weatherAPICall);
        System.out.println("***** Usecase5: Forming dynamic API calls Ended *****\n");
    }

    /**
     * Method used to bind the values to the MVEL syntax and return the complete expression to understand by any other engine.
     * 
     * @param expression
     * @param parameterMap
     * @return
     *         Jun 19, 2015
     */
    public String applyTemplate(String expression, Map<String, Object> parameterMap) {
        String executeExpression = null;

        if (expression != null && (parameterMap != null && !parameterMap.isEmpty())) {
            // compile the mvel expression
            CompiledTemplate compliedTemplate = TemplateCompiler.compileTemplate(expression);
            // bind the values in the Map input to the expression string.
            executeExpression = (String) TemplateRuntime.execute(compliedTemplate, parameterMap);
        }

        return executeExpression;
    }

    /**
     * Method used to validate the input
     * 
     * @param input
     * @return
     *         Jun 19, 2015
     */
    public static boolean validateInput(String input) {
        boolean isValid = false;

        if (input != null && input.equals("example")) {
            isValid = true;
        }

        return isValid;
    }
}

Output

Conclusion

  • MVEL expression is clean and its syntax is easy to understand.
  • There will be a number of use cases where the MVEL will be used efficiently and effectively.
  • MVEL engine performance is good compared to other EL engine.
  • Apache drools use MVEL template for the dynamic code generation and Apache Camel use the MVEL template for the message generation.

References

  • https://github.com/mvel/mvel
  • https://en.wikipedia.org/wiki/MVEL
  • https://en.wikipedia.org/wiki/MVEL_Language_Guide


This post first appeared on Front-end Code Review & Validation Tools | Treselle Systems, please read the originial post: here

Share the post

JAVA and MVEL

×

Subscribe to Front-end Code Review & Validation Tools | Treselle Systems

Get updates delivered right to your inbox!

Thank you for your subscription

×