我遇到了一个奇怪的案子。在给定的数据库中,我得到了一个具有VARCHAR
字段的记录,因此在我的实体模型中,我添加了此字段,以及getter和setter。现在是乐趣开始的地方:
下面的字符串实际上是方法的主体。它看起来像这样:
if (score <= 0.7) {return 0;} else if (score <=0.8) {return 1;} else if (score <=0.9) {return 2;} else {return 3}
现在 - 我需要将这个字符串变成一个方法,说实话我不知道如何实现这一点。这个实际的方法需要从我那里得到一个双倍的分数,并根据给定的分数返回一个整数值。
任何?
我知道最简单的方法是不使用这样的解决方案,但这不是我的电话,此外,数据库中还有大量这样的记录,而且每条记录都不同。我们无法解决这个问题。我必须处理这个问题 - 所以请求解决方案的想法,我保证我会做所有的讨厌,并说它是愚蠢的:) 相信我,我和我一样,我会抱怨很长一段时间。
答案 0 :(得分:16)
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();
}
这里我假设,JavaScript语法是可能的;你可能必须填写score
在某处拦截所有未知的自由变量。
答案 1 :(得分:6)
您应该查看Java Scripting API。有几个实现此API的项目允许您添加运行Java代码脚本的功能。
答案 2 :(得分:1)
最好的方法是使用Scripting API,因为大多数回答者已经指出过。你可以从那里运行JavaScript。如果您想要更多并且尝试运行Java代码(并且作为一个eretic指出),您可以尝试使用JavaCompiler
编译代码并使用类加载器运行它。
请注意:这是使用Java的最常用的方法之一。你应该只使用它来调试,只作为最后的希望。绝对不应该在生产环境中使用它。
这将在类路径中创建一个DontTryThisAtHome.java
文件。记住只能将此策略用于娱乐和极少数其他情况:
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();
}
}
答案 3 :(得分:1)
我认为更好的解决方案是更改您的架构,但如果您被迫尝试以下内容:)您可以找到此代码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));
}
}