This is a personal memo as a result of investigating "Can some Java processing be injected from the outside?"
When I looked it up, there was a ** JavaScript scripting engine (Nashorn) ** on Java, so I tried using it. Nashorn can be called from the Java SE 8 javax.script package.
This is a sample code that delegates the filtering process of List to JavaScript.
Main.java
public class Main {
    public static void main(String[] args) throws Exception {
	    List<Person> list = Arrays.asList(new Person("a", 1), new Person("b", 2), new Person("c", 3));
        //Delegate JavaScript filtering
		List<Person> resultList = list.stream().filter(e -> eval(e)).collect(Collectors.toList());
		//Show list before filter
		System.out.println("Before filter: " + list);
		//Show filtered list
		System.out.println("After filtering: " + resultList);
    }
	/**
	 *Evaluate JavaScript execution results
	 * @param person
	 * @return true/false
	 */
	public static boolean eval(Person person) {
    	boolean result = false;
		try {
			ScriptEngineManager manager = new ScriptEngineManager();
			//Create a JavaScript engine
			ScriptEngine engine = manager.getEngineByName("javascript");
			//Set Java object to JavaScript variable
			engine.put("person", person);
			//Read a JavaScript file from a file
			Reader script = new InputStreamReader(Main.class.getResourceAsStream("sample.js"));
			//Execute JavaScript
			result = Boolean.valueOf(true).equals(engine.eval(script));
		} catch(ScriptException ex) {
			ex.printStackTrace();
		}
		return result;
	}
}
A Java object that is an element in the list.
We have defined a public getter so that we can access field variables from JavaScript.
Person.java
public class Person {
    private String name;
    private Integer age;
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public Integer getAge() {
        return age;
    }
    public String toString() {
        return "{ name: " + this.name + ", age: " + this.age + "}";
    }
}
The following sample.js is processing the filter method on the Java side.
I was also able to access the fields of the person object passed by Java.
sample.js
//person is an element of the list passed from the Java side
//Access the name field and use it in the judgment formula
person.name === 'a' || person.name === 'b';
The processing result of the above sample code is as follows.
From the evaluation result of sample.js, you can see that the contents of List have been filtered.
Before filter: [{ name: a, age: 1}, { name: b, age: 2}, { name: c, age: 3}]
After filtering: [{ name: a, age: 1}, { name: b, age: 2}]
If you use it like this case, For example, I found it convenient to create a list on the screen where the user can change the filtering conditions each time.
Below is a reference link. Basics of JavaScript engine Nashorn on Java OpenJDK wiki >> Nashorn
Recommended Posts