"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来搞定。 

posted @ 2011-10-13 19:52  FangwenYu  阅读(597)  评论(0编辑  收藏  举报