Spring Data

16
Jul

Searching with the help of Spring Data JPA

Posted by eugene as Spring Data

Let us review one of the most useful things in Spring Data JPA – generating of JPQL queries based on the method name. Spring Data JPA is able to automatically generate requests using the method name for hint. For example, the User.findByLoginAndPassword method will generate approximately the following code:

FROM User u where u.login = :login and password = :password

Generally Spring Data JPA is trying to be smart so the implementation of the findBy{…} methods looks as follows:

  • At first you should look the @Query annotation on the method declaring, if it exists then it’s being used.
  • Then you should look the @NamedQuery annotation with the name like Entity.findMethodNme, in the above case it will be User.findByLoginAndPassword.
  • If you haven’t found anything then the request is generated due to method signature.

@Query contains the following benefits:

  • Allows not to clutter up the annotation of the domain entity.
  • Greatly helps if there’re implicit joins in the request because Spring Data JPA cannot correctly generate the SELECT COUNT(*) request which is necessary in cases when the method should return Page.

Obviously that while using the requests we should point the parameters for the requests. There’s the @Param annotation:

@Query("select u from User u where u.login = :login and u.password = :password")
Page<User> findByLoginAndPassword(@Param("login") String login, @Param("password") String password);

In addition, Spring Data JPA supports the concept of different specifications. The specifications allow you to make up complex queries from the set of simple ones. To support the specifications it is necessary to declare a method in the repository.

Page<User> findAll(Specification<User> spec, Pageable pageable);

The specification is essentially a filter and allows the combination of filters which makes it a powerful tool for building queries. An example of the use of specifications: Let’s declare our specifications:

public static Specification<User> firstNameOrLastNameOrLoginLike(final String search) {
    return new Specification<User>() {
        @Override
        public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
 
            Predicate loginPredicate = builder.like(root.get(User_.login), search);
            Predicate firstnamePredicate = builder.like(root.get(User_.firstname), search);
            Predicate lastnamePredicate = builder.like(root.get(User_.lastname), search);
 
            return builder.or(loginPredicate, firstnamePredicate, lastnamePredicate);
        }
    };
}
 
public static Specification<User> hasRole(final Role role) {
    return new Specification<User>() {
        @Override
        public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
            return builder.equal(root.get(User_.role), role);
        }
    };
}

And combine them in our service:

public Page<User> searchUser(Role role, String search, Pageable pageable) {
    Specifications<User> mainSpec = where(hasRole(role));
 
    // уточняем запрос, если была передана строка для поиска
    if (StringUtils.isNotBlank(search)) {
        mainSpec = mainSpec.and(firstNameOrLastNameOrLoginLike(search));
    }
 
    return userRepository.findAll(mainSpec, pageable);
}
11
Jul

Own implementation of methods in Spring Data JPA

Posted by eugene as Spring Data

Obviously we cannot always use the automatic code generation provided by Spring Data JPA. For example, we have a very complicated request or we need to call a procedure in database or we have complex business logic. Consider the following example – for example we need functionality of the counter which we decided to implement with the help of sequence. First of all we define an interface where we describe all the methods that we’ll implement by ourselves. In our case this will be only one method.

public interface UserRepositoryCustom {
    /**
     * Returns next unique id.
     *
     * @return next unique id.
     */
    Integer getNextUniqueId();
}

Next we’ll update the repository announcement so that it will inherit a new UserRepositoryCustom interface

public interface UserRepository extends JpaRepository<User, Integer>, UserRepositoryCustom {
   ...
}

Now let’s write up the method realization:

public class UserRepositoryImpl implements UserRepositoryCustom {
 
    @PersistenceContext
    private EntityManager entityManager;
 
    @Override
    public Integer getNextUniqueId() {
 
        // When using Hibernate via JPA native queries fails with mapping exception, so just use Hibernate directly:
        Session session = (Session) entityManager.getDelegate();
        SQLQuery nativeQuery = session.createSQLQuery("SELECT \"nextval\"('unique_id_seq') ");
        List<BigInteger> list = nativeQuery.list();
        if (list.isEmpty()) {
            throw new IncorrectResultSizeDataAccessException(1);
        }
 
        BigInteger result = list.get(0);
 
        return result.intValue();
    }
}

And finally let’s point out Spring Data JPA so that our class with the implementation of its own methods will be used as a proxy class. To do this we need another section of the repositories in the configuration file:

<repositories base-package="[base.repository.package]"/>
 
<repositories base-package="[base.repository.package]">
    <repository id="userRepository" custom-impl-ref="userRepositoryImpl"/>
</repositories>
 
<beans:bean id="userRepositoryImpl" class="...UserRepositoryImpl"/>

And that is all.

17
Jun

Simplifiying work with JPA by means of Spring Data JPA

Posted by eugene as Spring Data

Introduction

It’s been several years since JPA appeared. Using the EntityManager is fascinating but the developers write nice API, and hide the details of work with the database. At the same, the common problem is duplication of implementation, when one and the same code is gradually migrating from one DAO to another, at best, the code is transferred to the abstract base DAO. Spring Data radically solves the problem – when you use it is just an API-level interfaces, the overall implementation is automatically created using AOP.

History of Spring Data

Despite the fact that the project has only recently reached version 1.0, it has enough rich history – it has been developing in scopes of the Hades project before.

Declaring DAO-Interface

So, first we need to declare the DAO-interface where we declare methods for working with the entity.

public interface UserRepository extends CrudRepository<User, Long> {
}

This code is sufficient for normal DAO with the CRUD-methods.

  • save – saves or updates the transferred entity.
  • findOne – looking for the entity by the primary key.
  • findAll – returns the collection of all entities
  • count – returns the number of entities
  • delete – removes the entity
  • exists – checks whether there is an entity with this primary key
  • Full list of methods declared in CrudRepository can be found in javadoc. If we do not need all the methods, it is possible to make the inheritance of the interface Repository and transferred to the successor only the methods of the interface CrudRepository, are needed.

    Support for sorting and paging

    Very often the required functionality is the ability to return only part of the entity from the database, for example, to implement paging in the UI. Spring Data is also good here and gives us the opportunity to add this functionality to our DAO. To do this, simply add the following method declaration to our DAO-Interface:

    Page<User> findAll(Pageable pageable);

    The pageable interface encapsulates information about the number of the requested page, page size, and sorting required.

    Looking for the data

    As a rule, the conventional DAO CRUD is not the end point and often the additional methods are required which return only those entities that satisfy the given conditions. In my opinion, Spring Data greatly simplifies the life in this area. For example, we need a method to find user by the login name and his e-mail address:

    User findByLogin(String login);
    User findByEmail(String email);

    It’s simple. If we need more complicated search terms, then it is also implemented. Spring Data supports the following operators:

    • Between
    • IsNotNull
    • NotNull
    • IsNull
    • Null
    • LessThan
    • LessThanEqual
    • GreaterThan
    • GreaterThanEqual
    • NotLike
    • Like
    • NotIn
    • In
    • Near
    • Within
    • Regex
    • Exists
    • IsTrue
    • True
    • IsFalse
    • False
    • Not
    • The space for imagination opens such an impressive list, so you can create the arbitrarily complex query. If you want the search results contain more than one entity, it is necessary to call a method as findAllByBlahBlah.

      Support for Spring MVC

      This part is based on the official documentation. Imagine that you develop a web application using Spring MVC. Then you will need to load the entity from the database using the parameters of HTTP-request. It may look as follows:

      @Controller
      @RequestMapping("/users")
      public class UserController {
       
      	private final UserRepository userRepository;
       
      	public UserController(UserRepository userRepository) {
      		this.userRepository = userRepository;
      	}
       
      	@RequestMapping("/{id}")
      	public String showUserForm(@PathVariable("id") Long id, Model model) {
      		// Do null check for id
      		User user = userRepository.findOne(id);
      		// Do null check for user
      		// Populate model
      		return "user";
      	}
      }

      First, you declare the dependency on the DAO, and secondly always call the findOne() method to load the entity. Fortunately, Spring allows us to convert the string value of the HTTP-requests in any desired type using either the PropertyEditor or ConversionService. If you are using Spring 3.0 and above, then you need to add the following configuration:

      <mvc:annotation-driven conversion-service="conversionService" />
      <bean id="conversionService" class="...context.support.ConversionServiceFactoryBean">
      <property name="converters">
      <list>
      			<bean class="org.springframework.data.repository.support.DomainClassConverter">
      				<constructor-arg ref="conversionService" />
      			</bean>
      		</list>
      	</property>
      </bean>

      If you are using the older version of Spring, then you need the following configuration:

      <bean class="….web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
      <property name="webBindingInitializer">
      		<bean class="….web.bind.support.ConfigurableWebBindingInitializer">
      <property name="propertyEditorRegistrars">
      				<bean class="org.springframework.data.repository.support.DomainClassPropertyEditorRegistrar" />
      			</property>
      		</bean>
      	</property>
      </bean>

      After these changes in the configuration, the controller can be rewritten as follows:

      @Controller
      @RequestMapping("/users")
      public class UserController {
       
      	@RequestMapping("/{id}")
      	public String showUserForm(@PathVariable("id") User user, Model model) {
      		// Do null check for user
      		// Populate model
      		return "userForm";
      	}
      }

      Note how the code is simplified and how well we got rid of its duplicating.

      Documentation

      Currently there’s not so much project documentation, but nevertheless, it exists:

      • Spring Data JPA – Reference Documentation
      • Spring Data Commons – Reference Documentation
      • Sources to github

      Conclusion

      Spring Data simplifies life when using JPA. Recommended for use in your projects.