Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I use Java 8 default methods for manually implemented Spring Data repository methods?

Tags:

When using the new Spring Data Evans release it's nice to be able to use some of the nice stuff that came with java 8. One of them is default implementations in interfaces. The repository below uses QueryDSL to make queries type safe.

My problem is that before when I wrote this I used the pattern of a separate UserRepositoryCustom interface for the findByLogin and then another class UserRepositoryImpl and in that class I would have the @PersistenceContext to get the current EntityManager.

How do I get the EntityManager when I don't have a class? Is it even possible?

@Repository
public interface UserRepository extends JpaRepository<User, UUID> {

    final QUser qUser = QUser.user;

    // How do I get the entityManager since this is a interface, i cannot have any variables?
    //@PersistenceContext
    //EntityManager entityManager;

    public default Optional<User> findByLogin(String login) {
        JPAQuery query = new JPAQuery(entityManager);
        User user = query
                .from(qUser)
                .where(
                        qUser.deleter.isNull(),
                        qUser.locked.isFalse(),
                        qUser.login.equalsIgnoreCase(login)
                )
                .singleResult(qUser);

        return Optional.ofNullable(user);
    }
}
like image 337
Leon Radley Avatar asked Oct 24 '14 07:10

Leon Radley


People also ask

What is the default method of a repository in Spring data?

Default available methods CrudRepository and PagingAndSortingRepository offer default methods such as: findAll, findAllById, findById, deleteAll, deleteById, save, saveAll.

How are Spring data repositories actually implemented?

In the repository interfaces, we can add the methods like findByCustomerNameAndPhone() (assuming customerName and phone are fields in the domain object). Then, Spring provides the implementation by implementing the above repository interface methods at runtime (during the application run).

Do you have to implement default methods?

Default methods are methods that can have a body. However, sometimes methods have only single implementation and there is no need to provide their implementation in each class. In that case, we can declare that method as a default in the interface and provide its implementation in the interface itself.

Is @repository mandatory in Spring boot?

It is indeed not necessary to put the @Repository annotation on interfaces that extend JpaRepository ; Spring recognizes the repositories by the fact that they extend one of the predefined Repository interfaces. From the javadoc: Annotation to enable JPA repositories.


1 Answers

Default methods should only be used to delegate calls to other repository methods. Default methods - by definition - cannot access any state of an instance (as an interface has none). They only can delegate to other interface methods or call static ones of other classes.

Actually, using a custom implementation as described in the reference documentation is the right approach. Here's the short version for reference (in case others wonder, too):

/**
 * Interface for methods you want to implement manually.
 */
interface UserRepositoryCustom {
  Optional<User> findByLogin(String login);
}

/**
 * Implementation of exactly these methods.
 */
class UserRepositoryImpl extends QueryDslRepositorySupport implements UserRepositoryCustom {

  private static final QUser USER = QUser.user;

  @Override
  public Optional<User> findByLogin(String login) {

    return Optional.ofNullable(
      from(USER).
      where(
        USER.deleter.isNull(),
        USER.locked.isFalse(), 
        USER.login.equalsIgnoreCase(login)).
      singleResult(USER));
  }
}

/**
 * The main repository interface extending the custom one so that the manually
 * implemented methods get "pulled" into the API.
 */
public interface UserRepository extends UserRepositoryCustom, 
  CrudRepository<User, Long> { … }

Be aware that the naming conventions are important here (but can be customized if needed). By extending QueryDslRepositorySupport you get access to the from(…) method so that you don't have to interact with the EntityManager yourself.

Alternatively you can let UserRepository implement QueryDslPredicateExecutor and hand in the predicates from outside the repository but that'd let you end up with the clients needing to work with Querydsl (which might be unwanted) plus you don't get the Optional wrapper type OOTB.

like image 50
Oliver Drotbohm Avatar answered Oct 11 '22 16:10

Oliver Drotbohm