如何创建通用 MVEL 表达式
How to create generic MVEL expression
我正在为 Java 个对象编写通用 MVEL 表达式。因此,为了便于理解,我举了一个例子。
class Student {
String name;
String rollNo;
List<Course> courses;
}
class Course {
String courseName;
String facultyName;
String fee;
String classRoom;
}
我可以写 MVEL 表达式 如果我的查询是:
检查学生是否给出姓名和 rollNo
MVEL.eval(" name == 'XYZ' && rollNo == '3456' ", Student)
但是如果查询是:
检查一个学生是否参加了同一教室的所有课程?
MVEL.eval(" courses[0].classRoom == 'A' ", Student);
但这只检查一门课程的 classRoom。但是我想检查一个学生的所有课程是否都发生在课堂上 'A'。
我找不到任何资源来解决这个问题。我是 MVEL 的新手。有疑问可以问我
谢谢
为此需要几个步骤 - 您将需要使用 MVEL 变量及其 foreach
operator。
方法如下:
import org.mvel2.MVEL;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
public class App {
public static void main(String[] args) {
List<Course> courses = new ArrayList<>();
courses.add(new Course("Math", "123"));
courses.add(new Course("Physics", "123"));
courses.add(new Course("Chemistry", "123"));
Student student = new Student("XYZ", "3456", courses);
// Check If a student has given name and rollNo:
boolean b1 = MVEL.eval(" name == 'XYZ' && rollNo == '3456' ", student, Boolean.class);
boolean b2 = MVEL.eval(" name == 'XYP' && rollNo == '3456' ", student, Boolean.class);
//System.out.println(b1);
//System.out.println(b2);
// Check If a student attends all the courses in the same classroom:
boolean allClassesInSameRoom = true;
String prevRoom = null;
Map vars = new HashMap();
vars.put( "sameRoom", allClassesInSameRoom );
vars.put( "prevRoom", prevRoom );
String expression = String.join("\n",
"sameRoom = true;",
"prevRoom = null;",
"foreach (course : courses) {",
" if (sameRoom == true && prevRoom != null && course.classRoom != prevRoom) {",
" sameRoom = false;",
" }",
" prevRoom = course.classRoom;",
"}",
"sameRoom");
allClassesInSameRoom = MVEL.eval(expression, student, vars, Boolean.class);
System.out.println(allClassesInSameRoom);
}
}
首先我们定义两个Java变量,这两个变量在MVEL脚本中是需要的。它们通过 Java 映射传递给 MVEL eval
运算符:
boolean allClassesInSameRoom = true;
String prevRoom = null;
Map<String, Object> vars = new HashMap<>();
vars.put( "sameRoom", allClassesInSameRoom );
vars.put( "prevRoom", prevRoom );
然后我们构建一个包含我们需要使用的MVEL脚本的字符串:
String expression = String.join("\n",
"sameRoom = true;",
"prevRoom = null;",
"foreach (course : courses) {",
" if (sameRoom == true && prevRoom != null && course.classRoom != prevRoom) {",
" sameRoom = false;",
" }",
" prevRoom = course.classRoom;",
"}",
"sameRoom");
最后一行 returns sameRoom
变量。
eval
语句组装了我们需要的项目:
allClassesInSameRoom = MVEL.eval(expression, student, vars, Boolean.class);
注意Course
class需要定义为public
:
public class Course {
private final String courseName;
private final String classRoom;
public Course (String courseName, String classRoom) {
this.courseName = courseName;
this.classRoom = classRoom;
}
public String getCourseName() {
return courseName;
}
public String getClassRoom() {
return classRoom;
}
}
可以将 MVEL 脚本创建为模板,我认为这有助于避免像我在这里那样逐行构建 Java 字符串的有点混乱的过程。
与不使用 MVEL 简单地检查 student
对象相比,这可能会增加工作量。但是 MVEL 也支持函数和 lambda 表达式——所以可能有一些方法可以简化我的方法并简化 MVEL 脚本。
更新
这是一个更紧凑的例子:
Map<String, String> rooms = new HashMap<>();
Map<String, Object> vars2 = new HashMap<>();
vars2.put( "rooms", rooms );
String expression2 = String.join("\n",
"foreach (course : courses) {",
" rooms.put(course.classRoom, course.classRoom);",
"}",
"(rooms.size() == 1) ? true : false;");
allClassesInSameRoom = MVEL.eval(expression2, student, vars2, Boolean.class);
System.out.println(allClassesInSameRoom);
在这种情况下,脚本将每个房间名称添加到地图中。重复的房间名称将具有相同的地图键,因此不会增加地图的大小。如果我们最终得到一张只包含一个条目的地图,那就意味着只有一个房间用于所有课程。
作为替代方案,您可以使用 Java(Java 8 或更高)计算学生课程列表中不同房间名称的数量:
import static java.util.stream.Collectors.toList;
...
long roomsCount = courses.stream()
.map(Course::getClassRoom) // get the room name from each course
.collect(toList()) // build a list of these room names
.stream().distinct().count(); // count the number of unique room names
这是一行代码。但由于您的目标是探索和理解 MVEL,因此这只是旁注。
我正在为 Java 个对象编写通用 MVEL 表达式。因此,为了便于理解,我举了一个例子。
class Student {
String name;
String rollNo;
List<Course> courses;
}
class Course {
String courseName;
String facultyName;
String fee;
String classRoom;
}
我可以写 MVEL 表达式 如果我的查询是: 检查学生是否给出姓名和 rollNo
MVEL.eval(" name == 'XYZ' && rollNo == '3456' ", Student)
但是如果查询是: 检查一个学生是否参加了同一教室的所有课程?
MVEL.eval(" courses[0].classRoom == 'A' ", Student);
但这只检查一门课程的 classRoom。但是我想检查一个学生的所有课程是否都发生在课堂上 'A'。 我找不到任何资源来解决这个问题。我是 MVEL 的新手。有疑问可以问我
谢谢
为此需要几个步骤 - 您将需要使用 MVEL 变量及其 foreach
operator。
方法如下:
import org.mvel2.MVEL;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
public class App {
public static void main(String[] args) {
List<Course> courses = new ArrayList<>();
courses.add(new Course("Math", "123"));
courses.add(new Course("Physics", "123"));
courses.add(new Course("Chemistry", "123"));
Student student = new Student("XYZ", "3456", courses);
// Check If a student has given name and rollNo:
boolean b1 = MVEL.eval(" name == 'XYZ' && rollNo == '3456' ", student, Boolean.class);
boolean b2 = MVEL.eval(" name == 'XYP' && rollNo == '3456' ", student, Boolean.class);
//System.out.println(b1);
//System.out.println(b2);
// Check If a student attends all the courses in the same classroom:
boolean allClassesInSameRoom = true;
String prevRoom = null;
Map vars = new HashMap();
vars.put( "sameRoom", allClassesInSameRoom );
vars.put( "prevRoom", prevRoom );
String expression = String.join("\n",
"sameRoom = true;",
"prevRoom = null;",
"foreach (course : courses) {",
" if (sameRoom == true && prevRoom != null && course.classRoom != prevRoom) {",
" sameRoom = false;",
" }",
" prevRoom = course.classRoom;",
"}",
"sameRoom");
allClassesInSameRoom = MVEL.eval(expression, student, vars, Boolean.class);
System.out.println(allClassesInSameRoom);
}
}
首先我们定义两个Java变量,这两个变量在MVEL脚本中是需要的。它们通过 Java 映射传递给 MVEL eval
运算符:
boolean allClassesInSameRoom = true;
String prevRoom = null;
Map<String, Object> vars = new HashMap<>();
vars.put( "sameRoom", allClassesInSameRoom );
vars.put( "prevRoom", prevRoom );
然后我们构建一个包含我们需要使用的MVEL脚本的字符串:
String expression = String.join("\n",
"sameRoom = true;",
"prevRoom = null;",
"foreach (course : courses) {",
" if (sameRoom == true && prevRoom != null && course.classRoom != prevRoom) {",
" sameRoom = false;",
" }",
" prevRoom = course.classRoom;",
"}",
"sameRoom");
最后一行 returns sameRoom
变量。
eval
语句组装了我们需要的项目:
allClassesInSameRoom = MVEL.eval(expression, student, vars, Boolean.class);
注意Course
class需要定义为public
:
public class Course {
private final String courseName;
private final String classRoom;
public Course (String courseName, String classRoom) {
this.courseName = courseName;
this.classRoom = classRoom;
}
public String getCourseName() {
return courseName;
}
public String getClassRoom() {
return classRoom;
}
}
可以将 MVEL 脚本创建为模板,我认为这有助于避免像我在这里那样逐行构建 Java 字符串的有点混乱的过程。
与不使用 MVEL 简单地检查 student
对象相比,这可能会增加工作量。但是 MVEL 也支持函数和 lambda 表达式——所以可能有一些方法可以简化我的方法并简化 MVEL 脚本。
更新
这是一个更紧凑的例子:
Map<String, String> rooms = new HashMap<>();
Map<String, Object> vars2 = new HashMap<>();
vars2.put( "rooms", rooms );
String expression2 = String.join("\n",
"foreach (course : courses) {",
" rooms.put(course.classRoom, course.classRoom);",
"}",
"(rooms.size() == 1) ? true : false;");
allClassesInSameRoom = MVEL.eval(expression2, student, vars2, Boolean.class);
System.out.println(allClassesInSameRoom);
在这种情况下,脚本将每个房间名称添加到地图中。重复的房间名称将具有相同的地图键,因此不会增加地图的大小。如果我们最终得到一张只包含一个条目的地图,那就意味着只有一个房间用于所有课程。
作为替代方案,您可以使用 Java(Java 8 或更高)计算学生课程列表中不同房间名称的数量:
import static java.util.stream.Collectors.toList;
...
long roomsCount = courses.stream()
.map(Course::getClassRoom) // get the room name from each course
.collect(toList()) // build a list of these room names
.stream().distinct().count(); // count the number of unique room names
这是一行代码。但由于您的目标是探索和理解 MVEL,因此这只是旁注。