Add support for providing default Querydsl bindings.
We now consider default Querydsl bindings when registering a DefaultQuerydslBinderCustomizer bean. The default bindings are applied before applying type-specific bindings. Closes #206. Original Pull Request: #2292
This commit is contained in:
committed by
Christoph Strobl
parent
e3a8edf581
commit
4e07b85934
@@ -1667,6 +1667,8 @@ interface UserRepository extends CrudRepository<User, String>,
|
|||||||
<5> Exclude the `password` property from `Predicate` resolution.
|
<5> Exclude the `password` property from `Predicate` resolution.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
Additionally, you can register a `DefaultQuerydslBinderCustomizer` bean to apply default Querydsl bindings before applying specific bindings from the repository or `@QuerydslPredicate`.
|
||||||
|
|
||||||
[[core.repository-populators]]
|
[[core.repository-populators]]
|
||||||
=== Repository Populators
|
=== Repository Populators
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 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
|
||||||
|
*
|
||||||
|
* https://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.querydsl.binding;
|
||||||
|
|
||||||
|
import com.querydsl.core.types.EntityPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A component for {@link QuerydslBindings} customization acting as default customizer the given entity path regardless
|
||||||
|
* of the domain type. Instances can be registered with the application context to be applied.
|
||||||
|
*
|
||||||
|
* @author Mark Paluch
|
||||||
|
* @since 2.5
|
||||||
|
*/
|
||||||
|
public interface DefaultQuerydslBinderCustomizer extends QuerydslBinderCustomizer<EntityPath<?>> {}
|
||||||
@@ -15,8 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.querydsl.binding;
|
package org.springframework.data.querydsl.binding;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
@@ -37,6 +39,7 @@ import com.querydsl.core.types.EntityPath;
|
|||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
|
* @author Mark Paluch
|
||||||
* @since 1.11
|
* @since 1.11
|
||||||
*/
|
*/
|
||||||
public class QuerydslBindingsFactory implements ApplicationContextAware {
|
public class QuerydslBindingsFactory implements ApplicationContextAware {
|
||||||
@@ -48,6 +51,7 @@ public class QuerydslBindingsFactory implements ApplicationContextAware {
|
|||||||
|
|
||||||
private Optional<AutowireCapableBeanFactory> beanFactory;
|
private Optional<AutowireCapableBeanFactory> beanFactory;
|
||||||
private Optional<Repositories> repositories;
|
private Optional<Repositories> repositories;
|
||||||
|
private QuerydslBinderCustomizer<EntityPath<?>> defaultCustomizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link QuerydslBindingsFactory} using the given {@link EntityPathResolver}.
|
* Creates a new {@link QuerydslBindingsFactory} using the given {@link EntityPathResolver}.
|
||||||
@@ -62,6 +66,7 @@ public class QuerydslBindingsFactory implements ApplicationContextAware {
|
|||||||
this.entityPaths = new ConcurrentReferenceHashMap<>();
|
this.entityPaths = new ConcurrentReferenceHashMap<>();
|
||||||
this.beanFactory = Optional.empty();
|
this.beanFactory = Optional.empty();
|
||||||
this.repositories = Optional.empty();
|
this.repositories = Optional.empty();
|
||||||
|
this.defaultCustomizer = NoOpCustomizer.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -73,6 +78,7 @@ public class QuerydslBindingsFactory implements ApplicationContextAware {
|
|||||||
|
|
||||||
this.beanFactory = Optional.of(applicationContext.getAutowireCapableBeanFactory());
|
this.beanFactory = Optional.of(applicationContext.getAutowireCapableBeanFactory());
|
||||||
this.repositories = Optional.of(new Repositories(applicationContext));
|
this.repositories = Optional.of(new Repositories(applicationContext));
|
||||||
|
this.defaultCustomizer = findDefaultCustomizer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -126,6 +132,7 @@ public class QuerydslBindingsFactory implements ApplicationContextAware {
|
|||||||
EntityPath<?> path = verifyEntityPathPresent(domainType);
|
EntityPath<?> path = verifyEntityPathPresent(domainType);
|
||||||
|
|
||||||
QuerydslBindings bindings = new QuerydslBindings();
|
QuerydslBindings bindings = new QuerydslBindings();
|
||||||
|
defaultCustomizer.customize(bindings, path);
|
||||||
findCustomizerForDomainType(customizer, domainType.getType()).customize(bindings, path);
|
findCustomizerForDomainType(customizer, domainType.getType()).customize(bindings, path);
|
||||||
|
|
||||||
return bindings;
|
return bindings;
|
||||||
@@ -151,9 +158,32 @@ public class QuerydslBindingsFactory implements ApplicationContextAware {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains registered {@link DefaultQuerydslBinderCustomizer} instances from the
|
||||||
|
* {@link org.springframework.beans.factory.BeanFactory}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private QuerydslBinderCustomizer<EntityPath<?>> findDefaultCustomizer() {
|
||||||
|
return beanFactory.map(this::getDefaultQuerydslBinderCustomizer).orElse(NoOpCustomizer.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QuerydslBinderCustomizer<EntityPath<?>> getDefaultQuerydslBinderCustomizer(
|
||||||
|
AutowireCapableBeanFactory beanFactory) {
|
||||||
|
|
||||||
|
List<DefaultQuerydslBinderCustomizer> customizers = beanFactory
|
||||||
|
.getBeanProvider(DefaultQuerydslBinderCustomizer.class).stream().collect(Collectors.toList());
|
||||||
|
|
||||||
|
return (bindings, root) -> {
|
||||||
|
for (DefaultQuerydslBinderCustomizer defaultQuerydslBinderCustomizer : customizers) {
|
||||||
|
defaultQuerydslBinderCustomizer.customize(bindings, root);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the {@link QuerydslBinderCustomizer} for the given domain type. Will inspect the given annotation for a
|
* Obtains the {@link QuerydslBinderCustomizer} for the given domain type. Will inspect the given annotation for a
|
||||||
* dedicatedly configured one or consider the domain types's repository.
|
* dedicated configured one or consider the domain type's repository.
|
||||||
*
|
*
|
||||||
* @param annotation
|
* @param annotation
|
||||||
* @param domainType
|
* @param domainType
|
||||||
@@ -194,7 +224,7 @@ public class QuerydslBindingsFactory implements ApplicationContextAware {
|
|||||||
}).orElseGet(() -> BeanUtils.instantiateClass(type));
|
}).orElseGet(() -> BeanUtils.instantiateClass(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static enum NoOpCustomizer implements QuerydslBinderCustomizer<EntityPath<?>> {
|
private enum NoOpCustomizer implements QuerydslBinderCustomizer<EntityPath<?>> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ import java.util.Optional;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||||
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
import org.springframework.data.querydsl.QUser;
|
import org.springframework.data.querydsl.QUser;
|
||||||
import org.springframework.data.querydsl.SimpleEntityPathResolver;
|
import org.springframework.data.querydsl.SimpleEntityPathResolver;
|
||||||
import org.springframework.data.querydsl.User;
|
import org.springframework.data.querydsl.User;
|
||||||
@@ -33,6 +35,7 @@ import org.springframework.data.util.TypeInformation;
|
|||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
import com.querydsl.core.types.EntityPath;
|
||||||
import com.querydsl.core.types.Path;
|
import com.querydsl.core.types.Path;
|
||||||
import com.querydsl.core.types.Predicate;
|
import com.querydsl.core.types.Predicate;
|
||||||
|
|
||||||
@@ -95,6 +98,27 @@ class QuerydslBindingsFactoryUnitTests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // #206
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
void shouldApplyDefaultCustomizers() {
|
||||||
|
|
||||||
|
GenericApplicationContext context = new GenericApplicationContext();
|
||||||
|
context.registerBean(DefaultCustomizer.class);
|
||||||
|
context.refresh();
|
||||||
|
|
||||||
|
QuerydslBindingsFactory factory = new QuerydslBindingsFactory(SimpleEntityPathResolver.INSTANCE);
|
||||||
|
factory.setApplicationContext(context);
|
||||||
|
|
||||||
|
QuerydslBindings bindings = factory.createBindingsFor(USER_TYPE, SpecificBinding.class);
|
||||||
|
Optional<MultiValueBinding<Path<Object>, Object>> binding = bindings
|
||||||
|
.getBindingForPath(PropertyPathInformation.of("inceptionYear", User.class));
|
||||||
|
|
||||||
|
assertThat(binding).hasValueSatisfying(it -> {
|
||||||
|
Optional<Predicate> bind = it.bind((Path) QUser.user.inceptionYear, Collections.singleton(1L));
|
||||||
|
assertThat(bind).hasValue(QUser.user.inceptionYear.gt(1L));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Test // DATACMNS-669
|
@Test // DATACMNS-669
|
||||||
void rejectsPredicateResolutionIfDomainTypeCantBeAutoDetected() {
|
void rejectsPredicateResolutionIfDomainTypeCantBeAutoDetected() {
|
||||||
|
|
||||||
@@ -123,4 +147,14 @@ class QuerydslBindingsFactoryUnitTests {
|
|||||||
bindings.bind(QUser.user.firstname).firstOptional((path, value) -> value.map(path::contains));
|
bindings.bind(QUser.user.firstname).firstOptional((path, value) -> value.map(path::contains));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class DefaultCustomizer implements DefaultQuerydslBinderCustomizer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void customize(QuerydslBindings bindings, EntityPath<?> root) {
|
||||||
|
|
||||||
|
bindings.bind(QUser.user.inceptionYear).first((path, value) -> QUser.user.inceptionYear.gt(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user