spring-projects / spring-data-geode

Spring Data support for Apache Geode
Apache License 2.0
50 stars 38 forks source link

From clause Region path error occurs when creating Indexes from application domain object fields annotated with @Indexed or @Id [DATAGEODE-68] #118

Closed spring-projects-issues closed 6 years ago

spring-projects-issues commented 6 years ago

John Blum opened DATAGEODE-68 and commented

When defining Indexes via SDG mapping annotations on application domain object properties/fields without an explicit from clause specified, as in...

@Region("Customers")
class Customer {

    @Id
    Long id;

    @Indexed
    String name;

    ...
}

Rather than...

@Region("Customers")
class Customer {

    @Id
    Long id;

    @Indexed(from = "/Customers")
    String name;

    ...
}

The Spring container, and specifically Apache Geode fails to bootstrap and initialize properly, which is caused by the following Exception...

Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2017-11-27 12:58:00.121 ERROR 57544 --- [           main] o.s.boot.SpringApplication               : Application startup failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'CustomersIdKeyIdx': Invocation of init method failed; nested exception is org.springframework.data.gemfire.GemfireIndexException: Failed to create Index [{ name = 'CustomersIdKeyIdx', expression = 'id', from = 'Customers', imports = 'null', type = KEY }]; nested exception is org.apache.geode.cache.query.RegionNotFoundException: DefaultQueryService::createIndex:First Iterator of Index >From Clause does not evaluate to a Region Path. The from clause used for Index creation is  Customers
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1710) ~[spring-beans-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:583) ~[spring-beans-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502) ~[spring-beans-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312) ~[spring-beans-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310) ~[spring-beans-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:742) ~[spring-beans-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:868) ~[spring-context-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
    at example.app.SpringBootApacheGeodeClientApplication.main(SpringBootApacheGeodeClientApplication.java:33) [classes/:na]
Caused by: org.springframework.data.gemfire.GemfireIndexException: Failed to create Index [{ name = 'CustomersIdKeyIdx', expression = 'id', from = 'Customers', imports = 'null', type = KEY }]; nested exception is org.apache.geode.cache.query.RegionNotFoundException: DefaultQueryService::createIndex:First Iterator of Index >From Clause does not evaluate to a Region Path. The from clause used for Index creation is  Customers
    at org.springframework.data.gemfire.IndexFactoryBean.createIndex(IndexFactoryBean.java:340) ~[spring-data-geode-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.data.gemfire.IndexFactoryBean.createIndex(IndexFactoryBean.java:234) ~[spring-data-geode-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.data.gemfire.IndexFactoryBean.afterPropertiesSet(IndexFactoryBean.java:120) ~[spring-data-geode-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1769) ~[spring-beans-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1706) ~[spring-beans-5.0.2.RELEASE.jar:5.0.2.RELEASE]
    ... 15 common frames omitted
Caused by: org.apache.geode.cache.query.RegionNotFoundException: DefaultQueryService::createIndex:First Iterator of Index >From Clause does not evaluate to a Region Path. The from clause used for Index creation is  Customers
    at org.apache.geode.cache.query.internal.DefaultQueryService.getRegionFromPath(DefaultQueryService.java:236) ~[geode-core-1.2.1.jar:na]
    at org.apache.geode.cache.query.internal.DefaultQueryService.createIndex(DefaultQueryService.java:168) ~[geode-core-1.2.1.jar:na]
    at org.apache.geode.cache.query.internal.DefaultQueryService.createIndex(DefaultQueryService.java:153) ~[geode-core-1.2.1.jar:na]
    at org.apache.geode.cache.query.internal.DefaultQueryService.createIndex(DefaultQueryService.java:218) ~[geode-core-1.2.1.jar:na]
    at org.apache.geode.cache.query.internal.DefaultQueryService.createKeyIndex(DefaultQueryService.java:141) ~[geode-core-1.2.1.jar:na]
    at org.springframework.data.gemfire.IndexFactoryBean.createKeyIndex(IndexFactoryBean.java:438) ~[spring-data-geode-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.data.gemfire.IndexFactoryBean.createIndex(IndexFactoryBean.java:248) ~[spring-data-geode-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    ... 19 common frames omitted

Affects: 2.0.2 (Kay SR2)

Referenced from: commits https://github.com/spring-projects/spring-data-gemfire/commit/c3b55ef2b7ca94f5d527248e58c9b6ed4f204806, https://github.com/spring-projects/spring-data-gemfire/commit/d9834794e538d73790efccd3ad22df4ed0b7ab99

Backported to: 2.0.3 (Kay SR3)

spring-projects-issues commented 6 years ago

John Blum commented

The workaround to this bug is to either 1) forgo using the SDG @EnableIndexing configuration annotation and resort to explicit Spring bean definitions for Indexes, like so...

@Bean
@DependsOn("Customers")
public IndexFactoryBean customersNameIndex(GemFireCache gemfireCache) {

    IndexFactoryBean customerNameIndex = new IndexFactoryBean();

    customerNameIndex.setCache(gemfireCache);
    customerNameIndex.setName("CustomersNameIdx");
    customerNameIndex.setExpression("name");
    customerNameIndex.setFrom("/Customers");

    return customerNameIndex;
}

2) Alternatively, a user can drop the explicit Spring Data @Id annotation on the application domain object identifier field or property as well as to explicitly call out the from clause on any @Indexed application domain object field or property, like so...

@Region("Customers")
class Customer {

    Long id;

    @Indexed(from = "/Customers")
    String name;

    ...
}

It is more than likely a bug in Apache Geode that it does not recognize the Region name (i.e. "Customers") and you must explicitly specify the Region "path" in the "from clause" of the Index definition.

Fortunately, SDG properly identifies the "identifier" field or property of your application domain objects without explicitly marking the field or property with the Spring Data org.springframework.data.annotation.Id providing the identifier is named "id", or the domain object JavaBean property is "getId()" and "setId(..)", respectively.