HowTo use Spring Data JPA with Errai

What?

Hi there,

since I had quite a hard time, to integrate Spring Data JPA into an Errai Application, I’d like to share my findings and of course the result.

In general these results can be mapped to any other JEE-App.

Hopefully, this will help someone sometime.

Why do that?

In general, I prefeer to use Spring for many reasons. The first one is, as I started developing my former colleague introduced me into a project where the Spring Framework was used. Before that, I only used Java SE and wasn’t familiar with such kind of technology at all.

After I moved to another company, JEE was more used there than Spring.  Nevertheless, JEE didn’t convince me. I was so happy with all the options Spring gave me:

  • Easy integration tests, by just powering up the needed components
  • Removal of boilerplate code
  • Easy usage of dependency Injection
  • No need for an Application Container
  • And so on…

I nevertheless wanted to have a look in the „plain JEE“ stuff, therefore I started to experiment with the Errai Framework, but I still wanted to use Spring Data JPA because it gives me the option to easily switch my Datasource and to run some tests.

How to do that?

By default, Spring Data offers the option to use it with CDI natively, at the point of time I wanted to make use of it, the documentation of Spring, was barely usable, but there has been opened a JIRA-Ticket for that.

Furthermore I’ve started a discussion in the JBoss Forum, but didn’t receive any answer in that point of time. So I investigated further on my own.

What you need!

You need the following libraries which can be found on mavencentral:

  • Spring-Data-Jpa
  • Spring-Core
  • Spring-Context
  • Spring-Aspects
  • Hibernate

A detailed listing can be found in the repository on github.

In the following I will skip the details about the Errai framework, like how to provide an Endpoint and how to call a service on the server side from client. Nevertheless the code examples can also be seen on github.

Let’s start!

We wan’t to provide the functionality that Users can register for our App. Therefore we have to Implement a POJO named User. A User can have some common values, like an Email-Adress, a username, a password and so on.

@Entity @Portable @Bindable @Table(uniqueConstraints=@UniqueConstraint(columnNames="email")) public class User implements Serializable { @Version private Integer version; @Id @GeneratedValue private Integer id; @NotNull private String email; @NotNull private String firstName; @NotNull private String name; @NotNull private String userName; @NotNull private String password;

In order to enable access to the Database we furthermore have to create a DAO, which needs to extend the interface JPA-Repository:

public interface UserRepository extends JpaRepository { @Query("Select u from User u where u.email = ?1") public User findUserByEmail(String email); }

So far, nothing new, at least if you are known to Spring. The cool thing is, that you have now the full functionality of a basic repository. Like persisting, removing and searching.

But since we want to use the Email-Adress of an user as the primary key, we have to expose a function which can search for the E-mail of an user.

In order to make the Entitymanager, which will be created by Spring, known to the rest of the application context, you have to expose it.

Therefore we have to create a new Class:

public class EntityManagerProducer { @PersistenceContext(name = "persistenceUnit", type= PersistenceContextType.EXTENDED) EntityManager em; @Produces public EntityManager createEntityManager() { return em; } public EntityManager getEm() { return em; } public void setEm(EntityManager em) { this.em = em; } }

That’s it… The last important note is, that you have to set the EntityManager in the context type, extended.  Like this you can use the @Transactional annotation, provided by Spring.

On the serverside we just have to inject the dao, and call the persist method at the wanted location.

@Service @Stateless public class UserEndpoint implements UserService{ @Inject UserRepository userDao; @Transactional @Override public boolean registerNewUser(User user) { if (user == null) { throw new IllegalArgumentException("Something went wrong"); } if (user.getEmail().isEmpty()) { throw new IllegalArgumentException("Email is not set…"); } User existingUser = userDao.findUserByEmail(user.getEmail()); if (existingUser != null) { return false; } else { try{ user = (User) userDao.saveAndFlush(user); }catch(Exception e){ return false; } return user == null ? false : true; } } }

That’s it!

Best Regards,

Malte