Skip to content

DATAJPA-1497 Allow to add a special parameter type from a Spring Data JPA extension #305

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
*
* @author Thomas Darimont
* @author Mark Paluch
* @author Réda Housni Alaoui
*/
public class JpaParameters extends Parameters<JpaParameters, JpaParameter> {

Expand Down Expand Up @@ -73,7 +74,7 @@ protected JpaParameters createFrom(List<JpaParameter> parameters) {
* @author Thomas Darimont
* @author Oliver Gierke
*/
static class JpaParameter extends Parameter {
public static class JpaParameter extends Parameter {

private final @Nullable Temporal annotation;
private @Nullable TemporalType temporalType;
Expand All @@ -83,7 +84,7 @@ static class JpaParameter extends Parameter {
*
* @param parameter must not be {@literal null}.
*/
JpaParameter(MethodParameter parameter) {
protected JpaParameter(MethodParameter parameter) {

super(parameter);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
* @author Réda Housni Alaoui
*/
public final class JpaQueryLookupStrategy {

Expand All @@ -56,17 +57,21 @@ private abstract static class AbstractQueryLookupStrategy implements QueryLookup

private final EntityManager em;
private final QueryExtractor provider;
private final JpaQueryMethodFactory queryMethodFactory;

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

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

/*
Expand All @@ -76,7 +81,7 @@ public AbstractQueryLookupStrategy(EntityManager em, QueryExtractor extractor) {
@Override
public final RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
NamedQueries namedQueries) {
return resolveQuery(new JpaQueryMethod(method, metadata, factory, provider), em, namedQueries);
return resolveQuery(queryMethodFactory.build(method, metadata, factory, provider), em, namedQueries);
}

protected abstract RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries);
Expand All @@ -93,10 +98,9 @@ private static class CreateQueryLookupStrategy extends AbstractQueryLookupStrate
private final PersistenceProvider persistenceProvider;
private final EscapeCharacter escape;

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

super(em, extractor);
public CreateQueryLookupStrategy(EntityManager em, QueryExtractor extractor, EscapeCharacter escape, JpaQueryMethodFactory queryMethodFactory) {

super(em, extractor, queryMethodFactory);
this.persistenceProvider = PersistenceProvider.fromEntityManager(em);
this.escape = escape;
}
Expand All @@ -123,12 +127,13 @@ private static class DeclaredQueryLookupStrategy extends AbstractQueryLookupStra
*
* @param em
* @param extractor
* @param queryMethodFactory
* @param evaluationContextProvider
*/
public DeclaredQueryLookupStrategy(EntityManager em, QueryExtractor extractor,
QueryMethodEvaluationContextProvider evaluationContextProvider) {
JpaQueryMethodFactory queryMethodFactory, QueryMethodEvaluationContextProvider evaluationContextProvider) {

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

Expand Down Expand Up @@ -186,13 +191,15 @@ private static class CreateIfNotFoundQueryLookupStrategy extends AbstractQueryLo
*
* @param em
* @param extractor
* @param queryMethodFactory
* @param createStrategy
* @param lookupStrategy
*/
public CreateIfNotFoundQueryLookupStrategy(EntityManager em, QueryExtractor extractor,
CreateQueryLookupStrategy createStrategy, DeclaredQueryLookupStrategy lookupStrategy) {
JpaQueryMethodFactory queryMethodFactory, CreateQueryLookupStrategy createStrategy,
DeclaredQueryLookupStrategy lookupStrategy) {

super(em, extractor);
super(em, extractor, queryMethodFactory);

this.createStrategy = createStrategy;
this.lookupStrategy = lookupStrategy;
Expand All @@ -219,26 +226,27 @@ protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em,
* @param em must not be {@literal null}.
* @param key may be {@literal null}.
* @param extractor must not be {@literal null}.
* @param queryMethodFactory 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) {
JpaQueryMethodFactory queryMethodFactory, 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);
return new CreateQueryLookupStrategy(em, extractor, escape, queryMethodFactory);
case USE_DECLARED_QUERY:
return new DeclaredQueryLookupStrategy(em, extractor, evaluationContextProvider);
return new DeclaredQueryLookupStrategy(em, extractor, queryMethodFactory, evaluationContextProvider);
case CREATE_IF_NOT_FOUND:
return new CreateIfNotFoundQueryLookupStrategy(em, extractor,
new CreateQueryLookupStrategy(em, extractor, escape),
new DeclaredQueryLookupStrategy(em, extractor, evaluationContextProvider));
return new CreateIfNotFoundQueryLookupStrategy(em, extractor,queryMethodFactory,
new CreateQueryLookupStrategy(em, extractor, escape, queryMethodFactory),
new DeclaredQueryLookupStrategy(em, extractor, queryMethodFactory, evaluationContextProvider));
default:
throw new IllegalArgumentException(String.format("Unsupported query lookup strategy %s!", key));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
* @author Nicolas Cirigliano
* @author Mark Paluch
* @author Сергей Цыпанов
* @author Réda Housni Alaoui
*/
public class JpaQueryMethod extends QueryMethod {

Expand Down Expand Up @@ -97,7 +98,7 @@ public class JpaQueryMethod extends QueryMethod {
* @param factory must not be {@literal null}
* @param extractor must not be {@literal null}
*/
public JpaQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
protected JpaQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
QueryExtractor extractor) {

super(method, metadata, factory);
Expand Down Expand Up @@ -426,4 +427,19 @@ StoredProcedureAttributes getProcedureAttributes() {

return storedProcedureAttributes;
}

public static class Factory implements JpaQueryMethodFactory {

public static final Factory INSTANCE = new Factory();

private Factory() {

}

@Override
public JpaQueryMethod build(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
QueryExtractor extractor) {
return new JpaQueryMethod(method, metadata, factory, extractor);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository.query;

import java.lang.reflect.Method;

import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.repository.core.RepositoryMetadata;

/**
* @author Réda Housni Alaoui
*/
public interface JpaQueryMethodFactory {

/**
* Creates a {@link JpaQueryMethod}.
*
* @param method must not be {@literal null}
* @param metadata must not be {@literal null}
* @param factory must not be {@literal null}
* @param extractor must not be {@literal null}
*/
JpaQueryMethod build(Method method, RepositoryMetadata metadata, ProjectionFactory factory, QueryExtractor extractor);

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package org.springframework.data.jpa.repository.support;

import static org.springframework.data.querydsl.QuerydslUtils.*;
import static org.springframework.data.querydsl.QuerydslUtils.QUERY_DSL_PRESENT;

import lombok.extern.slf4j.Slf4j;

Expand All @@ -37,6 +37,7 @@
import org.springframework.data.jpa.repository.query.EscapeCharacter;
import org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy;
import org.springframework.data.jpa.repository.query.JpaQueryMethod;
import org.springframework.data.jpa.repository.query.JpaQueryMethodFactory;
import org.springframework.data.jpa.util.JpaMetamodel;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.querydsl.EntityPathResolver;
Expand Down Expand Up @@ -65,6 +66,7 @@
* @author Christoph Strobl
* @author Jens Schauder
* @author Stefan Fussenegger
* @author Réda Housni Alaoui
*/
public class JpaRepositoryFactory extends RepositoryFactorySupport {

Expand All @@ -74,6 +76,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {

private EntityPathResolver entityPathResolver;
private EscapeCharacter escapeCharacter = EscapeCharacter.DEFAULT;
private JpaQueryMethodFactory queryMethodFactory;

/**
* Creates a new {@link JpaRepositoryFactory}.
Expand All @@ -88,6 +91,7 @@ public JpaRepositoryFactory(EntityManager entityManager) {
this.extractor = PersistenceProvider.fromEntityManager(entityManager);
this.crudMethodMetadataPostProcessor = new CrudMethodMetadataPostProcessor();
this.entityPathResolver = SimpleEntityPathResolver.INSTANCE;
this.queryMethodFactory = JpaQueryMethod.Factory.INSTANCE;

addRepositoryProxyPostProcessor(crudMethodMetadataPostProcessor);
addRepositoryProxyPostProcessor((factory, repositoryInformation) -> {
Expand Down Expand Up @@ -134,6 +138,17 @@ public void setEscapeCharacter(EscapeCharacter escapeCharacter) {
this.escapeCharacter = escapeCharacter;
}

/**
* Configures the {@link JpaQueryMethodFactory} to be used. Defaults to {@link JpaQueryMethod.Factory#INSTANCE}.
*
* @param queryMethodFactory must not be {@literal null}.
*/
public void setQueryMethodFactory(JpaQueryMethodFactory queryMethodFactory) {
Assert.notNull(queryMethodFactory, "QueryMethodFactory must not be null!");

this.queryMethodFactory = queryMethodFactory;
}

/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.core.RepositoryMetadata)
Expand Down Expand Up @@ -197,7 +212,8 @@ protected ProjectionFactory getProjectionFactory(ClassLoader classLoader, BeanFa
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(@Nullable Key key,
QueryMethodEvaluationContextProvider evaluationContextProvider) {
return Optional
.of(JpaQueryLookupStrategy.create(entityManager, key, extractor, evaluationContextProvider, escapeCharacter));
.of(
JpaQueryLookupStrategy.create(entityManager, key, extractor, queryMethodFactory, evaluationContextProvider, escapeCharacter));
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.query.EscapeCharacter;
import org.springframework.data.jpa.repository.query.JpaQueryMethod;
import org.springframework.data.jpa.repository.query.JpaQueryMethodFactory;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.querydsl.SimpleEntityPathResolver;
Expand All @@ -38,6 +40,7 @@
* @author Eberhard Wolff
* @author Mark Paluch
* @author Jens Schauder
* @author Réda Housni Alaoui
* @param <T> the type of the repository
*/
public class JpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
Expand All @@ -46,6 +49,7 @@ public class JpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
private @Nullable EntityManager entityManager;
private EntityPathResolver entityPathResolver;
private EscapeCharacter escapeCharacter = EscapeCharacter.DEFAULT;
private JpaQueryMethodFactory queryMethodFactory;

/**
* Creates a new {@link JpaRepositoryFactoryBean} for the given repository interface.
Expand Down Expand Up @@ -86,6 +90,17 @@ public void setEntityPathResolver(ObjectProvider<EntityPathResolver> resolver) {
this.entityPathResolver = resolver.getIfAvailable(() -> SimpleEntityPathResolver.INSTANCE);
}

/**
* Configures the {@link JpaQueryMethodFactory} to be used. Will expect a canonical bean to be present but fallback to
* {@link JpaQueryMethod.Factory#INSTANCE} in case none is available.
*
* @param resolver must not be {@literal null}.
*/
@Autowired
public void setQueryMethodFactory(ObjectProvider<JpaQueryMethodFactory> resolver) {
this.queryMethodFactory = resolver.getIfAvailable(() -> JpaQueryMethod.Factory.INSTANCE);
}

/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport#doCreateRepositoryFactory()
Expand All @@ -106,6 +121,8 @@ protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityM
JpaRepositoryFactory jpaRepositoryFactory = new JpaRepositoryFactory(entityManager);
jpaRepositoryFactory.setEntityPathResolver(entityPathResolver);
jpaRepositoryFactory.setEscapeCharacter(escapeCharacter);
jpaRepositoryFactory.setQueryMethodFactory(queryMethodFactory);

return jpaRepositoryFactory;
}

Expand Down
Loading