Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ConfigDataResourceNotFoundException incorrectly thrown for valid classpath locations #24143

Closed
bratkartoffel opened this issue Nov 13, 2020 · 14 comments
Assignees
Milestone

Comments

@bratkartoffel
Copy link

@bratkartoffel bratkartoffel commented Nov 13, 2020

Hi,

after upgrading from spring boot 2.3.6 to 2.4.0 our application fails to startup. We tracked the error to our startup options, we use the following to setup the configuration resources paths:
--spring.config.location=classpath:/,file:../etc/

This results in the following error message:

***************************
APPLICATION FAILED TO START
***************************

Description:

Config data resource 'class path resource []' via location 'classpath:/' does not exist

Action:

Check that the value 'classpath:/' is correct, or prefix it with 'optional:'

07:53:54.024 [main] ERROR com.xxx.server.launcher.XxxServerApplication - Error starting up / running context
org.springframework.boot.context.config.ConfigDataResourceNotFoundException: Config data resource 'class path resource []' via location 'classpath:/' cannot be found
        at org.springframework.boot.context.config.ConfigDataResourceNotFoundException.withLocation(ConfigDataResourceNotFoundException.java:97)
        at org.springframework.boot.context.config.ConfigDataImporter.handle(ConfigDataImporter.java:133)
        at org.springframework.boot.context.config.ConfigDataImporter.resolve(ConfigDataImporter.java:104)
        at org.springframework.boot.context.config.ConfigDataImporter.resolve(ConfigDataImporter.java:93)
        at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:81)
        at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:118)
        at org.springframework.boot.context.config.ConfigDataEnvironment.processInitial(ConfigDataEnvironment.java:230)
        at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:217)
        at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:88)
        at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:80)
        at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:100)
        at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:86)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:203)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:196)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:170)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:148)
        at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:82)
        at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:63)
        at java.util.ArrayList.forEach(ArrayList.java:1257)
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:117)
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:111)
        at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:62)
        at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:362)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1309)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1298)
        at com.xxx.xxx.server.launcher.XxxServerApplication.main(XxxServerApplication.java:49)

The same setting works fine on the previous spring boot version.
We need this setting as we ship some default profiles within our jar, but also allow the user to use custom profiles within the "etc" folder.
Prefixing the "classpath:" with "optional:" doesn't print any error, but then the embedded profiles are not found.

Thanks,
Simon

@wilkinsona
Copy link
Member

@wilkinsona wilkinsona commented Nov 13, 2020

Thanks for the report, @bratkartoffel. I've tried to reproduce the behaviour that you have described but have been unable to do so. Specifying the root of the classpath as a spring.config.location works as expected for me both when running an application in my IDE and when packaged as a jar file.

If you would like us to spend some more time investigating, please spend some time providing a complete yet 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 up and attaching it to this issue.

@bratkartoffel
Copy link
Author

@bratkartoffel bratkartoffel commented Nov 13, 2020

I've created a minimal example and could reproduce this. While testing I found out, that this only happens when running on Java 8. Using Java 11 is fine. Running in IntelliJ works also fine.
See the "reproduce.sh" script on how to reproduce.

GH24143.zip

@wilkinsona
Copy link
Member

@wilkinsona wilkinsona commented Nov 13, 2020

Thanks for the sample, @bratkartoffel. I've reproduced the problem.

The failure seems to be due to a difference in how the root of the classpath is resolved. As you have observed, this difference is specific to Java 8. It also only occurs when there are only jars on the classpath. If I modify the GH24143 script to add a directory to the classpath (I added .), the problem does not occur and the properties are resolved as expected:

./bin/GH24143 --spring.profiles.active=embedded,external --spring.config.location=classpath:/,file:../../../etc/


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.0)

2020-11-13 09:05:19.702  INFO 29925 --- [           main] org.example.TestApplication              : Starting TestApplication using Java 1.8.0_252 on wilkinsona-a01.vmware.com with PID 29925 (/Users/awilkinson/Downloads/GH24143/build/install/GH24143/lib/GH24143-1.0-SNAPSHOT.jar started by awilkinson in /Users/awilkinson/Downloads/GH24143/build/install/GH24143)
2020-11-13 09:05:19.704  INFO 29925 --- [           main] org.example.TestApplication              : The following profiles are active: embedded,external
2020-11-13 09:05:20.343  INFO 29925 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-11-13 09:05:20.351  INFO 29925 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-11-13 09:05:20.351  INFO 29925 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.39]
2020-11-13 09:05:20.394  INFO 29925 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-11-13 09:05:20.394  INFO 29925 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 656 ms
2020-11-13 09:05:20.514  INFO 29925 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-11-13 09:05:20.639  INFO 29925 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-11-13 09:05:20.646  INFO 29925 --- [           main] org.example.TestApplication              : Started TestApplication in 1.242 seconds (JVM running for 1.522)
2020-11-13 09:05:20.648  INFO 29925 --- [           main] org.example.TestApplication              : example.embedded=1
2020-11-13 09:05:20.649  INFO 29925 --- [           main] org.example.TestApplication              : example.external=2
2020-11-13 09:05:20.715  INFO 29925 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'

We'll continue to investigate to see what a potential fix may be.

Rather than adding a directory to the classpath, an alternative workaround is to enable legacy configuration file processing by setting spring.config.use-legacy-processing=true One way to do this is as a system property:

JAVA_OPTS=-Dspring.config.use-legacy-processing=true ./bin/GH24143 --spring.profiles.active=embedded,external --spring.config.location=classpath:/,file:../../../etc/
@wilkinsona wilkinsona changed the title Config data resource 'class path resource []' via location 'classpath:/' cannot be found Config data resource 'class path resource []' via location 'classpath:/' cannot be found with Java 8 and only jar files on the classpath Nov 13, 2020
@wilkinsona
Copy link
Member

@wilkinsona wilkinsona commented Nov 13, 2020

The following references are being resolved:

  • classpath:/application.properties
  • classpath:/application.xml
  • classpath:/application.yml
  • classpath:/application.yaml

The directory for each of these is classpath:/ represented by a ClassPathResource with a path that's the empty string. The existence of these resources is checked by calling ClassLoader.getResource("") and requiring a non-null result. The result is null on Java 8 and non-null on Java 11.

Modifying the sample's main method to output the result of the getResource("") call produces jar:file:/Users/awilkinson/Downloads/GH24143/build/install/GH24143/lib/log4j-api-2.13.3.jar!/META-INF/versions/9/ with Java 11 and null with Java 8.

Modifying the sample to apply Spring Boot's plugin and building and running a fat jar produces jar:file:/Users/awilkinson/Downloads/GH24143/build/libs/GH24143-1.0-SNAPSHOT.jar!/BOOT-INF/classes!/ with both Java 8 and Java 11.

Modifying the sample to remove log4j-api-2.13.3.jar from the classpath causes it to fail with Java 11 (and continue to fail with Java 8). In other words, it only works with Java 11 when there's only jars on the classpath if one of those jars is a multi-release jar.

@wilkinsona
Copy link
Member

@wilkinsona wilkinsona commented Nov 13, 2020

I think we've been here before: spring-projects/spring-framework#16711.

@wilkinsona wilkinsona added this to the 2.4.1 milestone Nov 13, 2020
@philwebb philwebb self-assigned this Dec 1, 2020
@philwebb philwebb changed the title Config data resource 'class path resource []' via location 'classpath:/' cannot be found with Java 8 and only jar files on the classpath ConfigDataResourceNotFoundException incorrectly thown for valid classpath locations Dec 2, 2020
@philwebb philwebb closed this in 3dc03ac Dec 2, 2020
@scottfrederick scottfrederick changed the title ConfigDataResourceNotFoundException incorrectly thown for valid classpath locations ConfigDataResourceNotFoundException incorrectly thrown for valid classpath locations Dec 3, 2020
@lakxtxue
Copy link

@lakxtxue lakxtxue commented Jan 6, 2021

Please pay attention to this issue again.I encountered the same problem in version 2.4.1, and I returned to 2.4.0 and it was normal. I use graalvm 20.3.0 OpenJDK11.0.9

Description:

Config data location 'classpath:/' does not exist

Action:

Check that the value 'classpath:/' is correct, or prefix it with 'optional:'

This is my code
public static void main(String[] args) { ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(DemoApplication.class) .properties("spring.config.name:application,cache", "spring.config.location:classpath:/,classpath:/config/properties/") .build().run(args); }
I created a demo example that reproduces the problem
demo.zip

@snicoll
Copy link
Member

@snicoll snicoll commented Jan 6, 2021

Thanks for letting us know. FWIW this project works fine for me with Spring Boot 2.4.2-SNAPSHOT.

@lakxtxue
Copy link

@lakxtxue lakxtxue commented Jan 6, 2021

I can't use 2.4.2-SNAPSHOT and the following error is displayed:

Plugin [id: 'org.springframework.boot', version: '2.4.2-SNAPSHOT'] was not found in any of the following sources:

Even if I use spring initializr to generate new projects, the same error occurs.

I noticed the modification of 2.4.1 on this issue. If there is no property file in the classpath:/ path, an error will be thrown:

Config data location'classpath:/' does not exist

If I add the properties file in the classpath:/ path, everything is normal. I do need to have no properties files in the directory. Can the modification ignore this judgment?

@snicoll
Copy link
Member

@snicoll snicoll commented Jan 6, 2021

Even if I use spring initializr to generate new projects, the same error occurs.

A project generated using start.spring.io works fine for me. Perhaps you're trying to adapt the new project to your existing project and you forgot to update settings.gradle? If you can reproduce the problem with 2.4.2-SNAPSHOT, please create a separate issue as this one is closed in a released version and we won't reopen it. If you need guidance on how to switch to the snapshot, please follow-up on StackOverflow or Gitter.

@lakxtxue
Copy link

@lakxtxue lakxtxue commented Jan 7, 2021

The project I generated at start.spring.io used gradle project before, but now I use maven and it is indeed normal. This is the demo I used to reproduce the issue with version 2.4.2-SNAPSHOT
demo.zip

@snicoll
Copy link
Member

@snicoll snicoll commented Jan 8, 2021

@lakxtxue thank you for creating the issue (#24696).

@taoshide
Copy link

@taoshide taoshide commented Feb 4, 2021

image

@wafim
Copy link

@wafim wafim commented Feb 4, 2021

Hello,
i upgrated spring boot from 2.2 to 2.4.1 ,i have a config as following :

1-context xml file :Environment name="spring.config.additional-location" value="file:/opt/etc/" type="java.lang.String"
2- in /opt/etc/ i have this file:idra-app-war.properties
3- war is the active profile
before the upgrade every thing work fine,after the upgrade i had this error:

Caused by: org.springframework.boot.context.config.ConfigDataLocationNotFoundException: Config data location 'classpath:/opt/etc/' cannot be found
@wilkinsona
Copy link
Member

@wilkinsona wilkinsona commented Feb 4, 2021

@wafim From what you've described, that doesn't sound related to this issue. If you'd like us to investigate, please open a new issue and provide a minimal sample that reproduces the problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
8 participants