Charts with jqPlot, Spring REST, AJAX and JQuery

One of the most notable features of HTML5 is Canvas API which provides a rectangular region for custom drawing. There are several uses of it like: building games, image compositions, animations but this time we will see how to use it to render charts in web browser. Of course, we could write source code for drawing charts ourselves but it would be tedious and time-consuming task. Fortunately, there are several good JavaScript libraries which can perform this task for us.

One of them is jqPlot which we will use to render a very simple chart showing sales in given country in the current month:

springrestchart

Creating web page

Our only web page sales.jsp is pretty simple:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="s" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>Sales</title>
        <script type="text/javascript"
                src="<s:url value='/resources/libs/jquery/jquery.min.js' />" >
        </script>
        <script type="text/javascript"
                src="<s:url value='/resources/libs/jqplot/jquery.jqplot.min.js' />" >
        </script>
        <link href="<s:url value='/resources/libs/jqplot/jquery.jqplot.min.css'/>"
              rel="stylesheet" type="text/css" />

        <script type="text/javascript"
                src="<s:url value='/resources/js/sales.js' />" >
        </script>
        <link href="<s:url value='/resources/css/styles.css'/>"
              rel="stylesheet" type="text/css" />
    </head>
    <body>
        <form>
            <label for="countrySelect">Country:</label>
            <select id="countrySelect" >
                <c:forEach var="country" items="${countries}">
                    <option value="${country.code}">${country.name}</option>
                </c:forEach>
            </select>
        </form>

        <div id="chartError">Failed to contact server</div>
        <div id="chart"></div>
    </body>
</html>

First, we include JQuery and jqPlot libraries which we are going to use later. Then we add our custom js/sales.js JavaScript file which contains logic to asynchronously update the web page once the country is changed (we will look at this file later) and css/styles.css CSS stylesheet:

#countrySelect {
    padding: 0.2em;
}

#chart {
    margin: 1em;
    width: 90%;
    height: auto;
    clear: both;
}

#chartError {
    margin: 1em;
    border-style: solid;
    border-width: medium;
    border-color: black;
    background-color: lightpink;
    font-weight: bold;
    padding: 0.5em;
    display: none;
}

Finally, we add a drop-down menu with the list of all supported countries, a message to inform user about error (hidden by default) and a div element with identifier chart in which jqPlot will draw the chart. There are no canvas elements at the moment but they will be added later to the DOM tree by jqPlot.

Creating Spring MVC controller

The JSP web page retrieves the list of all supported countries from ${countries} model attribute which was populated by the following Spring controller:

package com.example.springrestchart;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(value = "/sales")
public class SalesController {
    
    @Autowired
    private SalesProvider salesProvider;
    
    @RequestMapping(method = RequestMethod.GET)
    public String list(Model model) {
        
        List<Country> countries = salesProvider.getCountries();
        model.addAttribute("countries", countries);
        
        return "sales";
    }
}

The controller uses injected instance of SalesProvider singleton bean:

package com.example.springrestchart;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;

@Component
public class SalesProvider {

    private static final List<Country> COUNTRIES = Arrays.asList(
            new Country("UK", "United Kingdom"),
            new Country("DE", "Germany"),
            new Country("FR", "France"));

    private Map<String, Sales> sales;

    @PostConstruct
    protected void init() {
        sales = createSales();
    }

    public List<Country> getCountries() {
        return Collections.unmodifiableList(COUNTRIES);
    }

    public Sales getSales(String countryCode) {
        Sales result = sales.get(countryCode);
        if (result != null) {
            return result;
        } else {
            throw new CountryNotFoundException("Country not found: " + countryCode);
        }
    }

    private static Map<String, Sales> createSales() {
       // omitted
    }

    private static Sales createRandomValues(Country country, int count) {
       // omitted
    }

}

This provider is responsible for returning the list of all supported countries and their sales from the first day of the current month till today (one value per day). The actual sales values are auto-generated but the source code for this was omitted for clarity.

One important thing to notice is that getSales() method throws CountryNotFoundException exception if the sales for given country do not exist. The definitions of Country, Sales and CountryNotFoundException classes are straightforward:

Country:

package com.example.springrestchart;

public class Country {
    private String code;
    private String name;

    public Country(String code, String name) {
        this.code = code;
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public String getName() {
        return name;
    }
    
}

Sales:

package com.example.springrestchart;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Sales {
    private Country country;
    private List<Double> values;

    public Sales(Country country, List<Double> values) {
        this.country = country;
        this.values = new ArrayList<>(values);
    }

    public Country getCountry() {
        return country;
    }
    
    public List<Double> getValues() {
        return Collections.unmodifiableList(values);
    }
}

CountryNotFoundException:

package com.example.springrestchart;

public class CountryNotFoundException extends RuntimeException {

    public CountryNotFoundException(String message) {
        super(message);
    }
    
}

Creating Spring REST Controller

Now, we should have the web page display in web browser but nothing happens when country is changed. We are going to improve this by exposing the sales data using REST web service and later consuming it from web browser using AJAX and JQuery.

Let’s first look at the implementation of REST web service:

package com.example.springrestchart;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

@Controller
public class SalesRestController {
    
    @Autowired
    private SalesProvider salesProvider;
    
    @RequestMapping(value = "/services/sales/{countryCode}", method = RequestMethod.GET,
            produces = "application/json")
    public @ResponseBody Sales getSales(@PathVariable("countryCode") String countryCode) {
        return salesProvider.getSales(countryCode);
    }
    
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(CountryNotFoundException.class)
    public void countryNotFound() {
    }
}

It is a standard Spring controller with @Controller annotation. Alternatively, we could use RestController annotation and remove @ResponseBody annotation from getSales() method.

We inject the same SalesProvider as before to access sales data. Method getSales() of the controller is annotated with @RequestMapping to inform Spring that it should be invoked whenever HTTP GET request is sent to relative and parameterized URL services/sales/{countryCode} where {countryCode} should be replaced by one of the available country codes. In our case it would be UK, DE or FR.

Finally, we add @ResponseBody annotation to the method and specify produces element to indicate that the returned instance of Sales class should be automatically converted to JSON format before sending over HTTP. Spring uses Jackson library for this task so it must be added as a dependency to Maven POM file:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.4.1.1</version>
</dependency>

If you have been following the article closely, you should remember that getSales() method in SalesProvider class throws CountryNotFoundException if the country code is unknown. Therefore, we install exception handler for it and inform Spring to return HTTP status 404 (Not Found) in case of the exception.

Implementing client-side logic

Finally, after all setup is done we can take a look at previously mentioned js/sales.js file:


function renderPlot(data) {
    $("#chart").empty();
    $("#chartError").hide();

    var countryName = data.country.name;
    var values = data.values;
    $.jqplot("chart", [values], {
        title: "<h2> Sales in " + countryName + " in current month</h2>",
        axes: {
            xaxis: {
                label: 'Day of month',
                pad: 0
            },
            yaxis: {
                label: 'Mln USD'
            }
        }});
}

function renderError() {
    $("#chart").empty();
    $("#chartError").show();
}

function reloadPlot(countryCode) {
    $.ajax({
        url: encodeURI("services/sales/" + countryCode),
        type: "GET",
        dataType: "json",
        success: renderPlot,
        error: renderError
    });
}

function initializeCountries() {
    $("#countrySelect").change(function() {
        var countryCode = $(this).val();
        reloadPlot(countryCode);
    });
    reloadPlot($("#countrySelect").val());
}

$(document).ready(initializeCountries);

Function initializeCountries(), which is called once the document is fully loaded, registers listener to be called when the country is changed. If it happens, the plot is reloaded to show the data for the chosen country.

Function reloadPlot() issues AJAX request to our REST service and passes country code as part of the URL path. If the request succeeds, renderPlot() function is called to render the chart with sales. Because the sales data was returned in JSON format, we can easily access it from JavaScript. We extract the country name and its sales (as an array of real numbers).

Finally, we call $.jqplot() function and pass it identifier of the div element where the chart should be rendered and the actual data. jqPlot can draw multiple data series on a single chart. We have only one series so we have to create an array with one element (our array with sales data) beforehand. jqPlot can take multiple options to customize appearance and behavior of the chart but for simplicity we specify axes labels and padding only.

Conclusion

jqPlot is versatile and very easy to use JavaScript library to render charts in web browser. The functionality used in this article is only a small portion of what it can do.

From user point of view charts generated by such library are more responsive and interactive than the charts generated on a server. It is for example possible to use highlighting, zooming, cursor tracking and even modify the values using drag-and-drop.

The complete source code for the example is available at GitHub.

Posted in AJAX, Java, Spring | Tagged , , , , , , | Leave a comment

Accessing local files from a web browser using HTML5 File API

HTML5 introduced a standard interface called File API which lets programmers access meta-data and read contents of local files selected by a user. The selection is typically done using input element but the recent browsers also allow using drag and drop for this task. The number of opportunities this new API gives us is very wide and include at least: checking files before sending to server, showing thumbnails while uploading files and processing files without interaction with server.

In this article I would like to show how to use this API to read basic properties of a file chosen by a user and additionally read it and calculate its SHA-1 hash. The main window of the sample application will look like this:
html5fileapi

Because the File API is quite new, it is supported only by the latest versions of the web browsers. So if you still have an older one, I strongly suggest upgrading it.

Accessing selected files

The classic method to select a file from local disk is to add HTML input element with type file:

<input id="fileInput" type="file" />

If optional attribute multiple is specified, it is possible to select many files at once.

In JavaScript it is possible to access FileList object, representing files selected by a user, using files property of file input element. FileList behaves like an array so accessing individual File objects is easy:

var fileInput = $("#fileInput")[0];
var fileList = fileInput.files;
for (var i = 0; i < fileList.length; i++) {
    var file = fileList[i];
    // handle file
}

Of course, if user selected only one file (e.g. because multiple attribute was not specified), FileList object contains only one file at index 0.

Once we get a reference to File object representing file selected by a user, we can access one of the following attributes providing useful information about the file:

  • name – The name of the file without any path information
  • size – The size of the file in bytes
  • type – The MIME type of the file (e.g. text/plain) or empty string if it is not available
  • lastModifiedDate – The date of the last modification of the file

Reading file contents

Reading the contents of the file is a bit more complicated. First, we have to create FileReader object, assign listeners to one or more of its events and then call one of these asynchronous methods to start reading the file:

  • FileReader.readAsText(Blob or File, optional_encoding) – Starts reading a text file using given encoding. If the encoding is not specified, file contents is interpreted as UTF-8 text.
  • FileReader.readAsDataURL(Blob or File) – Starts reading a file into data URL string. Typically, this operation is used to read an image file and the result of thss operation can be assigned to src attribute of img element.
  • FileReader.readAsArrayBuffer(Blob or File) – Starts reading a binary file into ArrayBuffer object.

These three methods are asynchronous which means that they finish immediately but the reading operation continues in the background. Once the operation finishes successfully, onload event of FileReader is triggered and the read data can be accessed using result property of the FileReader object. The complete list of available events is below:

  • onloadstart – Triggered when reading operation is starting
  • onload – Triggered when reading operation is finished successfully
  • onloadend – Triggered when reading operation finished (either successfully or with an error)
  • onprogress – Triggered multiple times while reading. Can be used to monitor the progress.
  • onerror – Triggered when reading operation finished with an error
  • onabort – Triggered when reading operation is aborted

Example

Knowing the basics we can start writing sample application by creating index.html file:

<!DOCTYPE html>
<html>
    <head>
        <title>HTML5 File API</title>
        <meta charset="UTF-8" />
        <script type="text/javascript" src="js/libs/jquery/jquery.js"></script>
        <script type="text/javascript" src="js/libs/sha1.js"></script>
        <script type="text/javascript" src="js/process.js"></script>
        <link type="text/css" rel="stylesheet" href="css/styles.css" />
    </head>
    <body>
        <form id="fileForm" class="fileForm">
            <input id="fileInput" type="file" required="required" />
            <button id="processButton" type="submit">Process</button>
        </form>

        <div class="fileStatus">
            <progress id="processProgress" max="1" value="0"></progress>
            <p><span id="processError" class="error"></span></p>
            <table id="processResults">
                <thead>
                    <tr><th>Param</th><th>Value</th></tr>
                </thead>
                <tbody>
                    <tr><td>Name</td><td id="nameValue"></td></tr>
                    <tr><td>Size</td><td id="sizeValue"></td></tr>
                    <tr><td>Type</td><td id="typeValue"></td></tr>
                    <tr><td>Hash</td><td id="hashValue"></td></tr>
                </tbody>
            </table>
        </div>
    </body>
</html>

We use JQuery to simplify several DOM operations and a very nice JavaScript library to calculate SHA-1 hashes (created by T. Michael Keesey). We use a basic form to select single file from local disk and submit it for processing. Once the file is submitted, we are periodically informing the user about the progress of the operation using progress element and finally update the values in the table. Alternatively, if the reading fails, we show the error.

One important thing I did not mention yet is js/process.js file where lives logic of our application:

function calculateHash(fileContents) {
    return sha1.hash(fileContents);
}

function startProcessing(fileInput, onsuccess, onerror, onprogress) {
    var fileList = fileInput[0].files;
    var file = fileList[0];
    var results = {
        name: file.name,
        size: file.size,
        type: file.type,
        hash: ""
    };

    var fileReader = new FileReader();
    fileReader.onload = function(e) {
        results.hash = calculateHash(e.target.result);
        onsuccess(results);
    };
    fileReader.onerror = function(e) {
        onerror(e.target.error.name);
    };
    fileReader.onprogress = function(e) {
        onprogress(e.loaded, e.total);
    };
    fileReader.readAsArrayBuffer(file);
}

function setResults(name, size, type, hash) {
    var table = $("#processResults");
    table.find("#nameValue").text(name);
    table.find("#sizeValue").text(size);
    table.find("#typeValue").text(type);
    table.find("#hashValue").text(hash);
}

function clearResults() {
    $("#processProgress").val(0).show();
    $("#processError").hide();
    $("#processResults").hide();
    setResults("", "", "", "");
}

function populateResults(data) {
    $("#processProgress").val(1);
    $("#processResults").show();
    setResults(data.name, data.size, data.type, data.hash);
}

function populateError(msg) {
    $("#processProgress").hide();
    $("#processError").text("Failed to read file: " + msg);
    $("#processError").show();
}

function populateProgress(loaded, total) {
    $("#processProgress").val(loaded / total);
}

function initialize() {
    $("#fileForm").submit(function(e) {
        e.preventDefault();
        clearResults();
        startProcessing($("#fileInput"), populateResults, populateError, populateProgress);
    });
    clearResults();
}

$(document).ready(initialize);

The most interesting things happen in two first functions. Function calculateHash() calculates and returns SHA-1 hash based on already read contents of the file (passed in as ArrayBuffer object). This function is synchronous which means that it may take some time to finish. On my system it is about 2 seconds per 100MB of data which in practice is not a big issue. Should it become a problem, you may consider putting SHA-1 calculation in a separate thread using web workers.

Function startProcessing() is the place where all the reading happens. At first, we obtain an object named file representing a file selected by a user and create object named results holding the data to be returned after reading operation finishes successfully. Then we create FileReader, setup listeners for onload, onerror and onprogress events of FileReader, and start reading the file into ArrayBuffer. The call fileReader.readAsArrayBuffer() ends immediately.

When the reading operation finishes successfully, event onload is triggered and the first event listener is called. In this event listener we calculate the SHA-1 hash and invoke onsuccess callback. Please, note that e.target.result is actually the same as fileReader.results and holds the contents of the file. In case of an error, event onerror is triggered which in our application shows an error message to a user. Additionally, event onprogress is called several times while reading the file and is used to update the progress bar.

The rest of the functions are responsible for updating, showing and hiding elements on the web page. Function initialize() additionally registers event listener to be called when a user submits the form.

Conclusion

File API is nothing fancy but if used correctly it can significantly improve user experience by reducing the number of round-trips to server and providing better feedback to user (e.g. showing thumbnails of selected files or monitoring progress of file upload).

The article shows only a portion of what File API can do. If you are interested in knowing more, take a look at W3C Working Draft.

The source code for the example can be found at GitHub.

Posted in HTML, JavaScript | Tagged , , | Leave a comment

Adding external/custom jars into Maven project

One of the strongest points of Maven is that it automatically manages project dependencies. The developer just needs to specify which dependencies and in which version are needed and the Maven takes care of the rest including downloading and storing them at the right location and additionally packaging them into final artifact (e.g. WAR). This is very convenient and almost completely removes a need to hold additional jars in lib/ project subdirectory.

However, there is a small assumption that all required dependencies are available at one or more public repositories. It is usually the case but sometimes you may need to use a jar which is not available there for some reason. Luckily, there are few popular approaches to overcome this problem which are described below.

Adding jar to public Maven repository

Theoretically, the best way would be to add a jar to a public Maven repository. However, if the jar is proprietary, it is usually impossible to get the permission from the company to do so.

Using system dependency

The second method is to add the required dependency with the system scope and additionally provide an absolute path to the a jar file placed somewhere on the local disc:

<dependencies>
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>evalpostfix</artifactId>
    <version>1.0</version>
    <scope>system</scope>
    <systemPath>${basedir}/lib/evalpostfix-1.0.jar</systemPath>
  </dependency>
</dependencies>

The problem with this approach is that this dependency will be completely ignored during packaging and forcing Maven to add it to the final artifact (e.g. WAR) would result in a very clumsy POM file.

Installing jar into local Maven repository

Much better solution is to add the required dependency manually to the local repository using command:

$ mvn install:install-file -Dfile=<path-to-file> \
    -DgroupId=<group-id> -DartifactId=<artifact-id> \
    -Dversion=<version> -Dpackaging=<packaging>

For example adding external jar evalpostfix-1.0.jar to the local repository could look like this:

$ mvn install:install-file -Dfile=evalpostfix-1.0.jar \
     -DgroupId=com.example -DartifactId=evalpostfix \
     -Dversion=1.0 -Dpackaging=jar
(...)
[INFO] --- maven-install-plugin:2.4:install-file (default-cli) @ standalone-pom ---
[INFO] Installing /home/robert/informatyka/softwarecave/infixtopostfix/target/evalpostfix-1.0.jar to /home/robert/.m2/repository/com/example/evalpostfix/1.0/evalpostfix-1.0.jar
[INFO] Installing /tmp/mvninstall2671284263455462989.pom to /home/robert/.m2/repository/com/example/evalpostfix/1.0/evalpostfix-1.0.pom
(...)

Once the dependency is available in the local repository it can be added to POM file like any other dependency:

<dependencies>
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>evalpostfix</artifactId>
    <version>1.0</version>
  </dependency>
</dependencies>

This solution is still inconvenient because every new developer working on the project would have to run mvn install:install command on its own workstation.

Using internal Maven repository in a company

One of the best ideas is to setup an internal Maven repository in a company for storing such dependencies. The repository should be available to every developer working on a project though HTTP or other protocol supported by Maven. Of course, the repository server does not have to be available from outside of the company.

The required dependencies should be installed on the repository server using mvn install:install-file command:

$ mvn install:install-file -Dfile=evalpostfix-1.0.jar \
      -DgroupId=com.example -DartifactId=evalpostfix \
      -Dversion=1.0 -Dpackaging=jar \
      -DlocalRepositoryPath=/opt/mvn-repository/

The only difference from the command in the previous section is that it additionally specifies the path on the repository server where the jars and metadata should be stored.

Once it is finished, the dependency can be added to the POM file. Additionally, the location of the new repository server is provided:

<repositories>
  <repository>
    <id>Internal company repository</id>
    <url>http://mvnrepo.company.com/</url>
  </repository>
</repositories>
(...)
<dependencies>
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>evalpostfix</artifactId>
    <version>1.0</version>
  </dependency>
</dependencies>

The advantages of this approach should be clearly visible:

  • new developers can start building the project without any additional preparation tasks
  • no need to send jars though emails, IM or downloading them from the Internet
  • reduced or completely removed need for build instructions
  • all external jars are managed in a single place
  • dependencies and the server can be shared by multiple projects

Using in-project Maven repository

The idea is quite similar to using internal repository server but this time the repository is stored in a directory (e.g. called lib) located in a project root directory. After creating the directory and installing jar files there using mvn install:install-file command, the dependencies and the repository can be referenced from a POM file:

<repositories>
  <repository>
    <id>Internal company repository</id>
    <url>file://${basedir}/lib</url>
  </repository>
</repositories>
(...)
<dependencies>
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>evalpostfix</artifactId>
    <version>1.0</version>
  </dependency>
</dependencies>

The created repository including jars, pom files and checksums must be stored in a version control system so that it is available to other developers. The biggest issue with this solution is that it clutters VCS repository with files that such never be placed there (e.g. jars).

Conclusion

Choosing the right solution is not always easy. Personally, I would first try to add the jar into public or at least internal Maven repository in a company. If it is not be possible, I would go for in-project Maven repository and use the other methods as a last resort.

Posted in Java, Maven | Tagged , | 1 Comment

Integrating Hibernate with Spring

When building a web application, we will sooner or later need to somehow store data entered by users and retrieve it later. In most cases the best place to keep such data is a database because it additionally provides many useful features like transactions.

Therefore, in this article I would like to show how to extend our previous Spring MVC application to use Hibernate to access database and manage transactions. The configuration details slightly depend on the database being used. In our case it will be Oracle 11gR2 database.

Configuring Hibernate session factory

Before we start we have to configure Hibernate session factory in our Spring configuration file:

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com.example.springhibernate" />
    <property name="hibernateProperties">
        <props>
            <prop key="dialect">
                org.hibernate.dialect.Oracle10gDialect
            </prop>
            <prop key="hibernate.show_sql">
                true
            </prop>
            <prop key="hibernate.hbm2ddl.auto">
                create
            </prop>
        </props>
    </property>
</bean>

In property dataSource we refer to the data source configured in our application server and exposed via JNDI with name java:/orcl:

    <jee:jndi-lookup id="dataSource" jndi-name="java:/orcl" />

The second property packagesToScan specifies Java package to automatically scan for annotated entity classes. This way it is no longer necessary to prepare Hibernate mapping file.

Finally, the third property hibernateProperties gives us possibility to configure various Hibernate properties. In property dialect we specify that we use Oracle database, then we inform Hibernate to print issued SQL commands to the server log and to generate necessary objects (like tables) in the database. Please, note that the last option cannot be used in the production code because it may drop already existing tables in the database. We use it only to simplify the example.

Configuring transaction support

Because we plan to use Hibernate transactions and declare them using annotations, we have to add two additional elements to our Spring configuration:

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:annotation-driven/>

The first one informs Spring to instantiate HibernateTransactionManager transaction manager and associate it with the previously configured Hibernate session factory. The second one tells Spring to scan all classes for @Transactional annotation on a class or method level in order to use it with the transaction manager.

Using annotations

After we have finished the configuration, we can add standard persistence annotations to our Person entity class:

package com.example.springhibernate;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table(name = "springhibernate_person")
@NamedQuery(name = "Person.selectAll", query = "select o from Person o")
public class Person implements Serializable {
    private static final long serialVersionUID = 3297423984732894L;
    
    @Id
    @GeneratedValue
    private int id;
    private String firstName;
    private String lastName;
    private Integer age;
    // constructor, setters and getters
}

To access the database we create a simple repository class annotated with @Repository:

package com.example.springhibernate;

import java.io.Serializable;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional
public class PersonList implements Serializable {
    private static final long serialVersionUID = 324589274837L;

    @Autowired
    private SessionFactory sessionFactory;
    
    @Transactional
    public void addPerson(Person person) {
        sessionFactory.getCurrentSession().save(person);
    }
    
    @Transactional
    public List<Person> getAll() {
        Query query = sessionFactory.getCurrentSession().getNamedQuery("Person.selectAll");
        return (List<Person>) query.list();
    }
}

In this class we obtain a reference to the correct SessionFactory instance using plain @Autowired annotation. Additionally, both methods of this class are annotated with @Transactional to inform Spring that these methods should be executed in a transaction.

Conclusion

Configuration of Hibernate in Spring is not very difficult but still requires setting several parameters specific to the environment in XML configuration files. The rest of the code is totally independent of it so changes necessary to switch to the other database or application server are limited to few lines of the configuration.

The example above uses version 4 of Hibernate but switching to version 3 is pretty simple and requires only replacing hibernate4 by hibernate3 in two places in Spring XML file.

The complete source code of the example can be found at GitHub.

Posted in Hibernate, Java, Java EE, Spring | Tagged , , , , , | 1 Comment

Repeating annotations in Java 8

In Java 7 and before attaching more than one annotation of the same type to the same part of the code (e.g. a class or a method) was forbidden. Therefore, the developers had to group them together into single container annotation as a workaround:

@Authors({
    @Author(name = "John"),
    @Author(name = "George")
})
public class Book { ... }

Java 8 brought a small yet very useful improvement called repeating annotations which allows us to rewrite the same code without explicitly using the container annotation:

@Author(name = "John")
@Author(name = "George")
public class Book { ... }

For compatibility reasons, the container annotation is still used but this time the Java compiler is responsible for wrapping the repeating annotations into a container annotation.

Declaring repeatable annotation type

User-defined annotations are not repeatable by default and have to be annotated with @Repeatable annotation:

package com.example.customannotation;

import java.lang.annotation.Repeatable;

@Repeatable(value = Authors.class)
public @interface Author {
    String name() default "";
}

The element value of @Repeatable annotation represents the type of the container annotation:

package com.example.customannotation;

public @interface Authors {
    Author[] value();
}

When repeating annotation Author is used multiple times on the same part of the code, the Java compiler automatically creates container annotation Authors and stores all repeating annotations Author into its value element.

This is the minimal working configuration but in most cases you may decide to additionally specify at least target and retention of the annotation type.

Accessing annotations via reflection

Repeating annotations can be accessed in two ways. The first one is to access them by first getting their container annotation using getAnnotation() or getDeclaredAnnotation() methods of AnnotatedElement interface:

Authors authors = klazz.getAnnotation(Authors.class);
for (Author author : authors.value())
    System.out.println("Author=" + author.name());

The second method relies on newly introduced getAnnotationsByType() and/or getDeclaredAnnotationsByType() methods which automatically scan though the container annotation, extract the repeating annotations and return them at once as an array:

Author[] authors = klazz.getAnnotationsByType(Author.class);
for (Author author : authors)
    System.out.println("Author=" + author.name());

Conclusion

Repeating annotations is a small addition to Java which simplifies usage of some annotations in various frameworks (especially in Hibernate and JPA). Because the feature is quite new, you may still need to explicitly use container annotation for some time (until @Repeatable is added to all necessary annotation types).

Posted in Java | Tagged | Leave a comment

Custom annotations in Java

Java developers are not limited to using built-in annotations only but can also create their own annotations to provide additional functionality. For example many Java frameworks define custom annotations to provide (or at least simplify usage of) such functionality as:

  • unit testing
  • ORM mapping
  • bean validation
  • Java class to XML mapping
  • web-service description

Of course, the list is not even one percent complete. In this article I would like to describe how to create custom annotations and later access them through reflection.

Creating custom annotation

Annotation type definition is very similar to an interface definition:

public @interface Version {
    int major();
    int minor() default 0;
    String date();
}

The most visible difference is the usage of interface keyword preceded by the at sign (@) when defining annotation type. The similar syntax is not a coincidence because in fact annotations are visible to the virtual machine as plain interfaces extending Annotation interface and the annotation elements are visible as abstract methods. It is also possible to create static fields, static classes and enums inside an annotation. It is, however, impossible to create a new annotation type by extending (inheriting from) existing annotation type.

Another important difference is the ability to specify a default value for the annotation element. If the element has a default value, it can but don’t have to be specified when using the annotation. If it is not specified, the default value is used. The default value must be a constant and can never be a null value. The latter requirement is somewhat inconvenient and forces programmers to use other default values like “” or Void.class.

Additionally, annotation elements cannot have arguments, cannot define thrown exceptions, cannot be generic and their element types are limited to:

  • primitive types like int, long, double or boolean
  • String class
  • Class class with optional bounds
  • enum types
  • annotation types
  • an array containing one of the above types

Here is another annotation using most of the types above:

public @interface ClassInfo {
    enum AccessLevel { PUBLIC, PROTECTED, PACKAGE_PROTECTED, PRIVATE};

    String author();
    Version version();
    AccessLevel accessLevel() default AccessLevel.PACKAGE_PROTECTED;
    String[] reviewers() default { };
    Class<?>[] testCases() default { };
}

Please, note that in the second element we refer to the previously defined Version annotation. In the next one we use enum type (defined within the same annotation) as the element type and we also provide one of its values as a default value. The last two elements can be assigned an array – if they are not set, they default to an empty array.

Meta-annotations

Java provides several meta-annotations – annotations which can be applied to other annotations. The custom annotation can be annotated with one or more of such meta-annotations to provide additional information how the custom annotation can be used.

@Target

@Target annotation restricts to which source code elements the custom annotation can be applied. The value of the @Target annotation is an array containing one or more of the following values:

  • ElementType.ANNOTATION_TYPE – can be applied to another annotation type (creates meta-annotation)
  • ElementType.CONSTRUCTOR – can be applied to a constructor
  • ElementType.FIELD – can be applied to a field (includes enum constants)
  • ElementType.LOCAL_VARIABLE – can be applied to a local variable
  • ElementType.METHOD – can be applied to a method
  • ElementType.PACKAGE – can be applied to a package (placed in package-info.java file)
  • ElementType.PARAMETER – can be applied to a method parameter
  • ElementType.TYPE – can be applied to a type (class, interface, enum or annotation)
  • ElementType.TYPE_PARAMETER – can be applied to a type parameter (new concept in Java 8)
  • ElementType.TYPE_USE – can be applied to a use of type (new concept in Java 8)

If the @Target annotation is missing, the annotation can be applied almost everywhere except type parameter.

@Retention

@Retention annotation indicates how the custom annotation is stored. Its value can be one of the following values:

  • RetentionPolicy.SOURCE – annotations are analyzed by the compiler only and are never stored into class files
  • RetentionPolicy.CLASS – annotations are stored into class files but are not retained by the virtual machine at run-time
  • RetentionPolicy.RUNTIME – annotations are stored into class files and are retained by the virtual machine at run-time so they are available via reflection

If the @Retention annotation is missing, the value defaults to Retention.CLASS. In most cases RetentionPolicy.RUNTIME policy is used in order to be able to examine the annotations at run-time.

@Documented

@Documented annotation indicates whether the custom annotation should appear on the annotated elements in Javadoc documentation. If @Documented is applied to the custom annotation, all classes annotated with the custom annotation will be marked as such in Javadoc documentation. If @Documentation is missing, Javadoc documentation may contain information about the custom annotation (depending on its access modifiers and JavaDoc parameters) but won’t contain information about which classes were annotated with the custom annotation.

@Inherited

@Inherited annotation indicates whether the custom annotation is inherited from the super class. This annotation does not have any effect if the custom annotation is applied to anything other than a class. By default the annotations are not inherited.

@Repeatable

@Repeatable annotation indicates whether the custom annotation can be applied to the same source code element multiple times. By default the same annotation type can be used only once on the same source code element.

Accessing annotations via reflection

Information about annotations applied to classes, methods and many other elements can be extracted using AnnotatedElement interface which is implemented by the following reflective classes: Class, Constructor, Field, Method, Package and Parameter. The presence of the annotation can be checked using isAnnotationPresent() method and the actual annotations can be retrieved using methods: getAnnotation(), getAnnotations() and few more.

The element values can be accessed by calling appropriate methods (named the same as annotation elements) on the returned instances of Annotation interface.

If the annotations have a retention policy different than RetentionPolicy.RUNTIME, they won’t be accessible though reflection.

Example

As an example we will create a very, very simple annotation-based unit test framework. The methods to test will be annotated using following annotation:

package com.example.customannotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest {
    String name() default "";
    MyTestState state() default MyTestState.ACTIVE;
    Class<? extends Throwable> expected() default None.class;
    
    static class None extends Throwable {
    }
}

Annotation MyTest uses @Retention(RetentionPolicy.RUNTIME) to make it accessible through reflection at run-time and @Target(ElementType.METHOD) to restrict its usage only to methods. Because we cannot use null as a default value for expected element, we create an empty class None and set its class object as a default value. Additionally, we allow the tests to be enabled or disabled using this enumeration:

package com.example.customannotation;

public enum MyTestState {
    ACTIVE, INACTIVE
}

Once we have the annotation ready, we can apply it to the test methods:

package com.example.customannotation;

import static com.example.customannotation.MyAsserts.*;

public class SimpleTestCase {

    @MyTest(name = "test1WithCustomName", state = MyTestState.ACTIVE)
    public void test1() {
        assertEquals(2, 1 + 1);
        assertEquals(Integer.parseInt("-3"), -3);
    }
    
    @MyTest(expected = NumberFormatException.class)
    public void test2() {
        Integer.parseInt("1.23ddd");
    }
    
    @MyTest(state = MyTestState.INACTIVE)
    public void test3() {
        throw new IllegalStateException("Test case is inactive");
    }
}

The last step is to create a simple test runner which accepts a list of classes to test:

package com.example.customannotation;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MyTestRunner {

    public void run(Class<?>... klasses) {
        for (Class<?> testClass : klasses) {
            runTestClass(testClass);
        }
    }
    
    private void runTestClass(Class<?> klass) {
        for (Method method : klass.getMethods()) {
            MyTest annotation = method.getAnnotation(MyTest.class);
            if (annotation != null)
                runTestMethod(klass, method, annotation);
        }
    }

    private void runTestMethod(Class<?> klass, Method method, MyTest annotation) {
        if (annotation.state() != MyTestState.ACTIVE)
            return;
        try {
            System.out.println("Running test: " + getTestName(method, annotation));
            Object testInstance = klass.newInstance();
            method.invoke(testInstance);
            System.out.println("SUCCESS");
        } catch (InstantiationException e) {
            System.err.println("FAILED: Failed to instantiate class " + klass.getName());
        } catch (IllegalAccessException e) {
            System.err.println("FAILED: Failed to call test method " + method.getName());
        } catch (InvocationTargetException e) {
            checkThrowable(annotation, e.getCause());
        }
    }

    private static String getTestName(Method method, MyTest annotation) {
        return !annotation.name().isEmpty() ? annotation.name() : method.getName();
    }
    
    private void checkThrowable(MyTest annotation, Throwable th) {
        if (annotation.expected() == th.getClass())
            System.out.println("SUCCESS");
        else
            System.out.println("FAILED: " + th.getMessage());
    }
}

and use the runner to execute the tests:

package com.example.customannotation;

import java.io.IOException;

public class Main {

    public static void main(String[] args) throws IOException {
        MyTestRunner runner = new MyTestRunner();
        runner.run(SimpleTestCase.class);
    }

}

The Method.getAnnotation() method is used to extract MyTest annotation (if present) for each method. Later the elements of MyTest annotation are accessed in getTestName() and checkThrowable() methods. The lack of null checks in both methods is normal because annotation elements cannot be null.

Conclusion

Creating custom annotations is not a very common task because most of the time we are just using existing annotations defined in various frameworks. However, sometimes it may be necessary to create our own annotation to extend existing framework (e.g. Bean Validation or Spring). To keep the article concise I have almost silently omitted several rarely used concepts like repeated annotations or use of types. I am going to cover them in near future.

The complete source code for the example is available at GitHub.

Another example of custom annotations is described in article Custom bean validation constraints.

Posted in Java | Tagged , | 1 Comment

Annotation basics in Java

Annotations are a kind of metadata attached to various parts of the source code in Java. Although they do not directly affect how the code works, they are processed and used by different tools to provide additional functionality or services to the application. The typical use cases are:

  • instructions to the Java compiler – checking various assumptions (e.g. whether a method was correctly overridden), suppressing warnings, marking and reporting usage of deprecated code and more
  • instructions to the environment – generating code, XML files and more
  • runtime processing – taking different actions at runtime depending on the presence and the contents of the annotation

Annotations are used extensively in various frameworks to simplify source code, reduce the length of configuration, provide loose coupling between components and much more. The notable frameworks using annotations are Java EE, Spring, Hibernate and JUnit.

Basic usage

Annotation can be attached to a source code element (e.g. a class or a method) by placing its name preceded with an at sign character (@) before the element to annotate:

@Override
void doAction() { ... }

In case of many annotations it is also possible to provide additional elements in parentheses:

@SuppressWarnings(value = "unchecked")
void doAction() { ... }

If only one element named value is provided, its name may be omitted as shown below:

@SuppressWarnings("unchecked")
void doAction() { ... }

If needed multiple annotations of different types may be attached to the same source code element:

@Entity
@Table(name = "PEOPLE_PERSON")
public class Person implements Serializable { ... }

If there are at least two annotations of the same type (also called repeating annotations), they have to be grouped into one composed annotation. In the code below, two different @NamedQuery annotations could not be attached to the same class so they were put as a part of @NamedQueries annotation:

@Entity
@Table(name = "PEOPLE_PERSON")
@NamedQueries({
    @NamedQuery(name = "selectAllPersons",
                query = "select o from Person o"),
    @NamedQuery(name = "countAllPersons",
                query = "select count(o) from Person o")
})
public class Person implements Serializable { ... }

Since Java 8 it is possible to use repeating annotations without explicit grouping but it requires a small change to a definition of each annotation type. Therefore, it may not be yet possible in many cases.

Common annotations

Java SE comes with few predefined annotations. Some of them used by the Java compiler are described below.

@Override

@Override annotation informs the compiler that given method is intended to override a method declared in a superclass. If the method with this annotation fails to override any method (e.g. due to incompatible signature), the Java compiler raises an error. Although using this annotation is not necessary (omitting it does not cause any compilation errors), it is very useful to detect possible issues when doing large modifications or refactoring.

class MyFile implements AutoCloseable {
    @Override
    public void close() throws Exception { ...  }
}

@Deprecated

@Deprecated annotation informs that given element (e.g. constructor, class, method) is deprecated and its usage is discouraged. When a deprecated element is used somewhere in the source code, a warning is reported during compilation. Many IDE provide also visual indication to a developer by striking through all deprecated elements and their usage.

@Deprecated annotation is closely related with JavaDoc @deprecated tag. If @Deprecated annotation is used, it is also a good idea to add @deprecated tag to a JavaDoc comment explaining why it was deprecated and what could be used in place of it.

/**
 * Closes the file.
 * @deprecated Does not report errors.
 *             Use closeFile() instead.
 */
@Deprecated
void close() { ... }

@SuppressWarnings

@SuppressWarnings annotation instructs the compiler to suppress given warnings for annotated elements and all of its children. At the moment there are only two official (described in the Java Language Specification) categories of warnings which can be suppressed:

  • deprecation – suppresses warnings about usage of deprecated elements
  • unchecked – suppresses warnings about usage of raw (unchecked) types

However, IDE (e.g. Eclipse or IntelliJ IDEA) and Java compilers can and usually do implement their own custom categories. For example you can get all categories supported by Oracle Java compiler using command:

$ javac -X

and searching for ‘-Xlint’ option.

Here is a sample code which suppresses warning regarding usage of deprecated LineNumberInputStream class:

@SuppressWarnings("deprecation")
void read() {
    LineNumberInputStream is = new LineNumberInputStream(System.in);
}

@SafeVarargs

@SafeVarargs annotation informs compiler that the annotated method or constructor does not do any potentially unsafe operations on its varargs arguments. This annotation is generally used to suppress unchecked warnings related to the usage of varargs in the code like this:

@SafeVarargs
static <T> void print(T... args) {
    for (T t : args)
        System.out.println(t);
}
   
void callPrint() {
    print(new ArrayList<Integer>(), new ArrayList<Long>());
}

Because looking at the body of the print() method, we don’t see any dangerous casts or assignments, we can safely add @SafeVarargs annotation. Without @SafeVarargs the compiler would generate warnings similar to these:

warning: [unchecked] Possible heap pollution from parameterized vararg type T
warning: [unchecked] unchecked generic array creation for varargs parameter of type ArrayList...

@FunctionalInterface

@FunctionalInterface annotation (available since Java 8) informs the Java compiler that given interface is intended to be a functional interface. The functional interface is an interface with exactly one abstract method (not counting default methods and abstract methods overriding methods of Object class) and which can be used together with lambda expressions. If the interface annotated with @FunctionalInterface contains different number of abstract methods than one, the Java compiler raises an error. Although using this annotation is not necessary (omitting it does not cause any compilation errors), it is very useful to detect possible issues when doing bigger modifications or refactoring.

In the example below removing existing method test() or adding a new abstract method (except the ones mentioned above) would result in a compilation error:

@FunctionalInterface
public interface MyPredicate<T> {
    boolean test(T data);
}

Annotations and marker interfaces

Marker interface is simply an interface without any methods. Although it does not define any behavior in a typical sense, it carries type information (information whether the class implements given marker interface or not) which can be used by various mechanisms in Java to perform some special handling. Two widely known examples of such interfaces are Serializable and Cloneable.

Most probably annotations would be better suited for marking the class as serializable or cloneable but they were not available in Java at the time serialization and cloning were introduced. Nowadays, we may think about marker interfaces as very limited and unattractive predecessors of annotations.

Conclusion

These days, annotations are used almost everywhere in Java so it is very important to know them. Although this article covers only the basic usage of few existing annotations, it should be enough to start using other annotations available in various frameworks.

Posted in Java | Tagged | 1 Comment