Spring Boot Geode Unsatisfied dependency expressed through method 'sessionRegion'

1.3k Views Asked by At

The correct dependencies for my gradle.build are driving me crazy!

In order to access an Apache Geode 1.10 server, I am using:

// Geode client dependency
implementation 'org.springframework.geode:spring-geode-starter:1.2.13.RELEASE'    
implementation 'org.springframework.data:spring-data-geode:2.2.12.RELEASE' 
implementation 'org.springframework.boot:spring-boot-starter-tomcat:2.2.13.RELEASE' 

This fails with the error:

org.springframework.context.support.AbstractApplicationContext 596 refresh: 
Exception encountered during context initialization - cancelling refresh attempt:
org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'ClusteredSpringSessions' defined in class path resource 
[org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfiguration.class]: 
Unsatisfied dependency expressed through method 'sessionRegion' parameter 0; 
nested exception is org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'org.springframework.data.gemfire.config.annotation.ClientCacheConfiguration': 
Initialization of bean failed; nested exception is java.lang.IllegalAccessError: 
class org.springframework.data.gemfire.config.annotation.AbstractCacheConfiguration$$Lambda$703/0x0000000801025d10 
tried to access protected method 'boolean org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport.hasValue(java.lang.Number)' 
(org.springframework.data.gemfire.config.annotation.AbstractCacheConfiguration$$Lambda$703/0x0000000801025d10 
and org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport are in unnamed module of loader 'app')

What is there to tell me the dependency missing for the UnsatisfiedDependencyException for 'ClusteredSpringSessions'?

If I remove the @EnableGemFireHttpSession annotation then I get the error

2021-02-02T19:29:49,011 WARN  [main] org.springframework.context.support.AbstractApplicationContext 596 refresh: 
Exception encountered during context initialization - cancelling refresh attempt:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'cacheManager' defined in class path resource [org/springframework/data/gemfire/cache/config/GemfireCachingConfiguration.class]:
Unsatisfied dependency expressed through method 'cacheManager' parameter 0; 
nested exception is org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'org.springframework.data.gemfire.config.annotation.ClientCacheConfiguration': 
Initialization of bean failed; nested exception is java.lang.IllegalAccessError: 
class org.springframework.data.gemfire.config.annotation.AbstractCacheConfiguration$$Lambda$679/0x00000008010306b8 
tried to access protected method 'boolean org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport.hasValue(java.lang.Number)'
(org.springframework.data.gemfire.config.annotation.AbstractCacheConfiguration$$Lambda$679/0x00000008010306b8 
and org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport are in unnamed module of loader 'app')

What is there to tell me the dependency missing for the UnsatisfiedDependencyException for 'cacheManager'?

Thanks

UPDATE The App is run like Spring Boot @ComponentScan finds candidate component class but does not inject @Configuration beans but more specifically

@SpringBootApplication
@ComponentScan({"api", "rsocket", "pricing", "listeners", "dealing", "web"}) // scans packages for @ components
@EnableLogging(logLevel="debug", logFile="geodeApi.log")
public class Api {
    
    private static final Logger log = LogManager.getLogger(Api.class);

    public static void main(String[] args) {
        log.info("In Main");
        
        SpringApplication app = new SpringApplication(Api.class);
        app.setWebApplicationType(WebApplicationType.REACTIVE);
        SpringApplication.run(Api.class, args);
        
        log.info("Out Main");
    }
}

The component scan finds various @Component annotated classes for example

@Component
@EnableClusterDefinedRegions(clientRegionShortcut=ClientRegionShortcut.PROXY)
public class ClientCache {
    
    private static final Logger log = LogManager.getLogger(ClientCache.class);
    
    @Resource
    private Region<String, String> admin;
    
    @Autowired
    LQuote lQuote;
    
    @Autowired
    LReject lReject;    
    
    @Autowired
    LDeal lDeal;
    
    @Autowired
    DealNumber dealNumber;
    
    @Autowired
    PriceService priceService;
    
    @PreDestroy
    public void onDestroy() throws Exception {
        
        log.info("onDestroy");
        
        String guid = UUID.randomUUID().toString().substring(0, 8).toUpperCase();           
        admin.put(guid, "API Shutdown");
        
        // TODO: Cancel all open quote streams
        
        log.traceExit();
    }
    
    @Bean
    ApplicationRunner StartedUp(){      
        log.traceEntry("StartedUp");
            
        return args -> {            
        String guid = UUID.randomUUID().toString().substring(0, 8).toUpperCase();       
        admin.put(guid, "API Started");
        
        lQuote.addListener();
        lReject.addListener();
        lDeal.addListener();
        
        // Get latest deal number
        int currentId = dealNumber.readCurrentId();
        
        // Set it + 1 in case the web server was reboot on the fly
        priceService.setCurrentId(currentId + 1);

        log.traceExit();
    };
}
2

There are 2 best solutions below

0
On BEST ANSWER

A lot of the problem was using Java JDK version 15. The correct versions require Java 11.

// Geode client dependency
implementation 'org.springframework.geode:spring-geode-starter:1.2.8.RELEASE'    
implementation 'org.springframework.data:spring-data-geode:2.2.8.RELEASE' 
implementation 'org.springframework.boot:spring-boot-starter-tomcat'
8
On

Technically, it is not necessary to explicitly declare the SDG dependency.

The SBDG dependency (i.e. org.springframework.geode:spring-geode-starter) already includes SDG (org.springframework.data:spring-data-geode). You can follow the dependency trail starting here, then here and finally, here.

As the Version Compatibility Matrix for SBDG specifies, SBDG 1.2.13.RELEASE specifically includes, and is based on, SDG 2.2.12.RELEASE (already), which is (technically) based on Apache Geode 1.9.2.

However, if you need to use Apache Geode 1.10, then you could (recommended) simply declare dependency management to enforce the use of Apache Geode 1.10 in your Gradle build:

plugins {
  id 'org.springframework.boot' version '2.2.13.RELEASE'
  id 'io.spring.dependency-management' version '1.0.10.RELEASE'
  id 'java'
}

dependencyManagement {
  dependencies {
    dependency 'org.apache.geode:geode-core:1.10.0'
    dependency 'org.apache.geode:geode-cq:1.10.0'
    dependency 'org.apache.geode:geode-lucene:1.10.0'
    dependency 'org.apache.geode:geode-wan:1.10.0'
  }
}

dependencies {
  implementation 'org.springframework.geode:spring-geode-starter:1.2.13.RELEASE`
  implementation 'org.springframework.boot:spring-boot-starter-tomcat' 
}

...

WARNING: SDG 2.2.12.RELEASE is officially based on Apache Geode 1.9.2, and though it should work reasonably well with Apache Geode 1.10, there could expectedly be limitations in certain use cases.

This is not unlike what Spring Initializer conveniently generates for you. Of course, Spring Initializer now uses the new SBDG BOM that makes managing individual SBDG module dependencies even easier, which is not unlike how Spring Boot's dependency management manages transitive dependencies, including 3rd party libs.

Regarding the Exceptions...

It really seems to me like you are having configuration problems rather than dependency problems, actually.

Of course, it is hard to say for certain given you shared very minimal Gradle build configuration and no code snippets from your Spring Boot application configuration, only mentions and what I am able to derive from the Exception messages. So, for now, I'll proceed based on what you provided and what I know or could derive.

Looking at this part of the (first) Exception message:

Error creating bean with name 'ClusteredSpringSessions' defined in class path resource 
[org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfiguration.class]: 
Unsatisfied dependency expressed through method 'sessionRegion' parameter 0

And, specifically:

Unsatisfied dependency expressed through method 'sessionRegion' parameter 0

This message refers to the (Spring Java) configuration provided by SSDG and imported/auto-configured by SBDG.

The "Unsatisfied dependency", or "parameter 0", is the 1st method parameter in the sessionRegion(..) (Spring JavaConfig-based) @Bean definition method declared in SSDG's configuration. It is the dependency on the GemFire cache instance (e.g. ClientCache) required to create the "ClusteredSpringSessions" Region.

So now, the question becomes, how is the cache created?

Well, this is what the framework is trying to do next... resolve the cache bean dependency (instance reference), which necessary triggers the cache creation first (due to dependency order)...

Error creating bean with name 'org.springframework.data.gemfire.config.annotation.ClientCacheConfiguration': 
Initialization of bean failed; nested exception is java.lang.IllegalAccessError

We see that an IllegalAccessError occurred (O.o) which already smells like a version problem to me, but...

The ClientCacheConfiguration is provided by SDG.

Finally, we arrive at the underlying cause...

class org.springframework.data.gemfire.config.annotation.AbstractCacheConfiguration$$Lambda$703/0x0000000801025d10 
tried to access protected method 'boolean org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport.hasValue(java.lang.Number)'

NOTE: ClientCacheConfiguration extends AbstractCacheConfiguration, which extends AbstractAnnotationConfigSupport, and therefore should have "access" to the protected hasValue(:Number) method.

The main Thread appears to be in one of these Lambdas where the AbstractAnnotationConfig.hasValue(:Number) method is used.

I am no entirely sure what this means...

org.springframework.data.gemfire.config.annotation.AbstractCacheConfiguration$$Lambda$703/0x0000000801025d10 
and org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport are in unnamed module of loader 'app'

Are you possibly using Spring Boot's new (Layered) Docker Image support by chance?

The 2nd Exception message (involving the cacheManager bean this time) leads to the same outcome, actually. It is no different, but simply involves another bean (i.e. cacheManager bean) with the same dependency on the cache instance:

Error creating bean with name 'cacheManager' defined in class path resource 
[org/springframework/data/gemfire/cache/config/GemfireCachingConfiguration.class]
: Unsatisfied dependency expressed through method 'cacheManager' parameter 0; 
nested exception is org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'org.springframework.data.gemfire.config.annotation.ClientCacheConfiguration': 
Initialization of bean failed; nested exception is java.lang.IllegalAccessError: 
class org.springframework.data.gemfire.config.annotation.AbstractCacheConfiguration$$Lambda$679/0x00000008010306b8 
tried to access protected method 'boolean org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport.hasValue(java.lang.Number)'
(org.springframework.data.gemfire.config.annotation.AbstractCacheConfiguration$$Lambda$679/0x00000008010306b8 
and org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport are in unnamed module of loader 'app')

And, specifically:

Initialization of bean failed; nested exception is java.lang.IllegalAccessError: 

tried to access protected method 'boolean org.springframework.data.gemfire
 .config.annotation.support.AbstractAnnotationConfigSupport
    .hasValue(java.lang.Number)'

And:

(org.springframework.data.gemfire.config.annotation.AbstractCacheConfiguration$$Lambda$679/0x00000008010306b8 
and org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport 

are in unnamed module of loader 'app')

I am not familiar with this error messages (basically, said class(es) "are in unnamed module of loader 'app'.") What?

How is this Spring Boot app being run?

Definitely providing a sample app, one or more tests, your configuration, logs, Stack Traces in addition to Exception messages, setup, runtime environment, etc, etc, will go along way in trying to understand the context of this problem.

At this point, I am really trying to point you in a direction to start untangling the problem.

Sorry, I cannot (currently) be of more help in this case.