⬆️ ⬇️

Java 8, Spring, Hibernate, SSP - we start playing

Most recently, Java 8 came out. And I had a desire to write something using new plush, which gives 8-erka.

Lamba specifically, the new collection api, which allows you to work with collections in a more functional style and default-methods in interfaces.



This article is a summary of my experience in integrating Java 8, Spring MVC, Hibernate, and SSP.



Who cares, I ask under the cat.



Foreword



For a long time I (and still) continue to admire the language of Scala, but unfortunately, my brain still saturated with mynthetic primer prevents me from switching to pure Scala.

')

First of all, due to binding to external libraries (Hibernate, Spring, Spring MVC), to which I still have weakness.

I tried to use them in Scala-projects, but there is a constant impression that you are engaged in the permanent arrangement of crutches and supports and you can’t write in Scala-style,

rather, you write in Java, but with Scala syntax + crutches and supports in the form of implicit conversions of Java collections to Scala collections and back.



So I decided to go a little more "soft" way and use the familiar stack. The only change I've come to is using SSP (Scala Server Pages) instead of JSP (Java Server Pages),

to get static support on the side of View and not have a strong headache with the fact

that something breaks during refactoring and you will find out after the deployment (when a block stupidly stops being displayed, or worse, it spoils the data in the database)



Start



So, let's begin.



We will use my favorite maven.



Let's give Maven an idea that our 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 the necessary dependencies on Spring (version 4, which supports changes in the new version of the JDK, as well as pulls a library that can work with bytecode generated by the 8th Java) / Hibernate and SSP. Everything else to taste. Versions are rendered in the “dependency management” section in the parent pom'e.

 <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 that came across is the incompatibility of the Scala compiler, which comes with dependency with the Scalate library (thanks to it, we have SSP support) with Java 8 byte-code.

I had to explicitly write the dependency to the Scala project compiler, so that everything would take off:



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




// initially wanted to upgrade the dependency to 2.11, but the “guts” have changed a lot and this is not yet supported in the latest available version of Scalate (1.6.1).



We also want our SSPs to be precompiled and we will know about the problem during compilation, but not in production.

Therefore, we add a plugin for this:



 <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 it is noticeable, the same hook is added with the Scala compiler



Some code





Well, with almost all the configuration



Now you can start messing with the code and enjoy the JDK 8 buns:



My base 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, we could not manage without an additional layer in the form of 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; } } 




Specific DAO Interface:

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




Well and appropriately implementation:



 @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 get a CRUD for the repository and, in my opinion, we clear the implementation of the side noise.

// Of course, Spring Data JPA could be used and then CRUD would not have to write at all, but I don’t like some things from there: In the case of manually generated / assigned IDs, it will always do merge instead of persist. Yes, and so it is quite easier to control the behavior of the system.



We also get rid of the need to use third-party libraries such as Guava, which allow you to write in a more functional style and get everything out of the box:



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




View to display the list:



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


Build the project is simple. If you have deflated my project and want to support it in a servlet container, say in Tomcat, then run:

mvn -P = build clean package



And we see how our SSP's 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 God forbid something went wrong and we broke something in them from what is being compiled, then we will know about it now, and not after deploying to dev / qa / staging / production environment.



In the example I used Twitter Bootstrap, because I like it.



Screenshots
Create user:





A list of users:





Editing user:









Example code:

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



As a free bonus:



Same for Java 7:

github.com/dargiri/spring-mvc-java-web-app-template



Same on Scala:

github.com/dargiri/spring-mvc-scala-web-app-template



And if you're still reading this and pulled out your code and want to play with it.



I prefer to run from under the IDE, rather than use plugins for the IDE.

Therefore, in the web-app-launcher module we find the Launcher class.

If you use Idea, then everything will start without problems.

If you use Eclipse / Netbeans, then some manipulations are needed.

For Eclipse, initially get Eclipse with JDK 8 support: www.eclipse.org/downloads/index-java8.php



PPS Write the code and may the force be with you.



Next for the project you need to select the build maven-profile.

And in the Launcher class, change the value of the variable MULTI_MODULE_DEFAULT_PATH from “web / src / main / webapp” to “../web/src/main/webapp” or to the full path from the root of your file system.



References:



Apache Maven - maven.apache.org

Scalate - scalate.fusesource.org

Scala - www.scala-lang.org

Apache Tomcat - tomcat.apache.org

Twitter Bootstrap - getbootstrap.com

Spring Data JPA - projects.spring.io/spring-data-jpa

Hibernate ORM - hibernate.org/orm

JDK 8 - www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

Spring - projects.spring.io/spring-framework

Source: https://habr.com/ru/post/222077/



All Articles