quinta-feira, 21 de setembro de 2017

Hello World, Maven!

This year, I am demanding students to manage their projects using Maven. Around 2015 or 2016, I started to see an increasing usage of IntelliJ among students to the detriment of Eclipse. This raised a problem, as I am much more experienced with Eclipse than with IntelliJ, and I'm not willing to master both (as some students kept loyal to Eclipse). Hence, I pretty much saw Maven as an opportunity to settle the differences. Working with Maven is also a great opportunity for students to gain and practice a competence they might well need in their future jobs.

The disadvantage is that Maven might be truly painful to configure, use and debug and might well stand in the way of inexperienced users, easily consuming more time than its fair share.

The first thing to understand about Maven is that, by default, it always tries to do something like compiling, testing, etc. To see this, let's first create a Maven project based on the "Maven Quickstart Archetype". This archetype is available both on Eclipse and IntelliJ. This archetype creates the following structure (see here):

project
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- App.java
    `-- test
        `-- java
            `-- AppTest.java

and, if I specify the groupId to be 'blog' and the artifact id to be 'example', I get the following 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>blog</groupId>
  <artifactId>example</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>example</name>
  <url>http://maven.apache.org</url>

  <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>


This Archetype brings an App.java file in the blog.example package in the src/main/java folder that will run the classic "Hello World!" program.

package blog.example;

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

}


Now, in my Eclipse installation, I immediately get a warning, because my project sets up the J2SE-1.5 JRE system library, and I don't have any JRE compatible with that version. This must be fixed, and this fix should help us to exactly understand how Maven works.

The first thing to notice is that we haven't specified anything about compilation in the pom.xml. Hence, Maven will assume a default compilation phase, which as of September 2017 uses Java version 5 as input and output. That's why we see this issue in the project (with the 1.5 JRE). To make the problem more evident let's include a feature in our program that was not available in Java 5: streams.

package blog.example;

import java.util.stream.IntStream;

public class App 
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
IntStream.range(1, 4)
.forEach(System.out::println);
}

}


Now, we have errors, instead of a simple warning. We need to change our compiler from version 5 to version 8 (or whatever last version is available). In Eclipse (and IntelliJ) projects, we would use the mouse, navigate menus and so on, to change the installed libraries. We will do it in Maven now, by specifying a plugin that changes the default behavior of the compilation phase.

<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>blog</groupId>
<artifactId>example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>example</name>
<url>http://maven.apache.org</url>

<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>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>

</project>


We can see the different options of the maven-compiler-plugin in the appropriate web site (click here). I just changed the source and the target, but I've seen cases with some students, where it was necessary to specify the location of the Java compiler in a slightly more complicated configuration, also available in the page I mentioned. This plugin will change the way Maven behaves, when going through the compilation of our project. But, in the case of Eclipse, the errors in the project persist, because Eclipse still doesn't know about the changes we did to the pom.xml. We need to update the project, to put the pom.xml and the Eclipse project in sync or 'updated' (this is available in the context menu over the name of the project, under the title 'Maven'). In IntelliJ, a step like this is also necessary and may be configured to run automatically.

Note that we don't need to do a Maven update or, in other words, to put the project in sync, to compile the project with Maven or run any other phase of the Maven lifecycle, like packaging. We do this for the sake of working in a clean IDE environment, and for being able to get the benefits of using the IDE. If we don't update, and the project is kept with errors, Eclipse (or IntelliJ) won't be able to compile your source code on the fly. If everything is in sync, both Eclipse and yourself (manually via Maven) will be able to compile the source code and generate the classes. So, an update is clearly useful.

Eclipse (and IntelliJ) will compile the source code on their own and run the program if necessary. To do this ourselves in Eclipse, we need to specify a goal for the Maven build. In this case it is compile, as you can see in the 'Goals' box:



If you press the 'Run' button, what you actually get is a compilation, not an execution. You should get something along the lines:

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building example 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/filipius/aulas/2017-18/IS/code/example/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.7.0:compile (default-compile) @ example ---
[INFO] Nothing to compile - all classes are up to date
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.815 s
[INFO] Finished at: 2017-09-21T15:47:45+01:00
[INFO] Final Memory: 8M/155M

[INFO] ------------------------------------------------------------------------

The way to execute the program will depend on the IDE. If you now run the program, you should get:

Hello World!
1
2
3

The funny thing and the true power of Maven comes from the fact that we now may do the same thing in the command line, as long as we install Maven (although a different version of Maven, compared to that used by Eclipse/IntelliJ might cause some glitches). Just change directory to the folder where the pom.xml is and run the following command. Note that this is optional, as Eclipse/IntelliJ should do this for you:

mvn compile

We should get the same thing as before:

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building example 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/filipius/aulas/2017-18/IS/code/example/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.7.0:compile (default-compile) @ example ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/filipius/aulas/2017-18/IS/code/example/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.659 s
[INFO] Finished at: 2017-09-21T15:52:57+01:00
[INFO] Final Memory: 13M/155M

[INFO] ------------------------------------------------------------------------


This action will generate the new App.class, if necessary, under the target directory. No Eclipse and no IntelliJ. Everything is ready for command line automation!

Of course, Maven can get much more complicated than this, especially as projects become larger and we need additional control. For now, there are two important things to learn. 1- there are more lifecycle phases than compile; 2 - we can add up dependencies, aka libraries to our project.

Regarding lifecycles, it's unnecessary to repeat what is available here, but I will list the most important ones for convenience:

  • validate - validate the project is correct and all necessary information is available
  • compile - compile the source code of the project
  • test - test the compiled source code using a suitable unit testing framework. These tests should not require the code be packaged or deployed
  • package - take the compiled code and package it in its distributable format, such as a JAR.
  • verify - run any checks on results of integration tests to ensure quality criteria are met
  • install - install the package into the local repository, for use as a dependency in other projects locally
  • deploy - done in the build environment, copies the final package to the remote repository for sharing with other developers and projects.
For example, you might want to generate a .jar package using Maven. Therefore,  a phase with that same name exists for that purpose. How do you control the packaging process? Through a plugin. Configuring plugins, as we saw in the case of compile, might be relatively complicated, but there should be a lot of documentation around.

To include libraries in our project, we just need to add another <dependency>, under the <dependencies> element, like this, if you need jsoup, for example:

<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.8.3</version>

</dependency>

You can look for the last versions of the dependencies in the Maven Repository. You can look for more details regarding dependencies here, although I'm afraid that this seemingly introductory page is incredibly complicated for beginners.

7 comentários:

  1. Greetings. I know this is somewhat off-topic, but I was wondering if you knew where I could get a captcha plugin for my comment form? I’m using the same blog platform like yours, and I’m having difficulty finding one? Thanks a lot.

    AWS Training in Bangalore | Amazon Web Services Training in Bangalore

    Amazon Web Services Training in Pune | Best AWS Training in Pune

    AWS Online Training | Online AWS Certification Course - Gangboard

    ResponderEliminar
  2. The knowledge of technology you have been sharing thorough this post is very much helpful to develop new idea. here by i also want to share this.
    angularjs Training in bangalore

    angularjs Training in btm

    angularjs Training in electronic-city

    angularjs Training in online

    angularjs Training in marathahalli

    ResponderEliminar
  3. I recently came across your blog and have been reading along. I thought I would leave my first comment.
    python interview questions and answers | python tutorials

    ResponderEliminar
  4. Excellant post!!!. The strategy you have posted on this technology helped me to get into the next level and had lot of information in it.
    Devops training in sholinganallur
    Devops training in velachery
    Devops training in annanagar
    Devops training in tambaram

    ResponderEliminar
  5. A very nice guide. I will definitely follow these tips. Thank you for sharing such detailed article. I am learning a lot from you.

    rpa training in electronic-city | rpa training in btm | rpa training in marathahalli | rpa training in pune

    ResponderEliminar
  6. Have you been thinking about the power sources and the tiles whom use blocks I wanted to thank you for this great read!! I definitely enjoyed every little bit of it and I have you bookmarked to check out the new stuff you post
    Java training in Indira nagar | Java training in Rajaji nagar

    Java training in Marathahalli | Java training in Btm layout

    ResponderEliminar