Transform string into code in Java

前端 未结 4 1263
说谎
说谎 2021-02-06 08:47

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

4条回答
  •  旧时难觅i
    2021-02-06 09:09

    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 {
    
            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 diagnostics = new DiagnosticCollector();
            JavaFileObject file = new JavaSourceFromString(className, classBody);
            Iterable 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 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 newProxyInstance(Class 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));
        }
    
    }
    

提交回复
热议问题