DATAKV-197 - Introduce usage of nullable annotations for API validation.
Annotate all packages with Spring Frameworks @NonNullApi and @NonNullFields. Add Spring's @Nullable to methods, parameters and fields that take or produce null values. Adapted using code to make sure the IDE can evaluate the null flow properly. Fix Javadoc in places where an invalid null handling policy was advertised. Strengthened null requirements for types that expose null-instances. Original Pull Request: #28
This commit is contained in:
committed by
Christoph Strobl
parent
f1935f73b7
commit
83057f1288
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Key-Value annotations for declarative keyspace configuration.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.keyvalue.annotation;
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.keyvalue.core;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Base implementation of {@link KeyValueAdapter} holds {@link QueryEngine} to delegate {@literal find} and
|
||||
@@ -42,7 +43,7 @@ public abstract class AbstractKeyValueAdapter implements KeyValueAdapter {
|
||||
*
|
||||
* @param engine will be defaulted to {@link SpelQueryEngine} if {@literal null}.
|
||||
*/
|
||||
protected AbstractKeyValueAdapter(QueryEngine<? extends KeyValueAdapter, ?, ?> engine) {
|
||||
protected AbstractKeyValueAdapter(@Nullable QueryEngine<? extends KeyValueAdapter, ?, ?> engine) {
|
||||
|
||||
this.engine = engine != null ? engine : new SpelQueryEngine();
|
||||
this.engine.registerAdapter(this);
|
||||
@@ -61,6 +62,7 @@ public abstract class AbstractKeyValueAdapter implements KeyValueAdapter {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.keyvalue.core.KeyValueAdapter#get(java.lang.Object, java.lang.String, java.lang.Class)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T get(Object id, String keyspace, Class<T> type) {
|
||||
return type.cast(get(id, keyspace));
|
||||
@@ -70,6 +72,7 @@ public abstract class AbstractKeyValueAdapter implements KeyValueAdapter {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.keyvalue.core.KeyValueAdapter#delete(java.lang.Object, java.lang.String, java.lang.Class)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T delete(Object id, String keyspace, Class<T> type) {
|
||||
return type.cast(delete(id, keyspace));
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.springframework.data.keyvalue.core.query.KeyValueQuery;
|
||||
* Resolves the criteria object from given {@link KeyValueQuery}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @param <T>
|
||||
*/
|
||||
public interface CriteriaAccessor<T> {
|
||||
@@ -29,7 +30,7 @@ public interface CriteriaAccessor<T> {
|
||||
* Checks and reads {@link KeyValueQuery#getCriteria()} of given {@link KeyValueQuery}. Might also apply additional
|
||||
* transformation to match the desired type.
|
||||
*
|
||||
* @param query can be {@literal null}.
|
||||
* @param query must not be {@literal null}.
|
||||
* @return the criteria extracted from the query.
|
||||
* @throws IllegalArgumentException in case the criteria is not valid for usage with specific
|
||||
* {@link CriteriaAccessor}.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-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.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.keyvalue.core;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -26,13 +27,14 @@ import org.springframework.util.Assert;
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
* @param <K>
|
||||
* @param <V>
|
||||
*/
|
||||
public class ForwardingCloseableIterator<T> implements CloseableIterator<T> {
|
||||
|
||||
private final Iterator<? extends T> delegate;
|
||||
private final Runnable closeHandler;
|
||||
private final @Nullable Runnable closeHandler;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ForwardingCloseableIterator}.
|
||||
@@ -50,7 +52,7 @@ public class ForwardingCloseableIterator<T> implements CloseableIterator<T> {
|
||||
* @param delegate must not be {@literal null}.
|
||||
* @param closeHandler may be {@literal null}.
|
||||
*/
|
||||
public ForwardingCloseableIterator(Iterator<? extends T> delegate, Runnable closeHandler) {
|
||||
public ForwardingCloseableIterator(Iterator<? extends T> delegate, @Nullable Runnable closeHandler) {
|
||||
|
||||
Assert.notNull(delegate, "Delegate iterator must not be null!");
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.List;
|
||||
* Converter capable of transforming a given {@link Iterable} into a collection type.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public final class IterableConverter {
|
||||
|
||||
@@ -37,10 +38,6 @@ public final class IterableConverter {
|
||||
*/
|
||||
public static <T> List<T> toList(Iterable<T> source) {
|
||||
|
||||
if (source == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if (source instanceof List) {
|
||||
return (List<T>) source;
|
||||
}
|
||||
|
||||
@@ -21,12 +21,14 @@ import java.util.Map;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link KeyValueAdapter} unifies access and shields the underlying key/value specific implementation.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface KeyValueAdapter extends DisposableBean {
|
||||
|
||||
@@ -55,33 +57,41 @@ public interface KeyValueAdapter extends DisposableBean {
|
||||
* @param keyspace must not be {@literal null}.
|
||||
* @return {@literal null} in case no matching item exists.
|
||||
*/
|
||||
@Nullable
|
||||
Object get(Object id, String keyspace);
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param keyspace
|
||||
* @param type
|
||||
* @return
|
||||
* Get the object with given id from keyspace.
|
||||
*
|
||||
* @param id must not be {@literal null}.
|
||||
* @param keyspace must not be {@literal null}.
|
||||
* @param type must not be {@literal null}.
|
||||
* @return {@literal null} in case no matching item exists.
|
||||
* @since 1.1
|
||||
*/
|
||||
@Nullable
|
||||
<T> T get(Object id, String keyspace, Class<T> type);
|
||||
|
||||
/**
|
||||
* Delete and return the obect with given type and id.
|
||||
* Delete and return the object with given type and id.
|
||||
*
|
||||
* @param id must not be {@literal null}.
|
||||
* @param keyspace must not be {@literal null}.
|
||||
* @return {@literal null} if object could not be found
|
||||
*/
|
||||
@Nullable
|
||||
Object delete(Object id, String keyspace);
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param keyspace
|
||||
* @param type
|
||||
* @return
|
||||
* Delete and return the object with given type and id.
|
||||
*
|
||||
* @param id must not be {@literal null}.
|
||||
* @param keyspace must not be {@literal null}.
|
||||
* @param type must not be {@literal null}.
|
||||
* @return {@literal null} if object could not be found
|
||||
* @since 1.1
|
||||
*/
|
||||
@Nullable
|
||||
<T> T delete(Object id, String keyspace, Class<T> type);
|
||||
|
||||
/**
|
||||
@@ -95,7 +105,7 @@ public interface KeyValueAdapter extends DisposableBean {
|
||||
/**
|
||||
* Returns a {@link CloseableIterator} that iterates over all entries.
|
||||
*
|
||||
* @param keyspace
|
||||
* @param keyspace must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
CloseableIterator<Map.Entry<Object, Object>> entries(String keyspace);
|
||||
@@ -115,17 +125,17 @@ public interface KeyValueAdapter extends DisposableBean {
|
||||
/**
|
||||
* Find all matching objects within {@literal keyspace}.
|
||||
*
|
||||
* @param query
|
||||
* @param query must not be {@literal null}.
|
||||
* @param keyspace must not be {@literal null}.
|
||||
* @return empty {@link Collection} if no match found.
|
||||
*/
|
||||
Iterable<?> find(KeyValueQuery<?> query, String keyspace);
|
||||
|
||||
/**
|
||||
* @param query
|
||||
* @param keyspace
|
||||
* @param type
|
||||
* @return
|
||||
* @param query must not be {@literal null}.
|
||||
* @param keyspace must not be {@literal null}.
|
||||
* @param type must not be {@literal null}.
|
||||
* @return empty {@link Collection} if no match found.
|
||||
* @since 1.1
|
||||
*/
|
||||
<T> Iterable<T> find(KeyValueQuery<?> query, String keyspace, Class<T> type);
|
||||
@@ -134,13 +144,14 @@ public interface KeyValueAdapter extends DisposableBean {
|
||||
* Count number of objects within {@literal keyspace}.
|
||||
*
|
||||
* @param keyspace must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
long count(String keyspace);
|
||||
|
||||
/**
|
||||
* Count all matching objects within {@literal keyspace}.
|
||||
*
|
||||
* @param query
|
||||
* @param query must not be {@literal null}.
|
||||
* @param keyspace must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -15,11 +15,14 @@
|
||||
*/
|
||||
package org.springframework.data.keyvalue.core;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Generic callback interface for code that operates on a {@link KeyValueAdapter}. This is particularly useful for
|
||||
* delegating code that needs to work closely on the underlying key/value store implementation.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @param <T>
|
||||
*/
|
||||
public interface KeyValueCallback<T> {
|
||||
@@ -31,5 +34,6 @@ public interface KeyValueCallback<T> {
|
||||
* @param adapter
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
T doInKeyValue(KeyValueAdapter adapter);
|
||||
}
|
||||
|
||||
@@ -22,11 +22,13 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.keyvalue.annotation.KeySpace;
|
||||
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Interface that specifies a basic set of key/value operations. Implemented by {@link KeyValueTemplate}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface KeyValueOperations extends DisposableBean {
|
||||
|
||||
@@ -81,6 +83,7 @@ public interface KeyValueOperations extends DisposableBean {
|
||||
* @param action must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
<T> T execute(KeyValueCallback<T> action);
|
||||
|
||||
/**
|
||||
@@ -139,6 +142,7 @@ public interface KeyValueOperations extends DisposableBean {
|
||||
* @param objectToDelete must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
<T> T delete(T objectToDelete);
|
||||
|
||||
/**
|
||||
@@ -148,6 +152,7 @@ public interface KeyValueOperations extends DisposableBean {
|
||||
* @param type must not be {@literal null}.
|
||||
* @return the deleted item or {@literal null} if no match found.
|
||||
*/
|
||||
@Nullable
|
||||
<T> T delete(Object id, Class<T> type);
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.NoSuchElementException;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -27,6 +28,7 @@ import org.springframework.util.Assert;
|
||||
* exception to an appropriate exception from the {@code org.springframework.dao} hierarchy.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class KeyValuePersistenceExceptionTranslator implements PersistenceExceptionTranslator {
|
||||
|
||||
@@ -34,6 +36,7 @@ public class KeyValuePersistenceExceptionTranslator implements PersistenceExcept
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException exception) {
|
||||
|
||||
@@ -51,6 +54,7 @@ public class KeyValuePersistenceExceptionTranslator implements PersistenceExcept
|
||||
if (exception.getClass().getName().startsWith("java")) {
|
||||
return new UncategorizedKeyValueException(exception.getMessage(), exception);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentProperty
|
||||
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
|
||||
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -55,7 +56,7 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationEventPub
|
||||
private final IdentifierGenerator identifierGenerator;
|
||||
|
||||
private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_PERSISTENCE_EXCEPTION_TRANSLATOR;
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
private @Nullable ApplicationEventPublisher eventPublisher;
|
||||
private boolean publishEvents = true;
|
||||
private @SuppressWarnings("rawtypes") Set<Class<? extends KeyValueEvent>> eventTypesToPublish = Collections
|
||||
.emptySet();
|
||||
@@ -215,14 +216,10 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationEventPub
|
||||
|
||||
Assert.notNull(type, "Type to fetch must not be null!");
|
||||
|
||||
return execute(adapter -> {
|
||||
return executeRequired(adapter -> {
|
||||
|
||||
Iterable<?> values = adapter.getAllOf(resolveKeySpace(type));
|
||||
|
||||
if (values == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
ArrayList<T> filtered = new ArrayList<>();
|
||||
for (Object candidate : values) {
|
||||
if (typeCheck(type, candidate)) {
|
||||
@@ -336,6 +333,7 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationEventPub
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.keyvalue.core.KeyValueOperations#execute(org.springframework.data.keyvalue.core.KeyValueCallback)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T execute(KeyValueCallback<T> action) {
|
||||
|
||||
@@ -348,6 +346,24 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationEventPub
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute {@link KeyValueCallback} and require a non-{@literal null} return value.
|
||||
*
|
||||
* @param action
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
protected <T> T executeRequired(KeyValueCallback<T> action) {
|
||||
|
||||
T result = execute(action);
|
||||
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format("KeyValueCallback %s returned null value!", action));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.keyvalue.core.KeyValueOperations#find(org.springframework.data.keyvalue.core.query.KeyValueQuery, java.lang.Class)
|
||||
@@ -355,12 +371,9 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationEventPub
|
||||
@Override
|
||||
public <T> Iterable<T> find(KeyValueQuery<?> query, Class<T> type) {
|
||||
|
||||
return execute((KeyValueCallback<Iterable<T>>) adapter -> {
|
||||
return executeRequired((KeyValueCallback<Iterable<T>>) adapter -> {
|
||||
|
||||
Iterable<?> result = adapter.find(query, resolveKeySpace(type), type);
|
||||
if (result == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
List<T> filtered = new ArrayList<>();
|
||||
|
||||
@@ -410,8 +423,7 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationEventPub
|
||||
*/
|
||||
@Override
|
||||
public long count(KeyValueQuery<?> query, Class<?> type) {
|
||||
|
||||
return execute(adapter -> adapter.count(query, resolveKeySpace(type)));
|
||||
return executeRequired(adapter -> adapter.count(query, resolveKeySpace(type)));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -460,7 +472,7 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationEventPub
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean typeCheck(Class<?> requiredType, Object candidate) {
|
||||
private static boolean typeCheck(Class<?> requiredType, @Nullable Object candidate) {
|
||||
return candidate == null || ClassUtils.isAssignable(requiredType, candidate.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,28 +16,31 @@
|
||||
package org.springframework.data.keyvalue.core;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Base implementation for accessing and executing {@link KeyValueQuery} against a {@link KeyValueAdapter}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @param <ADAPTER>
|
||||
* @param <CRITERIA>
|
||||
* @param <SORT>
|
||||
*/
|
||||
public abstract class QueryEngine<ADAPTER extends KeyValueAdapter, CRITERIA, SORT> {
|
||||
|
||||
private final CriteriaAccessor<CRITERIA> criteriaAccessor;
|
||||
private final SortAccessor<SORT> sortAccessor;
|
||||
private final Optional<CriteriaAccessor<CRITERIA>> criteriaAccessor;
|
||||
private final Optional<SortAccessor<SORT>> sortAccessor;
|
||||
|
||||
private ADAPTER adapter;
|
||||
private @Nullable ADAPTER adapter;
|
||||
|
||||
public QueryEngine(CriteriaAccessor<CRITERIA> criteriaAccessor, SortAccessor<SORT> sortAccessor) {
|
||||
public QueryEngine(@Nullable CriteriaAccessor<CRITERIA> criteriaAccessor, @Nullable SortAccessor<SORT> sortAccessor) {
|
||||
|
||||
this.criteriaAccessor = criteriaAccessor;
|
||||
this.sortAccessor = sortAccessor;
|
||||
this.criteriaAccessor = Optional.ofNullable(criteriaAccessor);
|
||||
this.sortAccessor = Optional.ofNullable(sortAccessor);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,8 +52,8 @@ public abstract class QueryEngine<ADAPTER extends KeyValueAdapter, CRITERIA, SOR
|
||||
*/
|
||||
public Collection<?> execute(KeyValueQuery<?> query, String keyspace) {
|
||||
|
||||
CRITERIA criteria = this.criteriaAccessor != null ? this.criteriaAccessor.resolve(query) : null;
|
||||
SORT sort = this.sortAccessor != null ? this.sortAccessor.resolve(query) : null;
|
||||
CRITERIA criteria = this.criteriaAccessor.map(it -> it.resolve(query)).orElse(null);
|
||||
SORT sort = this.sortAccessor.map(it -> it.resolve(query)).orElse(null);
|
||||
|
||||
return execute(criteria, sort, query.getOffset(), query.getRows(), keyspace);
|
||||
}
|
||||
@@ -64,8 +67,8 @@ public abstract class QueryEngine<ADAPTER extends KeyValueAdapter, CRITERIA, SOR
|
||||
*/
|
||||
public <T> Collection<T> execute(KeyValueQuery<?> query, String keyspace, Class<T> type) {
|
||||
|
||||
CRITERIA criteria = this.criteriaAccessor != null ? this.criteriaAccessor.resolve(query) : null;
|
||||
SORT sort = this.sortAccessor != null ? this.sortAccessor.resolve(query) : null;
|
||||
CRITERIA criteria = this.criteriaAccessor.map(it -> it.resolve(query)).orElse(null);
|
||||
SORT sort = this.sortAccessor.map(it -> it.resolve(query)).orElse(null);
|
||||
|
||||
return execute(criteria, sort, query.getOffset(), query.getRows(), keyspace, type);
|
||||
}
|
||||
@@ -79,7 +82,7 @@ public abstract class QueryEngine<ADAPTER extends KeyValueAdapter, CRITERIA, SOR
|
||||
*/
|
||||
public long count(KeyValueQuery<?> query, String keyspace) {
|
||||
|
||||
CRITERIA criteria = this.criteriaAccessor != null ? this.criteriaAccessor.resolve(query) : null;
|
||||
CRITERIA criteria = this.criteriaAccessor.map(it -> it.resolve(query)).orElse(null);
|
||||
return count(criteria, keyspace);
|
||||
}
|
||||
|
||||
@@ -91,7 +94,8 @@ public abstract class QueryEngine<ADAPTER extends KeyValueAdapter, CRITERIA, SOR
|
||||
* @param keyspace
|
||||
* @return
|
||||
*/
|
||||
public abstract Collection<?> execute(CRITERIA criteria, SORT sort, long offset, int rows, String keyspace);
|
||||
public abstract Collection<?> execute(@Nullable CRITERIA criteria, @Nullable SORT sort, long offset, int rows,
|
||||
String keyspace);
|
||||
|
||||
/**
|
||||
* @param criteria
|
||||
@@ -104,8 +108,8 @@ public abstract class QueryEngine<ADAPTER extends KeyValueAdapter, CRITERIA, SOR
|
||||
* @since 1.1
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Collection<T> execute(CRITERIA criteria, SORT sort, long offset, int rows, String keyspace,
|
||||
Class<T> type) {
|
||||
public <T> Collection<T> execute(@Nullable CRITERIA criteria, @Nullable SORT sort, long offset, int rows,
|
||||
String keyspace, Class<T> type) {
|
||||
return (Collection<T>) execute(criteria, sort, offset, rows, keyspace);
|
||||
}
|
||||
|
||||
@@ -114,17 +118,35 @@ public abstract class QueryEngine<ADAPTER extends KeyValueAdapter, CRITERIA, SOR
|
||||
* @param keyspace
|
||||
* @return
|
||||
*/
|
||||
public abstract long count(CRITERIA criteria, String keyspace);
|
||||
public abstract long count(@Nullable CRITERIA criteria, String keyspace);
|
||||
|
||||
/**
|
||||
* Get the {@link KeyValueAdapter} used.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
protected ADAPTER getAdapter() {
|
||||
return this.adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the required {@link KeyValueAdapter} used or throw {@link IllegalStateException} if the adapter is not set.
|
||||
*
|
||||
* @return the required {@link KeyValueAdapter}.
|
||||
* @throws IllegalStateException if the adapter is not set.
|
||||
*/
|
||||
protected ADAPTER getRequiredAdapter() {
|
||||
|
||||
ADAPTER adapter = getAdapter();
|
||||
|
||||
if (adapter != null) {
|
||||
return adapter;
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Required KeyValueAdapter is not set!");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param adapter
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -23,6 +23,7 @@ import org.springframework.data.keyvalue.core.query.KeyValueQuery;
|
||||
* representation that can be used by the {@link QueryEngine} implementation.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @param <T>
|
||||
*/
|
||||
public interface SortAccessor<T> {
|
||||
@@ -31,7 +32,7 @@ public interface SortAccessor<T> {
|
||||
* Reads {@link KeyValueQuery#getSort()} of given {@link KeyValueQuery} and applies required transformation to match
|
||||
* the desired type.
|
||||
*
|
||||
* @param query can be {@literal null}.
|
||||
* @param query must not be {@literal null}.
|
||||
* @return {@literal null} in case {@link Sort} has not been defined on {@link KeyValueQuery}.
|
||||
*/
|
||||
T resolve(KeyValueQuery<?> query);
|
||||
|
||||
@@ -19,12 +19,15 @@ import java.util.Comparator;
|
||||
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Comparator} implementation using {@link SpelExpression}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
* @param <T>
|
||||
*/
|
||||
public class SpelPropertyComparator<T> implements Comparator<T> {
|
||||
@@ -34,16 +37,19 @@ public class SpelPropertyComparator<T> implements Comparator<T> {
|
||||
|
||||
private boolean asc = true;
|
||||
private boolean nullsFirst = true;
|
||||
private SpelExpression expression;
|
||||
private @Nullable SpelExpression expression;
|
||||
|
||||
/**
|
||||
* Create new {@link SpelPropertyComparator} for the given property path an {@link SpelExpressionParser}..
|
||||
* Create new {@link SpelPropertyComparator} for the given property path an {@link SpelExpressionParser}.
|
||||
*
|
||||
* @param path must not be {@literal null} or empty.
|
||||
* @param parser must not be {@literal null}.
|
||||
*/
|
||||
public SpelPropertyComparator(String path, SpelExpressionParser parser) {
|
||||
|
||||
Assert.hasText(path, "Path must not be null or empty!");
|
||||
Assert.notNull(parser, "SpelExpressionParser must not be null!");
|
||||
|
||||
this.path = path;
|
||||
this.parser = parser;
|
||||
}
|
||||
@@ -109,9 +115,9 @@ public class SpelPropertyComparator<T> implements Comparator<T> {
|
||||
*/
|
||||
protected String buildExpressionForPath() {
|
||||
|
||||
String rawExpression = "new org.springframework.util.comparator.NullSafeComparator(new org.springframework.util.comparator.ComparableComparator(), "
|
||||
+ Boolean.toString(this.nullsFirst) + ").compare(" + "#arg1?." + (path != null ? path.replace(".", "?.") : "")
|
||||
+ "," + "#arg2?." + (path != null ? path.replace(".", "?.") : "") + ")";
|
||||
String rawExpression = String.format(
|
||||
"new org.springframework.util.comparator.NullSafeComparator(new org.springframework.util.comparator.ComparableComparator(), %s).compare(#arg1?.%s,#arg2?.%s)",
|
||||
Boolean.toString(this.nullsFirst), path.replace(".", "?."), path.replace(".", "?."));
|
||||
|
||||
return rawExpression;
|
||||
}
|
||||
@@ -120,6 +126,7 @@ public class SpelPropertyComparator<T> implements Comparator<T> {
|
||||
* (non-Javadoc)
|
||||
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public int compare(T arg1, T arg2) {
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.data.keyvalue.core.query.KeyValueQuery;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link QueryEngine} implementation specific for executing {@link SpelExpression} based {@link KeyValueQuery} against
|
||||
@@ -52,7 +53,7 @@ class SpelQueryEngine extends QueryEngine<KeyValueAdapter, SpelCriteria, Compara
|
||||
*/
|
||||
@Override
|
||||
public Collection<?> execute(SpelCriteria criteria, Comparator<?> sort, long offset, int rows, String keyspace) {
|
||||
return sortAndFilterMatchingRange(getAdapter().getAllOf(keyspace), criteria, sort, offset, rows);
|
||||
return sortAndFilterMatchingRange(getRequiredAdapter().getAllOf(keyspace), criteria, sort, offset, rows);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -61,12 +62,13 @@ class SpelQueryEngine extends QueryEngine<KeyValueAdapter, SpelCriteria, Compara
|
||||
*/
|
||||
@Override
|
||||
public long count(SpelCriteria criteria, String keyspace) {
|
||||
return filterMatchingRange(IterableConverter.toList(getAdapter().getAllOf(keyspace)), criteria, -1, -1).size();
|
||||
return filterMatchingRange(IterableConverter.toList(getRequiredAdapter().getAllOf(keyspace)), criteria, -1, -1)
|
||||
.size();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<?> sortAndFilterMatchingRange(Iterable<?> source, SpelCriteria criteria, Comparator sort, long offset,
|
||||
int rows) {
|
||||
private List<?> sortAndFilterMatchingRange(Iterable<?> source, SpelCriteria criteria, @Nullable Comparator sort,
|
||||
long offset, int rows) {
|
||||
|
||||
List<?> tmp = IterableConverter.toList(source);
|
||||
if (sort != null) {
|
||||
@@ -76,7 +78,8 @@ class SpelQueryEngine extends QueryEngine<KeyValueAdapter, SpelCriteria, Compara
|
||||
return filterMatchingRange(tmp, criteria, offset, rows);
|
||||
}
|
||||
|
||||
private static <S> List<S> filterMatchingRange(List<S> source, SpelCriteria criteria, long offset, int rows) {
|
||||
private static <S> List<S> filterMatchingRange(List<S> source, @Nullable SpelCriteria criteria, long offset,
|
||||
int rows) {
|
||||
|
||||
Stream<S> stream = source.stream();
|
||||
|
||||
@@ -93,6 +96,7 @@ class SpelQueryEngine extends QueryEngine<KeyValueAdapter, SpelCriteria, Compara
|
||||
return stream.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private static boolean evaluateExpression(SpelCriteria criteria, Object candidate) {
|
||||
|
||||
try {
|
||||
|
||||
@@ -53,7 +53,7 @@ class SpelSortAccessor implements SortAccessor<Comparator<?>> {
|
||||
@Override
|
||||
public Comparator<?> resolve(KeyValueQuery<?> query) {
|
||||
|
||||
if (query == null || query.getSort() == null || query.getSort().isUnsorted()) {
|
||||
if (query.getSort().isUnsorted()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -18,12 +18,22 @@ package org.springframework.data.keyvalue.core;
|
||||
import org.springframework.dao.UncategorizedDataAccessException;
|
||||
|
||||
/**
|
||||
* Normal superclass when we can't distinguish anything more specific than "something went wrong with the underlying
|
||||
* resource".
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class UncategorizedKeyValueException extends UncategorizedDataAccessException {
|
||||
|
||||
private static final long serialVersionUID = -8087116071859122297L;
|
||||
|
||||
/**
|
||||
* Creates a new {@link UncategorizedKeyValueException}.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
* @param cause the root cause (usually from using a underlying data access API).
|
||||
*/
|
||||
public UncategorizedKeyValueException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.keyvalue.core.event;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link KeyValueEvent} gets published for operations executed by eg.
|
||||
@@ -24,6 +25,7 @@ import org.springframework.context.ApplicationEvent;
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
* @param <T>
|
||||
*/
|
||||
public class KeyValueEvent<T> extends ApplicationEvent {
|
||||
@@ -71,7 +73,7 @@ public class KeyValueEvent<T> extends ApplicationEvent {
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static <T> AfterGetEvent<T> afterGet(Object id, String keyspace, Class<T> type, T value) {
|
||||
public static <T> AfterGetEvent<T> afterGet(Object id, String keyspace, Class<T> type, @Nullable T value) {
|
||||
return new AfterGetEvent<>(id, keyspace, type, value);
|
||||
}
|
||||
|
||||
@@ -125,7 +127,7 @@ public class KeyValueEvent<T> extends ApplicationEvent {
|
||||
* @return
|
||||
*/
|
||||
public static <T> AfterUpdateEvent<T> afterUpdate(Object id, String keyspace, Class<? extends T> type, T actualValue,
|
||||
Object previousValue) {
|
||||
@Nullable Object previousValue) {
|
||||
return new AfterUpdateEvent<>(id, keyspace, type, actualValue, previousValue);
|
||||
}
|
||||
|
||||
@@ -172,7 +174,8 @@ public class KeyValueEvent<T> extends ApplicationEvent {
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static <T> AfterDeleteEvent<T> afterDelete(Object id, String keyspace, Class<? extends T> type, T value) {
|
||||
public static <T> AfterDeleteEvent<T> afterDelete(Object id, String keyspace, Class<? extends T> type,
|
||||
@Nullable T value) {
|
||||
return new AfterDeleteEvent<>(id, keyspace, type, value);
|
||||
}
|
||||
|
||||
@@ -223,9 +226,9 @@ public class KeyValueEvent<T> extends ApplicationEvent {
|
||||
@SuppressWarnings("serial")
|
||||
abstract static class KeyBasedEventWithPayload<T> extends KeyBasedEvent<T> {
|
||||
|
||||
private final T payload;
|
||||
private final @Nullable T payload;
|
||||
|
||||
KeyBasedEventWithPayload(Object key, String keyspace, Class<? extends T> type, T payload) {
|
||||
KeyBasedEventWithPayload(Object key, String keyspace, Class<? extends T> type, @Nullable T payload) {
|
||||
super(key, keyspace, type);
|
||||
this.payload = payload;
|
||||
}
|
||||
@@ -235,6 +238,7 @@ public class KeyValueEvent<T> extends ApplicationEvent {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public T getPayload() {
|
||||
return payload;
|
||||
}
|
||||
@@ -264,7 +268,7 @@ public class KeyValueEvent<T> extends ApplicationEvent {
|
||||
@SuppressWarnings("serial")
|
||||
public static class AfterGetEvent<T> extends KeyBasedEventWithPayload<T> {
|
||||
|
||||
protected AfterGetEvent(Object key, String keyspace, Class<T> type, T payload) {
|
||||
protected AfterGetEvent(Object key, String keyspace, Class<T> type, @Nullable T payload) {
|
||||
super(key, keyspace, type, payload);
|
||||
}
|
||||
|
||||
@@ -279,7 +283,7 @@ public class KeyValueEvent<T> extends ApplicationEvent {
|
||||
@SuppressWarnings("serial")
|
||||
public static class BeforeInsertEvent<T> extends KeyBasedEventWithPayload<T> {
|
||||
|
||||
public BeforeInsertEvent(Object key, String keyspace, Class<? extends T> type, T payload) {
|
||||
public BeforeInsertEvent(Object key, String keyspace, Class<? extends T> type, @Nullable T payload) {
|
||||
super(key, keyspace, type, payload);
|
||||
|
||||
}
|
||||
@@ -294,7 +298,7 @@ public class KeyValueEvent<T> extends ApplicationEvent {
|
||||
@SuppressWarnings("serial")
|
||||
public static class AfterInsertEvent<T> extends KeyBasedEventWithPayload<T> {
|
||||
|
||||
public AfterInsertEvent(Object key, String keyspace, Class<? extends T> type, T payload) {
|
||||
public AfterInsertEvent(Object key, String keyspace, Class<? extends T> type, @Nullable T payload) {
|
||||
super(key, keyspace, type, payload);
|
||||
}
|
||||
}
|
||||
@@ -308,7 +312,7 @@ public class KeyValueEvent<T> extends ApplicationEvent {
|
||||
@SuppressWarnings("serial")
|
||||
public static class BeforeUpdateEvent<T> extends KeyBasedEventWithPayload<T> {
|
||||
|
||||
public BeforeUpdateEvent(Object key, String keyspace, Class<? extends T> type, T payload) {
|
||||
public BeforeUpdateEvent(Object key, String keyspace, Class<? extends T> type, @Nullable T payload) {
|
||||
super(key, keyspace, type, payload);
|
||||
}
|
||||
}
|
||||
@@ -322,9 +326,10 @@ public class KeyValueEvent<T> extends ApplicationEvent {
|
||||
@SuppressWarnings("serial")
|
||||
public static class AfterUpdateEvent<T> extends KeyBasedEventWithPayload<T> {
|
||||
|
||||
private final Object existing;
|
||||
private final @Nullable Object existing;
|
||||
|
||||
public AfterUpdateEvent(Object key, String keyspace, Class<? extends T> type, T payload, Object existing) {
|
||||
public AfterUpdateEvent(Object key, String keyspace, Class<? extends T> type, T payload,
|
||||
@Nullable Object existing) {
|
||||
super(key, keyspace, type, payload);
|
||||
this.existing = existing;
|
||||
}
|
||||
@@ -334,6 +339,7 @@ public class KeyValueEvent<T> extends ApplicationEvent {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public Object before() {
|
||||
return existing;
|
||||
}
|
||||
@@ -371,7 +377,7 @@ public class KeyValueEvent<T> extends ApplicationEvent {
|
||||
@SuppressWarnings("serial")
|
||||
public static class AfterDeleteEvent<T> extends KeyBasedEventWithPayload<T> {
|
||||
|
||||
public AfterDeleteEvent(Object key, String keyspace, Class<? extends T> type, T payload) {
|
||||
public AfterDeleteEvent(Object key, String keyspace, Class<? extends T> type, @Nullable T payload) {
|
||||
super(key, keyspace, type, payload);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Support classes for key-value events, like standard persistence lifecycle events.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.keyvalue.core.event;
|
||||
@@ -19,6 +19,7 @@ import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
import org.springframework.data.keyvalue.annotation.KeySpace;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -28,6 +29,7 @@ import org.springframework.util.ClassUtils;
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
enum AnnotationBasedKeySpaceResolver implements KeySpaceResolver {
|
||||
|
||||
@@ -38,6 +40,7 @@ enum AnnotationBasedKeySpaceResolver implements KeySpaceResolver {
|
||||
* @see org.springframework.data.keyvalue.core.KeySpaceResolver#resolveKeySpace(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public String resolveKeySpace(Class<?> type) {
|
||||
|
||||
Assert.notNull(type, "Type for keyspace for null!");
|
||||
@@ -48,6 +51,7 @@ enum AnnotationBasedKeySpaceResolver implements KeySpaceResolver {
|
||||
return keySpace != null ? keySpace.toString() : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Object getKeySpace(Class<?> type) {
|
||||
|
||||
KeySpace keyspace = AnnotatedElementUtils.findMergedAnnotation(type, KeySpace.class);
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.keyvalue.core.mapping;
|
||||
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -24,6 +25,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
* @param <T>
|
||||
*/
|
||||
public class BasicKeyValuePersistentEntity<T, P extends KeyValuePersistentProperty<P>>
|
||||
@@ -37,14 +39,15 @@ public class BasicKeyValuePersistentEntity<T, P extends KeyValuePersistentProper
|
||||
* @param information must not be {@literal null}.
|
||||
* @param keySpaceResolver can be {@literal null}.
|
||||
*/
|
||||
public BasicKeyValuePersistentEntity(TypeInformation<T> information, KeySpaceResolver fallbackKeySpaceResolver) {
|
||||
public BasicKeyValuePersistentEntity(TypeInformation<T> information,
|
||||
@Nullable KeySpaceResolver fallbackKeySpaceResolver) {
|
||||
|
||||
super(information);
|
||||
|
||||
this.keyspace = detectKeySpace(information.getType(), fallbackKeySpaceResolver);
|
||||
}
|
||||
|
||||
private static String detectKeySpace(Class<?> type, KeySpaceResolver fallback) {
|
||||
private static String detectKeySpace(Class<?> type, @Nullable KeySpaceResolver fallback) {
|
||||
|
||||
String keySpace = AnnotationBasedKeySpaceResolver.INSTANCE.resolveKeySpace(type);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-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.
|
||||
@@ -15,11 +15,14 @@
|
||||
*/
|
||||
package org.springframework.data.keyvalue.core.mapping;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link KeySpaceResolver} determines the {@literal keyspace} a given type is assigned to. A keyspace in this context
|
||||
* is a specific region/collection/grouping of elements sharing a common keyrange. <br />
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface KeySpaceResolver {
|
||||
|
||||
@@ -29,5 +32,6 @@ public interface KeySpaceResolver {
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
String resolveKeySpace(Class<?> type);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.Property;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Default implementation of a {@link MappingContext} using {@link KeyValuePersistentEntity} and
|
||||
@@ -36,7 +37,7 @@ import org.springframework.data.util.TypeInformation;
|
||||
public class KeyValueMappingContext<E extends KeyValuePersistentEntity<?, P>, P extends KeyValuePersistentProperty<P>>
|
||||
extends AbstractMappingContext<E, P> {
|
||||
|
||||
private KeySpaceResolver fallbackKeySpaceResolver;
|
||||
private @Nullable KeySpaceResolver fallbackKeySpaceResolver;
|
||||
|
||||
/**
|
||||
* Configures the {@link KeySpaceResolver} to be used if not explicit key space is annotated to the domain type.
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Infrastructure for the Key-Value mapping context.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.keyvalue.core.mapping.context;
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Infrastructure for the Key-Value mapping subsystem and keyspace resolution.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.keyvalue.core.mapping;
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Core key/value implementation.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.keyvalue.core;
|
||||
@@ -16,6 +16,8 @@
|
||||
package org.springframework.data.keyvalue.core.query;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
@@ -27,7 +29,7 @@ public class KeyValueQuery<T> {
|
||||
private Sort sort = Sort.unsorted();
|
||||
private long offset = -1;
|
||||
private int rows = -1;
|
||||
private T criteria;
|
||||
private @Nullable T criteria;
|
||||
|
||||
/**
|
||||
* Creates new instance of {@link KeyValueQuery}.
|
||||
@@ -39,17 +41,17 @@ public class KeyValueQuery<T> {
|
||||
*
|
||||
* @param criteria can be {@literal null}.
|
||||
*/
|
||||
public KeyValueQuery(T criteria) {
|
||||
public KeyValueQuery(@Nullable T criteria) {
|
||||
this.criteria = criteria;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new instance of {@link KeyValueQuery} with given {@link Sort}.
|
||||
*
|
||||
* @param sort can be {@literal null}.
|
||||
* @param sort must not be {@literal null}.
|
||||
*/
|
||||
public KeyValueQuery(Sort sort) {
|
||||
this.sort = sort;
|
||||
setSort(sort);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,6 +60,7 @@ public class KeyValueQuery<T> {
|
||||
* @return
|
||||
* @since 2.0
|
||||
*/
|
||||
@Nullable
|
||||
public T getCriteria() {
|
||||
return criteria;
|
||||
}
|
||||
@@ -113,26 +116,28 @@ public class KeyValueQuery<T> {
|
||||
* @param sort
|
||||
*/
|
||||
public void setSort(Sort sort) {
|
||||
|
||||
Assert.notNull(sort, "Sort must not be null!");
|
||||
|
||||
this.sort = sort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given {@link Sort}.
|
||||
*
|
||||
* @param sort {@literal null} {@link Sort} will be ignored.
|
||||
* @param sort must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public KeyValueQuery<T> orderBy(Sort sort) {
|
||||
|
||||
if (sort == null) {
|
||||
return this;
|
||||
}
|
||||
Assert.notNull(sort, "Sort must not be null!");
|
||||
|
||||
if (this.sort != null) {
|
||||
if (this.sort.isSorted()) {
|
||||
this.sort = this.sort.and(sort);
|
||||
} else {
|
||||
this.sort = sort;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -142,7 +147,9 @@ public class KeyValueQuery<T> {
|
||||
* @return
|
||||
*/
|
||||
public KeyValueQuery<T> skip(long offset) {
|
||||
|
||||
setOffset(offset);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Key/value specific query and abstractions.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.keyvalue.core.query;
|
||||
@@ -35,6 +35,7 @@ import org.springframework.data.repository.config.AnnotationRepositoryConfigurat
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationSource;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
@@ -42,6 +43,7 @@ import org.springframework.util.CollectionUtils;
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public abstract class KeyValueRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
|
||||
|
||||
@@ -177,6 +179,7 @@ public abstract class KeyValueRepositoryConfigurationExtension extends Repositor
|
||||
*
|
||||
* @return {@literal null} to explicitly not register a template.
|
||||
*/
|
||||
@Nullable
|
||||
protected AbstractBeanDefinition getDefaultKeyValueTemplateBeanDefinition(
|
||||
RepositoryConfigurationSource configurationSource) {
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Support infrastructure for the configuration of key/value specific repositories.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.keyvalue.repository.config;
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Key/value specific repository implementation.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.keyvalue.repository;
|
||||
@@ -21,17 +21,19 @@ import org.springframework.data.repository.query.EvaluationContextProvider;
|
||||
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.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link KeyValuePartTreeQuery} implementation deriving queries from {@link PartTree} using a predefined
|
||||
* {@link AbstractQueryCreator} that caches the once created query.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @since 1.1
|
||||
*/
|
||||
public class CachingKeyValuePartTreeQuery extends KeyValuePartTreeQuery {
|
||||
|
||||
private KeyValueQuery<?> cachedQuery;
|
||||
private @Nullable KeyValueQuery<?> cachedQuery;
|
||||
|
||||
public CachingKeyValuePartTreeQuery(QueryMethod queryMethod, EvaluationContextProvider evaluationContextProvider,
|
||||
KeyValueOperations keyValueOperations, Class<? extends AbstractQueryCreator<?, ?>> queryCreator) {
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.springframework.data.repository.query.parser.AbstractQueryCreator;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -94,6 +95,7 @@ public class KeyValuePartTreeQuery implements RepositoryQuery {
|
||||
* @param parameters
|
||||
* @param query
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
protected Object doExecute(Object[] parameters, KeyValueQuery<?> query) {
|
||||
|
||||
@@ -179,8 +181,12 @@ public class KeyValuePartTreeQuery implements RepositoryQuery {
|
||||
|
||||
PartTree tree = new PartTree(getQueryMethod().getName(), getQueryMethod().getEntityInformation().getJavaType());
|
||||
|
||||
Constructor<? extends AbstractQueryCreator<?, ?>> constructor = ClassUtils
|
||||
.getConstructorIfAvailable(queryCreator, PartTree.class, ParameterAccessor.class);
|
||||
Constructor<? extends AbstractQueryCreator<?, ?>> constructor = ClassUtils.getConstructorIfAvailable(queryCreator,
|
||||
PartTree.class, ParameterAccessor.class);
|
||||
|
||||
Assert.state(constructor != null, String.format("Constructor %s(PartTree, ParameterAccessor) not available!",
|
||||
ClassUtils.getShortName(queryCreator)));
|
||||
|
||||
KeyValueQuery<?> query = (KeyValueQuery<?>) BeanUtils.instantiateClass(constructor, tree, accessor).createQuery();
|
||||
|
||||
if (tree.isLimiting()) {
|
||||
|
||||
@@ -89,7 +89,7 @@ public class SpelQueryCreator extends AbstractQueryCreator<KeyValueQuery<SpelExp
|
||||
|
||||
KeyValueQuery<SpelExpression> query = new KeyValueQuery<>(this.expression);
|
||||
|
||||
if (sort != null) {
|
||||
if (sort.isSorted()) {
|
||||
query.orderBy(sort);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Query derivation mechanism for key/value specific repositories providing a generic SpEL based implementation.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.keyvalue.repository.query;
|
||||
@@ -37,6 +37,7 @@ import com.querydsl.core.types.dsl.PathBuilder;
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
abstract class KeyValueQuerydslUtils {
|
||||
|
||||
@@ -47,17 +48,14 @@ abstract class KeyValueQuerydslUtils {
|
||||
/**
|
||||
* Transforms a plain {@link Order} into a QueryDsl specific {@link OrderSpecifier}.
|
||||
*
|
||||
* @param sort
|
||||
* @param sort must not be {@literal null}.
|
||||
* @param builder must not be {@literal null}.
|
||||
* @return empty {@code OrderSpecifier<?>[]} when sort is {@literal null}.
|
||||
*/
|
||||
static OrderSpecifier<?>[] toOrderSpecifier(Sort sort, PathBuilder<?> builder) {
|
||||
|
||||
Assert.notNull(builder, "Builder must not be 'null'.");
|
||||
|
||||
if (sort == null) {
|
||||
return new OrderSpecifier<?>[0];
|
||||
}
|
||||
Assert.notNull(sort, "Sort must not be null.");
|
||||
Assert.notNull(builder, "Builder must not be null.");
|
||||
|
||||
List<OrderSpecifier<?>> specifiers = null;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.keyvalue.repository.support;
|
||||
|
||||
import static org.springframework.data.querydsl.QuerydslUtils.QUERY_DSL_PRESENT;
|
||||
import static org.springframework.data.querydsl.QuerydslUtils.*;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -41,6 +41,7 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -75,7 +76,7 @@ public class KeyValueRepositoryFactory extends RepositoryFactorySupport {
|
||||
* {@link AbstractQueryCreator}-type.
|
||||
*
|
||||
* @param keyValueOperations must not be {@literal null}.
|
||||
* @param queryCreator defaulted to {@link #DEFAULT_QUERY_CREATOR} if {@literal null}.
|
||||
* @param queryCreator must not be {@literal null}.
|
||||
*/
|
||||
public KeyValueRepositoryFactory(KeyValueOperations keyValueOperations,
|
||||
Class<? extends AbstractQueryCreator<?, ?>> queryCreator) {
|
||||
@@ -154,9 +155,10 @@ public class KeyValueRepositoryFactory extends RepositoryFactorySupport {
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getQueryLookupStrategy(org.springframework.data.repository.query.QueryLookupStrategy.Key, org.springframework.data.repository.query.EvaluationContextProvider)
|
||||
*/
|
||||
@Override
|
||||
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(Key key, EvaluationContextProvider evaluationContextProvider) {
|
||||
return Optional.of(new KeyValueQueryLookupStrategy(key, evaluationContextProvider, this.keyValueOperations, this.queryCreator,
|
||||
this.repositoryQueryType));
|
||||
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(@Nullable Key key,
|
||||
EvaluationContextProvider evaluationContextProvider) {
|
||||
return Optional.of(new KeyValueQueryLookupStrategy(key, evaluationContextProvider, this.keyValueOperations,
|
||||
this.queryCreator, this.repositoryQueryType));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,7 +196,7 @@ public class KeyValueRepositoryFactory extends RepositoryFactorySupport {
|
||||
* @param queryCreator
|
||||
* @since 1.1
|
||||
*/
|
||||
public KeyValueQueryLookupStrategy(Key key, EvaluationContextProvider evaluationContextProvider,
|
||||
public KeyValueQueryLookupStrategy(@Nullable Key key, EvaluationContextProvider evaluationContextProvider,
|
||||
KeyValueOperations keyValueOperations, Class<? extends AbstractQueryCreator<?, ?>> queryCreator,
|
||||
Class<? extends RepositoryQuery> repositoryQueryType) {
|
||||
|
||||
@@ -224,6 +226,11 @@ public class KeyValueRepositoryFactory extends RepositoryFactorySupport {
|
||||
.getConstructorIfAvailable(this.repositoryQueryType, QueryMethod.class, EvaluationContextProvider.class,
|
||||
KeyValueOperations.class, Class.class);
|
||||
|
||||
Assert.state(constructor != null,
|
||||
String.format(
|
||||
"Constructor %s(QueryMethod, EvaluationContextProvider, KeyValueOperations, Class) not available!",
|
||||
ClassUtils.getShortName(this.repositoryQueryType)));
|
||||
|
||||
return BeanUtils.instantiateClass(constructor, queryMethod, evaluationContextProvider, this.keyValueOperations,
|
||||
this.queryCreator);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.springframework.data.repository.core.support.RepositoryFactoryBeanSup
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -36,9 +37,9 @@ import org.springframework.util.Assert;
|
||||
public class KeyValueRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
|
||||
extends RepositoryFactoryBeanSupport<T, S, ID> {
|
||||
|
||||
private KeyValueOperations operations;
|
||||
private Class<? extends AbstractQueryCreator<?, ?>> queryCreator;
|
||||
private Class<? extends RepositoryQuery> repositoryQueryType;
|
||||
private @Nullable KeyValueOperations operations;
|
||||
private @Nullable Class<? extends AbstractQueryCreator<?, ?>> queryCreator;
|
||||
private @Nullable Class<? extends RepositoryQuery> repositoryQueryType;
|
||||
|
||||
/**
|
||||
* Creates a new {@link KeyValueRepositoryFactoryBean} for the given repository interface.
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.data.querydsl.EntityPathResolver;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.data.querydsl.SimpleEntityPathResolver;
|
||||
import org.springframework.data.repository.core.EntityInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -47,6 +48,7 @@ import com.querydsl.core.types.dsl.PathBuilder;
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
* @param <T> the domain type to manage
|
||||
* @param <ID> the identifier type of the domain type
|
||||
*/
|
||||
@@ -55,7 +57,6 @@ public class QuerydslKeyValueRepository<T, ID> extends SimpleKeyValueRepository<
|
||||
|
||||
private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
|
||||
|
||||
private final EntityPath<T> path;
|
||||
private final PathBuilder<T> builder;
|
||||
|
||||
/**
|
||||
@@ -84,7 +85,7 @@ public class QuerydslKeyValueRepository<T, ID> extends SimpleKeyValueRepository<
|
||||
|
||||
Assert.notNull(resolver, "EntityPathResolver must not be null!");
|
||||
|
||||
this.path = resolver.createPath(entityInformation.getJavaType());
|
||||
EntityPath<T> path = resolver.createPath(entityInformation.getJavaType());
|
||||
this.builder = new PathBuilder<>(path.getType(), path.getMetadata());
|
||||
}
|
||||
|
||||
@@ -142,12 +143,12 @@ public class QuerydslKeyValueRepository<T, ID> extends SimpleKeyValueRepository<
|
||||
|
||||
AbstractCollQuery<T, ?> query = prepareQuery(predicate);
|
||||
|
||||
if (pageable != null) {
|
||||
if (pageable.isPaged() || pageable.getSort().isSorted()) {
|
||||
|
||||
query.offset(pageable.getOffset());
|
||||
query.limit(pageable.getPageSize());
|
||||
|
||||
if (pageable.getSort() != null) {
|
||||
if (pageable.getSort().isSorted()) {
|
||||
query.orderBy(toOrderSpecifier(pageable.getSort(), builder));
|
||||
}
|
||||
}
|
||||
@@ -196,7 +197,7 @@ public class QuerydslKeyValueRepository<T, ID> extends SimpleKeyValueRepository<
|
||||
* @param predicate
|
||||
* @return
|
||||
*/
|
||||
protected AbstractCollQuery<T, ?> prepareQuery(Predicate predicate) {
|
||||
protected AbstractCollQuery<T, ?> prepareQuery(@Nullable Predicate predicate) {
|
||||
|
||||
CollQuery<T> query = new CollQuery<>();
|
||||
query.from(builder, findAll());
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Support infrastructure for query derivation of key/value specific repositories.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.keyvalue.repository.support;
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Repository implementation backed by generic {@link java.util.Map} instances.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.map;
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Support infrastructure for the configuration of {@link java.util.Map} repositories.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.map.repository.config;
|
||||
Reference in New Issue
Block a user