How to Setup Maven 3.5 on macOS 10 and Create a Java Project from Archetype

  • This post shows how to setup Maven and how to create, build and run a new Maven Java project on macOS 10.
  • Before continuing, make sure that a Java SDK 1.7 or greater is installed and that the commands are available in your PATH environment variable. In a terminal window, run the following command to confirm this:
java -version

MacBookPro:opt admin$ java -version
java version "1.8.0_77"
Java(TM) SE Runtime Environment (build 1.8.0_77-b03)
Java HotSpot(TM) 64-Bit Server VM (build 25.77-b03, mixed mode)
MacBookPro:opt admin$
 
  • For a related post on installing a Java SDK and seting up a Java EE development environment refer to the below post on this site:

Summary

  1. Installing and Configuring Maven 3.5 on macOS 10
  2. Creating a Maven Java Project from an Archetype
  3. Adding Project Dependencies in the POM File
  4. Execute the Java Application with the Maven exec Plugin

  • In this example, Maven 3.5 is used. It can be downloaded as a binary distribution from the Apache Maven Website.

Download Maven Binary Distribution from Apache Maven Website

  • Unzip the Maven 3.5 files into some folder on the local disk. In this example, the Maven files are unzipped into the ${maven.home} folder at:
/opt/apache-maven-3.5.0

Maven Home Folder Contents

  • For instructions on how to add the Maven commands from the ${maven.home}\bin folder to the PATH environment variable on macOS see:
  • Open a terminal window and verify that maven is installed properly by executing the below command to view the Maven version:
mvn -version
  • The output should look like the example below, showing the Java version and Java home folder:

Last login: Wed Oct 11 01:07:07 on ttys000
MacBookPro:~ admin$ /opt/apache-maven-3.5.0/bin/mvn -version
Apache Maven 3.5.0 (ff8f5e7444045639af65f6095c62210b5713f426; 2017-04-03T15:39:06-04:00)
Maven home: /opt/apache-maven-3.5.0
Java version: 1.8.0_77, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_77.jdk/Contents/Home/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.12.5", arch: "x86_64", family: "mac"
MacBookPro:~ admin$

  • If a proxy is needed to connect to the Internet, edit ${maven.home}/.m2/conf/settings.xml:
  <!-- proxies
   | This is a list of proxies which can be used on this machine to connect to the network.
   | Unless otherwise specified (by system property or command-line switch), the first proxy
   | specification in this list marked as active will be used.
   |-->
  <proxies>
    <!-- proxy
     | Specification for one proxy, to be used in connecting to the network.
     |-->
    <proxy>
      <id>optional</id>
      <active>true</active>
      <protocol>http</protocol>
      <username>domain\username</username>
      <password>password</password>
      <host>proxy.host.com</host>
      <port>80</port>
      <nonProxyHosts>local.net|some.host.com</nonProxyHosts>
    </proxy>
  </proxies>
  • When a Maven project is built, Maven will download all dependent artifacts (JAR files) from a remote repository to a local repository. By default, Maven will create the local repository in:
${user.home}/.m2/repository
  • The Maven local repository contains all downloaded artifacts and looks like the example below:

Default Maven Local Repository Location on macOS

  • To change the location of the local repository, edit ${maven.home}/.m2/conf/settings.xml:
  <!-- localRepository
   | The path to the local repository maven will use to store artifacts.
   | Default: ${user.home}/.m2/repository
   |-->
  <localRepository>/my/local/repository</localRepository>

  • To create a Maven Java project with JUnit support, using the archetype maven-archetype-quickstart, execute the command:
mvn archetype:generate -DgroupId=com.company.app -DartifactId=my-app 
    -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
  • When Maven first downloads required dependencies to the local repository, the build may take a while.
  • The output should look like below and result in a BUILD SUCCESS message.
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/archetype/maven-archetype-parent/1/maven-archetype-parent-1.pom
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/archetype/maven-archetype-parent/1/maven-archetype-parent-1.pom (1.3 kB at 8.7 kB/s)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-parent/4/maven-parent-4.pom
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/maven-parent/4/maven-parent-4.pom (10.0 kB at 54 kB/s)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/archetypes/maven-archetype-quickstart/1.0/maven-archetype-quickstart-1.0.jar
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/archetypes/maven-archetype-quickstart/1.0/maven-archetype-quickstart-1.0.jar (4.3 kB at 28 kB/s)
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: basedir, Value: /Users/admin/Desktop/MyProjects/pegaxchange.com/posts/3506
[INFO] Parameter: package, Value: com.company.app
[INFO] Parameter: groupId, Value: com.company.app
[INFO] Parameter: artifactId, Value: my-app
[INFO] Parameter: packageName, Value: com.company.app
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: /Users/admin/Desktop/MyProjects/pegaxchange.com/posts/3506/my-app
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.639 s
[INFO] Finished at: 2017-10-18T18:07:10-04:00
[INFO] Final Memory: 19M/308M
[INFO] ------------------------------------------------------------------------
MacBookPro:3506 admin$ 
  • Maven will create a folder using the artifactId and create the standard project structure based on the groupId:
my-app
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- com
    |           `-- company
    |               `-- app
    |                   `-- App.java
    `-- test
        `-- java
            `-- com
                `-- company
                    `-- app
                        `-- AppTest.java
  • The root folder of the Maven project contains a POM file (Project Object Model). Here, the file contains:
<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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.company.app</groupId>
    <artifactId>my-app</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>my-app</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
  • To compile and package the Java project, execute in the project root folder (containing the pom.xml file):
mvn clean compile package
[INFO] Compiling 1 source file to /Users/admin/my-app/target/test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ my-app ---
[INFO] Surefire report directory: /Users/admin/my-app/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.company.app.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.005 sec

Results :

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

[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ my-app ---
[INFO] Building jar: /Users/admin/my-app/target/my-app-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.568 s
[INFO] Finished at: 2017-10-18T19:12:04-04:00
[INFO] Final Memory: 16M/186M
[INFO] ------------------------------------------------------------------------
MacBookPro:my-app admin$
  • The resulting JAR file is located in the target folder of the project:

Maven Java Standard Project Structure

  • It can be executed from the project folder with the java command:
java -cp target/my-app-1.0-SNAPSHOT.jar com.company.app.App
  • Which will produce the below output:
MacBookPro:my-app admin$ java -cp target/my-app-1.0-SNAPSHOT.jar com.company.app.App
Hello World!
MacBookPro:my-app admin$ 
  • As per the App.java source file:
package com.company.app;

public class App {

    public static void main( String[] args ) {
        System.out.println( "Hello World!" );
    }
}

  • The Maven Central Repository is used to find and add dependencies to a project’s POM file.
  • For example, to add support for JSON processing to the project, Google’s GSON API can be used.
  • Search for "GSON" in the Maven Central Repository to find the Maven dependency information.

Maven Central Repository - Search for Artifact

  • Click on the version link, here 2.8.2, to view the dependency information:

Maven Central Repository - GSON 2.8.2 Artifact Details

  • Copy and paste the dependency information from the Apache Maven section into the project’s POM file:
<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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.company.app</groupId>
    <artifactId>my-app</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>my-app</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <!-- Support for JSON Processing -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.2</version>
        </dependency>
    </dependencies>
</project>
  • The scope of the new dependency is not specified. It is compile by default. See Dependency Scope for more information.
  • The GSON API can now be used in the App.java source file to serialize Java objects:
package com.company.app;

import com.google.gson.Gson;

public class App {

    public static void main( String[] args ) {
        Car car = new App().new Car();
        car.setMake("BMW");
        car.setModel("335i");

        System.out.println(new Gson().toJson(car));
    }

    class Car {

        private String make;
        private String model;

        public String getMake() {
            return make;
        }

        public void setMake(String make) {
            this.make = make;
        }

        public void setModel(String model) {
            this.model = model;
        }

        public String getModel() {
            return model;
        }
    }
}

  • Maven can be used to compile and then execute the App class using the exec plugin:
mvn compile exec:java -Dexec.mainClass="com.company.app.App"
  • The output will be a JSON representation of the Car object:
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ my-app ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/admin/my-app/target/classes
[INFO] 
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ my-app ---
{"make":"BMW","model":"335i"}
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.421 s
[INFO] Finished at: 2017-10-19T12:52:29-04:00
[INFO] Final Memory: 18M/301M
[INFO] ------------------------------------------------------------------------
{"make":"BMW","model":"335i"}

Add Entry to PATH Variable on macOS 10 Sierra: for Current Terminal Session, Permanently for Current User and Permanently for All Users (Global)

This post shows how the PATH variable can be set on macOS 10 Sierra for the current terminal session only, permanently for the current user only and permanently for all users on the system.

In this example, the Tomcat startup.sh executable is added to the PATH variable so that is can be run from the terminal without having to use the full path name.

Summary

  1. Add Entry to PATH Variable for the Current Terminal Session Only
  2. Add Permanent Entry to PATH Variable for the Current User Only
  3. Add Permanent Entry to PATH Variable for all Users on the System (Global)

  • Open a new terminal window and use the echo command to view the PATH variable.
echo $PATH
  • By default, the variable should be set to something like this on macOS 10 Sierra (here 10.12.5):
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

macOS 10 Sierra Terminal - view current PATH variable

  • On my system, the Tomcat home is located at /Applications/apache-tomcat-9.0.0.M17
  • Staring the server using the startup.sh, requires using the full path name, otherwise it is not found.
sudo startup.sh

macOS 10 Sierra  Terminal - run Tomcat startup.sh

  • To add the Tomcat bin folder to the PATH variable for the current terminal session only, execute:
PATH=$PATH:/Applications/apache-tomcat-9.0.0.M17/bin
  • Use echo again to confirm the new entry to PATH:

macOS 10 Sierra  Terminal - add entry to PATH variable for current session

  • For the current terminal session, Tomcat can now be started by running startup.sh from any location.

macOS 10 Sierra  Terminal - run Tomcat startup.sh - server started successfully

  • This PATH entry will be lost when closing the current terminal or when opening a new terminal window.

  • To permanently add a PATH entry for the current user, navigate to the home folder:
cd $home
  • And execute the below command to edit the user’s bash profile. Bash is the default shell on macOS.
nano ~/.bash_profile

macOS 10 Sierra  Terminal - Start nano to edit user bash profile

  • Add the desired PATH entry with e.g. GNU nano as shown below. Use CTRL+O to save changes and CTRL+X to exit.

macOS 10 Sierra  Terminal - Use nano to edit user's bash profile and add entry to PATH variable

  • For the changes to take effect, close the current terminal window and open a new one.
  • Use echo $PATH again to confirm the entry was added.

macOS 10 Sierra  Terminal - confirm PATH entry was added to current user's bash profile

  • Whenever a terminal is opened by the current user, the bash profile will add the specified PATH entry.

  • To permanently add a PATH entry for all users on the macOS system (global), the /etc/paths file is used.
  • Open the file for editing by running:
sudo nano /etc/paths

macOS Terminal - view /etc/paths file and use nano to open for edit

  • Add the desired PATH entry as shown below. This file maintains a list of PATH entries, one per row:

macOS 10 Sierra  Terminal - edit /etc/paths file with nano and add entry to PATH variable for all users

  • Use CTRL+O to save changes and CTRL+X to exit.
  • Switch to another user on the Mac and confirm that the PATH entry is present.

macOS 10 Sierra  Terminal - confirm different user sees new PATH entry in /etc/paths

  • Note: In this example, the user edgar will only be able to actually run the Tomcat startup.sh if the permissions have been set correctly by the user that owns the files. Refer to chmod for setting permissions.
  • If read and execute permissions have not been set, errors indicating that the file was not found and other permission errors will occur.
  • Please register to leave a comment if you know additional or better approaches.