English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Javaの動的コンパイルおよび実行コードの例

ある場合、動的にjavaコードを生成し、その後コンパイルして実行する必要があります。JAVAAPIは動的コンパイルを実現するためのツール(JavaCompiler)を提供しています。以下に、JavaCompilerを使用してjavaコードを動的コンパイルする方法について簡単な例を紹介します。

1. JavaCompilerを取得する

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

JDKが提供するjavaコンパイラを取得します。コンパイラが提供されていない場合、nullを返します。

2. コンパイル

//javaファイル管理クラスを取得する
StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
//javaファイルオブジェクトのイテレータを取得する
Iterable<? extends JavaFileObject> it = manager.getJavaFileObjects(files);
//コンパイルパラメータを設定します
ArrayList<String> ops = new ArrayList<String>();
ops.add("-Xlint:unchecked");
//classpathを設定する
ops.add("-classpath);
ops.add(CLASS_PATH);
//コンパイルタスクを取得する
JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, ops, null, it);
//コンパイルタスクを実行する
task.call();

コンパイルするソースコードが他のコードを参照している場合、参照コードのパスを設定する必要があります-classpathにない場合、コンパイル失敗します。

3. 実行

//読み込むクラス名
String className = "xxx.xxx.xxx";
//クラスローダーを取得する
ClassLoader classLoader = XXX.class.getClassLoader();
//クラスのロード
Class<?> cls = classLoader.loadClass(className);
//メソッド名を呼び出す
String methodName = "execute";
//メソッドパラメータタイプの配列
Class<?>[] paramCls = {...};
//メソッドを取得
Method method = cls.getDeclaredMethod(methodName , paramCls);
//クラスのインスタンスを作成
Object obj = cls.newInstance();
//メソッドの引数
Object[] params = {...};
//メソッドを呼び出す
Object result = method.invoke(obj, params);

4. 完全なコード

//ClassUtil.java
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class ClassUtil {
	private static final Log logger = LogFactory.getLog(ClassUtil.class);
	private static JavaCompiler compiler;
	static{
		compiler = ToolProvider.getSystemJavaCompiler();
	}
	/**
   * Javaファイルのパスを取得
   * @param file
   * @return
   */
	private static String getFilePath(String file){
		int last1 = file.lastIndexOf('/);
		int last2 = file.lastIndexOf('\');
		return file.substring(0, last1>last2?last1:last2)+File.separatorChar;
	}
	/**
   * javaファイルのコンパイル
   * @param ops 编译パラメータ
   * @param files 编译ファイル
   */
	private static void javac(List<String> ops,String... files){
		StandardJavaFileManager manager = null;
		try{
			manager = compiler.getStandardFileManager(null, null, null);
			Iterable<? extends JavaFileObject> it = manager.getJavaFileObjects(files);
			JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, ops, null, it);
			task.call();
			if(logger.isDebugEnabled()){
				for (String file:files)
				          logger.debug("Compile Java File:") + file);
			}
		}
		catch(Exception e){
			logger.error(e);
		}
		finally{
			if(manager!=null){
				try {
					manager.close();
				}
				catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	/**
   * javaファイルの生成
   * @param file ファイル名
   * @param source Javaコード
   * @throws Exception
   */
	private static void writeJavaFile(String file,String source)throws Exception{
		if(logger.isDebugEnabled()){
			logger.debug("Write Java Source Code to:")+file);
		}
		BufferedWriter bw = null;
		try{
			File dir = new File(getFilePath(file));
			if(!dir.exists())
			        dir.mkdirs();
			bw = new BufferedWriter(new FileWriter(file));
			bw.write(source);
			bw.flush();
		}
		catch(Exception e){
			throw e;
		}
		finally{
			if(bw!=null){
				bw.close();
			}
		}
	}
	/**
   * クラスのロード
   * @param name クラス名
   * @return
   */
	private static Class<?> load(String name){
		Class<?> cls = null;
		ClassLoader classLoader = null;
		try{
			classLoader = ClassUtil.class.getClassLoader();
			cls = classLoader.loadClass(name);
			if(logger.isDebugEnabled()){
				logger.debug("Load Class["+name+"] by \+classLoader);
			}
		}
		catch(Exception e){
			logger.error(e);
		}
		return cls;
	}
	/**
   * コードをコンパイルしてクラスをロード
   * @param filePath Javaコードパス
   * @param source Javaコード
   * @param clsName クラス名
   * @param ops 编译パラメータ
   * @return
   */
	public static Class<?> loadClass(String filePath, String source, String clsName, List<String> ops){
		try {
			writeJavaFile(CLASS_PATH+filePath,source);
			javac(ops,CLASS_PATH+filePath);
			return load(clsName);
		}
		catch (Exception e) {
			logger.error(e);
		}
		return null;
	}
	/**
   * 呼び出しクラスメソッド
   * @param cls 类
   * @param methodName 方法名
   * @param paramsCls 方法参数类型
   * @param params 方法参数
   * @return
   */
	public static Object invoke(Class<?> cls, String methodName, Class<?>[] paramsCls, Object[] params){
		Object result = null;
		try {
			Method method = cls.getDeclaredMethod(methodName, paramsCls);
			Object obj = cls.newInstance();
			result = method.invoke(obj, params);
		}
		catch (Exception e) {
			logger.error(e);
		}
		return result;
	}
}

五、テスト

public class ClassUtilTest {
	private static final Log logger = LogFactory.getLog(ClassUtilTest.class);
	public static void main(String args[]){
		StringBuilder sb = new StringBuilder();
		sb.append("package com.even.test;");
		sb.append("import java.util.Map;\nimport java.text.DecimalFormat;\n");
		sb.append("public class Sum{\n");
		sb.append("private final DecimalFormat df = new DecimalFormat(\"#.#####\");\n");
		sb.append("public Double calculate(Map<String,Double> data){\n");
		sb.append("double d = (30*data.get(\"f1\") + 20*data.get(\"f2\") + 50*data.get(\"f3\"))/100;\n");
		sb.append("return Double.valueOf(df.format(d));}}\n");
		//コンパイルパラメータを設定します
		ArrayList<String> ops = new ArrayList<String>();
		ops.add("-Xlint:unchecked");
		//コードをコンパイルし、classを返します
		Class<?> cls = ClassUtil.loadClass("/com/even/test/Sum.java",sb.toString(),"com.even.test.Sum",ops);
		//テストデータの準備
		Map<String,double> data = new HashMap<String,double>();
		data.put("f1", 10.0);
		data.put("f2", 20.0);
		data.put("f3", 30.0);
		//テストメソッドを実行します
		Object result = ClassUtil.invoke(cls, "calculate", new Class[]{Map.class}, new Object[]{data});
		//出力結果
		logger.debug(data);
		logger.debug("(30*f1+20*f2+50*f3)/100 = "+result);
	}

テスト結果

16:12:02.860 DEBUG com.even.tools.ClassUtil - Write Java Source Code to: .../classes//com/even/test/Sum.java
16:12:03.544 DEBUG com.even.tools.ClassUtil - Compile Java File:.../classes//com/even/test/Sum.java
16:12:03.545 DEBUG com.even.tools.ClassUtil - Load Class[com.even.test.Sum] by sun.misc.Launcher$AppClassLoader@73d16e93
16:12:03.547 DEBUG com.even.test.ClassUtilTest - {f1=10.0, f2=20.0, f3=30.0}
16:12:03.547 DEBUG com.even.test.ClassUtilTest - (30*f1+20*f2+50*f3)/100 = 22.0

まとめ

これで、本文におけるJavaの動的コンパイルおよび実行コードの例示に関するすべての内容が終了しました。皆様に役立つことを願っています。興味を持たれた方、このサイトを参照してください:

javaプログラミングにおける動的コンパイルおよびコードのロードのシェア

Javaの動的計画における編集距離問題の例示コード

Javaの参照と動的プロキシの実現について詳述

不十分な点があれば、コメントを残してください。皆様のこのサイトへのサポートに感謝します。

声明:この記事の内容はインターネットから収集され、著作権者による所有物です。インターネットユーザーにより自発的に貢献し、アップロードされたコンテンツを含みます。このウェブサイトは所有権を持ちません。人間による編集は行われていません。また、関連する法的責任を負いません。著作権侵害を疑う内容がある場合は、以下のメールアドレスまでご連絡ください:notice#oldtoolbag.com(メールを送信する際には、#を@に置き換えてください。報告を行い、関連する証拠を提供してください。一旦確認がとれましたら、このサイトは即座に侵害を疑われるコンテンツを削除します。)

おすすめ