talk to frank
talk to frank

Reputation: 1871

Different maven compiler versions for test and main

How can I configure the maven compiler to use java 5 for my test code and java 1.4 for my main code?

Upvotes: 34

Views: 15173

Answers (3)

Eddie Deng
Eddie Deng

Reputation: 1479

I found a solution at least for my case.

I am writing a library that needs to be Java 1.7 compatible but relies on the nashorn engine in JDK 8 to test some of its features, which is a perfect reason for using different compiler/jdk version for main and test.

When talking about using different compiler/JRE version for main and test, say version A for main and version B for test and A is strictly smaller than B, we really want to achieve the following:

  1. Make the IDE (in my case, the Eclipse) use the JDK version B during development for not introducing compilation error (red cross on your project icon).
  2. Make JUnit tests runnable from within your IDE.
  3. Make JUnit tests runnable from command line through mvn clean test which is required for releasing.
  4. Compile sources in main using JRE A, which enables automatic detection of using new features from JDK B.
  5. Free use of new features / new APIs from JDK B in test cases codes.

And the following pom declaration works (for example let A = 1.7 and B = 1.8):

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <fork>true</fork>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
                <executions>
                   <execution>
                      <id>default-compile</id>
                      <configuration>
                         <compilerArguments>
                            <source>1.7</source>
                            <target>1.7</target>
                         </compilerArguments>
                      </configuration>
                   </execution>
                   <execution>
                      <id>default-testCompile</id>
                      <configuration>
                         <compilerArguments>
                            <source>1.8</source>
                            <target>1.8</target>
                         </compilerArguments>
                      </configuration>
                   </execution>
                </executions>
            </plugin>

Firstly, <source>1.8</source> <target>1.8</target> is a must to make Eclipse happy and using 1.8 for the project itself, as others pointed out that Eclipse has a still pending bug and does not support different JDK version in a single project natively.

Secondly, use <execution> to override the source and target arguments during source compilation and test source compilation. default-compile and default-testCompile are special names for compiler plugin.

Thirdly, be sure to use compilerArguments but not compilerArgs. As far as I know, only compilerArguments can be used to override argument settings during runtime.

Upvotes: 1

Gerald M&#252;cke
Gerald M&#252;cke

Reputation: 11132

I had no luck with the accepted answer compiling java 7 source and java 8 test sources using the maven-compiler-plugin, version 3.5.1. Because the compile plugin used the source / target parameter for both, main and test sources.

But I found out, there are separate configuration parameters for the test source and target.

So for me the solution that worked was

 <build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
                <testSource>1.8</testSource>
                <testTarget>1.8</testTarget>
            </configuration>
        </plugin>
    </plugins>
</build>

Upvotes: 23

Rich Seller
Rich Seller

Reputation: 84038

If you want to set compliance to the relevant Java version, you can configure the compiler plugin for each execution. Assuming Maven is using a JDK at least as current as the highest version you specify. By using properties you can override that configuration on the commandline or in a child if needed:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>${compileSource}</source>
    <target>${compileSource}</target>
  </configuration>
  <executions>
    <execution>
      <id>test-compile</id>
      <phase>process-test-sources</phase>
      <goals>
        <goal>testCompile</goal>
      </goals>
      <configuration>
        <source>${testCompileSource}</source>
        <target>${testCompileSource}</target>
      </configuration>
    </execution>
  </executions>
</plugin>
...
<properties>
  <compileSource>1.4</compileSource>
  <testCompileSource>1.5</testCompileSource>
</properties>

If you mean using different compilers, that's a bit more involved. as you need to specify the path to the JDK and what compiler version you're using. Again these can be defined in properties. Though you may want to define them in your settings.xml

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>${compileSource}</source>
    <target>${compileSource}</target>
    <executable>${compileJdkPath}/bin/javac</executable>
    <compilerVersion>${compileSource}</compilerVersion>
  </configuration>
  <executions>
    <execution>
      <id>test-compile</id>
      <phase>process-test-sources</phase>
      <goals>
        <goal>testCompile</goal>
      </goals>
      <configuration>
        <source>${testCompileSource}</source>
        <target>${testCompileSource}</target>
        <executable>${testCompileJdkPath}/bin/javac</executable>
        <compilerVersion>${testCompileSource}</compilerVersion>
      </configuration>
    </execution>
  </executions>
</plugin>
...
<properties>
  <compileSource>1.4</compileSource>
  <testCompileSource>1.5</testCompileSource>
  <compileJdkPath>path/to/jdk</compileJdkPath>
  <testCompileJdkPath>path/to/test/jdk<testCompileJdkPath>
</properties>

Note it might make sense to define the compiler configurations in profiles, one for each JDK you support, so that your normal builds don't rely on properties being set.

Also, in Maven 3.x, you need to include the fork parameter when specifying the executable, e.g.:

  <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <executions>
      <execution>
        <id>default-testCompile</id>
        <phase>test-compile</phase>
        <goals>
          <goal>testCompile</goal>
        </goals>
        <configuration>
          <fork>true</fork>
          <executable>${testCompileJdkPath}/bin/javac</executable>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>            
      </execution>
    </executions>
  </plugin>

Upvotes: 34

Related Questions