diff --git a/libraries-7/pom.xml b/libraries-7/pom.xml
index 48a96b4b6cbe..ea91ca21b271 100644
--- a/libraries-7/pom.xml
+++ b/libraries-7/pom.xml
@@ -63,6 +63,11 @@
webmagic-extension
1.0.3
+
+ org.mvel
+ mvel2
+ ${mvel.version}
+
@@ -104,6 +109,7 @@
2024.1.20
47
5.5.0
+ 2.5.2.Final
diff --git a/libraries-7/src/main/java/com/baeldung/mvel/model/Employee.java b/libraries-7/src/main/java/com/baeldung/mvel/model/Employee.java
new file mode 100644
index 000000000000..277cb639dbc7
--- /dev/null
+++ b/libraries-7/src/main/java/com/baeldung/mvel/model/Employee.java
@@ -0,0 +1,85 @@
+package com.baeldung.mvel.model;
+
+public class Employee {
+ private String name;
+ private Job job;
+
+ public Employee(String name, Job job) {
+ this.name = name;
+ this.job = job;
+ }
+
+ public Employee(String name, int experienceInYears, double salary, String department) {
+ this.name = name;
+ this.job = new Job(experienceInYears, salary, department);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setJob(Job job) {
+ this.job = job;
+ }
+
+ public Job getJob() {
+ return job;
+ }
+
+
+ public static class Job {
+ private int experienceInYears;
+ private double salary;
+ private String department;
+
+ public Job(int experienceInYears, double salary) {
+ this.experienceInYears = experienceInYears;
+ this.salary = salary;
+ }
+
+ public Job(int experienceInYears, double salary, String department) {
+ this.experienceInYears = experienceInYears;
+ this.salary = salary;
+ this.department = department;
+ }
+
+ public int getExperienceInYears() {
+ return experienceInYears;
+ }
+
+ public void setExperienceInYears(int experienceInYears) {
+ this.experienceInYears = experienceInYears;
+ }
+
+ public double getSalary() {
+ return salary;
+ }
+
+ public void setSalary(double salary) {
+ this.salary = salary;
+ }
+
+ public String getDepartment() {
+ return department;
+ }
+
+ public void setDepartment(String department) {
+ this.department = department;
+ }
+
+ public double calculateAnnualBonus() {
+ if (experienceInYears > 10) {
+ return salary * 0.20;
+ } else if (experienceInYears > 5) {
+ return salary * 0.10;
+ } else {
+ return salary * 0.05;
+ }
+ }
+ }
+
+}
diff --git a/libraries-7/src/test/java/com/baeldung/mvel/MvelServiceUnitTest.java b/libraries-7/src/test/java/com/baeldung/mvel/MvelServiceUnitTest.java
new file mode 100644
index 000000000000..8892389e88dd
--- /dev/null
+++ b/libraries-7/src/test/java/com/baeldung/mvel/MvelServiceUnitTest.java
@@ -0,0 +1,143 @@
+package com.baeldung.mvel;
+
+import org.junit.jupiter.api.Test;
+import org.mvel2.*;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.baeldung.mvel.model.Employee;
+
+public class MvelServiceUnitTest {
+
+ @Test
+ public void givenSimpleExpression_whenEvaluate_thenCorrectResult() {
+ String expression = "5 + 3 * 2";
+ Object result = MVEL.eval(expression);
+
+ assertEquals(11, result);
+ }
+
+ @Test
+ public void givenVariables_whenEvaluateExpression_thenCorrectResult() {
+ Map variables = new HashMap<>();
+ variables.put("salary", 75000.0);
+ variables.put("experience", 8);
+
+ String expression = "salary * 0.10";
+ Object result = MVEL.eval(expression, variables);
+
+ assertEquals(7500.0, result);
+ }
+
+ @Test
+ public void givenBooleanExpression_whenEvaluate_thenCorrectResult() {
+ Map variables = new HashMap<>();
+ variables.put("experience", 12);
+ variables.put("salary", 95000.0);
+
+ String expression = "experience > 10 && salary > 80000";
+ Object result = MVEL.eval(expression, variables);
+
+ assertTrue((Boolean) result);
+ }
+
+ @Test
+ public void givenNullSafeNavigation_whenPropertyIsNull_thenNoException() {
+ Employee.Job job = new Employee.Job(5, 5000);
+ Employee employee = new Employee("David", job);
+ employee.getJob()
+ .setDepartment(null);
+ String expression = " (job.?department.length) ";
+ Object result = MVEL.eval(expression, employee);
+
+ assertNull(result);
+ }
+
+ @Test
+ public void givenEmployee_whenAccessProperties_thenCorrectValues() {
+ Employee.Job job = new Employee.Job(8, 75000.0);
+ Employee employee = new Employee("John Doe", job);
+
+ String expression = "name + ' has ' + job.experienceInYears + ' years of experience'";
+ Object result = MVEL.eval(expression, employee);
+
+ assertEquals("John Doe has 8 years of experience", result);
+ }
+
+ @Test
+ public void givenEmployee_whenCallMethod_thenCorrectResult() {
+ Employee.Job job = new Employee.Job(12, 90000.0);
+ Employee employee = new Employee("Jane Smith", job);
+
+ String expression = "job.calculateAnnualBonus()";
+ Object result = MVEL.eval(expression, employee);
+
+ assertEquals(18000.0, (Double) result, 0.01);
+ }
+
+ @Test
+ public void givenEmployee_whenEvaluateConditional_thenCorrectResult() {
+ Employee.Job job = new Employee.Job(15, 120000.0);
+ Employee employee = new Employee("Bob Johnson", job);
+
+ String expression = "if (job.experienceInYears > 10) { job.salary * 0.20 } " + "else if (job.experienceInYears > 5) { job.salary * 0.10 } " +
+ "else { job.salary * 0.05 }";
+ Object result = MVEL.eval(expression, employee);
+
+ assertEquals(24000.0, (Double) result, 0.01);
+ }
+
+ @Test
+ public void givenCompiledExpression_whenExecuteMultipleTimes_thenCorrectResults() {
+ String expression = "job.experienceInYears > 5 && job.salary > 50000";
+ Serializable compiledExpression = MVEL.compileExpression(expression);
+
+ Employee.Job job1 = new Employee.Job(7, 60000.0);
+ Employee employee1 = new Employee("Alice", job1);
+
+ Employee.Job job2 = new Employee.Job(3, 45000.0);
+ Employee employee2 = new Employee("Charlie", job2);
+
+ boolean result1 = (Boolean) MVEL.executeExpression(compiledExpression, employee1);
+ boolean result2 = (Boolean) MVEL.executeExpression(compiledExpression, employee2);
+
+ assertTrue(result1);
+ assertFalse(result2);
+ }
+
+ @Test
+ public void givenListProjection_whenFilter_thenCorrectResult() {
+ Map variables = new HashMap<>();
+ List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+ variables.put("numbers", numbers);
+
+ String expression = "($ in numbers if $ > 5)";
+ Object result = MVEL.eval(expression, variables);
+
+ assertInstanceOf(List.class, result);
+ List> filteredList = (List>) result;
+ assertEquals(5, filteredList.size());
+ }
+
+ @Test
+ public void givenListTransformation_whenProject_thenCorrectResult() {
+ Map variables = new HashMap<>();
+ List numbers = Arrays.asList(1, 2, 3, 4, 5);
+ variables.put("numbers", numbers);
+
+ String expression = "($ * 2 in numbers)";
+ Object result = MVEL.eval(expression, variables);
+
+ assertInstanceOf(List.class, result);
+ List> transformedList = (List>) result;
+ assertEquals(10, transformedList.get(4));
+ }
+
+}
+
diff --git a/libraries-7/src/test/java/com/baeldung/mvel/MvelTemplateServiceUnitTest.java b/libraries-7/src/test/java/com/baeldung/mvel/MvelTemplateServiceUnitTest.java
new file mode 100644
index 000000000000..0bc7d04fb36c
--- /dev/null
+++ b/libraries-7/src/test/java/com/baeldung/mvel/MvelTemplateServiceUnitTest.java
@@ -0,0 +1,83 @@
+package com.baeldung.mvel;
+
+import com.baeldung.mvel.model.Employee;
+
+import org.junit.jupiter.api.Test;
+import org.mvel2.templates.CompiledTemplate;
+import org.mvel2.templates.TemplateCompiler;
+import org.mvel2.templates.TemplateRuntime;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class MvelTemplateServiceUnitTest {
+
+ @Test
+ public void givenEmployeeData_whenGenerateReport_thenCorrectOutput() {
+ String template = """
+ Employee Report
+ ================
+ Name: @{name}
+ Experience: @{experience} years
+ Salary: $@{salary
+ """;
+
+ Map variables = new HashMap<>();
+ variables.put("name", "John Doe");
+ variables.put("experience", 12);
+ variables.put("salary", 95000.0);
+
+ CompiledTemplate compiledTemplate = TemplateCompiler.compileTemplate(template);
+ String result = (String) TemplateRuntime.execute(compiledTemplate, variables);
+
+ assertTrue(result.contains("John Doe"));
+ assertTrue(result.contains("12 years"));
+ }
+
+ @Test
+ public void givenSeniorEmployee_whenGenerateReport_thenCorrectStatus() {
+ String template = """
+ Employee Report
+ @if{experience > 10}
+ Status: Senior Employee\n
+ @else{}
+ Status: Junior/Mid-level Employee
+ @end{}
+ """;
+
+ Map variables = new HashMap<>();
+ variables.put("experience", 12);
+
+ CompiledTemplate compiledTemplate = TemplateCompiler.compileTemplate(template);
+ String result = (String) TemplateRuntime.execute(compiledTemplate, variables);
+
+ assertTrue(result.contains("Senior Employee"));
+ }
+
+ @Test
+ public void givenEmployeeList_whenGenerateListReport_thenCorrectOutput() {
+ String template = """
+ "Employee List:
+ "@foreach{emp : employees}
+ "- @{emp.name} (@{emp.job.department})
+ "@end{}
+ """;
+
+ List employees = Arrays.asList(new Employee("John", 10, 80000.0, "IT"), new Employee("Jane", 8, 75000.0, "HR"),
+ new Employee("Bob", 12, 95000.0, "Finance"));
+
+ Map variables = new HashMap<>();
+ variables.put("employees", employees);
+
+ CompiledTemplate compiledTemplate = TemplateCompiler.compileTemplate(template);
+ String result = (String) TemplateRuntime.execute(compiledTemplate, variables);
+
+ assertTrue(result.contains("John (IT)"));
+ assertTrue(result.contains("Jane (HR)"));
+ }
+}
+