Compile a dynamic Java class web project

I am developing a web application where I can import Java code, compile and execute it. This class may have some imports from other libraries that I added to my classpath. Running it as a desktop application, it works, but works under wildfly 9.0.2, it does not find my classpath libraries, and therefore I have errors for compiling my code.

Do I need to change any settings in the wildfly configuration? I tried my code with and without maven.

I use this library to compile my code, and as I said, it worked using an application such as the desktop: https://github.com/trung/InMemoryJavaCompiler

Errors:

13:44:57,686 ERROR [stderr] (default task-5) /br/com/project/webtest/service/CompileClass.java:2: error: package org.junit does not exist 13:44:57,686 ERROR [stderr] (default task-5) import static org.junit.Assert.*; 13:44:57,686 ERROR [stderr] (default task-5) ^ 13:44:57,687 ERROR [stderr] (default task-5) /br/com/project/webtest/service/CompileClass.java:3: error: cannot find symbol 13:44:57,687 ERROR [stderr] (default task-5) import br.com.project.webtest.service.SeleniumService; 13:44:57,688 ERROR [stderr] (default task-5) ^ 13:44:57,688 ERROR [stderr] (default task-5) symbol: class SeleniumService 13:44:57,688 ERROR [stderr] (default task-5) location: package br.com.project.webtest.service 13:44:57,689 ERROR [stderr] (default task-5) /br/com/project/webtest/service/CompileClass.java:4: error: package org.junit does not exist 13:44:57,689 ERROR [stderr] (default task-5) import org.junit.*; 

Error messages continue when everyone else imports the libraries and then, classformaterror:

 13:44:57,751 WARNING [javax.enterprise.resource.webcontainer.jsf.lifecycle] (default task-5) #{testController.action()}: java.lang.ClassFormatError: Truncated class file: javax.faces.FacesException: #{testController.action()}: java.lang.ClassFormatError: Truncated class file 

Edit: I added, using eclipse mars, in the Webcontent / web-inf / lib folder, added my libraries and right-clicked, added to the build path.

Edit 2: The class is responsible for creating the code and gets the result:

 package br.com.test; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Paths; import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; @ManagedBean @SessionScoped public class TestController { public void actionParent() { String javaCode = generateJavaCode(); Class<?> compile = null; try { compile = InMemoryCompilerTest.compile(Thread.currentThread().getContextClassLoader(), "br.com.project.webtest.service.CompileClass", javaCode); System.out.println("Worked: " + compile); } catch (Exception e) { e.printStackTrace(); } } public void actionClassLoader() { String javaCode = generateJavaCode(); Class<?> compile = null; try { compile = InMemoryCompilerTest.compile("br.com.project.webtest.service.CompileClass", javaCode); System.out.println("Worked: " + compile); } catch (Exception e) { e.printStackTrace(); } } static String readFile(String path, Charset encoding) throws IOException { byte[] encoded = Files.readAllBytes(Paths.get(path)); return new String(encoded, encoding); } private static String generateJavaCode() { String java = "package br.com.project.webtest.service;\r\n" + "import static org.junit.Assert.*;\r\n" + "public class CompileClass {\r\n" + " public CompileClass() {\r\n" + " System.out.println(\"Dynamically compiled\");\r\n" + " String text = \"Testing JUnit lib\";\r\n" + " assertEquals(\"Testing JUnit lib\", text);\r\n" + " System.out.println(\"completed\");\r\n" + " }\r\n" + " public static void main(String[] args) {\r\n" + " new CompileClass();\r\n" + " System.out.println(\"finish\");\r\n" + " }\r\n" + "}\r\n"; return java; } public static void main(String[] args) { TestController c = new TestController(); c.actionClassLoader(); c.actionParent(); } } 

I created a class that extends lib and changes the use of the parent class loader:

 public class InMemoryCompilerTest extends InMemoryJavaCompiler { static JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); public static Class<?> compile(ClassLoader parent, String className, String sourceCodeInText) throws Exception { SourceCode sourceCode = new SourceCode(className, sourceCodeInText); CompiledCode compiledCode = new CompiledCode(className); Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(sourceCode); DynamicClassLoader cl = new DynamicClassLoader(parent); ExtendedStandardJavaFileManager fileManager = new ExtendedStandardTest( javac.getStandardFileManager(null, null, null), compiledCode, cl); JavaCompiler.CompilationTask task = javac.getTask(null, fileManager, null, null, null, compilationUnits); boolean result = task.call(); return cl.loadClass(className); } } public class ExtendedStandardTest extends ExtendedStandardJavaFileManager{ protected ExtendedStandardTest(JavaFileManager fileManager, CompiledCode compiledCode, DynamicClassLoader cl) { super(fileManager, compiledCode, cl); } } 

XHTML:

 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <h:head></h:head> <h:body> <h:form> <h:commandButton action="#{testController.actionClassLoader()}" value="ClassLoader" /> <h:commandButton action="#{testController.actionParent()}" value="Parent" /> </h:form> </h:body> </html> 

I tested passing the parent classloader as you are sugested, but also did not work.

The first class is "TestController", executed from the main method that it works.

Edit:

I added the following code where I can set the classpath with my libs:

 // set the classpath List<String> options = new ArrayList<String>(); options.add("-classpath"); StringBuilder sb = new StringBuilder(); URLClassLoader urlClassLoader = (URLClassLoader) parent; for (URL url : urlClassLoader.getURLs()) { sb.append(url.getFile()).append(File.pathSeparator); } options.add(sb.toString()); 

Executing as a Java application returns:

 [-classpath, /C:/Users/dev/Automacao/workspace/test/build/classes/;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/InMemoryJavaCompiler-1.2.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/commons-io-2.5.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/client-combined-3.0.0-beta3-nodeps.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/commons-codec-1.10.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/commons-exec-1.3.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/commons-logging-1.2.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/gson-2.3.1.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/guava-19.0.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/hamcrest-core-1.3.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/hamcrest-library-1.3.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/httpclient-4.5.2.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/httpcore-4.4.4.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/httpmime-4.5.2.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/jna-4.1.0.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/jna-platform-4.1.0.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/junit-4.12.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/netty-3.5.7.Final.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/phantomjsdriver-1.3.0.jar;/C:/Users/dev/Automacao/workspace/test/WebContent/WEB-INF/lib/workspace_libs/cglib-nodep-3.2.4.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/annotations-api.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/catalina-ant.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/catalina-ha.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/catalina-storeconfig.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/catalina-tribes.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/catalina.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/ecj-4.3.1.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/el-api.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/jasper-el.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/jasper.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/jsp-api.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/servlet-api.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/tomcat-api.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/tomcat-coyote.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/tomcat-dbcp.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/tomcat-i18n-es.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/tomcat-i18n-fr.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/tomcat-i18n-ja.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/tomcat-jdbc.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/tomcat-jni.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/tomcat-spdy.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/tomcat-util-scan.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/tomcat-util.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/tomcat-websocket.jar;/C:/Program%20Files/Apache%20Software%20Foundation/Apache%20Tomcat%208.0.3/lib/websocket-api.jar;/C:/Users/dev/Automacao/workspace/libraries/JSF%202.2%20(Mojarra%202.2.0)/mojarra-2.2.0-FCS/lib/javax.faces.jar;] 

Execution as a web application:

 [-classpath, /C:/Users/dev/Automacao/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/test/WEB-INF/classes/;/C:/Users/dev/Automacao/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/test/WEB-INF/lib/commons-io-2.5.jar;/C:/Users/dev/Automacao/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/test/WEB-INF/lib/InMemoryJavaCompiler-1.2.jar;/C:/Users/dev/Automacao/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/test/WEB-INF/lib/javax.faces.jar;] 

How can I get the same result?

+1
source share
2 answers

Get a job.

I have to make this change, mentioned by @NicolasFilotto, to use the parent class loader when using webapp. After that, to work with JavaCompiler, since I use external libraries, I need to pass my classpath, as indicated in my last edit. Basically the code has changed to:

 public static Class<?> compile(ClassLoader parent, String className, String sourceCodeInText) throws Exception { SourceCode sourceCode = new SourceCode(className, sourceCodeInText); CompiledCode compiledCode = new CompiledCode(className); Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(sourceCode); DynamicClassLoader cl = new DynamicClassLoader(parent); ExtendedStandardJavaFileManager fileManager = new ExtendedStandard( javac.getStandardFileManager(null, null, null), compiledCode, cl); // set the classpath List<String> options = new ArrayList<String>(); options.add("-classpath"); StringBuilder sb = new StringBuilder(); Enumeration<URL> resources = parent.getResources("/"); while (resources.hasMoreElements()) { URL url = resources.nextElement(); sb.append(url.getFile()).append(File.pathSeparator); } options.add(sb.toString()); // execute the compiler Boolean call = javac.getTask(null, fileManager, null, options, null, compilationUnits).call(); if (call) { return cl.loadClass(className); } return null; } 

Using wildfly I had to change URLClassLoader urlClassLoader = (URLClassLoader) parent; on Enumeration<URL> resources = parent.getResources("/");

+1
source

@VictorBello I already implement these functions in Dynamic Loader . Even you can enable jar at runtime dynamic loader

 public void DynamicJarCodeTest() throws Exception { try { StringBuilder sourceCode = new StringBuilder(); sourceCode.append("package org.dvare.dynamic;\n"); sourceCode.append("import org.apache.commons.math3.Field;\n"); sourceCode.append("public class SourceClass {\n"); sourceCode.append(" public String test() { \n"); sourceCode.append(" return \"inside test method\";\n"); sourceCode.append(" }\n"); sourceCode.append("}"); DynamicCompiler dynamicCompiler = new DynamicCompiler(); dynamicCompiler.setSeparateContext(true); dynamicCompiler.setUpdateContextClassLoader(false); dynamicCompiler.addJar(getClass().getClassLoader().getResource("commons-math3.jar")); dynamicCompiler.addSource("org.dvare.dynamic.SourceClass", sourceCode.toString()); dynamicCompiler.build(); Class aClass = Class.forName("org.apache.commons.math3.Field", false, dynamicCompiler.getClassLoader()); Assert.assertNotNull(aClass); Class bClass = Class.forName("org.dvare.dynamic.SourceClass", false, dynamicCompiler.getClassLoader()); Assert.assertNotNull(bClass); } catch (DynamicCompilerException e) { System.out.println(e.getErrorList()); } catch (Exception e) { e.printStackTrace(); } } 
0
source

All Articles