Talk about JpaQueryLookupStrategy spring data jpa.

  jpa

Order

This article mainly studies JpaQueryLookupStrategy of spring data jpa.

QueryLookupStrategy

spring-data-commons-2.1.6.RELEASE-sources.jar! /org/springframework/data/repository/query/QueryLookupStrategy.java

public interface QueryLookupStrategy {

    public static enum Key {

        CREATE, USE_DECLARED_QUERY, CREATE_IF_NOT_FOUND;

        /**
         * Returns a strategy key from the given XML value.
         *
         * @param xml
         * @return a strategy key from the given XML value
         */
        @Nullable
        public static Key create(String xml) {

            if (!StringUtils.hasText(xml)) {
                return null;
            }

            return valueOf(xml.toUpperCase(Locale.US).replace("-", "_"));
        }
    }

    /**
     * Resolves a {@link RepositoryQuery} from the given {@link QueryMethod} that can be executed afterwards.
     *
     * @param method will never be {@literal null}.
     * @param metadata will never be {@literal null}.
     * @param factory will never be {@literal null}.
     * @param namedQueries will never be {@literal null}.
     * @return
     */
    RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
            NamedQueries namedQueries);
}
  • QueryLookupStrategy defines Key Enumeration, including CREATE, USE _ DECLARED _ QUERY, CREATE _ IF _ NOT _ FOUND
  • QueryLookupStrategy has an abstract class called AbstractQueryLookupStrategy, which has three implementation subclasses: CreateQueryLookupStrategy, DeclaredQueryLookupStrategy, CreateIFNOTFOUNDQueryLookupStrategy
  • QueryLookupStrategy also defines the resolveQuery method to resolve the QueryMethod to RepositoryQuery

RepositoryQuery

spring-data-commons-2.1.6.RELEASE-sources.jar! /org/springframework/data/repository/query/RepositoryQuery.java

public interface RepositoryQuery {

    /**
     * Executes the {@link RepositoryQuery} with the given parameters.
     *
     * @param parameters must not be {@literal null}.
     * @return execution result. Can be {@literal null}.
     */
    @Nullable
    Object execute(Object[] parameters);

    /**
     * Returns the related {@link QueryMethod}.
     *
     * @return never {@literal null}.
     */
    QueryMethod getQueryMethod();
}
  • The RepositoryQuery interface defines two methods: execute and getQueryMethod; . It has two abstract classes, one is AbstractJpaQuery and the other is AbstractStringBasedJpaQuery; , which inherits AbstractJpaQuery. AbstractJpaQuery has three implementation subclasses, namely NamedQuery, PartTreeJpaQuery, StoredProcedureJpaQuery; ; AbstractStringBasedJpaQuery has two implementation subclasses, SimpleJpaQuery and NativeJpaQuery respectively

AbstractQueryLookupStrategy

spring-data-jpa-2.1.6.RELEASE-sources.jar! /org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java

    /**
     * Base class for {@link QueryLookupStrategy} implementations that need access to an {@link EntityManager}.
     *
     * @author Oliver Gierke
     * @author Thomas Darimont
     */
    private abstract static class AbstractQueryLookupStrategy implements QueryLookupStrategy {

        private final EntityManager em;
        private final QueryExtractor provider;

        /**
         * Creates a new {@link AbstractQueryLookupStrategy}.
         *
         * @param em
         * @param extractor
         */
        public AbstractQueryLookupStrategy(EntityManager em, QueryExtractor extractor) {

            this.em = em;
            this.provider = extractor;
        }

        /*
         * (non-Javadoc)
         * @see org.springframework.data.repository.query.QueryLookupStrategy#resolveQuery(java.lang.reflect.Method, org.springframework.data.repository.core.RepositoryMetadata, org.springframework.data.projection.ProjectionFactory, org.springframework.data.repository.core.NamedQueries)
         */
        @Override
        public final RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
                NamedQueries namedQueries) {
            return resolveQuery(new JpaQueryMethod(method, metadata, factory, provider), em, namedQueries);
        }

        protected abstract RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries);
    }
  • AbstractQueryLookupStrategy implements the resolveQuery method defined by the QueryLookupStrategy interface, but it calls its own defined abstract method resolveQuery

CreateQueryLookupStrategy

spring-data-jpa-2.1.6.RELEASE-sources.jar! /org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java

    /**
     * {@link QueryLookupStrategy} to create a query from the method name.
     *
     * @author Oliver Gierke
     * @author Thomas Darimont
     */
    private static class CreateQueryLookupStrategy extends AbstractQueryLookupStrategy {

        private final PersistenceProvider persistenceProvider;
        private final EscapeCharacter escape;

        public CreateQueryLookupStrategy(EntityManager em, QueryExtractor extractor, EscapeCharacter escape) {

            super(em, extractor);

            this.persistenceProvider = PersistenceProvider.fromEntityManager(em);
            this.escape = escape;
        }

        @Override
        protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries) {
            return new PartTreeJpaQuery(method, em, persistenceProvider, escape);
        }
    }
  • CreateQueryLookupStrategy inherits AbstractQueryLookupStrategy, and its resolveQuery method creates PartTreeJpaQuery.

DeclaredQueryLookupStrategy

spring-data-jpa-2.1.6.RELEASE-sources.jar! /org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java

    /**
     * {@link QueryLookupStrategy} that tries to detect a declared query declared via {@link Query} annotation followed by
     * a JPA named query lookup.
     *
     * @author Oliver Gierke
     * @author Thomas Darimont
     */
    private static class DeclaredQueryLookupStrategy extends AbstractQueryLookupStrategy {

        private final QueryMethodEvaluationContextProvider evaluationContextProvider;

        /**
         * Creates a new {@link DeclaredQueryLookupStrategy}.
         *
         * @param em
         * @param extractor
         * @param evaluationContextProvider
         */
        public DeclaredQueryLookupStrategy(EntityManager em, QueryExtractor extractor,
                QueryMethodEvaluationContextProvider evaluationContextProvider) {

            super(em, extractor);
            this.evaluationContextProvider = evaluationContextProvider;
        }

        /*
         * (non-Javadoc)
         * @see org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy.AbstractQueryLookupStrategy#resolveQuery(org.springframework.data.jpa.repository.query.JpaQueryMethod, javax.persistence.EntityManager, org.springframework.data.repository.core.NamedQueries)
         */
        @Override
        protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries) {

            RepositoryQuery query = JpaQueryFactory.INSTANCE.fromQueryAnnotation(method, em, evaluationContextProvider);

            if (null != query) {
                return query;
            }

            query = JpaQueryFactory.INSTANCE.fromProcedureAnnotation(method, em);

            if (null != query) {
                return query;
            }

            String name = method.getNamedQueryName();
            if (namedQueries.hasQuery(name)) {
                return JpaQueryFactory.INSTANCE.fromMethodWithQueryString(method, em, namedQueries.getQuery(name),
                        evaluationContextProvider);
            }

            query = NamedQuery.lookupFrom(method, em);

            if (null != query) {
                return query;
            }

            throw new IllegalStateException(
                    String.format("Did neither find a NamedQuery nor an annotated query for method %s!", method));
        }
    }
  • DeclaredQueryLookupStrategy inherits AbstractQueryLookupStrategy, and its resolveQuery method is generated by JPAQUERYFACTORY. INSTANCE. FromQUERY ARANOTATION, JPAQUERYFACTORY. INSTANCE. FromProcessureAnnotation, NamedQuery.lookupFrom.

CreateIfNotFoundQueryLookupStrategy

spring-data-jpa-2.1.6.RELEASE-sources.jar! /org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java

    /**
     * {@link QueryLookupStrategy} to try to detect a declared query first (
     * {@link org.springframework.data.jpa.repository.Query}, JPA named query). In case none is found we fall back on
     * query creation.
     *
     * @author Oliver Gierke
     * @author Thomas Darimont
     */
    private static class CreateIfNotFoundQueryLookupStrategy extends AbstractQueryLookupStrategy {

        private final DeclaredQueryLookupStrategy lookupStrategy;
        private final CreateQueryLookupStrategy createStrategy;

        /**
         * Creates a new {@link CreateIfNotFoundQueryLookupStrategy}.
         *
         * @param em
         * @param extractor
         * @param createStrategy
         * @param lookupStrategy
         */
        public CreateIfNotFoundQueryLookupStrategy(EntityManager em, QueryExtractor extractor,
                CreateQueryLookupStrategy createStrategy, DeclaredQueryLookupStrategy lookupStrategy) {

            super(em, extractor);

            this.createStrategy = createStrategy;
            this.lookupStrategy = lookupStrategy;
        }

        /*
         * (non-Javadoc)
         * @see org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy.AbstractQueryLookupStrategy#resolveQuery(org.springframework.data.jpa.repository.query.JpaQueryMethod, javax.persistence.EntityManager, org.springframework.data.repository.core.NamedQueries)
         */
        @Override
        protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries) {

            try {
                return lookupStrategy.resolveQuery(method, em, namedQueries);
            } catch (IllegalStateException e) {
                return createStrategy.resolveQuery(method, em, namedQueries);
            }
        }
    }
  • CreateIFnotFoundQueryLookupStrategy inherits AbstractQueryLookupStrategy, and its constructor requires that the DeclaredQueryLookupStrategy, CreateQueryLookupStrategy parameters be passed in. Its resolveQuery method first uses DeclaredQueryLookupStrategy to create RepositoryQuery, and if IllegalStateException is thrown, then createQueryQueryRepositoryQuery is created with CreateQueryQueryQueryQueryQueryQueryQuery

JpaQueryLookupStrategy

spring-data-jpa-2.1.6.RELEASE-sources.jar! /org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java

public final class JpaQueryLookupStrategy {

    /**
     * Private constructor to prevent instantiation.
     */
    private JpaQueryLookupStrategy() {}

    //......

    /**
     * Creates a {@link QueryLookupStrategy} for the given {@link EntityManager} and {@link Key}.
     *
     * @param em must not be {@literal null}.
     * @param key may be {@literal null}.
     * @param extractor must not be {@literal null}.
     * @param evaluationContextProvider must not be {@literal null}.
     * @param escape
     * @return
     */
    public static QueryLookupStrategy create(EntityManager em, @Nullable Key key, QueryExtractor extractor,
            QueryMethodEvaluationContextProvider evaluationContextProvider, EscapeCharacter escape) {

        Assert.notNull(em, "EntityManager must not be null!");
        Assert.notNull(extractor, "QueryExtractor must not be null!");
        Assert.notNull(evaluationContextProvider, "EvaluationContextProvider must not be null!");

        switch (key != null ? key : Key.CREATE_IF_NOT_FOUND) {
            case CREATE:
                return new CreateQueryLookupStrategy(em, extractor, escape);
            case USE_DECLARED_QUERY:
                return new DeclaredQueryLookupStrategy(em, extractor, evaluationContextProvider);
            case CREATE_IF_NOT_FOUND:
                return new CreateIfNotFoundQueryLookupStrategy(em, extractor,
                        new CreateQueryLookupStrategy(em, extractor, escape),
                        new DeclaredQueryLookupStrategy(em, extractor, evaluationContextProvider));
            default:
                throw new IllegalArgumentException(String.format("Unsupported query lookup strategy %s!", key));
        }
    }
}
  • JpaQueryLookupStrategy provides a static method create to create different QueryLookupStrategy according to different QueryLookupStrategy.Key. The defa ult is Key.CREATE_IF_NOT_FOUND, that is, CREATE EIFNOTFOUND QUERY LOOKUPSTRATEGY

Summary

  • QueryLookupStrategy defines Key Enumeration, including CREATE, USE _ DECLARED _ QUERY, CREATE _ IF _ NOT _ FOUND. QueryLookupStrategy has an abstract class called AbstractQueryLookupStrategy, which has three implementation subclasses: CreateQueryLookupStrategy, DeclaredQueryLookupStrategy, CreateIFNOTFOUNDQueryLookupStrategy; QueryLookupStrategy also defines the resolveQuery method to resolve the QueryMethod to RepositoryQuery
  • AbstractQueryLookupStrategy implements the resolveQuery method defined by the QueryLookupStrategy interface, but it calls its own defined abstract method resolveQuery

    • CreateQueryLookupStrategy inherits AbstractQueryLookupStrategy, and its resolveQuery method creates PartTreeJpaQuery (Resolution method name);
    • DeclaredQueryLookupStrategy inherits AbstractQueryLookupStrategy, and its resolveQuery method is based on JPAQUERYFACTORY. Instance. FromQueryOntotation (Resolve @Query comments)、JpaQueryFactory.INSTANCE.fromProcedureAnnotation(Resolve @Procedure comments)、NamedQuery.lookupFrom(Resolve @NamedQuery comments) to generate;
    • CreateIFnotFoundQueryLookupStrategy inherits AbstractQueryLookupStrategy, and its constructor requires that the DeclaredQueryLookupStrategy, CreateQueryLookupStrategy parameters be passed in. Its resolveQuery method first uses DeclaredQueryLookupStrategy to create RepositoryQuery, and if IllegalStateException is thrown, then createQueryQueryRepositoryQuery is created with CreateQueryQueryQueryQueryQueryQueryQuery
  • JpaQueryLookupStrategy provides a static method create to create different QueryLookupStrategy according to different QueryLookupStrategy.Key. The defa ult is Key.CREATE_IF_NOT_FOUND, that is, CREATE EIFNOTFOUND QUERY LOOKUPSTRATEGY

doc