Évaluer la source Java à partir de Java

Récemment, j'ai développé une application Java qui analyse le code source Java dans mon entreprise, mais il y a eu des cas où je voulais évaluer une partie du code source à analyser. J'ai donc évalué le code source Java et étudié légèrement comment obtenir les résultats.

Veuillez vous référer à tanzaku / eval \ -java \ -code pour le code source utilisé dans l'expérience. Le maître contient le code de test JDK10 et la branche eval_jdk8 contient le code de test JDK8.

Comment utiliser l'API Java Compiler

Vous pouvez obtenir une instance de Class par la méthode comme indiqué sur le site ci-dessous, afin de pouvoir l'évaluer en exécutant la méthode avec réflexion. Mémo de classe du compilateur Java \ (Mémo du compilateur Java de Hishidama )

Si vous ne souhaitez pas effectuer de personnalisations détaillées, il peut être plus facile d'utiliser une bibliothèque comme celle ci-dessous. OpenHFT/Java-Runtime-Compiler: Java Runtime Compiler

Comment évaluer en tant que script Groovy

Il peut être évalué simplement en appelant ScriptEngine # eval comme indiqué ci-dessous. (groovy-all doit être ajouté au chemin de classe)

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();
	}
}

Cependant, sachez que le code source Java peut ne pas être un script Groovy valide tel quel. Par exemple, une expression comme new String [] {" A "} doit être invalide dans groovy et comme [" A "] as String [].

Comment évaluer par JShell

Il peut être évalué à l'aide de l'API JShell ajoutée à 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()) {
			//Il semble que plusieurs déclarations ne peuvent pas être évaluées à la fois, alors évaluez-les séparément.
			return splitStatements(sourceCode)
						.flatMap(stmt -> jshell.eval(stmt).stream())
						.reduce((a,b)->b)
						.map(SnippetEvent::value)
						.orElse(null);
		}
	}
}

Comparaison du temps de traitement

Le temps de traitement évalué par chaque méthode a été mesuré. Nous mesurons le temps nécessaire pour évaluer 100 fois un petit processus. Les 100 opérations sont légèrement différentes de sorte qu'elles ne sont pas mises en cache. Veuillez vous référer au code source pour plus de détails.

Méthode JDK ver temps de traitement[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

Le code source est concis, et il semble qu'il ne soit pas inférieur en vitesse, il semble donc bon de l'évaluer avec groovy. Cependant, dans tous les cas, c'est définitivement un processus très lourd, il semble donc difficile de l'utiliser beaucoup. Bien sûr, si la version du compilateur change, les performances changeront, soyez donc prudent lors de la mise à niveau.

Recommended Posts

Évaluer la source Java à partir de Java
[Java] Flux du code source à l'exécution
Appeler Java depuis JRuby
Commentaires dans la source Java
java (fichier source fractionné)
Lire la source Java HashMap
Accédez à API.AI depuis Java
De Java à Ruby !!
Migration de Cobol vers JAVA
Java à partir du débutant, remplacer
Nouvelles fonctionnalités de Java7 à Java8
Connectez-vous de Java à PostgreSQL
Java, instance à partir du débutant
Java à partir de débutant, héritage
La vie Java à partir de zéro
[Java] Conseils pour l'écriture de la source
Utilisation de Docker depuis Java Gradle
De Java inefficace à Java efficace
JavaScript vu de Java
Exécuter des instructions non-Java à partir de Java
Appeler la classe scellée de Kotlin depuis Java
Java, classe abstraite pour commencer par débutant
Coder Java depuis Emacs avec Eclim
Deep Learning Java from scratch 6.4 Régularisation
Obtenir le pays à partir de l'adresse IP (Java)
Exécutez node.js depuis Android Java (traitement)
Exécuter le fichier de commandes à partir de Java
[Java] Supprimer les espaces dans les chaînes de caractères
Procédure de préparation pratique d'Akka à partir de Java
Accéder à Teradata depuis une application Java
Utiliser Chrome Headless de Selenium / Java
Java sera impliqué dès aujourd'hui
Java
De Java à VB.NET - Écriture de notes de contraste
Java, constructeur de surcharge à partir du débutant
Installez apache 2.4.46 à partir des sources sur CentOS 7
Code source Java lecture de la classe java.lang.Math
Travailler avec des feuilles de calcul Google à partir de Java
Java, interface pour partir du débutant
Java
La route de JavaScript à Java
Réintroduction de Java8, disponible depuis Android Studio 2.4
Appelez l'API Java de TensorFlow depuis Scala
[Java] Conversion d'un tableau à une liste
Exemple de code utilisant Minio de Java
Structure de base du code source Java
Générer le code source à partir du fichier JAR avec JD-GUI du projet Java Decompiler
Qu'est-ce que CHECKSTYLE: OFF trouvé dans la source Java? Checkstyle à savoir de
Étudiez le Deep Learning à partir de zéro en Java.
Java pour les débutants, les variables et les types
Importance de l'interface apprise de la collection Java
Traitement des données à l'aide de l'API de flux de Java 8
Installez samba4 à partir du code source sur CentOS8
Appeler la bibliothèque Java à partir de C avec JNI
Intégration API de Java avec Jersey Client
Utiliser le type de données PostgreSQL (jsonb) à partir de Java
Appel de méthodes Java à partir de JavaScript exécutées en Java
OCR en Java (reconnaissance de caractères à partir d'images)
Obtenir des informations sur l'appelant à partir de la trace de la pile (Java)
Appeler java depuis C ++ sur Android NDK