Eval Java source from Java

Recently, I have been developing a Java application that analyzes Java source code in my business, but there were cases where I wanted to eval a part of the source code to be analyzed. So I eval the Java source code and lightly investigated how to get the results.

Please refer to tanzaku / eval \ -java \ -code for the source code used for the experiment. The master contains the JDK10 test code, and the eval_jdk8 branch contains the JDK8 test code.

How to use the Java Compiler API

Since you can get an instance of Class by the method according to the site below, you can evaluate it by executing the method with reflection. Java Compiler Class Memo \ (Hishidama's JavaCompiler Memo )

If you do not want to make detailed customizations, it may be easier to use a library like the one below. OpenHFT/Java-Runtime-Compiler: Java Runtime Compiler

How to evaluate as a Groovy script

You can evaluate it just by calling ScriptEngine # eval as shown below. (You need to add groovy-all to your classpath)

package experiments.eval.evaluator;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class GroovyEvaluator {
	private static ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("groovy");

	public String eval(final String sourceCode) throws ScriptException {
		return scriptEngine.eval(sourceCode).toString();
	}
}

However, be aware that the Java source code may not be a valid Groovy script as is. For example, an expression like new String [] {"A "} is invalid in groovy and should be something like [" A "] as String [].

How to evaluate by JShell

It can be evaled using the JShell API added in Java 9. JShell (Java SE 9 & JDK 9 )

package experiments.eval.evaluator;

import java.util.Arrays;
import java.util.stream.Stream;

import jdk.jshell.JShell;
import jdk.jshell.SnippetEvent;

public class JShellEvaluator {
	private Stream<String> splitStatements(final String sourceCode) {
		return Arrays.stream(sourceCode.split(";")).map(stmt -> stmt + ";");
	}
	
	public String eval(final String sourceCode) {
		try (final JShell jshell = JShell.create()) {
			//It seems that multiple statements cannot be evaluated at once, so evaluate them separately.
			return splitStatements(sourceCode)
						.flatMap(stmt -> jshell.eval(stmt).stream())
						.reduce((a,b)->b)
						.map(SnippetEvent::value)
						.orElse(null);
		}
	}
}

Comparison of processing time

The processing time when evaluated by each method was measured. We are measuring the time it takes to eval a small process 100 times. The 100 operations are slightly different so that they are not cached. Please refer to the source code for details.

Method JDK ver processing time[sec]
Java Compiler API Oracle JDK 8 14.732
Java Compiler API Oracle JDK 10 42.743
groovy Oracle JDK 8 3.578
groovy Oracle JDK 10 4.914
JShell API Oracle JDK 10 147.294

Conclusion

The source code is concise, and it seems that it is not inferior in speed, so it seems good to evaluate it with groovy. However, in any case, it is definitely a very heavy process, so it seems to be difficult to use it a lot. Of course, if the version of the compiler changes, the performance will change, so be careful when upgrading.

Recommended Posts

Eval Java source from Java
[Java] Flow from source code to execution
Call Java from JRuby
Comments in Java source
java (split source file)
Read Java HashMap source
Access API.AI from Java
From Java to Ruby !!
Migration from Cobol to JAVA
Java starting from beginner, override
New features from Java7 to Java8
Connect from Java to PostgreSQL
Java, instance starting from beginner
Java starting from beginner, inheritance
Java life starting from scratch
[Java] Tips for writing source
Using Docker from Java Gradle
From Ineffective Java to Effective Java
JavaScript as seen from Java
Execute non-Java instructions from Java
Call Kotlin's sealed class from Java
Java, abstract classes starting from beginners
Code Java from Emacs with Eclim
Deep Learning Java from scratch 6.4 Regularization
Get country from IP address (Java)
Run node.js from android java (processing)
Run a batch file from Java
[Java] Remove whitespace from character strings
Akka hands-on preparation procedure from Java
Access Teradata from a Java application
Use Chrome Headless from Selenium / Java
Java to be involved from today
Java
From Java to VB.NET-Writing Contrast Memo-
Java overload constructor starting from beginner
Install apache 2.4.46 from source on CentOS7
Java source code reading java.lang.Math class
Work with Google Sheets from Java
Java, interface to start from beginner
Java
The road from JavaScript to Java
Reintroducing Java 8 available from Android Studio 2.4
Call TensorFlow Java API from Scala
[Java] Conversion from array to List
Sample code using Minio from Java
Basic structure of Java source code
Generate source code from JAR file with JD-GUI of Java Decompiler project
What is CHECKSTYLE: OFF found in the Java source? Checkstyle to know from
Note: Differences from Java as seen from C #
Study Deep Learning from scratch in Java.
Java starting from beginner, variables and types
Significance of interface learned from Java Collection
Data processing using stream API from Java 8
Install samba4 from source code on CentOS8
Call Java library from C with JNI
API integration from Java with Jersey Client
Use PostgreSQL data type (jsonb) from Java
Call Java method from JavaScript executed in Java
OCR in Java (character recognition from images)
Get caller information from stack trace (java)
Calling java from C ++ on Android NDK