Java 8 has been recently released. So I decided to write something using its new features.
Namely the new collection api, which allows to work with collections in a more functional style, and default methods in the interfaces.
This article is a brief review of my experience of Java 8, Spring MVC, Hibernate and SSP integration.

Foreword


I've always admired the Scala language. First of all, because of the binding with external libraries (Hibernate, Spring, Spring MVC), which I still have a weakness for.
I tried to use them in Scala projects, but it seemed as if I was arranging workarounds all the time and still couldn’t write in Scala style. As if I was writing in Java, but with Scala syntax and vice versa.
That’s why I decided to follow a bit “smooth” path and use a familiar stack.
I decided to use SSP (Scala Server Pages) instead of JSP (Java Server Pages), in order to get static support on the View side and to not worry about breaking at refactoring, while you learn about it after deployment only (when some block stops being displayed or even worse, damages some data in the database)

Beginning


So, let’s start.

We’re going to use my favorite Maven.

Let’s drop Maven a hint that the project will use Java 8:

...
<build>
    <plugins>
    ...
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <executions>
                <execution>
                    <phase>compile</phase>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <_source>1.8</_source>
                <target>1.8</target>
            </configuration>
        </plugin>
...
    </plugins>
</build>
...

Add necessary relations to Spring (generated by 8th Java the 4th version, which supports changes of the new JDK. It also provides a library which can operate with the byte code)/Hibernate and SSP. You may add other things to your liking. The versions are located at the «dependency management» section at the parent pom.

<dependencies>
...
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
    </dependency>

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
    </dependency>

    <dependency>
        <groupId>org.hibernate.javax.persistence</groupId>
        <artifactId>hibernate-jpa-2.0-api</artifactId>
    </dependency>
    
    <!-- Scalate (SSP) support-->
    <dependency>
        <groupId>org.fusesource.scalate</groupId>
        <artifactId>scalate-core_2.10</artifactId>
    </dependency>

    <dependency>
        <groupId>org.fusesource.scalate</groupId>
        <artifactId>scalate-spring-mvc_2.10</artifactId>
    </dependency>
...
</dependencies>

The first problem I faced was incompatibility of Scala compiler which depends on Scalate library (owing to it we have SSP support) with Java 8 byte code.

I had to write the dependency to the project at the Scala compiler, so that everything would operate.

<dependency>
    <groupId>org.scala-lang</groupId>
    <artifactId>scala-compiler</artifactId>
    <version>2.10.4</version>
</dependency>

At first I wanted to upgrade the dependency up to 2.11, but the content changed a lot and in the latest 1.6.1 Scalate version it’s not supported yet.

We also want our SSP to be recompiled so that we could find out about the problem during compilation, not at production.
So we added the following plug-in:

<build>
    <plugins>
        ...
        <plugin>
            <groupId>org.fusesource.scalate</groupId>
            <artifactId>maven-scalate-plugin_2.10</artifactId>
            <version>1.6.1</version>
            <!--Support jdk 8-->
            <dependencies>
                <dependency>
                    <groupId>org.scala-lang</groupId>
                    <artifactId>scala-compiler</artifactId>
                    <version>2.10.4</version>
                </dependency>
            </dependencies>
            <executions>
                <execution>
                    <goals>
                        <goal>precompile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        ...
    </plugins>
</build>

As you can notice, the same hack with Scala compiler has been added.

Some Code


I’m almost done with configuration

Now we can fool around with the code and be happy about JDK 8 facilities:

My basic DAO:

public interface BaseDAO<T extends Model<ID>, ID extends Serializable> extends EntityManagerAware {
    Class<T> getEntityClass();

    default void persist(T entity) {
        if (entity.isNew()) {
            entity.assignId();
        }

        getEntityManager().persist(entity);
        getEntityManager().flush();
    }

    default T find(ID id) {
        return getEntityManager().find(getEntityClass(), id);
    }

    default void delete(T entity) {
        getEntityManager().remove(entity);
    }

    default List<T> findByQuery(String jpqlQueryString) {
        return findByQueryWithParams(jpqlQueryString, Collections.emptyMap());
    }

    default List<T> findByQueryWithParams(String jpqlQueryString, Map<String, Object> params) {
        TypedQuery<T> query = getEntityManager().createQuery(jpqlQueryString, getEntityClass());
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            query.setParameter(entry.getKey(), entry.getValue());
        }
        return query.getResultList();
    }
}

Unfortunately, I couldn’t go without an additional layer (an abstract class):

public abstract class AbstractBaseDAO<T extends Model<ID>, ID extends Serializable> implements BaseDAO<T, ID> {
    @PersistenceContext
    EntityManager entityManager;

    @Override
    public EntityManager getEntityManager() {
        return entityManager;
    }
}

DAO interface:

public interface PersonDAO extends BaseDAO<Person, UUID> {
    @Override
    default Class<Person> getEntityClass() {
        return Person.class;
    }

    List<Person> findAll();
}

And implementation, accordingly:

@Repository
public class PersonDAOImpl extends AbstractBaseDAO<Person, UUID> implements PersonDAO {

    @Override
    public List<Person> findAll() {
        return findByQuery("select p from Person p");
    }
}

As a result, we have a CRUD fora repository and I think we are clearing the implementation from additional noise.
Of course, I could have used Spring Data JPA and I wouldn’t have to manually write CRUD at all, but I don’t like certain aspects of it. In a case of manually generated/assigned ID it will always execute merge instead of persist. Plus the system behavior is easier to control this way.

We also get rid of the need to use exterior libraries of Guava, which allows to write in a more functional style:

List<PersonForm> all = personService.findAll().stream().map(PersonForm::from).collect(Collectors.<PersonForm>toList());

View for the list display:

<%@ val people: java.util.List[name.dargiri.web.controller.PeopleController.PersonForm]%>
<div class="page-header">
<h1>People</h1>
</div>
<table class="table table-striped">
<thead>
    <tr>
        <th>#</th>
        <th>Username</th>
        <th>Action</th>
    </tr>
</thead>
<tbody>
    <% for(person <- people ) { %>
    <tr>
        <td>
            <%=person.id%>
        </td>
        <td>
            <%=person.username%>
        </td>
        <td>
            <a href="<%=uri("/people/edit/" + person.id)%>">Edit</a> |
            <a href="<%=uri("/people/delete/" + person.id)%>">Delete</a>
        </td>
    </tr>
    <% } %>
</tbody>
</table>

The project build is quite simple. If you have downloaded my project and want to deploy it to the servlet container, e.g. Tomcat, then run:
mvn -P=build clean package

And can see how SSPs are pre-compiled:

...
[INFO] --- maven-scalate-plugin_2.10:1.6.1:precompile (default) @ web ---
[INFO] Precompiling Scalate Templates into Scala classes...
[INFO]     processing /Users/dionis/projects/spring-mvc-java8-web-app-template/web/src/main/webapp/WEB-INF/views/scalate/main/person.ssp
[INFO]     processing /Users/dionis/projects/spring-mvc-java8-web-app-template/web/src/main/webapp/WEB-INF/views/scalate/main/people.ssp
[INFO]     processing /Users/dionis/projects/spring-mvc-java8-web-app-template/web/src/main/webapp/WEB-INF/scalate/layouts/default.ssp
...

So if anything has gone wrong and we have broken something that can be compiled, we will learn about it now, not after deployment at dev/qa/staging/production environment.

We used Twitter Bootstrap in the example, as I like it.

Adding new user

Users' list:

Editing a user:


Example code:
github.com/dargiri/spring-mvc-java8-web-app-template

As a free bonus:

The same on Java 7:
github.com/dargiri/spring-mvc-java-web-app-template

The same on Scala:
github.com/dargiri/spring-mvc-scala-web-app-template

If you are Still Reading It and Want to Fool Around with the Code

I prefer running under IDE, not using plug-ins for IDE.
So in web-app-launcher module we can see Launcher class.
If you’re using Idea everything will run with no trouble.
If you’re using Eclipse/Netbeans some manipulations are required.
For Eclipse you can download it with out-of-box JDK 8 support: www.eclipse.org/downloads/index-java8.php

P.P.S. Write code and best of luck!

You need to choose maven-profile build for the project.
In the Launcher class the variable MULTI_MODULE_DEFAULT_PATH value should be changed from «web/src/main/webapp» to "../web/src/main/webapp" or to the full path from your file system root.

Links

Write your own articles at Kukuruku Hub

0 comments

Read Next