简体   繁体   English

将字符串转换为Java中的代码

[英]Transform string into code in Java

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. 在给定的数据库中,我得到了一个具有VARCHAR字段的记录,因此在我的实体模型中,我添加了此字段,以及getter和setter。 Now is the point where the fun starts: 现在是有趣的开始点:

The string below is in fact a body of a method. 下面的字符串实际上是方法的主体。 It looks like this: 它看起来像这样:

if (score <= 0.7) {return 0;} else if (score <=0.8) {return 1;} else if (score <=0.9) {return 2;} else {return 3}

and now — I need to make this string into a method, and to tell the truth I have no clue how to achieve this. 现在 - 我需要将这个字符串变成一个方法,说实话我不知道如何实现这一点。 This actual method needs to get from me a score as a double, and return an integer value depending on given score. 这个实际的方法需要从我得到一个得分为double,并根据给定的分数返回一个整数值。

Anyone? 任何人?


EDIT 编辑

I know that the easiest way is to not to use solutions like this, but it's not my call, besides, there's a plenty of records like this in the database, and every record is different. 我知道最简单的方法是不使用这样的解决方案,但这不是我的电话,此外,数据库中有大量这样的记录,每条记录都不同。 We cannot move this out. 我们无法解决这个问题。 I have to deal with this — so please, solution ideas only, and I promise that I will do all the hating, and saying it's stupid :) 我必须处理这个问题 - 所以请求解决方案的想法,我保证我会做所有的讨厌,并说这是愚蠢的:)
Trust me, I am, and I do, and I will be doing complaining for quite some time. 相信我,我和我一样,我会抱怨很长一段时间。

Look at the java scripting API 看看java脚本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; 在这里我假设,JavaScript语法是可能的; had to fill in score , you might somewhere intercept all unknown free variables. 不得不填写score ,你可能会在某处拦截所有未知的自由变量。

You should look at the Java Scripting API . 您应该查看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. 有几个实现此API的项目允许您添加运行Java代码脚本的功能。

The best way to do it is using the Scripting API as most answerers already pointed out. 最好的方法是使用Scripting API,正如大多数回答者已经指出的那样。 You can run JavaScript from there. 你可以从那里运行JavaScript。 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. 如果你想要更多并且尝试运行Java代码(并且作为一个eretic指出),你可以尝试使用JavaCompiler编译代码并使用类加载器运行它。

BEWARE: This is one of the most ORRIFIC ways to use Java. 请注意:这是使用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. 这将在类路径中创建一个DontTryThisAtHome.java文件。 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();
}
}

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));
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM