Making use of the JPA and Spring Data JPA

In this section, we are going to wire the business logic we need for our application.

Because we have set up the configuration for the JPA and Spring Data JPA, and because we have defined our entities and their relationships, we can now use this model for time and energy-saving.

How to do it...

The following steps will guide you through the changes:

  1. In the edu.zipcloud.cloudstreetmarket.core.daos package, we can find the following two interfaces:
    public interface HistoricalIndexRepository {
      Iterable<HistoricalIndex> findIntraDay(String code, Date of);
      Iterable<HistoricalIndex> findLastIntraDay(String code);
      HistoricalIndex findLastHistoric(String code);
    }
    public interface TransactionRepository {
      Iterable<Transaction> findAll();
      Iterable<Transaction> findByUser(User user);
      Iterable<Transaction> findRecentTransactions(Date from);
      Iterable<Transaction> findRecentTransactions(int nb);
    }
  2. These two interfaces come with their respective implementations. The HistoricalIndexRepositoryImpl implementation out of the two is defined as follows:
    @Repository
    public class HistoricalIndexRepositoryImpl implements HistoricalIndexRepository{
    
      @PersistenceContext 
      private EntityManager em;
    
      @Override
      public Iterable<HistoricalIndex> findIntraDay(String code,Date of){
        TypedQuery<HistoricalIndex> sqlQuery = em.createQuery("from HistoricalIndex h where h.index.code = ? and h.fromDate >= ? and h.toDate <= ? ORDER BY h.toDate asc", HistoricalIndex.class);
    
        sqlQuery.setParameter(1, code);
        sqlQuery.setParameter(2, DateUtil.getStartOfDay(of));
        sqlQuery.setParameter(3, DateUtil.getEndOfDay(of));
    
        return sqlQuery.getResultList();
      }
    	
      @Override
      public Iterable<HistoricalIndex> findLastIntraDay(String code) {
        return findIntraDay(code,findLastHistoric(code).getToDate());
      }
    
      @Override
      public HistoricalIndex findLastHistoric(String code){
         TypedQuery<HistoricalIndex> sqlQuery =  em.createQuery("from HistoricalIndex h where h.index.code = ? ORDER BY h.toDate desc", HistoricalIndex.class);
    
      sqlQuery.setParameter(1, code);
    
        return sqlQuery.setMaxResults(1).getSingleResult();
      }
    }

    And the TransactionRepositoryImpl implementation is as follows:

    @Repository
    public class TransactionRepositoryImpl implements TransactionRepository{
      @PersistenceContext 
      private EntityManager em;
      @Autowired
      private TransactionRepositoryJpa repo;
      @Override
      public Iterable<Transaction> findByUser(User user) {
        TypedQuery<Transaction> sqlQuery = em.createQuery("from Transaction where user = ?", Transaction.class);
        return sqlQuery.setParameter(1, user).getResultList();
      }
      @Override
      public Iterable<Transaction> findRecentTransactions(Date from) {
        TypedQuery<Transaction> sqlQuery = em.createQuery("from Transaction t where t.quote.date >= ?", Transaction.class);
        return sqlQuery.setParameter(1, from).getResultList();
      }
      @Override
      public Iterable<Transaction> findRecentTransactions(int nb) {
      TypedQuery<Transaction> sqlQuery = em.createQuery("from Transaction t ORDER BY t.quote.date desc", Transaction.class);
        return sqlQuery.setMaxResults(nb).getResultList();
      }
      @Override
      public Iterable<Transaction> findAll() {
        return repo.findAll();
      }
    }
  3. All the other interfaces in the dao package don't have explicitly defined implementations.
  4. The following bean has been added to the Spring configuration file:
      <jdbc:initialize-database data-source="dataSource">
          <jdbc:script location="classpath:/META-INF/db/init.sql"/>
      </jdbc:initialize-database>
  5. This last configuration allows the application to execute the created init.sql file on startup.
  6. You will notice that the cloudstreetmarket-core module has been added in its pom.xml file, a dependency to zipcloud-core for the DateUtil class that we created.
  7. To replace the two dummy implementations that we created in Chapter 2, Designing a Microservice Architecture with Spring MVC, the CommunityServiceImpl and MarketServiceImpl implementations have been created.

    Note

    We have injected repository dependencies in these implementations using @Autowired annotations.

    Also,we have tagged these two implementations with the Spring @Service annotations using a declared value identifier:

    @Service(value="marketServiceImpl")
    @Service(value="communityServiceImpl")
  8. In the cloudstreetmarket-webapp module, the DefaultController has been modified in its @Autowired field to target these new implementations and no longer the dummy ones. This is achieved by specifying the @Qualifier annotations on the @Autowired fields.
  9. Starting the server and calling the home page URL, http://localhost:8080/portal/index, should log a couple of SQL queries into the console:
    How to do it...

Also, the Welcome page should remain the same.

How it works...

Let's see the breakdown of this recipe with the following sections.

Injecting an EntityManager instance

We saw in the first recipe of this chapter that the configuration of the entityManagerFactory bean reflects the persistence unit's configuration.

Historically created by the container, EntityManagers need to handle transactions (user or container-manager transactions).

The @PersistenceContext annotation is a JPA annotation. It allows us to inject an instance of EntityManager, whose lifecycle is managed by the container. In our case, Spring handles this role. With an EntityManager, we can interact with the persistence context, get managed or detached entities, and indirectly query the database.

Using JPQL

Using Java Persistence Query Language (JPQL) is a standardized way of querying the persistence context and, indirectly, the database. JPQL looks like SQL in the syntax, but operates on the JPA-managed entities.

You must have noticed the following query in the repositories:

from Transaction where user = ?

The select part of the query is optional. Parameters can be injected into the query and this step is managed by the persistence providers’ implementation. Those implementations offer protections against SQL injection (using Prepared Statements) With the example here, take a look at how practical it is to filter a subentity attribute:

from Transaction t where t.quote.date >= ?

It avoids declaring a join when the situation is appropriate. We can still declare a JOIN though:

from HistoricalIndex h where h.index.code = ? ORDER BY h.toDate desc

A couple of keywords (such as ORDER) can be used as part of JPQL to operate functions that are usually available in SQL. Find the full list of keywords in the JPQL grammar from the JavaEE 6 tutorial at http://docs.oracle.com/javaee/6/tutorial/doc/bnbuf.html.

JPQL has been inspired from the earlier-created Hibernate Query Language (HQL).

Reducing boilerplate code with Spring Data JPA

We have discussed in the How to do it… section that some of our repository interfaces don't have explicitly defined implementations. This is a very powerful feature of Spring Data JPA.

Query creation

Our UserRepository interface is defined as follows:

@Repository
public interface UserRepository extends JpaRepository<User, String>{
  User findByUserName(String username);
  User findByUserNameAndPassword(String username, String password);
}

We have made it extend the JpaRepository interface, passing through the generic types User (the entity type this repository will relate to) and String (the type of the user's identifier field).

By extending JpaRepository, UserRepository gets from Spring Data JPA capability to define query methods from Spring Data JPA by simply declaring their method signature. We have done this with the methods findByUserName and findByUserNameAndPassword.

Spring Data JPA transparently creates an implementation of our UserRepository interface at runtime. It infers the JPA queries from the way we have named our methods in the interface. Keywords and field names are used for this inference.

Find the following keywords table from the Spring Data JPA doc:

Query creation

Without specifying anything in the configuration, we have fallen back to the configuration by default for JPA repositories, which injects an instance of our single EntityManagerFactory bean and of our single TransactionManager bean.

Our custom TransactionRepositoryImpl is an example that uses both custom JPQL queries and a JpaRepository implementation. As you might guess, the TransactionRepositoryJpa implementation , which is autowired in TransactionRepositoryImpl, inherits several methods for saving, deleting, and finding, Transaction Entities.

We will also use interesting paging features offered with these methods. The findAll() method, which we have pulled, is one of them.

Persisting Entities

Spring Data JPA also specifies the following:

Saving an entity can be performed via the CrudRepository.save(…) method. It will persist or merge the given entity using the underlying JPA EntityManager. If the entity has not been persisted yet, Spring Data JPA will save the entity via a call to the entityManager.persist(…) method; otherwise, the entityManager.merge(…) will be called.

This is interesting behavior that we will use to prevent again, a significant amount of boilerplate code.

There's more...

There are more aspects that can be explored around this topic.

Using native SQL queries

We haven't made use of native SQL queries yet, but we will. It is important to know how to implement them because bypassing the JPA layer can sometimes be a better option performance-wise.

The following link points to an article from the Oracle website, which is interesting as it relates to native SQL queries:

http://www.oracle.com/technetwork/articles/vasiliev-jpql-087123.html

Transactions

We haven't applied any specific transaction configuration to our repository implementations. Refer to Chapter 7, Developing CRUD Operations and Validations, for more details about transactions.

See also

  • Custom implementations for Spring Data repositories: With the TransactionRepositoryImpl example, by redefining the methods we need from TransactionRepositoryJpa, we present a pattern for creating custom implementations of data repositories. It somehow forces us to maintain an intermediate proxy. The related Spring document proposes a different technique that solves this issue. This technique is detailed online at http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset