Search code examples
javamaven

On Mac How to change Java Version for Maven


On my mac I have 2 java versions installed, On checking with Java -version command I get 17 version, but when I am checking mvn -version it is showing java version as 22. I want java version 17 for maven as well. What I might be missing that should be corrected?


Solution

  • Newer Java can compile for older Java

    You can easily use the latest Java version to build (22) and run your app while compiling your code for an earlier version of Java (17).

    Here is a simple little app.

    public class App
    {
        public static void main ( String[] args )
        {
            System.out.println( Runtime.version( ) );
            System.out.println( "Hello World!" );
            // ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor( );  // Compiler error: Cannot find symbol.
        }
    }
    

    When run:

    22.0.1+10
    Hello World!
    

    We can see that:

    • The app is executing on Java 22 as reported by Runtime.version.
    • This app is compiling for Java 17 by the fact that if we uncomment the Executors.newVirtualThreadPerTaskExecutor line, we get a compiler error, Cannot find symbol. That feature was added in Java 21.

    As we write code, IntelliJ and the compiler is preventing us from accessing any classes bundled with version of Java after 17. The classes exist in the Java 22 running the compiler, but those newer classes are out-of-reach since we designated an older version of Java.

    To make this work, you must set some settings within your IDE. In IntelliJ, we must set:

    • File > Project Structure… > Project Settings > Modules > Language Level to 17 - Sealed types, always-strict floating-point semantics
    • Settings > Build, Execution, Deployment > Build Tools > Compiler > Java Compiler > Per-module bytecode version > Target bytecode version to 17.

    And we must specify the version within the Maven POM file. Here is an example. I started with the Maven archetype named QuickStart. I then revamped its long outdated version numbers.

    The crucial part is the <maven.compiler.release>17</maven.compiler.release> element that tells Maven to run the compiler in such a way as to output bytecode for Java 17.

    With modern versions of Maven, we can use this single ".release" element rather than a pair of ".source" & ".target" elements.

    <?xml version="1.0" encoding="UTF-8"?>
    
    <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>work.basil.example</groupId>
        <artifactId>ExJava17On22</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <name>ExJava17On22</name>
        <!-- FIXME change it to the project's website -->
        <url>http://www.example.com</url>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.release>17</maven.compiler.release>
        </properties>
    
        <dependencies>
    
            <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter -->
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter</artifactId>
                <version>5.10.2</version>
                <scope>test</scope>
            </dependency>
    
        </dependencies>
    
        <build>
            <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
                <plugins>
                    <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
                    <plugin>
                        <artifactId>maven-clean-plugin</artifactId>
                        <version>3.3.2</version>
                    </plugin>
                    <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
                    <plugin>
                        <artifactId>maven-resources-plugin</artifactId>
                        <version>3.3.1</version>
                    </plugin>
                    <plugin>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <version>3.13.0</version>
                    </plugin>
                    <plugin>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <version>3.2.2</version>
                    </plugin>
                    <plugin>
                        <artifactId>maven-jar-plugin</artifactId>
                        <version>3.3.0</version>
                    </plugin>
                    <plugin>
                        <artifactId>maven-install-plugin</artifactId>
                        <version>3.1.1</version>
                    </plugin>
                    <plugin>
                        <artifactId>maven-deploy-plugin</artifactId>
                        <version>3.1.1</version>
                    </plugin>
                    <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
                    <plugin>
                        <artifactId>maven-site-plugin</artifactId>
                        <version>4.0.0-M9</version>
                    </plugin>
                    <plugin>
                        <artifactId>maven-project-info-reports-plugin</artifactId>
                        <version>3.5.0</version>
                    </plugin>
                </plugins>
            </pluginManagement>
        </build>
    </project>
    

    While I do not have Maven installed separately, I can invoke man -version on the Maven bundled within IntelliJ IDE.

    /Users/basil_dot_work/Applications/'IntelliJ IDEA Ultimate.app'/Contents/plugins/maven/lib/maven3/bin/mvn -version
    

    Result:

    Apache Maven 3.9.6 (bc0240f3c744dd6b6ec2920b3cd08dcc295161ae)
    Maven home: /Users/basil_dot_work/Applications/IntelliJ IDEA Ultimate.app/Contents/plugins/maven/lib/maven3
    Java version: 22.0.1, vendor: BellSoft, runtime: /Users/basil_dot_work/.sdkman/candidates/java/22.0.1.fx-librca
    Default locale: en_US, platform encoding: UTF-8
    OS name: "mac os x", version: "14.4.1", arch: "aarch64", family: "Mac"
    

    So we can see that Maven 3.9.6 is running on my installation of the Liberica JDK 22.0.1 from BellSoft.


    On my Mac …

    Nothing above is Mac-specific.

    But, by the way, a tip: SDKMAN! is an excellent little command-line tool for finding, downloading, installing, and uninstalling JDKs and other kits of software. This bundle of shell scripts works quite well on Unix-oriented operating systems such as macOS.

    sdk list java
    
    sdk install java whatever
    
    sdk uninstall java whatever
    

    The only limitation is that SDKMAN! knows only about JDK products whose vendors choose to submit data. This includes multiple vendors of JDK/JRE offerings, but not all vendors.