I got a strange case. In the given database, I got a record that has a VARCHAR
field, so in my entity model I added this field, plus getters and setters. Now is the
Look at the java scripting API
int eval(String code) {
code = "function f () {" + code + "} f()"; // Or otherwise
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.put("score", 1.4);
Number num = (Number) engine.eval(code);
return num.intValue();
}
Here I assumed, that JavaScript syntax is possible; had to fill in score
, you might
somewhere intercept all unknown free variables.
I think a better solution is to change your architecture, but If you are forced to it try the following :) This code you can find here
public class DynamicProxy {
public interface CalculateScore {
double calculate(double score);
}
private static class JavaSourceFromString extends SimpleJavaFileObject {
final String code;
JavaSourceFromString(String name, String code) {
super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
this.code = code;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return code;
}
}
private static class JavaClassObject extends SimpleJavaFileObject {
protected final ByteArrayOutputStream bos = new ByteArrayOutputStream();
public JavaClassObject(String name, Kind kind) {
super(URI.create("string:///" + name.replace('.', '/') + kind.extension), kind);
}
public byte[] getBytes() {
return bos.toByteArray();
}
@Override
public OutputStream openOutputStream() throws IOException {
return bos;
}
}
private static class ClassFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
private JavaClassObject classObject;
private final String className;
public ClassFileManager(StandardJavaFileManager standardManager, String className) {
super(standardManager);
this.className = className;
}
@Override
public ClassLoader getClassLoader(Location location) {
return new SecureClassLoader(DynamicProxy.class.getClassLoader()) {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (name.contains(className)) {
byte[] b = classObject.getBytes();
return super.defineClass(name, classObject.getBytes(), 0, b.length);
}
return super.findClass(name);
}
};
}
@Override
public JavaFileObject getJavaFileForOutput(Location location, String className, javax.tools.JavaFileObject.Kind kind, FileObject sibling) throws IOException {
classObject = new JavaClassObject(className, kind);
return classObject;
}
}
private static class MyInvocationHandler implements InvocationHandler {
private final String className;
private final String classBody;
public MyInvocationHandler(String implClassName, String classBody) {
this.className = implClassName;
this.classBody = classBody;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Class<?> clazz = compileClass(className, classBody);
return method.invoke(clazz.newInstance(), args);
}
}
private static Class<?> compileClass(String className, String classBody) throws Throwable {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
JavaFileObject file = new JavaSourceFromString(className, classBody);
Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file);
JavaFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(null, null, null), className);
CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits);
boolean success = task.call();
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
System.out.println(diagnostic.getCode());
System.out.println(diagnostic.getKind());
System.out.println(diagnostic.getPosition());
System.out.println(diagnostic.getStartPosition());
System.out.println(diagnostic.getEndPosition());
System.out.println(diagnostic.getSource());
System.out.println(diagnostic.getMessage(null));
}
if (success) {
return fileManager.getClassLoader(null).loadClass(className);
}
return null;
}
@SuppressWarnings("unchecked")
public static <T> T newProxyInstance(Class<T> clazz, String className, String classBody) {
ClassLoader parentLoader = DynamicProxy.class.getClassLoader();
return (T) Proxy.newProxyInstance(parentLoader, new Class[] { clazz }, new MyInvocationHandler(className, classBody));
}
public static CalculateScore create(String body) {
StringWriter writer = new StringWriter();
PrintWriter out = new PrintWriter(writer);
out.println("public class CalculateScoreImpl implements pl.softech.stackoverflow.javac.DynamicProxy.CalculateScore {");
out.println(" public double calculate(double score) {");
out.println(body);
out.println(" }");
out.println("}");
out.close();
return newProxyInstance(CalculateScore.class, "CalculateScoreImpl", writer.toString());
}
public static void main(String[] args) {
CalculateScore calculator = create("if (score <= 0.7) {return 0;} else if (score <=0.8) {return 1;} else if (score <=0.9) {return 2;} else {return 3; }");
System.out.println(calculator.calculate(0.3));
}
}
The best way to do it is using the Scripting API as most answerers already pointed out. You can run JavaScript from there. If you want to dare more and try to run Java code (and get pointed at as an eretic) you can try to compile code with JavaCompiler
and the run it using a class loader.
BEWARE: This is one of the most ORRIFIC ways to use Java. You should use this only to debug and only as last hope. In no way at all you should use this in a production environment.
This will create a DontTryThisAtHome.java
file in your classpath. Remeber to use this strategy only for fun and very few other cases:
public class MyClass{
public static void main(String[] args) throws Exception {
JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager sjfm = jc.getStandardFileManager(null, null, null);
File jf = new File("DontTryThisAtHome.java");
PrintWriter pw = new PrintWriter(jf);
pw.println("public class DontTryThisAtHome{"
+ "static final int score = " + <your_score> + ";"
+ "public static void main(){}"
+ "public int getValue(){"
+ " return score<=0.7?0:score<=0.8?1: score<=0.9?2:3"
+ "}
+ "}");
pw.close();
Iterable<? extends JavaFileObject> fO = sjfm.getJavaFileObjects(jf);
if(!jc.getTask(null,sjfm,null,null,null,fO).call()) {
throw new Exception("compilation failed");
}
URL[] urls = new URL[]{new File("").toURI().toURL()};
URLClassLoader ucl = new URLClassLoader(urls);
Object o= ucl.loadClass("DontTryThisAtHome").newInstance();
int result = (int) o.getClass().getMethod("getValue").invoke(o);
ucl.close();
}
}
You should look at the Java Scripting API. There are a couple of projects which implement this API to allow you to add the ability to run scripts your Java code.