What is Apache Maven and why do we need it?

I was going to write a blog post about Spring framework but I thought maybe it’s better to start with Maven as the first step.

With an increase in the number of Java libraries and frameworks and projects, there was a need for a standard way of describing how a piece of software should be built and what are it’s dependencies. Normally a Java project is using a lot of frameworks and tools (e.g. Logging, Database, Encryption, Math, …). We need a standard (machine-readable) way of describing these dependencies and how to compile and build the project.

Using Maven enforces a specific directory structure to your project. There is a specific directory path for your source code, runtime resource files, … Another change in your project is adding a file named pom.xml which will describe dependencies and build options.

I will explain some basic concepts in the Maven world, then will proceed to create a new project based on Maven.

Artifact

An Artifact, is a JAR file which is available for use in a Java project. Artifacts can be downloaded from Maven Repository (a publicly available website), but normally this is done automatically by maven command line.

Each Artifact represents a small piece of software that can be re-used in a software project. For example, there are artifacts for logging and encryption. There are a number of Maven repositories available, but the well-known repository is the one provided by Maven itself which is available for search and browse at http://search.maven.org/. You can search for artifacts and download them. You also have a local repository which contains JAR files downloaded from remote repositories or installed locally.

Each artifact is uniquely identified by using 3 elements: group-id, artifact-id and version.

Group-id represents the name of the company or organization which has produced the artifact (e.g. org.apache.logging.log4j). Artifact-id is a unique string for the artifact (e.g. log4j) and version string (e.g. 1.2.17). When you specify your project’s dependencies, you have to write their Group-id, artifact-id and version.

You can also tell Maven to produce an artifact when compiling your project. The result will be a .jar file including metadata about the artifact. You can then install this jar file into a Maven repository and use it as a dependency in other projects.

Build lifecycle

A build lifecyle is a set of steps (phases) which Maven does to build the project. You can define your own lifecycle but the default lifecycle is used most of the time. Here is a list of most important phases in the default lifecycle:

  1. validate: Make sure project structure is correct and all required data are available
  2. compile: Compile source code files
  3. test: Run unit test files
  4. package: Package compiled files in a distributable format (e.g. JAR)
  5. install: Install package into the local repository.

There is also another important lifecycle named “clean“. This lifecycle will clean-up artifacts created during build lifecycle.

You can call Maven command like tool and give the name of the phase or lifecycle to execute:

mvn clean package

Above command will run clean lifecycle and then will run build lifecycle up to ‘package‘ step. The target of the operation is the current directory.

Directory structure

Maven expects a standard project structure in your project. You have to follow this structure:

Suppose the root directory of the project is named ‘myapp‘:

  • myapp/pom.xml
  • myapp/src/main/java/com/mahdix/App.java: Source code files should reside in this location and below, according to your package names.
  • myapp/src/test/java/com/mahdix/Test.java: Location for test files

You will run Maven command line utility on the root directory of the project where there is pom.xml file.

POM.xml

Here is the general structure of a pom.xml file:

<project xmlns="http://maven.apache.org/POM/4.0.0">
 <modelVersion>4.0.0</modelVersion>
 
 <groupId>com.mahdix</groupId>
 <artifactId>my-app</artifactId>
 <version>1.0</version>
 <packaging>jar</packaging>
 
 <name>Test Application</name>
 <url>http://www.mahdix.com</url>
 
 <dependencies>
   <dependency>
     <groupId>junit</groupId>
     <artifactId>junit</artifactId>
     <version>4.8.2</version>
   </dependency>
</dependencies>
</project>

Here is explanation of important parts:

  • modelVersion: Specifies the model version of the Maven tool we use, this should always be 4.0.0
  • groupId, artifactId, version: These tags specify information about the current project
  • dependencies: This tag lists dependencies of the project. Maven will automatically fetch, download and install required JAR files according to the dependency list provided. You just need to specify artifacts that you need.

 

Tutorial: Java Persistence API (JPA)

 

Java Persistence API or JPA is a standard specification and a set of classes which helps developers write a provider-independent persistence layer in his applications. JPA has taken best ideas from different persistence providers (e.g. Hibernate, TopLink, etc.).

The general workflow for JPA is:

  1. Define POJO classes corresponding to database entities. You annotate these classes to let JPA find them at runtime.
  2. Add persistence.xml file which explains about your POJO classes and database connection information.
  3. Write the code to work with database entities (CRUD operations) using JPA classes and JPQL language (which is similar to SQL).

Defining Entities

Entity classes are simple Java classes. These classes don’t need to inherit from a specific class. All you need to do is annotate the class, add relevant fields representing database table fields and adding getter/setter methods.

You can also annotate fields to indicate primary key or give some more information about database representation of the field.

Below is example of a student entity class:

import javax.persistence.*;

@Entity(name = "TBL_STUDENT")
public class Student {
    @Id
    @Column(name="ST_ID", nullable=false)
    @GeneratedValue
    private long id;

    @Column(name="FIRST_NAME")
    private String firstName;

    @Column(name="LAST_NAME")
    private String lastName;

    @Column(name="AVG_SCORE")
    private float avgScore;

    //getter and setter for fields go here
}

Note that we use Java annotations to represent metadata explaining more information about the entity.

  • @Column annotation is used to define database field name of the class field. You can omit this is names are the same.
  • @Entity is used to declare this class as a DB entity.
  • @Id is used to represent primary key of the entity
  • @GeneratedValue is used to declare JPA provider should automatically provide value for this field upon data insertion.

JPA has a lot of other annotations to explain the type of data that can be stored in a field, table inheritance, composite primary key, entity relationships and much more. These will be explained in a future post.

Adding persistence.xml

In this XML file, you declare some metadata which cannot be written in the code easily. This is a sample XML file:

<?xml version="1.0" encoding="UTF-8"?>
<persistence>
 <persistence-unit name="mytest" transaction-type="RESOURCE_LOCAL">
  <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
  <class>test.Student</class>
  <properties>
  <property name="javax.persistence.jdbc.driver" value="org.sqlite.JDBC" />
  <property name="javax.persistence.jdbc.url" value="jdbc:sqlite:sample.db" />
  <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
  <property name="eclipselink.ddl-generation.output-mode" value="database" />
  </properties>
 </persistence-unit>
</persistence>

The XML file structure is almost the same across different projects. I have highlighted two important parts of the file:

  • name of the persistence-unit is a unique string which is used in the code to refer to this XML file.
  • provider XML tag is used to indicate which provider will be used at runtime to talk to the database.

The properties section of the XML file contains database connection information (e.g. database driver type, database name, …).

The code

The last step is using JPA classes to get a connection to the database and working with your POJO classes and EntityManager to do CRUD operations.

The basic flow is:

  1. Getting an instance of EntityManagerFactory class through Persistence class. Here you specify the persistence-unit name from XML file.
  2. Getting an instance of EntityManager class through EntityManagerFactory.
  3. Working with EntityManager instance and it’s EntityTransaction instance to create, read, update or delete POJO classes.

Here is the basic code:

//step 1
EntityManagerFactory factory = Persistence.createEntityManagerFactory("mytest");
//step 2
EntityManager entityManager = factory.createEntityManager();
//step 3
EntityTransaction txn = entityManager.getTransaction();
txn.begin();

//step 4 - CRUD operations
...

//step 5 - finalization
txn.commit(); //you need this line if you have changed some db data
entityManager.close();
factory.close();

CRUD operations

The CRUD operations become pretty straightforward considering the fact that you just need to work with your POJO classes as a proxy to the database table rows.

  • Create: You instantiate POJO class, set field values, call persist method of EntityManager.
  • Read: You create a JPQL query and get the result as a List<POJOClass>.
  • Find: Calling find method on EntityManager and giving the primary key value of the row. The result will be an instance of a POJO class.
  • Update: First find the row, update the POJO class fields.
  • Delete: Find the row, then call EntityManager.remove method.

Below is sample code for CRUD operations:

//CREATE a new row
Student st = new Student();
st.setFirstName("mahdi");

entityManager.persist(st);

//UPDATE row
Student st = entityManager.find(Student.class, 19);
st.setLastName("Mohammadinasab");

//DELETE row
Student st = entityManager.find(Student.class, 19);
entityManager.remove(st);

//READ rows
Query q = entityManager.createQuery("SELECT s FROM Student s");
List<Student> students = q.getResultList();

Note that in the update process you don’t need to call any JPA method. Just update POJO fields and when you commit the transaction, data will be updated.

For the query which reads rows from a database, JPQL language is used. I will explain more about JPQL syntax and how to handle relationships (one-to-many and many-to-many) in a future post.