diff --git a/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/base/query/AbstractPartTreeBlazePersistenceQuery.java b/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/base/query/AbstractPartTreeBlazePersistenceQuery.java index be276cbdbe..ddb4fa83f7 100644 --- a/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/base/query/AbstractPartTreeBlazePersistenceQuery.java +++ b/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/base/query/AbstractPartTreeBlazePersistenceQuery.java @@ -24,6 +24,7 @@ import com.blazebit.persistence.criteria.BlazeCriteriaBuilder; import com.blazebit.persistence.criteria.BlazeCriteriaQuery; import com.blazebit.persistence.spring.data.base.query.JpaParameters.JpaParameter; +import com.blazebit.persistence.spring.data.repository.EntityViewSettingProcessor; import com.blazebit.persistence.view.EntityViewManager; import com.blazebit.persistence.view.EntityViewSetting; @@ -85,13 +86,14 @@ public AbstractPartTreeBlazePersistenceQuery(EntityViewAwareJpaQueryMethod metho this.parameters = method.getJpaParameters(); String methodName = method.getName(); - boolean matchesSpecificationSignature = parameters.hasSpecificationParameter() - && QUERY_PATTERN.matcher(methodName).matches(); - String source = matchesSpecificationSignature ? "" : methodName; + boolean skipMethodNamePredicateMatching = parameters.hasSpecificationParameter() + || QUERY_PATTERN.matcher(methodName).matches(); + String source = skipMethodNamePredicateMatching ? "" : methodName; this.tree = new PartTree(source, domainClass); + boolean hasEntityViewSettingProcessorParameter = parameters.hasEntityViewSettingProcessorParameter(); boolean recreateQueries = parameters.potentiallySortsDynamically() || entityViewClass != null - || matchesSpecificationSignature; + || skipMethodNamePredicateMatching || hasEntityViewSettingProcessorParameter; this.query = isCountProjection(tree) ? new AbstractPartTreeBlazePersistenceQuery.CountQueryPreparer(persistenceProvider, recreateQueries) : new AbstractPartTreeBlazePersistenceQuery.QueryPreparer(persistenceProvider, recreateQueries); } @@ -310,7 +312,15 @@ Query createPaginatedQuery(Object[] values, boolean withCount) { return binder.bind(jpaQuery); } - protected void processSetting(EntityViewSetting setting, Object[] values) { + @SuppressWarnings("unchecked") + protected void processSetting(EntityViewSetting setting, Object[] values) { + int entityViewSettingProcessorIndex = parameters.getEntityViewSettingProcessorIndex(); + if (entityViewSettingProcessorIndex >= 0) { + EntityViewSettingProcessor processor = (EntityViewSettingProcessor) values[entityViewSettingProcessorIndex]; + if (processor != null) { + setting = processor.acceptEntityViewSetting(setting); + } + } for (JpaParameter parameter : parameters.getOptionalParameters()) { String parameterName = parameter.getParameterName(); Object parameterValue = values[parameter.getIndex()]; diff --git a/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/base/query/JpaParameters.java b/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/base/query/JpaParameters.java index 1f491f7471..24862fb007 100644 --- a/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/base/query/JpaParameters.java +++ b/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/base/query/JpaParameters.java @@ -21,6 +21,11 @@ import org.springframework.core.MethodParameter; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Temporal; + +import com.blazebit.persistence.spring.data.annotation.OptionalParam; +import com.blazebit.persistence.spring.data.base.query.JpaParameters.JpaParameter; +import com.blazebit.persistence.spring.data.repository.EntityViewSettingProcessor; + import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Parameter; import org.springframework.data.repository.query.Parameters; @@ -144,6 +149,35 @@ public boolean hasSpecificationParameter() { return getSpecificationIndex() >= 0; } + /** + * Returns the index of the {@link EntityViewSettingProcessor} {@link Method} parameter if available. Will return + * {@literal -1} if there is no {@link EntityViewSettingProcessor} parameter in the {@link Method}'s parameter list. + * + * @return the index of the processor parameter, or -1 if not present + */ + public int getEntityViewSettingProcessorIndex() { + int index = 0; + + for (JpaParameter candidate : this) { + if (candidate.isEntityViewSettingProcessorParameter()) { + return index; + } + ++index; + } + + return -1; + } + + /** + * Returns whether the method the {@link Parameters} was created for contains a {@link EntityViewSettingProcessor} + * parameter. + * + * @return true if the methods has a processor parameter + */ + public boolean hasEntityViewSettingProcessorParameter() { + return getEntityViewSettingProcessorIndex() >= 0; + } + /* * (non-Javadoc) * @see org.springframework.data.repository.query.Parameters#createParameter(org.springframework.core.MethodParameter) @@ -214,7 +248,8 @@ public boolean isBindable() { @Override public boolean isSpecialParameter() { - return super.isSpecialParameter() || isOptionalParameter() || isSpecificationParameter(); + return super.isSpecialParameter() || isOptionalParameter() || isSpecificationParameter() + || isEntityViewSettingProcessorParameter(); } boolean isOptionalParameter() { @@ -225,6 +260,10 @@ boolean isSpecificationParameter() { return Specification.class.isAssignableFrom(parameter.getParameterType()); } + boolean isEntityViewSettingProcessorParameter() { + return EntityViewSettingProcessor.class.isAssignableFrom(parameter.getParameterType()); + } + /** * @return {@literal true} if this parameter is of type {@link Date} and has an {@link Temporal} annotation. */ diff --git a/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/repository/EntityViewSettingProcessor.java b/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/repository/EntityViewSettingProcessor.java new file mode 100644 index 0000000000..a950725276 --- /dev/null +++ b/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/repository/EntityViewSettingProcessor.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014 - 2018 Blazebit. + * + * 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 com.blazebit.persistence.spring.data.repository; + +import com.blazebit.persistence.view.EntityViewSetting; + +/** + * @author Giovanni Lovato + * @since 1.3.0 + */ +public interface EntityViewSettingProcessor { + + /** + * Processes the {@link EntityViewSetting} to allow additional Entity View customization during query creation. + * + * @param setting the {@link EntityViewSetting} to be processed + * @return the final {@link EntityViewSetting} to allow further processing + */ + EntityViewSetting acceptEntityViewSetting(EntityViewSetting setting); +} diff --git a/integration/spring-data/testsuite/src/test/java/com/blazebit/persistence/spring/data/testsuite/DocumentRepositoryTest.java b/integration/spring-data/testsuite/src/test/java/com/blazebit/persistence/spring/data/testsuite/DocumentRepositoryTest.java index 7d890301dc..7e7684caaf 100644 --- a/integration/spring-data/testsuite/src/test/java/com/blazebit/persistence/spring/data/testsuite/DocumentRepositoryTest.java +++ b/integration/spring-data/testsuite/src/test/java/com/blazebit/persistence/spring/data/testsuite/DocumentRepositoryTest.java @@ -29,11 +29,14 @@ import com.blazebit.persistence.spring.data.testsuite.tx.TransactionalWorkService; import com.blazebit.persistence.spring.data.testsuite.tx.TxWork; import com.blazebit.persistence.spring.data.testsuite.view.DocumentView; +import com.blazebit.persistence.spring.data.repository.EntityViewSettingProcessor; import com.blazebit.persistence.spring.data.repository.KeysetAwarePage; import com.blazebit.persistence.spring.data.repository.KeysetPageRequest; import com.blazebit.persistence.testsuite.base.jpa.category.NoDatanucleus; import com.blazebit.persistence.testsuite.base.jpa.category.NoEclipselink; import com.blazebit.persistence.testsuite.base.jpa.category.NoHibernate42; +import com.blazebit.persistence.view.EntityViewSetting; + import org.junit.Assume; import org.junit.Before; import org.junit.Test; @@ -564,6 +567,28 @@ public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery assertEquals(actual.get(0).getOptionalParameter(), param); } + @Test + public void testEntityViewSettingProcessorParameter() { + // Given + String name = "D1"; + String param = "Foo"; + createDocument(name); + + // When + List actual = documentRepository.findAll(new EntityViewSettingProcessor() { + + @Override + public EntityViewSetting acceptEntityViewSetting(EntityViewSetting setting) { + setting.addOptionalParameter("optionalParameter", "Foo"); + return setting; + } + }); + + // Then + assertEquals(1, actual.size()); + assertEquals(actual.get(0).getOptionalParameter(), param); + } + private List getIdsFromViews(Iterable views) { List ids = new ArrayList<>(); for (DocumentAccessor view : views) { diff --git a/integration/spring-data/testsuite/src/test/java/com/blazebit/persistence/spring/data/testsuite/repository/DocumentRepository.java b/integration/spring-data/testsuite/src/test/java/com/blazebit/persistence/spring/data/testsuite/repository/DocumentRepository.java index 66d0930952..fda82bf74f 100644 --- a/integration/spring-data/testsuite/src/test/java/com/blazebit/persistence/spring/data/testsuite/repository/DocumentRepository.java +++ b/integration/spring-data/testsuite/src/test/java/com/blazebit/persistence/spring/data/testsuite/repository/DocumentRepository.java @@ -18,6 +18,7 @@ import com.blazebit.persistence.spring.data.annotation.OptionalParam; import com.blazebit.persistence.spring.data.repository.EntityViewRepository; +import com.blazebit.persistence.spring.data.repository.EntityViewSettingProcessor; import com.blazebit.persistence.spring.data.repository.EntityViewSpecificationExecutor; import com.blazebit.persistence.spring.data.repository.KeysetAwarePage; import com.blazebit.persistence.spring.data.testsuite.entity.Document; @@ -78,4 +79,6 @@ public interface DocumentRepository extends EntityViewRepository, En Page findByNameOrderById(String name, Pageable pageable, @OptionalParam("optionalParameter") String optionalParameter); List findAll(Specification specification, @OptionalParam("optionalParameter") String optionalParameter); + + List findAll(EntityViewSettingProcessor processor); }