代码之家  ›  专栏  ›  技术社区  ›  Searene

JavaCompiler在直接运行main方法时工作,但在运行spring时不工作-boot:run

  •  0
  • Searene  · 技术社区  · 6 年前

    我有一个非常简单的spring boot项目,用于编译 .java 以编程方式将文件 .class 文件。神秘的是,它在运行 main 方法,但在运行时失败 spring-boot:run .

    首先,我将说明我在这个项目中拥有什么:

    编译器.java .java文件 文件到 .类

    package com.example.demo;
    
    import java.io.File;
    import java.io.IOException;
    import javax.tools.*;
    import java.net.URI;
    import java.util.Arrays;
    import java.util.Collections;
    
    public class Compiler {
        public static void compileTestClass() throws IOException {
            Compiler.compile("com.example.TestClass", "package com.example;\n" +
                    "\n" +
                    "import com.google.common.collect.ImmutableMap;\n" +
                    "\n" +
                    "public class TestClass {\n" +
                    "}\n", new File("/tmp"));
        }
        public static void compile(String className, String javaSource, File outputDir) throws IOException {
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
    
            outputDir.mkdirs();
            Iterable<String> options = Arrays.asList("-classpath", System.getProperty("user.home") + "/.m2/repository/com/google/guava/guava/19.0/guava-19.0.jar");
            fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(outputDir));
    
            JavaSourceFromString javaSourceFromString = new JavaSourceFromString(className, javaSource);
            Iterable<? extends JavaFileObject> compilationUnits = Collections.singletonList(javaSourceFromString);
            JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, compilationUnits);
            boolean success = task.call();
            if (!success) {
                throw new RuntimeException("Compilation failed.");
            }
        }
    }
    
    /**
     * A file object used to represent source coming from a string.
     */
    class JavaSourceFromString extends SimpleJavaFileObject {
        /**
         * The source code of this "file".
         */
        final String code;
    
        /**
         * Constructs a new JavaSourceFromString.
         *
         * @param name the name of the compilation unit represented by this file object
         * @param code the source code for the compilation unit represented by this file object
         */
        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;
        }
    }
    

    主控制器.java

    package com.example.demo;
    
    import com.google.common.collect.ImmutableMap;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.io.IOException;
    import java.util.Map;
    
    @RestController
    public class MainController {
        @GetMapping("/compilerTest")
        public Map<String, Object> compilerTest() throws IOException {
            Compiler.compileTestClass();
            return ImmutableMap.of("success", true);
        }
    }
    

    DemoApplicaiton.java ,随SpringBoot Generator一起提供

    package com.example.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class DemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }
    

    我还补充道 com.google.guava-guava-19.0 pom.xml 因为要以编程方式编译的文件需要它。

    1. mvn spring-boot:run

    localhost:8080/compilerTest 开始后,它起了作用。我有一个 {success: true}

    然后我尝试了第二种方法,并尝试访问相同的url localhost:8080/compilerTest 开始后,我这次失败了,我得到了一个错误:

    /com/example/TestClass.java:3: error: package com.google.common.collect does not exist
    import com.google.common.collect.ImmutableMap;
                                    ^
    1 error
    2018-10-02 11:45:06.002 ERROR 43525 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: Compilation failed.] with root cause
    
    java.lang.RuntimeException: Compilation failed.
        at com.example.demo.Compiler.compile(Compiler.java:32) ~[classes/:na]
        at com.example.demo.Compiler.compileTestClass(Compiler.java:12) ~[classes/:na]
        at com.example.demo.MainController.compilerTest(MainController.java:14) ~[classes/:na]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_151]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_151]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_151]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_151]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:891) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.34.jar:8.5.34]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493) [tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800) [tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806) [tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498) [tomcat-embed-core-8.5.34.jar:8.5.34]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.34.jar:8.5.34]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_151]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_151]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.34.jar:8.5.34]
        at java.lang.Thread.run(Thread.java:748) [na:1.8.0_151]
    

    弹簧-boot:run

    1 回复  |  直到 6 年前
        1
  •  0
  •   Searene    6 年前

    Compiler.java ,替换此行:

    Iterable<String> options = Arrays.asList("-classpath", System.getProperty("user.home") + "/.m2/repository/com/google/guava/guava/19.0/guava-19.0.jar");
    

    使用以下方法:

    fileManager.setLocation(StandardLocation.CLASS_PATH, System.getProperty("user.home") + "/.m2/repository/com/google/guava/guava/19.0/guava-19.0.jar");
    

    如果要添加多个类路径,只需使用列表:

    fileManager.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(new File("/tmp/jar1.jar"), new File("/tmp/jar2.jar")));
    

    fileManager.setLocation ,的 -classpath options 在某些情况下是行不通的,我不知道为什么。

    下面是完整的工作源代码 编译器.java ,供日后参考。

    package com.example.demo;
    
    import java.io.File;
    import java.io.IOException;
    import javax.tools.*;
    import java.net.URI;
    import java.util.Arrays;
    import java.util.Collections;
    
    public class Compiler {
        public static void compileTestClass() throws IOException {
            Compiler.compile("com.example.TestClass", "package com.example;\n" +
                    "\n" +
                    "import com.google.common.collect.ImmutableMap;\n" +
                    "\n" +
                    "public class TestClass {\n" +
                    "}\n", new File("/tmp"));
        }
        public static void compile(String className, String javaSource, File outputDir) throws IOException {
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
    
            outputDir.mkdirs();
            fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(outputDir));
            fileManager.setLocation(StandardLocation.CLASS_PATH, System.getProperty("user.home") + "/.m2/repository/com/google/guava/guava/19.0/guava-19.0.jar");
    
            JavaSourceFromString javaSourceFromString = new JavaSourceFromString(className, javaSource);
            Iterable<? extends JavaFileObject> compilationUnits = Collections.singletonList(javaSourceFromString);
            JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, compilationUnits);
            boolean success = task.call();
            if (!success) {
                throw new RuntimeException("Compilation failed.");
            }
        }
    }
    
    /**
     * A file object used to represent source coming from a string.
     */
    class JavaSourceFromString extends SimpleJavaFileObject {
        /**
         * The source code of this "file".
         */
        final String code;
    
        /**
         * Constructs a new JavaSourceFromString.
         *
         * @param name the name of the compilation unit represented by this file object
         * @param code the source code for the compilation unit represented by this file object
         */
        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;
        }
    }