Hello,

When using external Cassandra config ( datastax-java-driver { ... } ) on a reactive project it fails with exception: config:

spring:
  cassandra:
    config: cassandra.conf

Exception:

Caused by: java.io.FileNotFoundException: ReactiveWebContext resource [cassandra.conf] cannot be resolved to URL
    at org.springframework.core.io.AbstractResource.getURL(AbstractResource.java:108)
    at org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration.loadConfig(CassandraAutoConfiguration.java:187)
    ... 124 common frames omitted

The reason seems to be that in a reactive project resources are of type FilteredReactiveWebContextResource that do not implement getURL().

Then it fails in CassandraAutoConfiguration.

I would expect that such scenario would be possible.

As workaround we can use the following, but I would still expect it to work by default like in a non-reactive context:

spring:
  cassandra:
    config: classpath:cassandra.conf

Thanks

Comment From: scottfrederick

@ncheutin I have not been able to reproduce this issue by modifying existing tests that verify setup similar to this. If you would like us to spend some time investigating, please provide a complete minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it and attaching it to this issue.

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: ncheutin

@scottfrederick apologies for the delay. Attaching a demo project reproducing it. cassandra-reactive-demo.zip

Comment From: scottfrederick

@ncheutin Thanks for the sample.

As workaround we can use the following, but I would still expect it to work by default like in a non-reactive context:

Changing your sample to use non-reactive results in a similar failure. Changing these two lines in build.gradle.kts:

    implementation("org.springframework.boot:spring-boot-starter-data-cassandra-reactive")
    implementation("org.springframework.boot:spring-boot-starter-webflux")

to this:

    implementation("org.springframework.boot:spring-boot-starter-data-cassandra")
    implementation("org.springframework.boot:spring-boot-starter-web")

Results in the failure:

Caused by: java.io.FileNotFoundException: ServletContext resource [/cassandra.conf] cannot be resolved to URL because it does not exist
    at org.springframework.web.context.support.ServletContextResource.getURL(ServletContextResource.java:179)
    at org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration.loadConfig(CassandraAutoConfiguration.java:187)
    ... 124 more

In the non-reactive case, it is using a ServletContextResource by default, which FilteredReactiveWebContextResource is meant to replace in a reactive context. Although the error messages are not the same, I'd say the two stacks are working in a similar way.

Using a file: or classpath: prefix works in both cases. Is there a reason why you don't want to qualify the location of the resource?

Comment From: ncheutin

@scottfrederick thanks for the detailed explanation.

If that's the way to go, fine with it.

The reason I thought it was a limitation only in reactive context is because in this AWS example it works without a file: or classpath: prefix for a reason I still do not understand.

Comment From: scottfrederick

@ncheutin Looking at the build file for that AWS example, there are no Spring Web MVC or WebFlux dependencies, so it does not build a web application. The Spring Framework documentation has an explanation of how it loads resources with different types of application contexts:

Against a ClassPathXmlApplicationContext, that code returns a ClassPathResource. If the same method were run against a FileSystemXmlApplicationContext instance, it would return a FileSystemResource. For a WebApplicationContext, it would return a ServletContextResource. It would similarly return appropriate objects for each context.

On the other hand, you may also force ClassPathResource to be used, regardless of the application context type, by specifying the special classpath: prefix, as the following example shows:

The sample you provided will have a WebApplicationContext but the AWS example will have some other type of application context that would not use the servlet or reactive resource loader, so the default behaviors will be different.

Comment From: ncheutin

Thanks again for the detailed explanation. Much appreciated.