SGF-689 - Add support for JSR-107 JCache API Annotations in Caching-defined Regions.
This commit is contained in:
11
pom.xml
11
pom.xml
@@ -19,6 +19,7 @@
|
||||
<antlr.version>2.7.7</antlr.version>
|
||||
<apache-shiro.version>1.3.2</apache-shiro.version>
|
||||
<assertj.version>3.6.2</assertj.version>
|
||||
<cache-api.version>1.0.0</cache-api.version>
|
||||
<gemfire.version>9.1.1</gemfire.version>
|
||||
<google-code-findbugs.version>2.0.2</google-code-findbugs.version>
|
||||
<multithreadedtc.version>1.01</multithreadedtc.version>
|
||||
@@ -47,6 +48,14 @@
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- Java & Javax -->
|
||||
<dependency>
|
||||
<groupId>javax.cache</groupId>
|
||||
<artifactId>cache-api</artifactId>
|
||||
<version>${cache-api.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- CDI -->
|
||||
<!-- Dependency order required to build against CDI 1.0 and test with CDI 2.0 -->
|
||||
<dependency>
|
||||
@@ -55,7 +64,7 @@
|
||||
<version>1.0.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.interceptor</groupId>
|
||||
<artifactId>javax.interceptor-api</artifactId>
|
||||
|
||||
@@ -26,8 +26,13 @@ import org.springframework.data.gemfire.cache.GemfireCacheManager;
|
||||
* The {@link GemfireCachingConfiguration} class is a Spring {@link Configuration @Configuration} class
|
||||
* used to configure Pivotal GemFire or Apache Geode as the caching provider in Spring's Cache Abstraction.
|
||||
*
|
||||
* Additionally, this Spring {@link Configuration} class also enables the Spring Cache Abstraction
|
||||
* with {@link EnableCaching}.
|
||||
* This {@link Configuration @Configuration} class is specifically responsible for declaring and registering
|
||||
* Spring Data GemFire/Geode's {@link GemfireCacheManager} implementation to properly enable either Pivotal GemFire
|
||||
* or Apache Geode as the caching provider used with Springs Cache Abstraction.
|
||||
*
|
||||
* Additionally, this Spring {@link Configuration @Configuration} class also enables the Spring Cache Abstraction
|
||||
* by declaring Spring's {@link EnableCaching} annotation for the user extending or importing this class using
|
||||
* the SDG provided {@link EnableGemfireCaching} annotation.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
|
||||
@@ -16,14 +16,17 @@
|
||||
|
||||
package org.springframework.data.gemfire.config.annotation;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Arrays.stream;
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.asArray;
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
import static org.springframework.data.gemfire.util.StreamUtils.concat;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -32,6 +35,11 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.cache.annotation.CacheDefaults;
|
||||
import javax.cache.annotation.CacheRemove;
|
||||
import javax.cache.annotation.CacheRemoveAll;
|
||||
import javax.cache.annotation.CacheResult;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
@@ -45,7 +53,6 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.cache.annotation.CacheConfig;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.CachePut;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
@@ -105,21 +112,10 @@ import org.springframework.util.StringUtils;
|
||||
@Configuration
|
||||
public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfigSupport implements ImportAware {
|
||||
|
||||
private static final Class[] CLASS_CACHE_ANNOTATION_TYPES;
|
||||
|
||||
private static final Class[] METHOD_CACHE_ANNOTATION_TYPES =
|
||||
asArray(Cacheable.class, CacheEvict.class, CachePut.class);
|
||||
|
||||
static {
|
||||
|
||||
List<Class> annotationTypes = new ArrayList<>();
|
||||
|
||||
Collections.addAll(annotationTypes, METHOD_CACHE_ANNOTATION_TYPES);
|
||||
annotationTypes.add(CacheConfig.class);
|
||||
|
||||
CLASS_CACHE_ANNOTATION_TYPES = annotationTypes.toArray(new Class[annotationTypes.size()]);
|
||||
|
||||
}
|
||||
private final CacheNameResolver composableCacheNameResolver = type ->
|
||||
asList(new Jsr107CacheAnnotationsCacheNameResolver(), new SpringCacheAnnotationsCacheNameResolver()).stream()
|
||||
.flatMap(cacheNameResolver -> cacheNameResolver.resolveCacheNames(type).stream())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
private ClientRegionShortcut clientRegionShortcut = ClientRegionShortcut.PROXY;
|
||||
|
||||
@@ -142,6 +138,17 @@ public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfig
|
||||
return EnableCachingDefinedRegions.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured {@link CacheNameResolver} to resolve all the declared cache name on Spring application
|
||||
* beans/components declared and registered in the Spring container (context).
|
||||
*
|
||||
* @return the configured {@link CacheNameResolver} to resolve all teh caches used by the Spring application.
|
||||
* @see org.springframework.data.gemfire.config.annotation.CachingDefinedRegionsConfiguration.CacheNameResolver
|
||||
*/
|
||||
protected CacheNameResolver getCacheNameResolver() {
|
||||
return this.composableCacheNameResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link ClientRegionShortcut} specifying the data management policy to use
|
||||
* when creating a client {@link Region}.
|
||||
@@ -273,7 +280,7 @@ public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfig
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("all")
|
||||
public BeanDefinitionRegistryPostProcessor cacheAbstractionAnnotationsRegionBeanDefinitionRegistrar() {
|
||||
public BeanDefinitionRegistryPostProcessor cachingAnnotationsRegionBeanDefinitionRegistrar() {
|
||||
|
||||
return new BeanDefinitionRegistryPostProcessorSupport() {
|
||||
|
||||
@@ -284,24 +291,6 @@ public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfig
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("all")
|
||||
public BeanPostProcessor cacheAbstractionAnnotationsRegionBeanRegistrar(ConfigurableBeanFactory beanFactory) {
|
||||
|
||||
return new BeanPostProcessor() {
|
||||
|
||||
@Nullable @Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
|
||||
if (isNotInfrastructureBean(bean)) {
|
||||
registerRegionBeans(collectCacheNames(bean.getClass()), beanFactory);
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void registerBeanDefinitions(BeanDefinitionRegistry registry) {
|
||||
|
||||
for (String beanName : registry.getBeanDefinitionNames()) {
|
||||
@@ -310,73 +299,11 @@ public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfig
|
||||
|
||||
if (isNotInfrastructureBean(beanDefinition)) {
|
||||
resolveBeanClass(beanDefinition, registry).ifPresent(beanClass ->
|
||||
registerRegionBeanDefinitions(collectCacheNames(beanClass), registry));
|
||||
registerRegionBeanDefinitions(getCacheNameResolver().resolveCacheNames(beanClass), registry));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Set<String> collectCacheNames(Class<?> type) {
|
||||
|
||||
Set<String> cacheNames = new HashSet<>();
|
||||
|
||||
cacheNames.addAll(collectCachingCacheNames(type));
|
||||
cacheNames.addAll(collectCacheNames(type, CLASS_CACHE_ANNOTATION_TYPES));
|
||||
|
||||
stream(type.getMethods()).forEach(method -> {
|
||||
if (isUserLevelMethod(method)) {
|
||||
cacheNames.addAll(collectCachingCacheNames(method));
|
||||
cacheNames.addAll(collectCacheNames(method, METHOD_CACHE_ANNOTATION_TYPES));
|
||||
}
|
||||
});
|
||||
|
||||
return cacheNames;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
Set<String> collectCacheNames(AnnotatedElement annotatedElement,
|
||||
Class<? extends Annotation>... annotationTypes) {
|
||||
|
||||
Stream<String> cacheNames = stream(nullSafeArray(annotationTypes, Class.class))
|
||||
.map(annotationType -> resolveAnnotation(annotatedElement, annotationType))
|
||||
.flatMap(annotation -> collectCacheNames((Annotation) annotation).stream());
|
||||
|
||||
return cacheNames.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private Set<String> collectCacheNames(Annotation annotation) {
|
||||
|
||||
return Optional.ofNullable(annotation)
|
||||
.map(this::getAnnotationAttributes)
|
||||
.map(annotationAttributes -> annotationAttributes.getStringArray("cacheNames"))
|
||||
.map(CollectionUtils::asSet)
|
||||
.orElse(Collections.emptySet());
|
||||
}
|
||||
|
||||
private Set<String> collectCachingCacheNames(AnnotatedElement annotatedElement) {
|
||||
|
||||
Set<String> cacheNames = new HashSet<>();
|
||||
|
||||
Optional.ofNullable(resolveAnnotation(annotatedElement, Caching.class))
|
||||
.ifPresent(caching -> {
|
||||
|
||||
cacheNames.addAll(stream(nullSafeArray(caching.cacheable(), Cacheable.class))
|
||||
.flatMap(cacheable -> collectCacheNames(cacheable).stream())
|
||||
.collect(Collectors.toSet()));
|
||||
|
||||
cacheNames.addAll(stream(nullSafeArray(caching.evict(), CacheEvict.class))
|
||||
.flatMap(cacheEvict -> collectCacheNames(cacheEvict).stream())
|
||||
.collect(Collectors.toSet()));
|
||||
|
||||
cacheNames.addAll(stream(nullSafeArray(caching.put(), CachePut.class))
|
||||
.flatMap(cachePut -> collectCacheNames(cachePut).stream())
|
||||
.collect(Collectors.toSet()));
|
||||
|
||||
});
|
||||
|
||||
return cacheNames;
|
||||
}
|
||||
|
||||
private BeanDefinitionRegistry registerRegionBeanDefinitions(Set<String> cacheNames,
|
||||
BeanDefinitionRegistry registry) {
|
||||
|
||||
@@ -400,6 +327,24 @@ public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfig
|
||||
return registry;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("all")
|
||||
public BeanPostProcessor cachingAnnotationsRegionBeanRegistrar(ConfigurableBeanFactory beanFactory) {
|
||||
|
||||
return new BeanPostProcessor() {
|
||||
|
||||
@Nullable @Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
|
||||
if (isNotInfrastructureBean(bean)) {
|
||||
registerRegionBeans(getCacheNameResolver().resolveCacheNames(bean.getClass()), beanFactory);
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private ConfigurableBeanFactory registerRegionBeans(Set<String> cacheNames, ConfigurableBeanFactory beanFactory) {
|
||||
|
||||
cacheNames.forEach(cacheName -> {
|
||||
@@ -432,4 +377,148 @@ public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfig
|
||||
|
||||
return beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link CacheNameResolver} is a {@link FunctionalInterface} declaring a contract for all implementations
|
||||
* used to resolve all cache names declared and used by a Spring application. A resolver typically inspects
|
||||
* all the application beans/components declared and registered in the Spring container (context) setup by
|
||||
* the application to determine whether the application components require caching behavior.
|
||||
*
|
||||
* @see org.springframework.data.gemfire.config.annotation.CachingDefinedRegionsConfiguration.Jsr107CacheAnnotationsCacheNameResolver
|
||||
* @see org.springframework.data.gemfire.config.annotation.CachingDefinedRegionsConfiguration.SpringCacheAnnotationsCacheNameResolver
|
||||
*/
|
||||
@FunctionalInterface
|
||||
protected interface CacheNameResolver {
|
||||
Set<String> resolveCacheNames(Class<?> type);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AbstractCacheNameResolver} is an abstract base class encapsulating reusable functionality common
|
||||
* to all {@link CacheNameResolver} implementations.
|
||||
*
|
||||
* Current implementations support inlude JSR-107, JCache API annotation and Spring's Cache Abstraction annotations.
|
||||
*
|
||||
* @see org.springframework.data.gemfire.config.annotation.CachingDefinedRegionsConfiguration.CacheNameResolver
|
||||
*/
|
||||
protected abstract class AbstractCacheNameResolver implements CacheNameResolver {
|
||||
|
||||
private final String JSR_107_CACHE_NAME_ATTRIBUTE_NAME = "cacheName";
|
||||
private final String SPRING_CACHE_NAMES_ATTRIBUTE_NAME = "cacheNames";
|
||||
|
||||
private final String[] EMPTY_ARRAY = new String[0];
|
||||
|
||||
protected abstract Class<? extends Annotation>[] getClassCacheAnnotationTypes();
|
||||
|
||||
protected abstract Class<? extends Annotation>[] getMethodCacheAnnotationTypes();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Class[] append(Class[] annotationTypes, Class... additionalAnnotationTypes) {
|
||||
|
||||
List<Class> annotationTypeList = new ArrayList<>(Arrays.asList(annotationTypes));
|
||||
|
||||
Collections.addAll(annotationTypeList, additionalAnnotationTypes);
|
||||
|
||||
return annotationTypeList.toArray(new Class[annotationTypeList.size()]);
|
||||
}
|
||||
|
||||
protected Set<String> resolveCacheNames(Annotation annotation) {
|
||||
|
||||
return Optional.ofNullable(annotation)
|
||||
.map(it -> getAnnotationAttributes(it))
|
||||
.map(annotationAttributes -> {
|
||||
|
||||
String attributeName = annotationAttributes.containsKey(SPRING_CACHE_NAMES_ATTRIBUTE_NAME)
|
||||
? SPRING_CACHE_NAMES_ATTRIBUTE_NAME : JSR_107_CACHE_NAME_ATTRIBUTE_NAME;
|
||||
|
||||
return annotationAttributes.containsKey(attributeName)
|
||||
? annotationAttributes.getStringArray(attributeName)
|
||||
: EMPTY_ARRAY;
|
||||
|
||||
})
|
||||
.map(CollectionUtils::asSet)
|
||||
.orElse(Collections.emptySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<String> resolveCacheNames(Class<?> type) {
|
||||
|
||||
Set<String> cacheNames = new HashSet<>();
|
||||
|
||||
cacheNames.addAll(resolveCacheNames(type, getClassCacheAnnotationTypes()));
|
||||
|
||||
stream(type.getMethods())
|
||||
.filter(method -> isUserLevelMethod(method))
|
||||
.forEach(method -> cacheNames.addAll(resolveCacheNames(method, getMethodCacheAnnotationTypes())));
|
||||
|
||||
return cacheNames;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
protected Set<String> resolveCacheNames(AnnotatedElement annotatedElement,
|
||||
Class<? extends Annotation>... annotationTypes) {
|
||||
|
||||
Stream<String> cacheNames = stream(nullSafeArray(annotationTypes, Class.class))
|
||||
.map(annotationType -> resolveAnnotation(annotatedElement, annotationType))
|
||||
.flatMap(annotation -> resolveCacheNames((Annotation) annotation).stream());
|
||||
|
||||
return cacheNames.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
protected class Jsr107CacheAnnotationsCacheNameResolver extends AbstractCacheNameResolver {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Class<? extends Annotation>[] getClassCacheAnnotationTypes() {
|
||||
return append(getMethodCacheAnnotationTypes(), CacheDefaults.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends Annotation>[] getMethodCacheAnnotationTypes() {
|
||||
return asArray(javax.cache.annotation.CachePut.class, CacheRemove.class,
|
||||
CacheRemoveAll.class, CacheResult.class);
|
||||
}
|
||||
}
|
||||
|
||||
protected class SpringCacheAnnotationsCacheNameResolver extends AbstractCacheNameResolver {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Class<? extends Annotation>[] getClassCacheAnnotationTypes() {
|
||||
return append(getMethodCacheAnnotationTypes(), Caching.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends Annotation>[] getMethodCacheAnnotationTypes() {
|
||||
return asArray(Cacheable.class, CacheEvict.class, CachePut.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<String> resolveCacheNames(Class<?> type) {
|
||||
|
||||
Set<String> cacheNames = super.resolveCacheNames(type);
|
||||
|
||||
cacheNames.addAll(resolveCachingCacheNames(type));
|
||||
|
||||
stream(type.getMethods()).filter(method -> isUserLevelMethod(method))
|
||||
.forEach(method -> cacheNames.addAll(resolveCachingCacheNames(method)));
|
||||
|
||||
return cacheNames;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Set<String> resolveCachingCacheNames(AnnotatedElement annotatedElement) {
|
||||
|
||||
Set<String> cacheNames = new HashSet<>();
|
||||
|
||||
Optional.ofNullable(resolveAnnotation(annotatedElement, Caching.class)).ifPresent(caching ->
|
||||
concat(stream(caching.cacheable()), stream(caching.evict()), stream(caching.put()))
|
||||
.flatMap(cacheAnnotation -> resolveCacheNames(cacheAnnotation).stream())
|
||||
.collect(Collectors.toCollection(() -> cacheNames)));
|
||||
|
||||
return cacheNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ public @interface EnableLocator {
|
||||
*
|
||||
* Defaults to {@literal 10334}.
|
||||
*
|
||||
* Use the {@literal spring.data.gemfire.locator.host} property in {@literal application.properties}.
|
||||
* Use the {@literal spring.data.gemfire.locator.port} property in {@literal application.properties}.
|
||||
*/
|
||||
int port() default LocatorConfiguration.DEFAULT_LOCATOR_PORT;
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public abstract class ArrayUtils {
|
||||
* @return the given {@code array} if not {@literal null} or empty otherwise return the {@code defaultArray}.
|
||||
*/
|
||||
public static <T> T[] defaultIfEmpty(T[] array, T[] defaultArray) {
|
||||
return (!ObjectUtils.isEmpty(array) ? array : defaultArray);
|
||||
return !ObjectUtils.isEmpty(array) ? array : defaultArray;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,7 +76,7 @@ public abstract class ArrayUtils {
|
||||
* @see #getFirst(Object[], Object)
|
||||
*/
|
||||
public static <T> T getFirst(T[] array, T defaultValue) {
|
||||
return (isEmpty(array) ? defaultValue : array[0]);
|
||||
return isEmpty(array) ? defaultValue : array[0];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,8 +91,9 @@ public abstract class ArrayUtils {
|
||||
* @see java.lang.reflect.Array#newInstance(Class, int)
|
||||
*/
|
||||
public static Object[] insert(Object[] originalArray, int position, Object element) {
|
||||
Object[] newArray = (Object[]) Array.newInstance(originalArray.getClass().getComponentType(),
|
||||
originalArray.length + 1);
|
||||
|
||||
Object[] newArray =
|
||||
(Object[]) Array.newInstance(originalArray.getClass().getComponentType(), originalArray.length + 1);
|
||||
|
||||
|
||||
// copy all elements before the given position (here, position refers to the length, or number of elements
|
||||
@@ -106,7 +107,8 @@ public abstract class ArrayUtils {
|
||||
|
||||
// copy remaining elements from originalArray, starting at position, to new array
|
||||
if (position < originalArray.length) {
|
||||
System.arraycopy(originalArray, position, newArray, position + 1, originalArray.length - position);
|
||||
System.arraycopy(originalArray, position, newArray, position + 1,
|
||||
originalArray.length - position);
|
||||
}
|
||||
|
||||
return newArray;
|
||||
@@ -120,7 +122,7 @@ public abstract class ArrayUtils {
|
||||
* @see #length(Object...)
|
||||
*/
|
||||
public static boolean isEmpty(Object[] array) {
|
||||
return (length(array) == 0);
|
||||
return length(array) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,7 +132,7 @@ public abstract class ArrayUtils {
|
||||
* @return the length of the given array or 0 if the array reference is null.
|
||||
*/
|
||||
public static int length(Object[] array) {
|
||||
return (array != null ? array.length : 0);
|
||||
return array != null ? array.length : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,7 +147,7 @@ public abstract class ArrayUtils {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T[] nullSafeArray(T[] array, Class<T> componentType) {
|
||||
return (array != null ? array : (T[]) Array.newInstance(componentType, 0));
|
||||
return array != null ? array : (T[]) Array.newInstance(componentType, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,8 +161,9 @@ public abstract class ArrayUtils {
|
||||
* @see java.lang.reflect.Array#newInstance(Class, int)
|
||||
*/
|
||||
public static Object[] remove(Object[] originalArray, int position) {
|
||||
Object[] newArray = (Object[]) Array.newInstance(originalArray.getClass().getComponentType(),
|
||||
originalArray.length - 1);
|
||||
|
||||
Object[] newArray =
|
||||
(Object[]) Array.newInstance(originalArray.getClass().getComponentType(), originalArray.length - 1);
|
||||
|
||||
// copy all elements before position (here, position refers to the length, or number of elements to be copied
|
||||
if (position > 0) {
|
||||
@@ -169,7 +172,8 @@ public abstract class ArrayUtils {
|
||||
|
||||
// copy remaining elements after position from the originalArray
|
||||
if (position < originalArray.length - 1) {
|
||||
System.arraycopy(originalArray, position + 1, newArray, position, originalArray.length - 1 - position);
|
||||
System.arraycopy(originalArray, position + 1, newArray, position,
|
||||
originalArray.length - 1 - position);
|
||||
}
|
||||
|
||||
return newArray;
|
||||
@@ -184,7 +188,9 @@ public abstract class ArrayUtils {
|
||||
* @see java.util.Arrays#sort(Object[])
|
||||
*/
|
||||
public static <T extends Comparable<T>> T[] sort(T[] array) {
|
||||
|
||||
Arrays.sort(array);
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.CacheClosedException;
|
||||
import org.apache.geode.cache.CacheFactory;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.client.ClientCacheFactory;
|
||||
import org.apache.geode.distributed.DistributedSystem;
|
||||
@@ -67,13 +66,16 @@ public abstract class CacheUtils extends DistributedSystemUtils {
|
||||
/* (non-Javadoc) */
|
||||
public static boolean isDurable(ClientCache clientCache) {
|
||||
|
||||
DistributedSystem distributedSystem = getDistributedSystem(clientCache);
|
||||
|
||||
// NOTE technically the following code snippet would be more useful/valuable but is not "testable"!
|
||||
//((InternalDistributedSystem) distributedSystem).getConfig().getDurableClientId();
|
||||
|
||||
return (isConnected(distributedSystem) && StringUtils.hasText(distributedSystem.getProperties()
|
||||
.getProperty(DURABLE_CLIENT_ID_PROPERTY_NAME, null)));
|
||||
return Optional.ofNullable(clientCache)
|
||||
.<DistributedSystem>map(CacheUtils::getDistributedSystem)
|
||||
.filter(DistributedSystem::isConnected)
|
||||
.map(DistributedSystem::getProperties)
|
||||
.map(properties -> properties.getProperty(DURABLE_CLIENT_ID_PROPERTY_NAME, null))
|
||||
.filter(StringUtils::hasText)
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@@ -91,6 +93,7 @@ public abstract class CacheUtils extends DistributedSystemUtils {
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static boolean closeCache() {
|
||||
|
||||
try {
|
||||
CacheFactory.getAnyInstance().close();
|
||||
return true;
|
||||
@@ -102,6 +105,7 @@ public abstract class CacheUtils extends DistributedSystemUtils {
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static boolean closeClientCache() {
|
||||
|
||||
try {
|
||||
ClientCacheFactory.getAnyInstance().close();
|
||||
return true;
|
||||
@@ -113,6 +117,7 @@ public abstract class CacheUtils extends DistributedSystemUtils {
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static Cache getCache() {
|
||||
|
||||
try {
|
||||
return CacheFactory.getAnyInstance();
|
||||
}
|
||||
@@ -123,6 +128,7 @@ public abstract class CacheUtils extends DistributedSystemUtils {
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static ClientCache getClientCache() {
|
||||
|
||||
try {
|
||||
return ClientCacheFactory.getAnyInstance();
|
||||
}
|
||||
@@ -135,9 +141,4 @@ public abstract class CacheUtils extends DistributedSystemUtils {
|
||||
public static GemFireCache resolveGemFireCache() {
|
||||
return Optional.<GemFireCache>ofNullable(getClientCache()).orElseGet(CacheUtils::getCache);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static String toRegionPath(String regionName) {
|
||||
return String.format("%1$s%2$s", Region.SEPARATOR, regionName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.data.gemfire.util;
|
||||
|
||||
import static java.util.stream.StreamSupport.stream;
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -26,6 +27,7 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
@@ -61,11 +63,10 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
* @see java.util.Collection
|
||||
*/
|
||||
public static <E, T extends Collection<E>> T addAll(T collection, Iterable<E> iterable) {
|
||||
Assert.notNull(collection, "Collection must not be null");
|
||||
|
||||
for (E element : nullSafeIterable(iterable)) {
|
||||
collection.add(element);
|
||||
}
|
||||
Assert.notNull(collection, "Collection is required");
|
||||
|
||||
stream(nullSafeIterable(iterable).spliterator(), false).forEach(collection::add);
|
||||
|
||||
return collection;
|
||||
}
|
||||
@@ -79,8 +80,11 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static <T> Set<T> asSet(T... elements) {
|
||||
|
||||
Set<T> set = new HashSet<>(elements.length);
|
||||
|
||||
Collections.addAll(set, elements);
|
||||
|
||||
return Collections.unmodifiableSet(set);
|
||||
}
|
||||
|
||||
@@ -93,6 +97,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
* @see java.util.Collection#contains(Object)
|
||||
*/
|
||||
public static boolean containsAny(Collection<?> collection, Object... elements) {
|
||||
|
||||
if (collection != null) {
|
||||
for (Object element : nullSafeArray(elements, Object.class)) {
|
||||
if (collection.contains(element)) {
|
||||
@@ -104,20 +109,6 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given {@link Iterable} if not {@literal null} or empty, otherwise returns the {@code defaultIterable}.
|
||||
*
|
||||
* @param <T> concrete {@link Class} type of the {@link Iterable}.
|
||||
* @param <E> {@link Class} type of the elements in the {@link Iterable Iterables}.
|
||||
* @param iterable {@link Iterable} to evaluate.
|
||||
* @param defaultIterable {@link Iterable} to return if the given {@code iterable} is {@literal null} or empty.
|
||||
* @return {@code iterable} if not {@literal null} or empty otherwise return {@code defaultIterable}.
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
public static <E, T extends Iterable<E>> T defaultIfEmpty(T iterable, T defaultIterable) {
|
||||
return (iterable != null && iterable.iterator().hasNext() ? iterable : defaultIterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty {@link Iterable} object.
|
||||
*
|
||||
@@ -168,7 +159,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
* @see java.util.Collection
|
||||
*/
|
||||
public static <T> Collection<T> nullSafeCollection(Collection<T> collection) {
|
||||
return (collection != null ? collection : Collections.emptyList());
|
||||
return collection != null ? collection : Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,7 +173,21 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
* @see java.util.Iterator
|
||||
*/
|
||||
public static <T> Iterable<T> nullSafeIterable(Iterable<T> iterable) {
|
||||
return (iterable != null ? iterable : Collections::emptyIterator);
|
||||
return iterable != null ? iterable : Collections::emptyIterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given {@link Iterable} if not {@literal null} or empty, otherwise returns the {@code defaultIterable}.
|
||||
*
|
||||
* @param <T> concrete {@link Class} type of the {@link Iterable}.
|
||||
* @param <E> {@link Class} type of the elements in the {@link Iterable Iterables}.
|
||||
* @param iterable {@link Iterable} to evaluate.
|
||||
* @param defaultIterable {@link Iterable} to return if the given {@code iterable} is {@literal null} or empty.
|
||||
* @return {@code iterable} if not {@literal null} or empty otherwise return {@code defaultIterable}.
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
public static <E, T extends Iterable<E>> T nullSafeIterable(T iterable, T defaultIterable) {
|
||||
return Optional.ofNullable(iterable).filter(it -> it.iterator().hasNext()).orElse(defaultIterable);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,7 +201,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
* @see java.util.List
|
||||
*/
|
||||
public static <T> List<T> nullSafeList(List<T> list) {
|
||||
return (list != null ? list : Collections.emptyList());
|
||||
return list != null ? list : Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,7 +217,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public static <K, V> Map<K, V> nullSafeMap(Map<K, V> map) {
|
||||
return (map != null ? map : Collections.emptyMap());
|
||||
return map != null ? map : Collections.<K, V>emptyMap();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,7 +231,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
* @see java.util.Set
|
||||
*/
|
||||
public static <T> Set<T> nullSafeSet(Set<T> set) {
|
||||
return (set != null ? set : Collections.emptySet());
|
||||
return set != null ? set : Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,7 +244,9 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
* @see java.util.List
|
||||
*/
|
||||
public static <T extends Comparable<T>> List<T> sort(List<T> list) {
|
||||
|
||||
Collections.sort(list);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -257,7 +264,8 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
* @see java.util.List
|
||||
*/
|
||||
public static <T> List<T> subList(List<T> source, int... indices) {
|
||||
Assert.notNull(source, "List must not be null");
|
||||
|
||||
Assert.notNull(source, "List is required");
|
||||
|
||||
List<T> result = new ArrayList<>(indices.length);
|
||||
|
||||
@@ -270,6 +278,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static String toString(Map<?, ?> map) {
|
||||
|
||||
StringBuilder builder = new StringBuilder("{\n");
|
||||
|
||||
int count = 0;
|
||||
|
||||
@@ -57,7 +57,8 @@ public abstract class DistributedSystemUtils extends SpringUtils {
|
||||
String durableClientId, Integer durableClientTimeout) {
|
||||
|
||||
if (StringUtils.hasText(durableClientId)) {
|
||||
Assert.notNull(gemfireProperties, "gemfireProperties must not be null");
|
||||
|
||||
Assert.notNull(gemfireProperties, "gemfireProperties are required");
|
||||
|
||||
gemfireProperties.setProperty(DURABLE_CLIENT_ID_PROPERTY_NAME, durableClientId);
|
||||
|
||||
@@ -71,7 +72,7 @@ public abstract class DistributedSystemUtils extends SpringUtils {
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static boolean isConnected(DistributedSystem distributedSystem) {
|
||||
return (distributedSystem != null && distributedSystem.isConnected());
|
||||
return Optional.ofNullable(distributedSystem).filter(DistributedSystem::isConnected).isPresent();
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
|
||||
@@ -23,10 +23,12 @@ import org.apache.geode.cache.RegionAttributes;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The RegionUtils class...
|
||||
* The {@link RegionUtils} class is an abstract utility class for working with {@link Region Regions}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @since 1.0.0
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.RegionAttributes
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public abstract class RegionUtils extends CacheUtils {
|
||||
|
||||
@@ -38,4 +40,9 @@ public abstract class RegionUtils extends CacheUtils {
|
||||
.filter(StringUtils::hasText)
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static String toRegionPath(String regionName) {
|
||||
return String.format("%1$s%2$s", Region.SEPARATOR, regionName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.data.gemfire.util;
|
||||
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The {@link StreamUtils} class is a abstract utility class for working with {@link Stream Streams}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.stream.Stream
|
||||
* @since 2.0.2
|
||||
*/
|
||||
public abstract class StreamUtils {
|
||||
|
||||
/**
|
||||
* Concatenates an array of {@link Stream Streams} into a single, continuous {@link Stream}.
|
||||
*
|
||||
* @param <T> {@link Class type} of elements in the {@link Stream Streams}.
|
||||
* @param streams array of {@link Stream Streams} to concatenate.
|
||||
* @return the concatenated array of {@link Stream Streams} as a single, continuous {@link Stream}.
|
||||
* @see java.util.stream.Stream
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Stream<T> concat(Stream<T>... streams) {
|
||||
|
||||
Stream<T> concatenatedStream = Stream.empty();
|
||||
|
||||
for (Stream<T> stream : nullSafeArray(streams, Stream.class)) {
|
||||
concatenatedStream = Stream.concat(concatenatedStream, stream);
|
||||
}
|
||||
|
||||
return concatenatedStream;
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,7 @@ public class GemfireUtilsTest {
|
||||
|
||||
@Test
|
||||
public void isClientWithClientIsTrue() {
|
||||
|
||||
ClientCache mockClient = mock(ClientCache.class);
|
||||
|
||||
assertThat(GemfireUtils.isClient(mockClient), is(true));
|
||||
@@ -54,6 +55,7 @@ public class GemfireUtilsTest {
|
||||
|
||||
@Test
|
||||
public void isClientWithNonClientIsFalse() {
|
||||
|
||||
Cache mockCache = mock(Cache.class);
|
||||
|
||||
assertThat(GemfireUtils.isClient(mockCache), is(false));
|
||||
@@ -63,7 +65,9 @@ public class GemfireUtilsTest {
|
||||
|
||||
@Test
|
||||
public void isDurableWithDurableClientIsTrue() {
|
||||
|
||||
ClientCache mockClientCache = mock(ClientCache.class);
|
||||
|
||||
DistributedSystem mockDistributedSystem = mock(DistributedSystem.class);
|
||||
|
||||
Properties gemfireProperties = new Properties();
|
||||
@@ -83,7 +87,9 @@ public class GemfireUtilsTest {
|
||||
|
||||
@Test
|
||||
public void isDurableWhenNotDurableClientIsFalse() {
|
||||
|
||||
ClientCache mockClientCache = mock(ClientCache.class);
|
||||
|
||||
DistributedSystem mockDistributedSystem = mock(DistributedSystem.class);
|
||||
|
||||
Properties gemfireProperties = new Properties();
|
||||
@@ -103,7 +109,9 @@ public class GemfireUtilsTest {
|
||||
|
||||
@Test
|
||||
public void isDurableWhenDistributedSystemIsNotConnectedIsFalse() {
|
||||
|
||||
ClientCache mockClientCache = mock(ClientCache.class);
|
||||
|
||||
DistributedSystem mockDistributedSystem = mock(DistributedSystem.class);
|
||||
|
||||
when(mockClientCache.getDistributedSystem()).thenReturn(mockDistributedSystem);
|
||||
@@ -118,6 +126,7 @@ public class GemfireUtilsTest {
|
||||
|
||||
@Test
|
||||
public void isPeerWithPeerIsTrue() {
|
||||
|
||||
Cache mockCache = mock(Cache.class);
|
||||
|
||||
assertThat(GemfireUtils.isPeer(mockCache), is(true));
|
||||
@@ -127,6 +136,7 @@ public class GemfireUtilsTest {
|
||||
|
||||
@Test
|
||||
public void isPeerWithNonPeerIsFalse() {
|
||||
|
||||
ClientCache mockClientCache = mock(ClientCache.class);
|
||||
|
||||
assertThat(GemfireUtils.isPeer(mockClientCache), is(false));
|
||||
|
||||
@@ -20,11 +20,16 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.cache.annotation.CacheDefaults;
|
||||
import javax.cache.annotation.CacheRemoveAll;
|
||||
import javax.cache.annotation.CacheResult;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.cache.annotation.CachePut;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -48,44 +53,58 @@ public class EnableCachingDefinedRegionsIntegrationTests {
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private CacheableEchoService echoService;
|
||||
private JCacheEchoService jcacheEchoService;
|
||||
|
||||
@Autowired
|
||||
private SpringCacheableEchoService springEchoService;
|
||||
|
||||
@Autowired
|
||||
private GemFireCache gemfireCache;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
//System.err.printf("@Cacheable Beans [%s]%n",
|
||||
// Arrays.toString(applicationContext.getBeanNamesForAnnotation(Cacheable.class)));
|
||||
|
||||
assertThat(this.gemfireCache).isNotNull();
|
||||
|
||||
//System.err.printf("Cache Regions [%s]%n", this.gemfireCache.rootRegions().stream()
|
||||
// .map(Region::getFullPath).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheRegionsExists() {
|
||||
|
||||
assertThat(gemfireCache.getRegion("/Example")).isNotNull();
|
||||
assertThat(gemfireCache.getRegion("/Echo")).isNotNull();
|
||||
assertThat(gemfireCache.getRegion("/JCacheOne")).isNotNull();
|
||||
assertThat(gemfireCache.getRegion("/JCacheTwo")).isNotNull();
|
||||
assertThat(gemfireCache.getRegion("/SpringOne")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void echoServiceOperationsAreSuccessful() {
|
||||
public void echoServiceCachingWithJCacheIsSuccessful() {
|
||||
|
||||
assertThat(echoService.isCacheMiss()).isFalse();
|
||||
assertThat(echoService.echo("one")).isEqualTo("one");
|
||||
assertThat(echoService.isCacheMiss()).isTrue();
|
||||
assertThat(echoService.echo("two")).isEqualTo("two");
|
||||
assertThat(echoService.isCacheMiss()).isTrue();
|
||||
assertThat(echoService.echo("one")).isEqualTo("one");
|
||||
assertThat(echoService.isCacheMiss()).isFalse();
|
||||
assertThat(echoService.echo("three")).isEqualTo("three");
|
||||
assertThat(echoService.isCacheMiss()).isTrue();
|
||||
assertThat(echoService.echo("two")).isEqualTo("two");
|
||||
assertThat(echoService.isCacheMiss()).isFalse();
|
||||
assertThat(jcacheEchoService.isCacheMiss()).isFalse();
|
||||
assertThat(jcacheEchoService.echo("four")).isEqualTo("four");
|
||||
assertThat(jcacheEchoService.isCacheMiss()).isTrue();
|
||||
assertThat(jcacheEchoService.echo("five")).isEqualTo("five");
|
||||
assertThat(jcacheEchoService.isCacheMiss()).isTrue();
|
||||
assertThat(jcacheEchoService.echo("four")).isEqualTo("four");
|
||||
assertThat(jcacheEchoService.isCacheMiss()).isFalse();
|
||||
assertThat(jcacheEchoService.echo("six")).isEqualTo("six");
|
||||
assertThat(jcacheEchoService.isCacheMiss()).isTrue();
|
||||
assertThat(jcacheEchoService.echo("five")).isEqualTo("five");
|
||||
assertThat(jcacheEchoService.isCacheMiss()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void echoServiceCachingWithSpringIsSuccessful() {
|
||||
|
||||
assertThat(springEchoService.isCacheMiss()).isFalse();
|
||||
assertThat(springEchoService.echo("one")).isEqualTo("one");
|
||||
assertThat(springEchoService.isCacheMiss()).isTrue();
|
||||
assertThat(springEchoService.echo("two")).isEqualTo("two");
|
||||
assertThat(springEchoService.isCacheMiss()).isTrue();
|
||||
assertThat(springEchoService.echo("one")).isEqualTo("one");
|
||||
assertThat(springEchoService.isCacheMiss()).isFalse();
|
||||
assertThat(springEchoService.echo("three")).isEqualTo("three");
|
||||
assertThat(springEchoService.isCacheMiss()).isTrue();
|
||||
assertThat(springEchoService.echo("two")).isEqualTo("two");
|
||||
assertThat(springEchoService.isCacheMiss()).isFalse();
|
||||
}
|
||||
|
||||
@PeerCacheApplication(name = "EnableCachingDefinedRegionsIntegrationTests", logLevel = "warning")
|
||||
@@ -93,18 +112,28 @@ public class EnableCachingDefinedRegionsIntegrationTests {
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
CacheableEchoService echoService() {
|
||||
return new CacheableEchoService();
|
||||
JCacheEchoService jcacheEchoService() {
|
||||
return new JCacheEchoService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
TestService testService() {
|
||||
return new CachingTestService();
|
||||
@Qualifier("Spring")
|
||||
SpringCacheableEchoService springEchoService() {
|
||||
return new SpringCacheableEchoService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
TestService testServiceOne() {
|
||||
return new SpringCachingTestService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
TestService testServiceTwo() {
|
||||
return new Jsr107CachingTestService();
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
static class CacheableEchoService {
|
||||
static abstract class AbstractCacheableService {
|
||||
|
||||
private final AtomicBoolean cacheMiss = new AtomicBoolean(false);
|
||||
|
||||
@@ -112,9 +141,27 @@ public class EnableCachingDefinedRegionsIntegrationTests {
|
||||
return this.cacheMiss.compareAndSet(true, false);
|
||||
}
|
||||
|
||||
public void setCacheMiss() {
|
||||
this.cacheMiss.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
static class JCacheEchoService extends AbstractCacheableService {
|
||||
|
||||
@CacheResult(cacheName = "Echo")
|
||||
public Object echo(String key) {
|
||||
setCacheMiss();
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
static class SpringCacheableEchoService extends AbstractCacheableService {
|
||||
|
||||
@Cacheable("Echo")
|
||||
public Object echo(String key) {
|
||||
this.cacheMiss.set(true);
|
||||
setCacheMiss();
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@@ -123,9 +170,19 @@ public class EnableCachingDefinedRegionsIntegrationTests {
|
||||
Object testMethod(String key);
|
||||
}
|
||||
|
||||
static class CachingTestService implements TestService {
|
||||
@CacheDefaults(cacheName = "JCacheOne")
|
||||
@CacheRemoveAll(cacheName = "SpringOne")
|
||||
static class Jsr107CachingTestService implements TestService {
|
||||
|
||||
@CachePut("Example")
|
||||
@CacheResult(cacheName = "JCacheTwo")
|
||||
public Object testMethod(String key) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class SpringCachingTestService implements TestService {
|
||||
|
||||
@CachePut("SpringOne")
|
||||
public Object testMethod(String key) {
|
||||
return "test";
|
||||
}
|
||||
|
||||
@@ -33,6 +33,11 @@ import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.cache.annotation.CacheDefaults;
|
||||
import javax.cache.annotation.CacheRemove;
|
||||
import javax.cache.annotation.CacheRemoveAll;
|
||||
import javax.cache.annotation.CacheResult;
|
||||
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||
import org.junit.Before;
|
||||
@@ -88,7 +93,7 @@ public class EnableCachingDefinedRegionsUnitTests {
|
||||
return mockBeanDefinition;
|
||||
}
|
||||
catch (ClassNotFoundException cause) {
|
||||
throw newRuntimeException(cause, "Mock for class [%s] failed", beanClass.getName());
|
||||
throw newRuntimeException(cause, "Creating a mock for class [%s] failed", beanClass.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +116,16 @@ public class EnableCachingDefinedRegionsUnitTests {
|
||||
return mockBeanDefinitionRegistry;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void annotationTypeIsEnableCachingDefinedRegions() {
|
||||
assertThat(this.configuration.getAnnotationType()).isEqualTo(EnableCachingDefinedRegions.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCacheNameResolverIsConfiguredProperly() {
|
||||
assertThat(this.configuration.getCacheNameResolver()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setGetAndResolveClientRegionShortcut() {
|
||||
|
||||
@@ -319,13 +334,15 @@ public class EnableCachingDefinedRegionsUnitTests {
|
||||
verify(mockBeanDefinitionRegistry, times(registeredRegionBeanNames.size()))
|
||||
.registerBeanDefinition(anyString(), any(BeanDefinition.class));
|
||||
|
||||
registeredRegionBeanNames.forEach(beanName ->
|
||||
registeredRegionBeanNames.forEach(beanName -> {
|
||||
verify(mockBeanDefinitionRegistry, times(1)).containsBeanDefinition(eq(beanName));
|
||||
verify(mockBeanDefinitionRegistry, times(1))
|
||||
.registerBeanDefinition(eq(beanName), any(BeanDefinition.class)));
|
||||
.registerBeanDefinition(eq(beanName), any(BeanDefinition.class));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheableServiceOneTwoThreeRegistersTwentyTwoRegionBeans() {
|
||||
public void cacheableServiceOneTwoAndThreeRegistersTwentyTwoRegionBeans() {
|
||||
|
||||
Map<String, BeanDefinition> registeredBeanDefinitions = MapBuilder.<String, BeanDefinition>newMapBuilder()
|
||||
.put("cacheableServiceOne", mockBeanDefinition(CacheableServiceOne.class))
|
||||
@@ -345,45 +362,110 @@ public class EnableCachingDefinedRegionsUnitTests {
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(1)).getBeanDefinitionNames();
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(1))
|
||||
.getBeanDefinition(eq("cacheableServiceOne"));
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(1))
|
||||
.getBeanDefinition(eq("cacheableServiceTwo"));
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(1))
|
||||
.getBeanDefinition(eq("cacheableServiceThree"));
|
||||
Arrays.asList("cacheableServiceOne", "cacheableServiceTwo", "cacheableServiceThree").forEach(beanName ->
|
||||
verify(mockBeanDefinitionRegistry, times(1)).getBeanDefinition(eq(beanName)));
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(registeredRegionBeanNames.size()))
|
||||
.registerBeanDefinition(anyString(), any(BeanDefinition.class));
|
||||
|
||||
registeredRegionBeanNames.forEach(beanName ->
|
||||
registeredRegionBeanNames.forEach(beanName -> {
|
||||
|
||||
int wantedNumberOfInvocations = "RegionSix".equals(beanName) || "RegionTwo".equals(beanName) ? 2 : 1;
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(wantedNumberOfInvocations)).containsBeanDefinition(eq(beanName));
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(1))
|
||||
.registerBeanDefinition(eq(beanName), any(BeanDefinition.class)));
|
||||
.registerBeanDefinition(eq(beanName), any(BeanDefinition.class));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void collectCacheNamesForCacheableAndCachePutOnCacheableServiceThreeRegistersRegionFifteenSixteenSeventeen() {
|
||||
public void cacheableServiceFiveRegistersRegionOneTwoThreeFourFiveSixAndSeven() {
|
||||
|
||||
assertThat(this.configuration.collectCacheNames(CacheableServiceThree.class, Cacheable.class, CachePut.class))
|
||||
.containsExactly("RegionFifteen", "RegionSixteen", "RegionSeventeen");
|
||||
Map<String, BeanDefinition> registeredBeanDefinitions = MapBuilder.<String, BeanDefinition>newMapBuilder()
|
||||
.put("cacheableServiceFive", mockBeanDefinition(CacheableServiceFive.class))
|
||||
.build();
|
||||
|
||||
BeanDefinitionRegistry mockBeanDefinitionRegistry = mockBeanDefinitionRegistry(registeredBeanDefinitions);
|
||||
|
||||
this.configuration.registerBeanDefinitions(mockBeanDefinitionRegistry);
|
||||
|
||||
Set<String> registeredRegionBeanNames =
|
||||
asSet("RegionOne", "RegionTwo", "RegionThree", "RegionFour", "RegionFive",
|
||||
"RegionSix", "RegionSeven");
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(1)).getBeanDefinitionNames();
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(1))
|
||||
.getBeanDefinition(eq("cacheableServiceFive"));
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(registeredRegionBeanNames.size()))
|
||||
.registerBeanDefinition(anyString(), any(BeanDefinition.class));
|
||||
|
||||
registeredRegionBeanNames.forEach(beanName -> {
|
||||
verify(mockBeanDefinitionRegistry, times(1)).containsBeanDefinition(eq(beanName));
|
||||
verify(mockBeanDefinitionRegistry, times(1))
|
||||
.registerBeanDefinition(eq(beanName), any(BeanDefinition.class));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void collectCacheNamesForCacheableOnCacheableServiceThreeRegistersRegionFifteen() {
|
||||
public void cacheableServiceSixRegistersRegionOneTwoThreeFourAndFive() {
|
||||
|
||||
assertThat(this.configuration.collectCacheNames(CacheableServiceThree.class, Cacheable.class))
|
||||
.containsExactly("RegionFifteen");
|
||||
Map<String, BeanDefinition> registeredBeanDefinitions = MapBuilder.<String, BeanDefinition>newMapBuilder()
|
||||
.put("cacheableServiceSix", mockBeanDefinition(CacheableServiceSix.class))
|
||||
.build();
|
||||
|
||||
BeanDefinitionRegistry mockBeanDefinitionRegistry = mockBeanDefinitionRegistry(registeredBeanDefinitions);
|
||||
|
||||
this.configuration.registerBeanDefinitions(mockBeanDefinitionRegistry);
|
||||
|
||||
Set<String> registeredRegionBeanNames =
|
||||
asSet("RegionOne", "RegionTwo", "RegionThree", "RegionFour", "RegionFive");
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(1)).getBeanDefinitionNames();
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(1))
|
||||
.getBeanDefinition(eq("cacheableServiceSix"));
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(registeredRegionBeanNames.size()))
|
||||
.registerBeanDefinition(anyString(), any(BeanDefinition.class));
|
||||
|
||||
registeredRegionBeanNames.forEach(beanName -> {
|
||||
verify(mockBeanDefinitionRegistry, times(1)).containsBeanDefinition(eq(beanName));
|
||||
verify(mockBeanDefinitionRegistry, times(1))
|
||||
.registerBeanDefinition(eq(beanName), any(BeanDefinition.class));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void collectCacheNamesForCachePutOnCacheableServiceThreeRegistersRegionSixteenSeventeen() {
|
||||
public void cacheableServiceSevenRegistersRegionOneThroughEleven() {
|
||||
|
||||
assertThat(this.configuration.collectCacheNames(CacheableServiceThree.class, CachePut.class))
|
||||
.containsExactly("RegionSixteen", "RegionSeventeen");
|
||||
Map<String, BeanDefinition> registeredBeanDefinitions = MapBuilder.<String, BeanDefinition>newMapBuilder()
|
||||
.put("cacheableServiceSeven", mockBeanDefinition(CacheableServiceSeven.class))
|
||||
.build();
|
||||
|
||||
BeanDefinitionRegistry mockBeanDefinitionRegistry = mockBeanDefinitionRegistry(registeredBeanDefinitions);
|
||||
|
||||
this.configuration.registerBeanDefinitions(mockBeanDefinitionRegistry);
|
||||
|
||||
Set<String> registeredRegionBeanNames =
|
||||
asSet("RegionOne", "RegionTwo", "RegionThree", "RegionFour", "RegionFive", "RegionSix",
|
||||
"RegionSeven", "RegionEight", "RegionNine", "RegionTen", "RegionEleven");
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(1)).getBeanDefinitionNames();
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(1))
|
||||
.getBeanDefinition(eq("cacheableServiceSeven"));
|
||||
|
||||
verify(mockBeanDefinitionRegistry, times(registeredRegionBeanNames.size()))
|
||||
.registerBeanDefinition(anyString(), any(BeanDefinition.class));
|
||||
|
||||
registeredRegionBeanNames.forEach(beanName -> {
|
||||
verify(mockBeanDefinitionRegistry, times(1)).containsBeanDefinition(eq(beanName));
|
||||
verify(mockBeanDefinitionRegistry, times(1))
|
||||
.registerBeanDefinition(eq(beanName), any(BeanDefinition.class));
|
||||
});
|
||||
}
|
||||
|
||||
@Service
|
||||
@@ -450,4 +532,63 @@ public class EnableCachingDefinedRegionsUnitTests {
|
||||
public void cacheableMethodFive() {}
|
||||
|
||||
}
|
||||
|
||||
@CacheDefaults(cacheName = "RegionOne")
|
||||
@CacheRemoveAll(cacheName = "RegionSix")
|
||||
@CacheResult(cacheName = "RegionSeven")
|
||||
@SuppressWarnings("unused")
|
||||
static class CacheableServiceFive {
|
||||
|
||||
@javax.cache.annotation.CachePut(cacheName = "RegionTwo")
|
||||
public void cacheableMethodOne() {}
|
||||
|
||||
@CacheRemove(cacheName = "RegionThree")
|
||||
public void cacheableMethodTwo() {}
|
||||
|
||||
@CacheRemoveAll(cacheName = "RegionFour")
|
||||
public void cacheableMethodThree() {}
|
||||
|
||||
@CacheResult(cacheName = "RegionFive")
|
||||
public void cacheableMethodFour() {}
|
||||
|
||||
}
|
||||
|
||||
@CacheDefaults(cacheName = "RegionOne")
|
||||
@javax.cache.annotation.CachePut(cacheName = "RegionOne")
|
||||
@CacheRemoveAll(cacheName = "RegionFive")
|
||||
@SuppressWarnings("unused")
|
||||
static class CacheableServiceSix {
|
||||
|
||||
@javax.cache.annotation.CachePut(cacheName = "RegionTwo")
|
||||
@javax.cache.annotation.CacheResult(cacheName = "RegionOne")
|
||||
public void cacheableMethodOne() {}
|
||||
|
||||
@CacheRemove(cacheName = "RegionThree")
|
||||
public void cacheableMethodTwo() {}
|
||||
|
||||
@CacheRemoveAll(cacheName = "RegionThree")
|
||||
public void cacheableMethodThree() {}
|
||||
|
||||
@CacheResult(cacheName = "RegionFour")
|
||||
@CacheRemove(cacheName = "RegionFive")
|
||||
public void cacheableMethodFour() {}
|
||||
|
||||
}
|
||||
|
||||
@Caching(
|
||||
cacheable = { @Cacheable({ "RegionSix", "RegionSeven", "RegionEight" }), @Cacheable("RegionNine")},
|
||||
put = @CachePut("RegionTwo")
|
||||
)
|
||||
@CacheDefaults(cacheName = "RegionOne")
|
||||
static class CacheableServiceSeven extends CacheableServiceSix {
|
||||
|
||||
@CachePut("RegionTen")
|
||||
@CacheRemove(cacheName = "RegionFive")
|
||||
@CacheResult(cacheName = "RegionEleven")
|
||||
public void cacheableMethodFive() {}
|
||||
|
||||
@Cacheable("RegionThree")
|
||||
public void cacheableMethodSix() {}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.data.gemfire.util.CacheUtils.toRegionPath;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeList;
|
||||
import static org.springframework.data.gemfire.util.RegionUtils.toRegionPath;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -51,7 +51,6 @@ import org.apache.geode.cache.client.ClientRegionFactory;
|
||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
@@ -344,14 +343,11 @@ public class EnableEntityDefinedRegionsUnitTests {
|
||||
}
|
||||
|
||||
protected static <K, V> ClientCache mockClientCache() {
|
||||
|
||||
ClientCache mockClientCache = mock(ClientCache.class, mockName("ClientCache"));
|
||||
|
||||
Answer<ClientRegionFactory<K, V>> createClientRegionFactory = new Answer<ClientRegionFactory<K, V>>() {
|
||||
@Override @SuppressWarnings("unchecked")
|
||||
public ClientRegionFactory<K, V> answer(InvocationOnMock invocation) throws Throwable {
|
||||
return mockClientRegionFactory(invocation.getArgument(0));
|
||||
}
|
||||
};
|
||||
Answer<ClientRegionFactory<K, V>> createClientRegionFactory =
|
||||
invocation -> mockClientRegionFactory(invocation.getArgument(0));
|
||||
|
||||
when(mockClientCache.createClientRegionFactory(any(ClientRegionShortcut.class)))
|
||||
.thenAnswer(createClientRegionFactory);
|
||||
@@ -525,6 +521,7 @@ public class EnableEntityDefinedRegionsUnitTests {
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@SuppressWarnings("unused")
|
||||
protected static <T, R> Answer<R> newSetter(Class<T> parameterType, AtomicReference<T> argument, R returnValue) {
|
||||
|
||||
return invocation -> {
|
||||
|
||||
@@ -44,6 +44,7 @@ import org.junit.rules.ExpectedException;
|
||||
* Unit tests for {@link CollectionUtils}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.lang.Iterable
|
||||
* @see java.util.Collection
|
||||
* @see java.util.Collections
|
||||
* @see java.util.Enumeration
|
||||
@@ -63,6 +64,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void addAllIterableElementsToList() {
|
||||
|
||||
List<Integer> target = new ArrayList<>(Arrays.asList(1, 2, 3));
|
||||
Set<Integer> source = new HashSet<>(Arrays.asList(1, 2, 3));
|
||||
|
||||
@@ -75,6 +77,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void addAllIterableElementsToSet() {
|
||||
|
||||
Set<Integer> target = new HashSet<>(Arrays.asList(1, 2, 3));
|
||||
Set<Integer> source = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
|
||||
|
||||
@@ -87,15 +90,17 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void addIterableToNullCollection() {
|
||||
|
||||
exception.expect(IllegalArgumentException.class);
|
||||
exception.expectCause(is(nullValue(Throwable.class)));
|
||||
exception.expectMessage("Collection must not be null");
|
||||
exception.expectMessage("Collection is required");
|
||||
|
||||
CollectionUtils.addAll(null, Collections.emptySet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addEmptyIterableToCollection() {
|
||||
|
||||
Collection<Integer> target = new ArrayList<>(Arrays.asList(1, 2, 3));
|
||||
|
||||
target = CollectionUtils.addAll(target, Collections.emptyList());
|
||||
@@ -107,6 +112,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void addNullIterableToCollection() {
|
||||
|
||||
Collection<Integer> target = new ArrayList<>(Arrays.asList(1, 2, 3));
|
||||
|
||||
target = CollectionUtils.addAll(target, null);
|
||||
@@ -118,6 +124,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void asSetContainsAllArrayElements() {
|
||||
|
||||
Object[] elements = { "a", "b", "c" };
|
||||
|
||||
Set<?> set = CollectionUtils.asSet(elements);
|
||||
@@ -129,6 +136,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void asSetContainsUniqueArrayElements() {
|
||||
|
||||
Object[] elements = { 1, 2, 1 };
|
||||
|
||||
Set<?> set = CollectionUtils.asSet(elements);
|
||||
@@ -140,6 +148,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void asSetReturnsUnmodifiableSet() {
|
||||
|
||||
Set<Integer> set = CollectionUtils.asSet(1, 2, 3);
|
||||
|
||||
assertThat(set).isNotNull();
|
||||
@@ -176,36 +185,9 @@ public class CollectionUtilsUnitTests {
|
||||
assertThat(CollectionUtils.containsAny(null, 1)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultIfEmptyWithNonNullNonEmptyIterableReturnsIterable() {
|
||||
Iterable<Object> iterable = Collections.singleton(1);
|
||||
Iterable<Object> defaultIterable = Collections.singleton(2);
|
||||
|
||||
assertThat(CollectionUtils.defaultIfEmpty(iterable, defaultIterable)).isSameAs(iterable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultIfEmptyWithEmptyIterableReturnsDefault() {
|
||||
Iterable<Object> iterable = Collections.emptySet();
|
||||
Iterable<Object> defaultIterable = Collections.singleton(2);
|
||||
|
||||
assertThat(CollectionUtils.defaultIfEmpty(iterable, defaultIterable)).isSameAs(defaultIterable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultIfEmptyWithNullIterableReturnsDefault() {
|
||||
Iterable<?> defaultIterable = Collections.singleton(2);
|
||||
|
||||
assertThat(CollectionUtils.defaultIfEmpty(null, defaultIterable)).isSameAs(defaultIterable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultIfEmptyWithNullIterableAndNullDefaultReturnsNull() {
|
||||
assertThat(CollectionUtils.defaultIfEmpty((Iterable<?>) null, null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyIterableReturnsEmptyIterable() {
|
||||
|
||||
Iterable<?> iterable = CollectionUtils.emptyIterable();
|
||||
|
||||
assertThat(iterable).isNotNull();
|
||||
@@ -216,6 +198,7 @@ public class CollectionUtilsUnitTests {
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void iterableEnumeration() {
|
||||
|
||||
Enumeration<String> mockEnumeration = mock(Enumeration.class, "MockEnumeration");
|
||||
|
||||
when(mockEnumeration.hasMoreElements()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false);
|
||||
@@ -241,6 +224,7 @@ public class CollectionUtilsUnitTests {
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void iterableIterator() {
|
||||
|
||||
Iterator<String> mockIterator = mock(Iterator.class, "MockIterator");
|
||||
|
||||
when(mockIterator.hasNext()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false);
|
||||
@@ -265,6 +249,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void nullSafeCollectionWithNonNullCollection() {
|
||||
|
||||
Collection<?> mockCollection = mock(Collection.class);
|
||||
|
||||
assertThat(CollectionUtils.nullSafeCollection(mockCollection)).isSameAs(mockCollection);
|
||||
@@ -272,6 +257,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void nullSafeCollectionWithNullCollection() {
|
||||
|
||||
Collection collection = CollectionUtils.nullSafeCollection(null);
|
||||
|
||||
assertThat(collection).isNotNull();
|
||||
@@ -281,6 +267,7 @@ public class CollectionUtilsUnitTests {
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void nullSafeIterableWithNonNullIterable() {
|
||||
|
||||
Iterable<Object> mockIterable = mock(Iterable.class);
|
||||
|
||||
assertThat(CollectionUtils.nullSafeIterable(mockIterable)).isSameAs(mockIterable);
|
||||
@@ -288,6 +275,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void nullSafeIterableWithNullIterable() {
|
||||
|
||||
Iterable<Object> iterable = CollectionUtils.nullSafeIterable(null);
|
||||
|
||||
assertThat(iterable).isNotNull();
|
||||
@@ -295,8 +283,10 @@ public class CollectionUtilsUnitTests {
|
||||
assertThat(iterable.iterator().hasNext()).isFalse();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void nullSafeIterableIterator() {
|
||||
|
||||
Iterable<Object> iterable = CollectionUtils.nullSafeIterable(null);
|
||||
|
||||
assertThat(iterable).isNotNull();
|
||||
@@ -323,8 +313,40 @@ public class CollectionUtilsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullSafeIterableWithNonNullNonEmptyIterableReturnsIterable() {
|
||||
|
||||
Iterable<Object> iterable = Collections.singleton(1);
|
||||
Iterable<Object> defaultIterable = Collections.singleton(2);
|
||||
|
||||
assertThat(CollectionUtils.nullSafeIterable(iterable, defaultIterable)).isSameAs(iterable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullSafeIterableWithEmptyIterableReturnsDefault() {
|
||||
|
||||
Iterable<Object> iterable = Collections.emptySet();
|
||||
Iterable<Object> defaultIterable = Collections.singleton(2);
|
||||
|
||||
assertThat(CollectionUtils.nullSafeIterable(iterable, defaultIterable)).isSameAs(defaultIterable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullSafeIterableWithNullIterableReturnsDefault() {
|
||||
|
||||
Iterable<?> defaultIterable = Collections.singleton(2);
|
||||
|
||||
assertThat(CollectionUtils.nullSafeIterable(null, defaultIterable)).isSameAs(defaultIterable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullSafeIterableWithNullIterableAndNullDefaultReturnsNull() {
|
||||
assertThat(CollectionUtils.nullSafeIterable((Iterable<?>) null, null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullSafeListWithNonNullList() {
|
||||
|
||||
List<?> mockList = mock(List.class);
|
||||
|
||||
assertThat(CollectionUtils.nullSafeList(mockList)).isSameAs(mockList);
|
||||
@@ -332,6 +354,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void nullSafeListWithNullList() {
|
||||
|
||||
List<?> list = CollectionUtils.nullSafeList(null);
|
||||
|
||||
assertThat(list).isNotNull();
|
||||
@@ -340,6 +363,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void nullSafeMapWithNonNullMap() {
|
||||
|
||||
Map<?, ?> mockMap = mock(Map.class);
|
||||
|
||||
assertThat(CollectionUtils.nullSafeMap(mockMap)).isSameAs(mockMap);
|
||||
@@ -347,6 +371,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void nullSafeMapWithNullMap() {
|
||||
|
||||
Map<?, ?> map = CollectionUtils.nullSafeMap(null);
|
||||
|
||||
assertThat(map).isNotNull();
|
||||
@@ -355,6 +380,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void nullSafeSetWithNonNullSet() {
|
||||
|
||||
Set<?> mockSet = mock(Set.class);
|
||||
|
||||
assertThat(CollectionUtils.nullSafeSet(mockSet)).isSameAs(mockSet);
|
||||
@@ -362,6 +388,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void nullSafeSetWithNullSet() {
|
||||
|
||||
Set<?> set = CollectionUtils.nullSafeSet(null);
|
||||
|
||||
assertThat(set).isNotNull();
|
||||
@@ -370,6 +397,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void sortIsSuccessful() {
|
||||
|
||||
List<Integer> list = new ArrayList<Integer>(Arrays.asList(2, 3, 1));
|
||||
List<Integer> sortedList = CollectionUtils.sort(list);
|
||||
|
||||
@@ -379,6 +407,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void subListFromListWithIndexesReturnsSubList() {
|
||||
|
||||
List<Integer> list = Arrays.asList(0, 1, 2, 3);
|
||||
List<Integer> subList = CollectionUtils.subList(list, 1, 3);
|
||||
|
||||
@@ -390,6 +419,7 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void subListFromListWithNoIndexesReturnsEmptyList() {
|
||||
|
||||
List<Integer> subList = CollectionUtils.subList(Arrays.asList(0, 1, 2));
|
||||
|
||||
assertThat(subList).isNotNull();
|
||||
@@ -403,9 +433,10 @@ public class CollectionUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void subListWithNullSourceListThrowsIllegalArgumentException() {
|
||||
|
||||
exception.expect(IllegalArgumentException.class);
|
||||
exception.expectCause(is(nullValue(Throwable.class)));
|
||||
exception.expectMessage("List must not be null");
|
||||
exception.expectMessage("List is required");
|
||||
|
||||
CollectionUtils.subList(null, 1, 2, 3);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.data.gemfire.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link StreamUtils}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.stream.Stream
|
||||
* @see org.junit.Test
|
||||
* @see org.springframework.data.gemfire.util.StreamUtils
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class StreamUtilsTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void concatNoStreams() {
|
||||
|
||||
Stream<Object> stream = StreamUtils.concat();
|
||||
|
||||
assertThat(stream).isNotNull();
|
||||
assertThat(stream.count()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void concatOneStream() {
|
||||
|
||||
Stream<Integer> stream = StreamUtils.concat(Stream.of(1, 2, 3));
|
||||
|
||||
assertThat(stream).isNotNull();
|
||||
assertThat(stream.collect(Collectors.toList())).containsExactly(1, 2, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void concatTwoStreams() {
|
||||
|
||||
Stream<Integer> stream = StreamUtils.concat(Stream.of(1, 2, 3), Stream.of(4, 5, 6));
|
||||
|
||||
assertThat(stream).isNotNull();
|
||||
assertThat(stream.collect(Collectors.toList())).containsExactly(1, 2, 3, 4, 5, 6);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void concatThreeStreams() {
|
||||
|
||||
Stream<Integer> stream =
|
||||
StreamUtils.concat(Stream.of(1, 2, 3), Stream.of(4, 5, 6), Stream.of(7, 8, 9));
|
||||
|
||||
assertThat(stream).isNotNull();
|
||||
assertThat(stream.collect(Collectors.toList())).containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user