BaseJpaRepository.java

package com.reallifedeveloper.common.infrastructure.persistence;

import java.lang.reflect.Method;
import java.util.Optional;

import org.springframework.data.jpa.repository.Query;

/**
 * Base class for implementations of repositories that use JPA but that cannot use Spring Data, e.g., because they work with more than one
 * entity type.
 *
 * @author RealLifeDeveloper
 */
public class BaseJpaRepository {

    /**
     * Creates a new {@code BaseJpaRepository}, intended to be used by sub-classes.
     */
    protected BaseJpaRepository() {
        // The only constructor is protected, to disallow direct instantiation.
    }

    /**
     * Gives the value of the {@code @Query} annotation on the given method. The annotation can be on the method in the class, or on the
     * method in an implemented interface.
     *
     * @param methodName     the name of the method with the {@code @Query} annotation
     * @param parameterTypes the classes of the method parameters
     *
     * @return the query string, i.e., the value of the {@code @Query} annotation, or an empty Optional if no such annotation can be found
     */
    protected Optional<String> getQueryString(String methodName, Class<?>... parameterTypes) {
        try {
            return findQueryAnnotation(methodName, parameterTypes).map(Query::value);
        } catch (NoSuchMethodException e) {
            throw new IllegalStateException("Unexpected error, this should never occur", e);
        }
    }

    @SuppressWarnings("PMD.EmptyCatchBlock")
    private Optional<Query> findQueryAnnotation(String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
        Method method = getClass().getMethod(methodName, parameterTypes);
        Query query = method.getAnnotation(Query.class);
        if (query == null) {
            for (Class<?> c : getClass().getInterfaces()) {
                try {
                    method = c.getMethod(methodName, parameterTypes);
                    query = method.getAnnotation(Query.class);
                    if (query != null) {
                        break;
                    }
                } catch (NoSuchMethodException e) {
                    // Ignore, try next interface (if there is one)
                }
            }
        }
        return Optional.ofNullable(query);
    }
}