Introduction
Almost every application out there in the world has to access data to do its work. Using a domain driven design approach you will need to define and build repositories for the entities that make up your domain. Java developers nowadays often use JPA to implement these repositories. JPA has made this task easier, but still requires a lot of boilerplate code. Hades is an open source library that's built on top of JPA and Spring to significantly improve the implementation of data access layers by reducing the effort to the amount that's actually needed. This article will take you on a guided tour and give you an overview on what Hades can actually do for you regarding data access layer development and takes a look at the new features of the very recent version 2.0.
The very core part of Hades consists of a generic repository implementation that provides you not only with basic CRUD (create, read, update and delete) methods but adds some functionality on top that removes the need to implement common scenarios around that (e.g. pagination) yourself. This includes the ability to query the repository for pages of entities, dynamically adding sort definitions and so on.
Queries
As most of the data access operations you typically have to implement are querying operations one of Hades' core features is to ease defining and executing queries with the least effort possible. The process of doing so actually consists of three steps:
- Add an entity specific repository interface
- Add query methods
- Fine tune queries
In the first step you declare an interface that extends GenericDao<Entity, Id>
which will cause the CRUD operations defined in the Hades interface being available on your interface as well:
public interface UserRepository extends GenericDao<User, Long> { … }
The next step is adding methods for your queries to the interface that serve your business requirements:
List findByUsername(String username);
This should raise the question of how the query will be derived from the method. If you don't add any additional metadata, Hades will try to lookup a JPA named query of the form {entity}.{method-name}
and use that if available. In case it does not find any it will try to parse the method name and create a query from it. So the prior example would result in a query select u from User u where u.username = ?
. The query parser of course supports a lot more keywords, so feel free to check them out in the reference documentation.
If you prefer defining the query manually you can leverage Hades' @Query
annotation to define the query to be executed directly at the method:
@Query("select from User u where u.lastname = ?"); List someReallyStrangeName(String lastname);
This gives you freedom in naming methods the way you like while preserving the full control over the query definition without bothering you with the boilerplate query execution code. There's lots of other stuff around executing queries like using pagination with queries, executing modifying queries and so on.
Bootstrapping Hades
So now that you have seen how to create repository interfaces with query methods it's probably interesting how you get that stuff started and ready to be used. You can create instances for the repository interface by creating a GenericDaoFactory
instance and ask it to create repositories for you:
EntityManager em = … // Get access to EntityManager GenericDaoFactory factory = GenericDaoFactory.create(em); UserRepository userRepository = factory.getDao(UserRepository.class);
As repositories are usually handed to its clients by dependency injection there is sophisticated integration for Hades' usage inside a Spring application. So to bootstrap Hades in a Spring app you simply use the Hades namespace and declare a base package that shall be scanned for repositories.
<hades:dao-config base-package="com.acme.*.repository" />
This would pick up all repository interfaces extending GenericDao
and create Spring beans for each of them. Of course the namespace allows much more fine grained control over what's to be detected. The Hades Eclipse plugin provides seamless integration into Spring IDE and SpringSource Tool Suite (STS) so that you will be able to reference Hades repositories from other beans, have them marked as Spring beans in your workspace and so on. For details check out the reference documentation.
Auditing
It's a very common requirement to track creator, modifier and the according dates for entities. Hades provides an EntityListener
that will transparently do the job for you. To activate Hades auditing you need to define the AuditingEntityListener
in your orm.xml
<persistence-unit-metadata> <persistence-unit-defaults> <entity-listeners> <entity-listener class="org.synyx.hades.domain.auditing.support.AuditingEntityListener" /> </entity-listeners> </persistence-unit-defaults> </persistence-unit-metadata>
and then activate auditing in your Spring config as follows:
<hades:auditing auditor-aware-ref="auditorAware" />
The referenced Spring bean auditorAware
has to implement the AuditorAware
interface that you'd typically implement querying your security module for the current user. If you only want to track creation and modification date, just omit the attribute. For more on the auditing feature, consult the documentation.
JPA 2.0 and transactional repositories
As of version 2.0 Hades is based on JPA 2.0 as well as the according versions of Hibernate, EclipseLink and OpenJPA. Starting with that version the CRUD operations are transactional out of the box so that in very simple cases there's no need for a transactional wrapping layer anymore. Furthermore concrete repository interfaces can be made transactional easily as well.
public interface UserRepository extends GenericDao<User, Long> { @Transactional(readOnly = true); List<User> findByUsername(); @Override @Transactional(readOnly = true, timeout = 60); List<User> readAll(); }
As you can see you can simply annotate the query methods with @Transactional
to let them participate in transactions. You don't have to use annotations if you don't like to, XML based transaction configuration simply works as well. The CRUD operations implemented in GenericDao
are transactional by default (with readOnly
set to true for read-only operations). Reconfiguring transaction settings for those methods is done by simply redeclaring the method and applying a custom @Transactional
on it. For more details check out the reference documentation on transactions.
Specifications
A quite cool feature of the latest release is the extension ofGenericDao
to be able to execute specifications. A specification is a Domain Driven Design concept coined by Eric Evans and Martin Fowler that boils down to capturing business rules for an entity into a predicate. Hades provides an abstraction to easily build such predicates based on the JPA 2.0 criteria API. Supposed you have books written by authors. Hades let's you define specifications like that:
class BookSpecifications { public Specification<Book> hasAuthorWithFirstnameLike(final String firstname) { return new Specification<Book>() { public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> cq, CriteriaBuilder cb) { return cb.like(root.join("author").get("firstname"), firstname); } } } public Specification<Book> hasGenre(final Genre genre) { return new Specification<Book>() { public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> cq, CriteriaBuilder cb) { return cb.equal(root.get( "genre"), genre); } } } }
Admittedly this is not the most beautiful piece of code to be written (it will hopefully become a lot better with Java 8's Single Abstract Method (SAM) feature). On the positive side we gain the possibility to execute specifications right on the repository:
bookRepository.readAll(hasAuthorWithFirstnameLike("Oliv*"));
Okay, that's pretty much what we could have achieved with a declared query, right? The power of specifications really shines when combining them into new specifications. Hades provides a Specifications
helper class that allows on-the-fly composition:
bookRepository.readAll(where(hasAuthorWithFirstnameLike( "Oliv*").or(hasGenre(Genres.IT)));
This way, extending your repository becomes just a matter of adding new specifications. With a hand full of specs you get a quite flexible DSL-like API to query your repository without polluting the repository with query methods for every exotic use case. A more detailed introduction can be found at in the documentation.
Extensions
Another part of the 2.0 release is an extensions module that seamlessly integrates Hades with upper layer technologies of your application like Spring MVC. It provides a PropertyEditor
and Spring 3.0 Converter
that allows to transparently bind entities to Spring MVC controller methods by their id as well as an MVC extension that dynamically extracts pagination information from an HTTP request. So a controller displaying a page of users could look something like this:
@Controller class UserController { @Autowired UserRepository userRepository; @RequestMapping("/users") public void showUsers(Pageable pageable, Model model) { model.addAttribute("users", userRepository.readAll(pageable)); } @RequestMapping("/users/{id}") public String showUser(@PathVariable("id") User user, Model model) { model.addAttribute("user", user); return"user"; } }
As you can see for the showUsers(…)
method there's no need to parse the HttpServletRequest
for pagination information yourself. Note, that in showUser(…)
the method parameter bound to the id path variable is already the entity. As the configuration of Spring MVC infrastructure goes beyond the scope of this article feel free to checkout the reference documentation chapter on the extensions module provides configuration examples to ease the setup.
What's next?
Looking forward, beyond the 2.1.x line, Hades will become part of the Spring Data project where it's core will serve as a base for repository implementations for other datastores as well. Spring Data is a SpringSource project that aims to provide idiomatic Spring support for the varieties of emerging, specialized datastores, including NoSQL database.
Summary
Hades hugely eases implementing data access layers with JPA. You get sophisticated CRUD operations, execution of queries as well as specifications for free. It can be used standalone but integrates nicely with Spring as well. Beyond that, there's a Spring IDE/STS Eclipse plugin as well as a Spring Roo add-on to easily create repositories with Roo. For more information see the project website.
About the author
Oliver Gierke is Senior Consultant at SpringSource, a division of VMware and the project lead of the Hades open source project. He started the project at his former company Synyx about two years ago.