3

A simple unit test (without junit) gives weird exception

import java.io.StringReader;
import java.sql.PreparedStatement;

import org.codehaus.janino.SimpleCompiler;

public class TestJanino {
    public void testJanino() throws Exception {
        PreparedStatement ps = null;
        String sampleClass = "import java.sql.PreparedStatement; public class Test{}";
        SimpleCompiler sc = new SimpleCompiler();
        sc.setParentClassLoader(getClass().getClassLoader());
        sc.cook("Test.java", new StringReader(sampleClass));
        System.out.println(sc.getBytecodes().size());
    }

    public static void main(String[] args) throws Exception {
        TestJanino d = new TestJanino();
        d.testJanino();
    }
}

Message is:

[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ xx.xxx.server.nn ---
[WARNING] useSystemClassloader setting has no effect when not forking
[INFO] Surefire report directory: D:\workspace\XXXX\xx.xxx.server.nn\target\surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running xx.xxx.server.nn.TestJanino
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.057 sec <<< FAILURE!
xx.xxx.server.nn.TestJanino.testJanino()  Time elapsed: 0.056 sec  <<< FAILURE!
org.codehaus.commons.compiler.CompileException: File 'Test.java', Line 1, Column 1: A class "java.sql.PreparedStatement" could not be found
        at org.codehaus.janino.UnitCompiler.compileError(UnitCompiler.java:12679)
        at org.codehaus.janino.UnitCompiler.getSingleTypeImport(UnitCompiler.java:10639)
        at org.codehaus.janino.UnitCompiler.checkForConflictWithSingleTypeImport(UnitCompiler.java:454)
        at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:410)
        at org.codehaus.janino.UnitCompiler.access$400(UnitCompiler.java:231)
        at org.codehaus.janino.UnitCompiler$2.visitPackageMemberClassDeclaration(UnitCompiler.java:391)
        at org.codehaus.janino.UnitCompiler$2.visitPackageMemberClassDeclaration(UnitCompiler.java:386)
        at org.codehaus.janino.Java$PackageMemberClassDeclaration.accept(Java.java:1692)
        at org.codehaus.janino.UnitCompiler.compile(UnitCompiler.java:386)
        at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:359)
        at org.codehaus.janino.UnitCompiler.access$000(UnitCompiler.java:231)
        at org.codehaus.janino.UnitCompiler$1.visitCompilationUnit(UnitCompiler.java:333)
        at org.codehaus.janino.UnitCompiler$1.visitCompilationUnit(UnitCompiler.java:330)
        at org.codehaus.janino.Java$CompilationUnit.accept(Java.java:367)
        at org.codehaus.janino.UnitCompiler.compileUnit(UnitCompiler.java:330)
        at org.codehaus.janino.SimpleCompiler.cook(SimpleCompiler.java:245)
        at org.codehaus.janino.SimpleCompiler.compileToClassLoader(SimpleCompiler.java:473)
        at org.codehaus.janino.SimpleCompiler.cook(SimpleCompiler.java:223)
        at org.codehaus.janino.SimpleCompiler.cook(SimpleCompiler.java:209)
        at xx.xxx.server.nn.TestJanino.testJanino(TestJanino.java:14)


Results :

Failed tests:   xx.xxx.server.nn.TestJanino.testJanino(): File 'Test.java', Line 1, Column 1: A class "java.sql.PreparedStatement" could not be found

Tests run: 1, Failures: 1, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.738 s
[INFO] Finished at: 2021-12-14T07:52:08+01:00
[INFO] ------------------------------------------------------------------------

But if I run the main without maven it resolves:

enter image description here

How is that possible?

This is my pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>xx.xxx</groupId>
    <version>xxx-SNAPSHOT</version>
    <properties>
        <forkMode>never</forkMode>
    </properties>
    <artifactId>xxx</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.codehaus.janino</groupId>
            <artifactId>janino</artifactId>
            <version>3.1.6</version>
        </dependency>
    </dependencies>
</project>
Grim
  • 1,938
  • 10
  • 56
  • 123
  • 1
    I tested your code and it seems to work properly. Please, could you provide in your question further details about your `pom.xml` and the SDK you are using? The issue may be related to the classpath surefire is providing to your test. You seem to be running your test in a [non forked mode](https://maven.apache.org/surefire/maven-surefire-plugin/examples/class-loading.html) and it has influence in `useSystemClassloader` and the actual class loading. You could try tweaking that. In addition, to see if the problem has to do with surefire, try running your program from a different plugin... – jccampanero Jan 07 '22 at 13:50
  • like the [`exec-maven-plugin`](https://www.mojohaus.org/exec-maven-plugin/index.html) and see if it works. I hope it helps. – jccampanero Jan 07 '22 at 13:51
  • Thank you very much for the feedback @Grim. As I told in my previous comment, and although in my tests the test always runs successfully, I think the problem is related to surefire and the class loader used by Janino. Please, could you try removing the `forkMode` configuration and see if it works? As indicated in the documentation I linked before, it has influence in the surefire class loading mechanism. Please, could you indicate the maven and SDK versions you are using? – jccampanero Jan 08 '22 at 11:19

1 Answers1

3

I finally was able to reproduce your issue with Java 11 and Maven 3.8.

As indicated in the question comments, the problem seems to be related to the fact that the Maven surefire plugin is not using the system class loader. Please, consider read the relevant documentation.

You can verify that point using the following plugin configuration:

<build>
    <plugins>
       <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.12.4</version>
            <configuration>
                <useSystemClassLoader>false</useSystemClassLoader>
            </configuration>
       </plugin>
    </plugins>
</build>

You are not providing this configuration explicitly but as indicated in the Maven trace:

...
[WARNING] useSystemClassloader setting has no effect when not forking
...

you aren't using forking, which is coherent with the configuration provided in your pom.xml:

<properties>
    <forkMode>never</forkMode>
</properties>

In order to solve the problem you could remove that configuration, and the test will run without further problems.

Having said that, as I said in the comments as well, I tested the code with different Maven versions and JDK 8 and it worked even setting useSystemClassloader to false, so I honestly cannot tell you the exact reason of the problem, probably it may have to do with the JDK version, but it could be the Maven version or even Janino as well.

jccampanero
  • 50,989
  • 3
  • 20
  • 49