diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/IndexConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/IndexConfiguration.java index b17f5846..e74d91ed 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/IndexConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/IndexConfiguration.java @@ -181,10 +181,8 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration { indexFactoryBeanBuilder.addPropertyValue("name", indexName); - /* indexFactoryBeanBuilder.addPropertyValue("override", resolveOverride(persistentEntity, persistentProperty, indexedAttributes)); - */ indexFactoryBeanBuilder.addPropertyValue("type", resolveType(persistentEntity, persistentProperty, indexedAttributes, indexType).toString()); @@ -289,7 +287,6 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration { } /* (non-Javadoc) */ - /* @SuppressWarnings("unused") private boolean resolveOverride(GemfirePersistentEntity persistentEntity, GemfirePersistentProperty persistentProperty, AnnotationAttributes indexedAttributes) { @@ -297,7 +294,6 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration { return (indexedAttributes.containsKey("override") && indexedAttributes.getBoolean("override")); } - */ /* (non-Javadoc) */ @SuppressWarnings("unused") diff --git a/src/main/java/org/springframework/data/gemfire/mapping/annotation/Indexed.java b/src/main/java/org/springframework/data/gemfire/mapping/annotation/Indexed.java index 043c7b21..1d5a7184 100644 --- a/src/main/java/org/springframework/data/gemfire/mapping/annotation/Indexed.java +++ b/src/main/java/org/springframework/data/gemfire/mapping/annotation/Indexed.java @@ -70,6 +70,13 @@ public @interface Indexed { */ String from() default ""; + /** + * Determines whether this given {@link Index} definition should override any existing {@link Index} definition. + * + * Defaults to {@literal false}. + */ + boolean override() default false; + /** * Type of Index to create. * diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/EnableIndexesConfigurationUnitTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/EnableIndexesConfigurationUnitTests.java index be018836..c63dabff 100644 --- a/src/test/java/org/springframework/data/gemfire/config/annotation/EnableIndexesConfigurationUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/EnableIndexesConfigurationUnitTests.java @@ -25,10 +25,13 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.util.HashSet; import java.util.Map; import java.util.Optional; +import java.util.Set; import org.apache.geode.cache.Cache; +import org.apache.geode.cache.GemFireCache; import org.apache.geode.cache.RegionAttributes; import org.apache.geode.cache.RegionFactory; import org.apache.geode.cache.RegionShortcut; @@ -47,6 +50,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; +import org.springframework.data.gemfire.IndexFactoryBean; import org.springframework.data.gemfire.IndexType; import org.springframework.data.gemfire.config.annotation.test.entities.ClientRegionEntity; import org.springframework.data.gemfire.config.annotation.test.entities.CollocatedPartitionRegionEntity; @@ -67,11 +71,14 @@ import org.springframework.data.gemfire.config.annotation.test.entities.Replicat */ public class EnableIndexesConfigurationUnitTests { + private static final Set indexes = new HashSet<>(); + private ConfigurableApplicationContext applicationContext; @After public void tearDown() { Optional.ofNullable(this.applicationContext).ifPresent(ConfigurableApplicationContext::close); + indexes.clear(); } /* (non-Javadoc) */ @@ -113,7 +120,7 @@ public class EnableIndexesConfigurationUnitTests { assertLuceneIndex(luceneIndex, "TitleLuceneIdx", "Customers", "title"); } - protected void assertOqlIndexes(ConfigurableApplicationContext applicationContext) { + private void assertOqlIndexes(ConfigurableApplicationContext applicationContext) { Index customersIdIdx = applicationContext.getBean("CustomersIdKeyIdx", Index.class); assertIndex(customersIdIdx, "CustomersIdKeyIdx", "id", "Customers", IndexType.KEY); @@ -125,11 +132,11 @@ public class EnableIndexesConfigurationUnitTests { Index lastNameIdx = applicationContext.getBean("LastNameIdx", Index.class); - assertIndex(lastNameIdx, "LastNameIdx", "lastName", "Customers", IndexType.HASH); + assertIndex(lastNameIdx, "LastNameIdx", "surname", "Customers", IndexType.HASH); } @Test - public void noIndexesCreatedForIndexedPersistentEntities() { + public void persistentEntityIndexesWillNotBeCreated() { applicationContext = newApplicationContext(NoIndexesCreatedForIndexedPersistentEntityConfiguration.class); Map indexes = applicationContext.getBeansOfType(Index.class); @@ -138,6 +145,25 @@ public class EnableIndexesConfigurationUnitTests { assertThat(indexes.isEmpty()).isTrue(); } + @Test + public void indexAnnotatedEntityPropertyDoesNotOverrideIndexBeanDefinition() { + applicationContext = newApplicationContext(IndexAnnotatedEntityPropertyDoesNotOverrideBeanDefinitionConfiguration.class); + + Index lastNameIdx = applicationContext.getBean("LastNameIdx", Index.class); + + assertIndex(lastNameIdx, "LastNameIdx", "last_name", "/People", IndexType.HASH); + } + + @Test + public void indexAnnotatedEntityPropertyOverridesIndexBeanDefinition() { + applicationContext = newApplicationContext(IndexAnnotatedEntityPropertyOverridesIndexBeanDefinitionConfiguration.class); + + Index customersFirstNameIdx = applicationContext.getBean("CustomersFirstNameFunctionalIdx", Index.class); + + assertIndex(customersFirstNameIdx, "CustomersFirstNameFunctionalIdx", + "first_name", "/LoyalCustomers", IndexType.FUNCTIONAL); + } + @Configuration @SuppressWarnings("unused") static class GemFireConfiguration { @@ -145,13 +171,14 @@ public class EnableIndexesConfigurationUnitTests { @Bean @SuppressWarnings("unchecked") Cache gemfireCache() throws Exception { - return mockQueryService(mockRegionFactory(mock(Cache.class))); + return mockQueryService(mockRegionFactory(mock(Cache.class, "MockGemFireCache"))); } Cache mockQueryService(Cache mockCache) throws Exception { QueryService mockQueryService = mock(QueryService.class); when(mockCache.getQueryService()).thenReturn(mockQueryService); + when(mockQueryService.getIndexes()).thenReturn(indexes); when(mockQueryService.createHashIndex(anyString(), anyString(), anyString())) .thenAnswer(new HashIndexAnswer()); @@ -221,6 +248,8 @@ public class EnableIndexesConfigurationUnitTests { when(mockIndex.getFromClause()).thenReturn(from); when(mockIndex.getType()).thenReturn(getType().getGemfireIndexType()); + indexes.add(mockIndex); + return mockIndex; } @@ -268,4 +297,48 @@ public class EnableIndexesConfigurationUnitTests { static class NoIndexesCreatedForIndexedPersistentEntityConfiguration extends GemFireConfiguration { } + + @EnableIndexes + @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, + excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = { + ClientRegionEntity.class, CollocatedPartitionRegionEntity.class, GenericRegionEntity.class, + LocalRegionEntity.class, ReplicateRegionEntity.class })) + static class IndexAnnotatedEntityPropertyDoesNotOverrideBeanDefinitionConfiguration extends GemFireConfiguration { + + @Bean + @SuppressWarnings("unused") + IndexFactoryBean lastNameIndex(GemFireCache gemfireCache) { + IndexFactoryBean lastNameIndex = new IndexFactoryBean(); + + lastNameIndex.setCache(gemfireCache); + lastNameIndex.setExpression("last_name"); + lastNameIndex.setFrom("/People"); + lastNameIndex.setName("LastNameIdx"); + lastNameIndex.setType(IndexType.HASH); + + return lastNameIndex; + } + } + + @EnableIndexes + @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, + excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = { + ClientRegionEntity.class, CollocatedPartitionRegionEntity.class, GenericRegionEntity.class, + LocalRegionEntity.class, ReplicateRegionEntity.class })) + static class IndexAnnotatedEntityPropertyOverridesIndexBeanDefinitionConfiguration extends GemFireConfiguration { + + @Bean + @SuppressWarnings("unused") + IndexFactoryBean firstNameIndex(GemFireCache gemfireCache) { + IndexFactoryBean firstNameIndex = new IndexFactoryBean(); + + firstNameIndex.setCache(gemfireCache); + firstNameIndex.setExpression("given_name"); + firstNameIndex.setFrom("/ProspectiveCustomers"); + firstNameIndex.setName("CustomersFirstNameFunctionalIdx"); + firstNameIndex.setType(IndexType.HASH); + + return firstNameIndex; + } + } } diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/test/entities/PartitionRegionEntity.java b/src/test/java/org/springframework/data/gemfire/config/annotation/test/entities/PartitionRegionEntity.java index ea527af2..a88dc4ec 100644 --- a/src/test/java/org/springframework/data/gemfire/config/annotation/test/entities/PartitionRegionEntity.java +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/test/entities/PartitionRegionEntity.java @@ -42,10 +42,10 @@ public class PartitionRegionEntity { @Id private Long id; - @Indexed(expression = "first_name", from = "/LoyalCustomers", type = IndexType.FUNCTIONAL) + @Indexed(expression = "first_name", from = "/LoyalCustomers", override = true, type = IndexType.FUNCTIONAL) private String firstName; - @Indexed(name = "LastNameIdx") + @Indexed(name = "LastNameIdx", expression = "surname") private String lastName; @LuceneIndexed("TitleLuceneIdx")