User Tools

Site Tools


start:maven:totalnewbieintro

This is an old revision of the document!


Total newbie introduction to Maven

Anybody who wanted to start with Apache Maven probably at least skimmed through the official guide and I wasn't an exception. While reading, I started to think, what the hell… it was supposed to be simple. Instead of it, I had to enter this crazy command into shell just to create a basic empty project:

mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app \
                       -DarchetypeArtifactId=maven-archetype-quickstart \
                       -DinteractiveMode=false

Oh God, whyyyy!? Let's find out! :-D

Empty project structure

What really happens when you run aforementioned command is that it creates directory structure, pom.xml (Maven project file, so called Project Object Model) and a Hello world app (and its test):

fiisch@mothership:~> cd /tmp/
fiisch@mothership:/tmp> mkdir mvn-test
fiisch@mothership:/tmp> cd mvn-test/
fiisch@mothership:/tmp/mvn-test> mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app \
>                        -DarchetypeArtifactId=maven-archetype-quickstart \
>                        -DinteractiveMode=false
[INFO] Scanning for projects...
...
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.808 s
[INFO] Finished at: 2016-08-12T11:21:32+02:00
[INFO] Final Memory: 14M/343M
fiisch@mothership:/tmp/mvn-test> find
.
./my-app
./my-app/src
./my-app/src/main
./my-app/src/main/java
./my-app/src/main/java/com
./my-app/src/main/java/com/mycompany
./my-app/src/main/java/com/mycompany/app
./my-app/src/main/java/com/mycompany/app/App.java
./my-app/src/test
./my-app/src/test/java
./my-app/src/test/java/com
./my-app/src/test/java/com/mycompany
./my-app/src/test/java/com/mycompany/app
./my-app/src/test/java/com/mycompany/app/AppTest.java
./my-app/pom.xml

Also there is a generated pom.xml file which you have to edit if you take it seriously. Now let me explain the project-generation command:

  • mvn - Execute Maven binary.
  • archetype:generate - Use an archetype, archetypes are Maven plugins; we tell Maven that we want to run genereate plugin - which generates something from scratch.
  • -DgroupId=com.mycompany.app - Base namespace for your application. This is what you write to the package clause in your Java sources, in this case it would be package com.company.myapp;. Of course, this does not prevent you from creating subpackages.
  • -DartifactId=my-app - Root directory of your project. There is a pom.xml and src and test directories. There also appears target directory after you compile your application.
  • -DarchetypeArtifactId=maven-archetype-quickstart - This option specifies which artifact (= base setting) of the generate archetype will Maven use.
  • -DinteractiveMode=false - This is because nobody wants to scare beginners off at the beginning of the tutorial. I will write about it in later section of this post.

Creating empty project by hand

Now we will try to create empty project by hand. First, create directory for your project and then a structure the archetype originally created for you:

fiisch@mothership:/tmp> mkdir mvn-test-hand
fiisch@mothership:/tmp> cd mvn-test-hand/
fiisch@mothership:/tmp/mvn-test-hand>

# now we are starting to create project
# create equivalent of -DartifactId=my-app
fiisch@mothership:/tmp/mvn-test-hand> mkdir my-app

# create directory structure for -DgroupId=com.mycompany.app
fiisch@mothership:/tmp/mvn-test-hand> cd my-app/
fiisch@mothership:/tmp/mvn-test-hand/my-app> mkdir -pv src/{main,test}/java/com/mycompany/app
mkdir: created directory ‘src’
mkdir: created directory ‘src/main’
mkdir: created directory ‘src/main/java’
mkdir: created directory ‘src/main/java/com’
mkdir: created directory ‘src/main/java/com/mycompany’
mkdir: created directory ‘src/main/java/com/mycompany/app’
mkdir: created directory ‘src/test’
mkdir: created directory ‘src/test/java’
mkdir: created directory ‘src/test/java/com’
mkdir: created directory ‘src/test/java/com/mycompany’
mkdir: created directory ‘src/test/java/com/mycompany/app’

# create minimal pom.xml in the my-app folder
fiisch@mothership:/tmp/mvn-test-hand/my-app> cat 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>com.mycompany.app</groupId>
	<artifactId>my-app</artifactId>
	<version>1.0-SNAPSHOT</version>
</project>

# now try to compile empty project
fiisch@mothership:/tmp/mvn-test-hand/my-app> mvn compile
[INFO] Scanning for projects...
...
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.395 s
[INFO] Finished at: 2016-08-12T12:05:05+02:00
[INFO] Final Memory: 9M/481M

And that's it, no black magic necessary. We managed to setup empty project without using the archetype.

Please note that this project (and also its pom.xml) is emptier than the generated one. It is because I skipped Hello world app and whole tests thing. Also in the pom.xml I left out project name, url, description and whole lot of other sections to keep it truly minimal.

Interactive mode and problem of too many choices

Last thing I want to explain in this post is generating empty (or any other) project using interactive mode and also reasons why probably nobody uses it. Let's start with simple generate without any arguments:

fiisch@mothership:/tmp> mkdir mvn-test-interactive
fiisch@mothership:/tmp> cd mvn-test-interactive/
fiisch@mothership:/tmp/mvn-test-interactive> mvn archetype:generate
[INFO] Scanning for projects...

... very long output here ...

1639: remote -> us.fatehi:schemacrawler-archetype-plugin-command (-)
1640: remote -> us.fatehi:schemacrawler-archetype-plugin-dbconnector (-)
1641: remote -> us.fatehi:schemacrawler-archetype-plugin-lint (-)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 821:

So… we have neat 1641 choices of archetypeArtifactId. Not what we really want and it gets even worse. Suppose we want to create Spring based project, we get 141 choices, narrowing our search to “springframework” we end up with 28 choices. Yeah, ok. And which one to proceed with?

fiisch@mothership:/tmp/mvn-test-interactive> mvn archetype:generate < /dev/null | grep -ci "spring"
141
fiisch@mothership:/tmp/mvn-test-interactive> mvn archetype:generate < /dev/null | grep -ci "springframework"
28
fiisch@mothership:/tmp/mvn-test-interactive> mvn archetype:generate < /dev/null | grep -ci "jboss"
68
fiisch@mothership:/tmp/mvn-test-interactive> mvn archetype:generate < /dev/null | grep -ci "mule"
14
fiisch@mothership:/tmp/mvn-test-interactive> mvn archetype:generate < /dev/null | grep -ci "camel"
102

Maven is built around the idea that most projects have the same structure. In theory, this is very good thinking about standardization of project structure. Problem is that anyone can write such template and publish it for everyone else to see. In practice, we end up with almost 1700 templates to choose from. For a newbie, this is something really off putting.

Sad truth is, that there is no good way of choosing particular archetypeArtifactId unless someone explicitly tells you which one to use. When you are creating new project, it is better to do it by hand and write yourself a pom.xml from scratch.

But okay, let's give interactive mode a shot:

fiisch@mothership:/tmp> mkdir mvn-test-interactive
fiisch@mothership:/tmp> cd mvn-test-interactive/
fiisch@mothership:/tmp/mvn-test-interactive> mvn archetype:generate
[INFO] Scanning for projects...

... very long output here ...

1639: remote -> us.fatehi:schemacrawler-archetype-plugin-command (-)
1640: remote -> us.fatehi:schemacrawler-archetype-plugin-dbconnector (-)
1641: remote -> us.fatehi:schemacrawler-archetype-plugin-lint (-)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 821: 

# 821 is the quickstart archetype we previously specified as argument, hit ENTER

Choose org.apache.maven.archetypes:maven-archetype-quickstart version: 
1: 1.0-alpha-1
2: 1.0-alpha-2
3: 1.0-alpha-3
4: 1.0-alpha-4
5: 1.0
6: 1.1
Choose a number: 6:

# What the hell am I choosing? yeah, version of archetype.
# No idea about differences, hit ENTER and use latest version.

Define value for property 'groupId': : com.mycompany.app
Define value for property 'artifactId': : my-app
Define value for property 'version':  1.0-SNAPSHOT: : 
Define value for property 'package':  com.mycompany.app: : 
Confirm properties configuration:
groupId: com.mycompany.app
artifactId: my-app
version: 1.0-SNAPSHOT
package: com.mycompany.app
 Y: : y

...

[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 03:22 min
[INFO] Finished at: 2016-08-12T16:03:06+02:00
[INFO] Final Memory: 17M/477M

Well, without much explanation, I had to fill in the properties I previously specified on the command line. Interesting is, that Maven asked me about the package and version properties. Maven allows you to use different names for packaging (the package construct in your Java sources) than groupId, although if left out, package defaults to groupId). This is because groupId is meant as naming per person or group or company and therefore in the world of Java, those are prefixes for packages of particular apps they developed. Version property allows you to specify your app's first version - which is written into POM. Maven, as I show in some later post, is not very good at keeping version numbering by itself - and it cannot be, everyone numbers versions differently - so we need to adjust it according to project or development habits.

When we look at generated project, we see that it is the same as in the non-interactive generator created for us. In my case, pom.xml contains also this extra property:

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

Interactive mode fills it in by itself and according to this the property configures plain-text processing modules to use specific encoding.

Conclusion

I have shown three ways of creating basic Java project with Maven - interactive, non-interactive modes and creation by-hand. I deem to be very important to know what Maven does under the hood and to have absolute control over the generation process.

Also, from discussion with some of my colleagues, we got to the realization that none of us actually use project generation through Maven and that we do things by hand. The only thing we agreed upon is that specific project structure generation is useful when somebody else tells you which archetypeArtifactId to use.

Although it is very good idea to provide templating capabilities to Maven, it failed to restrict which templates are in core Maven installation - which lead to 1641 templates (in the time of writing). Solution to this may be pretty simple: Maven, as we see later, allows you to configure additional repositories for JAR libraries. It shouldn't be hard to extend this also on internal Maven components like project templates and with core Maven provide only, say, JAR and J2EE thingies (WAR/EAR packagings and such), leaving third-party projects to be explicitly allowed through JAR library with template or standalone repository.

start/maven/totalnewbieintro.1471014576.txt.gz · Last modified: 2016/08/12 15:09 by fiisch