Remove own code in favor of Spring Data KeyValue's extension points.

Remove code that would be duplicated by Spring Data KeyValue otherwise. Hook into extension points. Add package-info and nullability annotations.

Closes gh-151.
This commit is contained in:
Mark Paluch
2017-09-22 16:55:09 +02:00
parent f0111610ae
commit 4c079a0680
16 changed files with 310 additions and 261 deletions

View File

@@ -30,6 +30,7 @@ import org.springframework.data.keyvalue.repository.config.QueryCreatorType;
import org.springframework.data.repository.config.DefaultRepositoryBaseClass;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.vault.repository.query.VaultPartTreeQuery;
import org.springframework.vault.repository.query.VaultQueryCreator;
import org.springframework.vault.repository.support.VaultRepositoryFactoryBean;
@@ -46,7 +47,7 @@ import org.springframework.vault.repository.support.VaultRepositoryFactoryBean;
@Documented
@Inherited
@Import(VaultRepositoriesRegistrar.class)
@QueryCreatorType(VaultQueryCreator.class)
@QueryCreatorType(value = VaultQueryCreator.class, repositoryQueryType = VaultPartTreeQuery.class)
public @interface EnableVaultRepositories {
/**

View File

@@ -18,22 +18,14 @@ package org.springframework.vault.repository.configuration;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.keyvalue.repository.config.KeyValueRepositoryConfigurationExtension;
import org.springframework.data.keyvalue.repository.config.QueryCreatorType;
import org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery;
import org.springframework.data.keyvalue.repository.query.SpelQueryCreator;
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import org.springframework.data.repository.config.RepositoryConfigurationSource;
import org.springframework.vault.repository.core.VaultKeyValueAdapter;
@@ -69,70 +61,6 @@ public class VaultRepositoryConfigurationExtension extends
return "vaultKeyValueTemplate";
}
// TODO: Remove this as soon as KeyValue provides overrides for the mapping context
// name.
@Override
public void postProcess(BeanDefinitionBuilder builder,
AnnotationRepositoryConfigurationSource config) {
AnnotationAttributes attributes = config.getAttributes();
builder.addPropertyReference("keyValueOperations",
attributes.getString(KEY_VALUE_TEMPLATE_BEAN_REF_ATTRIBUTE));
builder.addPropertyValue("queryCreator", getQueryCreatorType(config));
builder.addPropertyValue("queryType", getQueryType(config));
builder.addPropertyReference("mappingContext", VAULT_MAPPING_CONTEXT_BEAN_NAME);
}
/**
* Detects the query creator type to be used for the factory to set. Will lookup a
* {@link QueryCreatorType} annotation on the {@code @Enable}-annotation or use
* {@link SpelQueryCreator} if not found.
*
* @param config
* @return
*/
private static Class<?> getQueryCreatorType(
AnnotationRepositoryConfigurationSource config) {
AnnotationMetadata metadata = config.getEnableAnnotationMetadata();
Map<String, Object> queryCreatorAnnotationAttributes = metadata
.getAnnotationAttributes(QueryCreatorType.class.getName());
if (queryCreatorAnnotationAttributes == null) {
return SpelQueryCreator.class;
}
AnnotationAttributes queryCreatorAttributes = new AnnotationAttributes(
queryCreatorAnnotationAttributes);
return queryCreatorAttributes.getClass("value");
}
/**
* Detects the query creator type to be used for the factory to set. Will lookup a
* {@link QueryCreatorType} annotation on the {@code @Enable}-annotation or use
* {@link SpelQueryCreator} if not found.
*
* @param config
* @return
*/
private static Class<?> getQueryType(AnnotationRepositoryConfigurationSource config) {
AnnotationMetadata metadata = config.getEnableAnnotationMetadata();
Map<String, Object> queryCreatorAnnotationAttributes = metadata
.getAnnotationAttributes(QueryCreatorType.class.getName());
if (queryCreatorAnnotationAttributes == null) {
return KeyValuePartTreeQuery.class;
}
AnnotationAttributes queryCreatorAttributes = new AnnotationAttributes(
queryCreatorAnnotationAttributes);
return queryCreatorAttributes.getClass("repositoryQueryType");
}
@Override
public void registerBeansForRoot(BeanDefinitionRegistry registry,
RepositoryConfigurationSource configurationSource) {
@@ -171,11 +99,11 @@ public class VaultRepositoryConfigurationExtension extends
AbstractBeanDefinition beanDefinition = getDefaultKeyValueTemplateBeanDefinition(configurationSource);
if (beanDefinition != null) {
registerIfNotAlreadyRegistered(beanDefinition, registry,
keyValueTemplateName.get(), configurationSource.getSource());
}
registerIfNotAlreadyRegistered(beanDefinition, registry,
keyValueTemplateName.get(), configurationSource.getSource());
}
super.registerBeansForRoot(registry, configurationSource);
}
private RootBeanDefinition createVaultMappingContext(
@@ -186,6 +114,7 @@ public class VaultRepositoryConfigurationExtension extends
RootBeanDefinition mappingContextBeanDef = new RootBeanDefinition(
VaultMappingContext.class);
mappingContextBeanDef.setConstructorArgumentValues(mappingContextArgs);
mappingContextBeanDef.setSource(configurationSource.getSource());
return mappingContextBeanDef;
}
@@ -214,4 +143,9 @@ public class VaultRepositoryConfigurationExtension extends
protected Collection<Class<? extends Annotation>> getIdentifyingAnnotations() {
return Collections.<Class<? extends Annotation>> singleton(Secret.class);
}
@Override
protected String getMappingContextBeanRef() {
return VAULT_MAPPING_CONTEXT_BEAN_NAME;
}
}

View File

@@ -0,0 +1,5 @@
/**
* Support infrastructure for the configuration of Vault specific repositories.
*/
@org.springframework.lang.NonNullApi
package org.springframework.vault.repository.configuration;

View File

@@ -27,6 +27,7 @@ import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.data.convert.JodaTimeConverters;
import org.springframework.data.convert.WritingConverter;
import org.springframework.lang.Nullable;
import org.springframework.vault.repository.mapping.VaultSimpleTypes;
/**
@@ -43,6 +44,7 @@ public class VaultCustomConversions extends
org.springframework.data.convert.CustomConversions {
private static final StoreConversions STORE_CONVERSIONS;
private static final List<Object> STORE_CONVERTERS;
static {
@@ -89,9 +91,10 @@ public class VaultCustomConversions extends
return new HashSet<>(Arrays.asList(localeToString, booleanToString));
}
public Object convert(Object source, TypeDescriptor sourceType,
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor sourceType,
TypeDescriptor targetType) {
return source.toString();
return source != null ? source.toString() : null;
}
}
}

View File

@@ -1,8 +1,6 @@
/**
* Spring Vault specific converter infrastructure.
*/
@NonNullApi
@org.springframework.lang.NonNullApi
package org.springframework.vault.repository.convert;
import org.springframework.lang.NonNullApi;

View File

@@ -66,7 +66,7 @@ public class VaultKeyValueAdapter extends AbstractKeyValueAdapter {
public VaultKeyValueAdapter(VaultOperations vaultOperations,
VaultConverter vaultConverter) {
super(VaultQueryEngine.INSTANCE);
super(new VaultQueryEngine());
Assert.notNull(vaultOperations, "VaultOperations must not be null");
Assert.notNull(vaultConverter, "VaultConverter must not be null");

View File

@@ -18,22 +18,15 @@ package org.springframework.vault.repository.core;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.NullHandling;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.keyvalue.core.CriteriaAccessor;
import org.springframework.data.keyvalue.core.QueryEngine;
import org.springframework.data.keyvalue.core.SortAccessor;
import org.springframework.data.keyvalue.core.SpelPropertyComparator;
import org.springframework.data.keyvalue.core.SpelSortAccessor;
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mapping.context.PersistentPropertyPath;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.vault.repository.query.VaultQuery;
/**
@@ -50,27 +43,26 @@ import org.springframework.vault.repository.query.VaultQuery;
class VaultQueryEngine extends
QueryEngine<VaultKeyValueAdapter, VaultQuery, Comparator<?>> {
static final VaultQueryEngine INSTANCE = new VaultQueryEngine();
private static final SpelExpressionParser parser = new SpelExpressionParser();
private VaultQueryEngine() {
super(VaultCriteriaAccessor.INSTANCE, SpelSortAccessor.INSTANCE);
VaultQueryEngine() {
super(VaultCriteriaAccessor.INSTANCE, new SpelSortAccessor(parser));
}
@Override
@SuppressWarnings("unchecked")
public Collection<?> execute(VaultQuery vaultQuery, Comparator<?> comparator,
long offset, int rows, String keyspace) {
public Collection<?> execute(@Nullable VaultQuery vaultQuery,
@Nullable Comparator<?> comparator, long offset, int rows, String keyspace) {
return execute(vaultQuery, comparator, offset, rows, keyspace, Object.class);
}
@Override
@SuppressWarnings("unchecked")
public <T> Collection<T> execute(VaultQuery vaultQuery, Comparator<?> comparator,
long offset, int rows, String keyspace, Class<T> type) {
public <T> Collection<T> execute(@Nullable VaultQuery vaultQuery,
@Nullable Comparator<?> comparator, long offset, int rows, String keyspace,
Class<T> type) {
validatePropertyPaths(vaultQuery);
Stream<String> stream = getAdapter().doList(keyspace).stream();
Stream<String> stream = getRequiredAdapter().doList(keyspace).stream();
if (vaultQuery != null) {
stream = stream.filter(vaultQuery::test);
@@ -87,7 +79,7 @@ class VaultQueryEngine extends
}
}
Stream<T> typed = stream.map(it -> getAdapter().get(it, keyspace, type));
Stream<T> typed = stream.map(it -> getRequiredAdapter().get(it, keyspace, type));
if (comparator != null) {
@@ -106,11 +98,9 @@ class VaultQueryEngine extends
}
@Override
public long count(VaultQuery vaultQuery, String keyspace) {
public long count(@Nullable VaultQuery vaultQuery, String keyspace) {
validatePropertyPaths(vaultQuery);
Stream<String> stream = getAdapter().doList(keyspace).stream();
Stream<String> stream = getRequiredAdapter().doList(keyspace).stream();
if (vaultQuery != null) {
stream = stream.filter(vaultQuery::test);
@@ -119,26 +109,6 @@ class VaultQueryEngine extends
return stream.count();
}
private void validatePropertyPaths(VaultQuery vaultQuery) {
if (vaultQuery == null) {
return;
}
Stream<PropertyPath> stream = vaultQuery.getPropertyPaths().stream();
stream.map(it -> getAdapter().getMappingContext().getPersistentPropertyPath(it))
.filter(it -> it.getLeafProperty() != null)
.map(PersistentPropertyPath::getLeafProperty)
.filter(it -> !it.isIdProperty())
.forEach(
property -> {
throw new InvalidDataAccessApiUsageException(String.format(
"Cannot create criteria for non-@Id property %s",
property));
});
}
enum VaultCriteriaAccessor implements CriteriaAccessor<VaultQuery> {
INSTANCE;
@@ -148,53 +118,4 @@ class VaultQueryEngine extends
}
}
/**
* {@link SortAccessor} implementation capable of creating
* {@link SpelPropertyComparator}.
*/
enum SpelSortAccessor implements SortAccessor<Comparator<?>> {
INSTANCE;
private final SpelExpressionParser parser = new SpelExpressionParser();
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Comparator<?> resolve(KeyValueQuery<?> query) {
if (query == null || query.getSort() == null || query.getSort().isUnsorted()) {
return null;
}
Optional<Comparator<?>> comparator = Optional.empty();
for (Order order : query.getSort()) {
SpelPropertyComparator<Object> spelSort = new SpelPropertyComparator<>(
order.getProperty(), parser);
if (Direction.DESC.equals(order.getDirection())) {
spelSort.desc();
if (!NullHandling.NATIVE.equals(order.getNullHandling())) {
spelSort = NullHandling.NULLS_FIRST.equals(order
.getNullHandling()) ? spelSort.nullsFirst() : spelSort
.nullsLast();
}
}
if (!comparator.isPresent()) {
comparator = Optional.of(spelSort);
}
else {
SpelPropertyComparator<Object> spelSortToUse = spelSort;
comparator = comparator.map(it -> it.thenComparing(spelSortToUse));
}
}
return comparator
.orElseThrow(() -> new IllegalStateException(
"No sort definitions have been added to this CompoundComparator to compare"));
}
}
}

View File

@@ -0,0 +1,6 @@
/**
* Spring Vault core repository implementation.
*/
@org.springframework.lang.NonNullApi
package org.springframework.vault.repository.core;

View File

@@ -0,0 +1,6 @@
/**
* Infrastructure for the Vault JSON-to-object mapping subsystem.
*/
@org.springframework.lang.NonNullApi
package org.springframework.vault.repository.mapping;

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2017 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.vault.repository.query;
import lombok.RequiredArgsConstructor;
import org.springframework.data.keyvalue.core.KeyValueOperations;
import org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.query.EvaluationContextProvider;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.vault.repository.mapping.VaultPersistentEntity;
import org.springframework.vault.repository.mapping.VaultPersistentProperty;
/**
* Vault-specific {@link KeyValuePartTreeQuery}.
*
* @author Mark Paluch
* @since 2.0
*/
public class VaultPartTreeQuery extends KeyValuePartTreeQuery {
/**
* Creates a new {@link VaultPartTreeQuery} for the given {@link QueryMethod},
* {@link EvaluationContextProvider}, {@link KeyValueOperations} and query creator
* type.
*
* @param queryMethod must not be {@literal null}.
* @param evaluationContextProvider must not be {@literal null}.
* @param keyValueOperations must not be {@literal null}.
* @param queryCreator must not be {@literal null}.
*/
@SuppressWarnings("unchecked")
public VaultPartTreeQuery(QueryMethod queryMethod,
EvaluationContextProvider evaluationContextProvider,
KeyValueOperations keyValueOperations,
Class<? extends AbstractQueryCreator<?, ?>> queryCreator) {
super(queryMethod, evaluationContextProvider, keyValueOperations,
new VaultQueryCreatorFactory(
(MappingContext) keyValueOperations.getMappingContext()));
}
@RequiredArgsConstructor
static class VaultQueryCreatorFactory implements
QueryCreatorFactory<VaultQueryCreator> {
private final MappingContext<VaultPersistentEntity<?>, VaultPersistentProperty> mappingContext;
@Override
public VaultQueryCreator queryCreatorFor(PartTree partTree,
ParameterAccessor accessor) {
return new VaultQueryCreator(partTree, accessor, mappingContext);
}
}
}

View File

@@ -15,12 +15,8 @@
*/
package org.springframework.vault.repository.query;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.util.Assert;
import org.springframework.vault.repository.convert.SecretDocument;
@@ -39,8 +35,6 @@ public class VaultQuery {
private final Predicate<String> predicate;
private final Set<PropertyPath> propertyPaths;
/**
* Create a new {@link VaultQuery} that evaluates unconditionally to {@literal true}.
*/
@@ -54,30 +48,10 @@ public class VaultQuery {
* @param predicate must not be {@literal null}.
*/
public VaultQuery(Predicate<String> predicate) {
this(predicate, Collections.emptySet());
}
/**
* Create a new {@link VaultQuery} given {@link Predicate} and {@link PropertyPath}.
*
* @param predicate must not be {@literal null}.
*/
public VaultQuery(Predicate<String> predicate, PropertyPath propertyPath) {
Assert.notNull(predicate, "Predicate must not be null");
Assert.notNull(propertyPath, "PropertyPath must not be null");
this.predicate = predicate;
this.propertyPaths = Collections.singleton(propertyPath);
}
private VaultQuery(Predicate<String> predicate, Set<PropertyPath> propertyPaths) {
Assert.notNull(propertyPaths, "PropertyPaths must not be null");
Assert.notNull(predicate, "Predicate must not be null");
this.predicate = predicate;
this.propertyPaths = propertyPaths;
}
/**
@@ -115,13 +89,19 @@ public class VaultQuery {
* @see Predicate#and(Predicate)
*/
public VaultQuery and(VaultQuery other) {
return new VaultQuery(this.predicate.and(other.predicate));
}
Set<PropertyPath> propertyPaths = new HashSet<>(this.propertyPaths.size()
+ other.propertyPaths.size(), 1);
propertyPaths.addAll(this.propertyPaths);
propertyPaths.addAll(other.propertyPaths);
return new VaultQuery(this.predicate.and(other.predicate), propertyPaths);
/**
* Compose a new {@link VaultQuery} using predicates of {@literal this} and the
* {@code other} query using logical {@code AND}.
*
* @param other must not be {@literal null}.
* @return a new composed {@link VaultQuery}.
* @see Predicate#and(Predicate)
*/
public VaultQuery and(Predicate<String> predicate) {
return new VaultQuery(this.predicate.and(predicate));
}
/**
@@ -133,30 +113,7 @@ public class VaultQuery {
* @see Predicate#and(Predicate)
*/
public VaultQuery or(VaultQuery other) {
Set<PropertyPath> propertyPaths = new HashSet<>(this.propertyPaths.size()
+ other.propertyPaths.size(), 1);
propertyPaths.addAll(this.propertyPaths);
propertyPaths.addAll(other.propertyPaths);
return new VaultQuery(this.predicate.or(other.predicate), propertyPaths);
}
/**
* Compose a new {@link VaultQuery} using predicates of {@literal this} query and the
* {@code other} {@link Predicate} using logical {@code AND}.
*
* @param other must not be {@literal null}.
* @return a new composed {@link VaultQuery}.
* @see Predicate#and(Predicate)
*/
public VaultQuery and(Predicate<String> predicate, PropertyPath propertyPath) {
Set<PropertyPath> propertyPaths = new HashSet<>(this.propertyPaths.size() + 1, 1);
propertyPaths.addAll(this.propertyPaths);
propertyPaths.add(propertyPath);
return new VaultQuery(this.predicate.and(predicate), propertyPaths);
return new VaultQuery(this.predicate.or(other.predicate));
}
/**
@@ -165,11 +122,4 @@ public class VaultQuery {
public Predicate<String> getPredicate() {
return predicate;
}
/**
* @return constrained {@link PropertyPath}s for this {@link VaultQuery}.
*/
public Set<PropertyPath> getPropertyPaths() {
return Collections.unmodifiableSet(propertyPaths);
}
}

View File

@@ -24,14 +24,19 @@ import java.util.regex.Pattern;
import lombok.Value;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Sort;
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.PersistentPropertyPath;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.data.repository.query.parser.Part.IgnoreCaseType;
import org.springframework.data.repository.query.parser.Part.Type;
import org.springframework.vault.repository.mapping.VaultPersistentEntity;
import org.springframework.vault.repository.mapping.VaultPersistentProperty;
/**
* Query creator for Vault queries. Vault queries are limited to criterias constraining
@@ -44,14 +49,7 @@ import org.springframework.data.repository.query.parser.Part.Type;
public class VaultQueryCreator extends
AbstractQueryCreator<KeyValueQuery<VaultQuery>, VaultQuery> {
/**
* Create a new {@link VaultQueryCreator} given {@link PartTree}.
*
* @param tree must not be {@literal null}.
*/
public VaultQueryCreator(PartTree tree) {
super(tree);
}
private final MappingContext<VaultPersistentEntity<?>, VaultPersistentProperty> mappingContext;
/**
* Create a new {@link VaultQueryCreator} given {@link PartTree} and
@@ -59,27 +57,38 @@ public class VaultQueryCreator extends
*
* @param tree must not be {@literal null}.
* @param parameters must not be {@literal null}.
* @param mappingContext must not be {@literal null}.
*/
public VaultQueryCreator(PartTree tree, ParameterAccessor parameters) {
public VaultQueryCreator(
PartTree tree,
ParameterAccessor parameters,
MappingContext<VaultPersistentEntity<?>, VaultPersistentProperty> mappingContext) {
super(tree, parameters);
this.mappingContext = mappingContext;
}
@Override
protected VaultQuery create(Part part, Iterator<Object> parameters) {
return new VaultQuery(createPredicate(part, parameters), part.getProperty());
return new VaultQuery(createPredicate(part, parameters));
}
@Override
protected VaultQuery and(Part part, VaultQuery base, Iterator<Object> parameters) {
if (base == null) {
return create(part, parameters);
}
return base.and(createPredicate(part, parameters), part.getProperty());
return base.and(createPredicate(part, parameters));
}
private static Predicate<String> createPredicate(Part part,
Iterator<Object> parameters) {
private Predicate<String> createPredicate(Part part, Iterator<Object> parameters) {
PersistentPropertyPath<VaultPersistentProperty> propertyPath = mappingContext
.getPersistentPropertyPath(part.getProperty());
if (propertyPath.getLeafProperty() != null
&& !propertyPath.getLeafProperty().isIdProperty()) {
throw new InvalidDataAccessApiUsageException(String.format(
"Cannot create criteria for non-@Id property %s",
propertyPath.getLeafProperty()));
}
VariableAccessor accessor = getVariableAccessor(part);
@@ -167,7 +176,7 @@ public class VaultQueryCreator extends
KeyValueQuery<VaultQuery> query = new KeyValueQuery<>(vaultQuery);
if (sort != null) {
if (sort.isSorted()) {
query.orderBy(sort);
}

View File

@@ -0,0 +1,6 @@
/**
* Query derivation mechanism for Vault specific repositories.
*/
@org.springframework.lang.NonNullApi
package org.springframework.vault.repository.query;

View File

@@ -0,0 +1,6 @@
/**
* Support infrastructure for query derivation of Vault specific repositories.
*/
@org.springframework.lang.NonNullApi
package org.springframework.vault.repository.support;

View File

@@ -0,0 +1,121 @@
/*
* Copyright 2017 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.vault.repository;
import java.util.List;
import lombok.Data;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.data.annotation.Id;
import org.springframework.data.map.repository.config.EnableMapRepositories;
import org.springframework.data.repository.CrudRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.vault.core.VaultTemplate;
import org.springframework.vault.repository.MultipleSpringDataModulesIntegrationTests.MultipleModulesActiveTestConfiguration;
import org.springframework.vault.repository.configuration.EnableVaultRepositories;
import org.springframework.vault.util.IntegrationTestSupport;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Mark Paluch
*/
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = MultipleModulesActiveTestConfiguration.class)
public class MultipleSpringDataModulesIntegrationTests extends IntegrationTestSupport {
@Configuration
@EnableMapRepositories(considerNestedRepositories = true, //
excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, value = VaultRepository.class))
@EnableVaultRepositories(considerNestedRepositories = true, //
excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, value = MapRepository.class))
static class MultipleModulesActiveTestConfiguration extends
VaultIntegrationTestConfiguration {
}
@Autowired
VaultRepository vaultRepository;
@Autowired
MapRepository mapRepository;
@Autowired
VaultTemplate vaultTemplate;
@Before
public void before() {
vaultRepository.deleteAll();
}
@Test
public void loadAndSave() {
Person person = new Person();
person.setId("foo-key");
person.setName("bar");
vaultRepository.save(person);
Iterable<Person> all = vaultRepository.findAll();
assertThat(all).contains(person);
assertThat(vaultRepository.findByIdStartsWith("foo-key")).contains(person);
}
@Test
public void loadAndSaveMapRepository() {
vaultRepository.findAll().forEach(vaultRepository::delete);
Person person = new Person();
person.setId("foo-key");
person.setName("bar");
mapRepository.save(person);
Iterable<Person> all = mapRepository.findAll();
assertThat(all).contains(person);
assertThat(mapRepository.findByNameStartsWith("bar")).contains(person);
assertThat(vaultRepository.findById("foo-key")).isEmpty();
}
interface VaultRepository extends CrudRepository<Person, String> {
List<Person> findByIdStartsWith(String prefix);
}
interface MapRepository extends CrudRepository<Person, String> {
List<Person> findByNameStartsWith(String prefix);
}
@Data
static class Person {
@Id
String id;
String name;
}
}

View File

@@ -20,10 +20,12 @@ import java.util.List;
import org.junit.Test;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.repository.query.DefaultParameters;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.util.ReflectionUtils;
import org.springframework.vault.repository.mapping.VaultMappingContext;
import static org.assertj.core.api.Assertions.assertThat;
@@ -34,6 +36,8 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class VaultQueryCreatorUnitTests {
private VaultMappingContext mappingContext = new VaultMappingContext();
@Test
public void greaterThan() {
@@ -178,6 +182,11 @@ public class VaultQueryCreatorUnitTests {
assertThat(query.getPredicate()).accepts("3", "4").rejects("2", "5", "6");
}
@Test(expected = InvalidDataAccessApiUsageException.class)
public void failsForNonIdProperties() {
createQuery("findByName", "");
}
VaultQuery createQuery(String methodName, String value) {
DefaultParameters defaultParameters = new DefaultParameters(
@@ -187,7 +196,8 @@ public class VaultQueryCreatorUnitTests {
PartTree partTree = new PartTree(methodName, Credentials.class);
VaultQueryCreator queryCreator = new VaultQueryCreator(
partTree,
new ParametersParameterAccessor(defaultParameters, new Object[] { value }));
new ParametersParameterAccessor(defaultParameters, new Object[] { value }),
mappingContext);
return queryCreator.createQuery().getCriteria();
}
@@ -201,7 +211,8 @@ public class VaultQueryCreatorUnitTests {
PartTree partTree = new PartTree(methodName, Credentials.class);
VaultQueryCreator queryCreator = new VaultQueryCreator(
partTree,
new ParametersParameterAccessor(defaultParameters, new Object[] { value }));
new ParametersParameterAccessor(defaultParameters, new Object[] { value }),
mappingContext);
return queryCreator.createQuery().getCriteria();
}
@@ -215,7 +226,7 @@ public class VaultQueryCreatorUnitTests {
PartTree partTree = new PartTree(methodName, Credentials.class);
VaultQueryCreator queryCreator = new VaultQueryCreator(partTree,
new ParametersParameterAccessor(defaultParameters, new Object[] { value,
anotherValue }));
anotherValue }), mappingContext);
return queryCreator.createQuery().getCriteria();
}
@@ -231,6 +242,6 @@ public class VaultQueryCreatorUnitTests {
static class Credentials {
String id;
String id, name;
}
}