"Execute Immediate" in Java
PL/SQL中可以用"Execute Immediate"来动态执行SQL或者PL/SQL代码,在有些时候用起来很方便。比如说我要动态创建一个Package,我可以用Excecute Immediate来执行"create or replace package xxx” 来创建一个package, 然后甚至可以执行package里面定义的procedure/function。
Java6中提供的动态编译Java类的功能,然后再借助反射机制,可以很容易实现上面说的类似PL/SQL中的Execute Immediate的功能。比如说如下这个例子...
package com.moodys.fang.play;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.List;
import javax.tools.JavaCompiler;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
/**
* @author YuFa
*
*/
public class MyCalculator {
static class StringSourceJavaObject extends SimpleJavaFileObject {
private String content = null;
public StringSourceJavaObject(String name, String content) throws URISyntaxException {
super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE);
this.content = content;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return content;
}
}
static class MyClassLoader extends ClassLoader {
public Class loadClass(final String className, final String classFileURL) throws ClassNotFoundException {
try {
URL classUrl = new URL(classFileURL);
URLConnection connection = classUrl.openConnection();
InputStream input = connection.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int data = input.read();
while(data != -1) {
buffer.write(data);
data = input.read();
}
input.close();
byte[] classData = buffer.toByteArray();
return defineClass(className, classData, 0, classData.length);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
private static boolean compileSource(final String className, final String source) throws URISyntaxException, IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
StringSourceJavaObject sourceObject = new MyCalculator.StringSourceJavaObject(className, source);
List<StringSourceJavaObject> fileObjects = Arrays.asList(sourceObject);
CompilationTask task = compiler.getTask(null, fileManager, null, null, null, fileObjects);
return task.call();
}
public static double calculate(final String expr) throws Exception {
final String className = "CalculatorMain";
final String methodName = "calculate";
String source = "public class " + className
+ " { public static double " + methodName + "() {" +
" return " + expr + ";" +
"} " +
"}";
boolean result = compileSource(className, source);
if (result) {
MyClassLoader loader = new MyClassLoader();
Class<?> clazz = loader.loadClass(className, "file:///" + System.getProperty("user.dir").replace('\\', '/') + "/" + className + ".class");
Method method = clazz.getMethod(methodName, new Class<?>[] {});
Object value = method.invoke(null, new Object[] {});
return (Double)value;
}
throw new Exception("Failed to compile the source code!");
}
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception{
System.out.println(calculate("(4+3.3)/5"));
}
}
MyCalculator主要是借助动态生成的类来进行算术表达式的计算,这样就不需要写代码去解析表达式了,而是把这些事情全都交给 JVM来搞定。
--------------------------------------
Regards,
FangwenYu