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

Classpath resources not found using layer-tools #42591

Closed
ferblaca opened this issue Oct 10, 2024 · 11 comments
Closed

Classpath resources not found using layer-tools #42591

ferblaca opened this issue Oct 10, 2024 · 11 comments
Assignees
Labels
for: external-project For an external project and not something we can fix

Comments

@ferblaca
Copy link

ferblaca commented Oct 10, 2024

Context

We are migrating our applications to using layer-tools but we are finding different behaviors in how applications search for classpath resources through the use of the PathMatchingResourcePatternResolver class.

It seems that the main problem is when using as location pattern an expression starting with wildcards, for example: classpath*:/**/*.avsc.

We have created a simple application that reproduces the case we are discussing.

Steps to reproduce

  1. Download application:
git clone https://github.com/ferblaca/DemoPathMatchingResourcePatternResolverApplication.git
  1. Compile:
cd DemoPathMatchingResourcePatternResolverApplication
mvn clean install
  1. Extract the FATJAR with layer-tools and start the application:
cd boot/target
java -Djarmode=tools -jar boot-0.0.1-SNAPSHOT.jar  extract --layers --destination extracted
cd extracted/application
mkdir lib
cp ../*/lib/*.jar lib/.
java -jar boot-0.0.1-SNAPSHOT.jar

Expected outcome

Using as AntPattern path classpath*:/**/*.avsc the application finds all the .avsc files that are in the classpath inside the jar resources of the artifact module:

+++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++ Resource: URL [jar:file:/home/fbc/workspaces/ferblaca/demoPathMatchingResolver/demoPathMatchingResourcePatternResolver/boot/target/extracted.fer/application/lib/artifact-0.0.1-SNAPSHOT.jar!/demo/statics/avro/file.avsc]
++++++++++ Resource: URL [jar:file:/home/fbc/workspaces/ferblaca/demoPathMatchingResolver/demoPathMatchingResourcePatternResolver/boot/target/extracted.fer/application/lib/artifact-0.0.1-SNAPSHOT.jar!/demo/statics/avro/file3.avsc]
++++++++++ Resource: URL [jar:file:/home/fbc/workspaces/ferblaca/demoPathMatchingResolver/demoPathMatchingResourcePatternResolver/boot/target/extracted.fer/application/lib/artifact-0.0.1-SNAPSHOT.jar!/demo/statics/avro/file2.avsc]
+++++++++++++++++++++++++++++++++++++++++++++++++

Observed outcome

The application running in layer-tools mode does NOT find the .avsc resources:

+++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++ NO RESOURCES FOUND!!!
++++++++++++++++++++++++++++++++++++++++++++++++

Details of tests performed

Application Type AntPattern Path Result
FATJAR classpath*:/**/*.avsc 🆗
LAYER-TOOLS classpath*:/**/*.avsc
LAYER-TOOLS classpath*:/demo/**/*.avsc 🆗

Versions

Spring-Boot version 3.3.4

@ferblaca ferblaca changed the title Classpath Resources not found using layertools Classpath resources not found using layertools Oct 10, 2024
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Oct 10, 2024
@ferblaca ferblaca changed the title Classpath resources not found using layertools Classpath resources not found using layer-tools Oct 11, 2024
@mhalbritter
Copy link
Contributor

The behavior can be observed without all that copying by leaving out --layers:

cd boot/target
java -Djarmode=tools -jar boot-0.0.1-SNAPSHOT.jar  extract --destination extracted
cd extracted/
java -jar boot-0.0.1-SNAPSHOT.jar

@mhalbritter
Copy link
Contributor

I think this warning applies here (from the JavaDoc of PathMatchingResourcePatternResolver):

WARNING: Note that "classpath*:" when combined with Ant-style patterns will only work reliably with at least one root directory before the pattern starts, unless the actual target files reside in the file system.

@mhalbritter
Copy link
Contributor

For example this:

this.resourceResolver.getResources("classpath:/**/file.avsc")

doesn't work in the Uber jar and in the extracted version.

this.resourceResolver.getResources("classpath:/demo/**/file.avsc")

works in uber jar and in the extracted version.

@ferblaca
Copy link
Author

ferblaca commented Oct 11, 2024

@mhalbritter thank you very much for answering so fast!

We are still wondering why using classpath*:/**/*.avsc does work with UBERJAR and not for EXTRACTED...

Using this.resourceResolver.getResources("classpath*:/**/*.avsc"):

  1. With Uberjar results:
+++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++ Resource: URL [jar:nested:/home/fbc/workspaces/ferblaca/demoPathMatchingResolver/demoPathMatchingResourcePatternResolver/boot/target/boot-0.0.1-SNAPSHOT.jar/!BOOT-INF/lib/artifact-0.0.1-SNAPSHOT.jar!/demo/statics/avro/file.avsc]
++++++++++ Resource: URL [jar:nested:/home/fbc/workspaces/ferblaca/demoPathMatchingResolver/demoPathMatchingResourcePatternResolver/boot/target/boot-0.0.1-SNAPSHOT.jar/!BOOT-INF/lib/artifact-0.0.1-SNAPSHOT.jar!/demo/statics/avro/file3.avsc]
++++++++++ Resource: URL [jar:nested:/home/fbc/workspaces/ferblaca/demoPathMatchingResolver/demoPathMatchingResourcePatternResolver/boot/target/boot-0.0.1-SNAPSHOT.jar/!BOOT-INF/lib/artifact-0.0.1-SNAPSHOT.jar!/demo/statics/avro/file2.avsc]
+++++++++++++++++++++++++++++++++++++++++++++++++
  1. With extracted results:
+++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++ NO RESOURCES FOUND!!!
++++++++++++++++++++++++++++++++++++++++++++++++

I am returning to the results as I think I did not explain myself correctly initially.

Note that we are using classpath* with asterisk.

Regards,

@mhalbritter
Copy link
Contributor

Maybe someone else from the team knows more about that stuff than I do. But I don't think this is a bug, because it's documented in the JavaDoc warning. But let's see what the rest of the team makes of it.

@mhalbritter mhalbritter added the for: team-attention An issue we'd like other members of the team to review label Oct 11, 2024
@wilkinsona
Copy link
Member

It's a bit unfortunate that it works with one form of packaging and not another. It would be interesting to know how the uber jar behaves when using the classic loader.

@mhalbritter
Copy link
Contributor

Classic one:

2024-10-11T14:05:39.475+02:00  INFO 111816 --- [demoPathMatchingResourcePatternResolver] [           main] tchingResourcePatternResolverApplication : +++++++++++++++++++++++++++++++++++++++++++++++++
2024-10-11T14:05:39.475+02:00  INFO 111816 --- [demoPathMatchingResourcePatternResolver] [           main] tchingResourcePatternResolverApplication : ++++++++++ Resource: URL [jar:file:/tmp/DemoPathMatchingResourcePatternResolverApplication/boot/boot-0.0.1-SNAPSHOT-classic.jar!/BOOT-INF/lib/artifact-0.0.1-SNAPSHOT.jar!/demo/statics/avro/file.avsc]
2024-10-11T14:05:39.476+02:00  INFO 111816 --- [demoPathMatchingResourcePatternResolver] [           main] tchingResourcePatternResolverApplication : ++++++++++ Resource: URL [jar:file:/tmp/DemoPathMatchingResourcePatternResolverApplication/boot/boot-0.0.1-SNAPSHOT-classic.jar!/BOOT-INF/lib/artifact-0.0.1-SNAPSHOT.jar!/demo/statics/avro/file2.avsc]
2024-10-11T14:05:39.476+02:00  INFO 111816 --- [demoPathMatchingResourcePatternResolver] [           main] tchingResourcePatternResolverApplication : ++++++++++ Resource: URL [jar:file:/tmp/DemoPathMatchingResourcePatternResolverApplication/boot/boot-0.0.1-SNAPSHOT-classic.jar!/BOOT-INF/lib/artifact-0.0.1-SNAPSHOT.jar!/demo/statics/avro/file3.avsc]
2024-10-11T14:05:39.476+02:00  INFO 111816 --- [demoPathMatchingResourcePatternResolver] [           main] tchingResourcePatternResolverApplication : +++++++++++++++++++++++++++++++++++++++++++++++++

Finds the resources, too.

@wilkinsona
Copy link
Member

Thanks, @mhalbritter.

This reminds me somewhat of #1744 where running in an IDE behaved one way and running as an uber jar behaved in another way. We decided not to make any changes there as the uber jar's behavior aligned with that of the JDK's jar support.

Here we appear to have an uber jar behaving one way and a standard JDK jar behaving in another way. If we were to align the behavior, it'd have to be by changing the uber jar to somehow stop this from working which, while more consistent, feels like a step backwards.

@philwebb
Copy link
Member

philwebb commented Oct 11, 2024

Debugging this and I think there's a potential enhancement that could be made to PathMatchingResourcePatternResolver. The addClassPathManifestEntries method has the following comment:

Determine jar file references from {@code Class-Path} manifest entries (which are added to the {@code java.class.path} JVM system property by the system class loader)

This doesn't actually appear to be the case. The result I see in System.getProperty("java.class.path") is just the single root jar. The manifest entries are missing.

Looking at jdk.internal.loader.URLClassPath there's a parseClassPath method that I wonder if we can replicate in Spring so we can find all the root jars.

@philwebb
Copy link
Member

I'm working on something to submit to Framework.

@philwebb
Copy link
Member

Closing in favor of Spring Framework PR spring-projects/spring-framework#33705

@philwebb philwebb closed this as not planned Won't fix, can't repro, duplicate, stale Oct 15, 2024
@philwebb philwebb added for: external-project For an external project and not something we can fix and removed status: waiting-for-triage An issue we've not yet triaged labels Oct 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: external-project For an external project and not something we can fix
Projects
None yet
Development

No branches or pull requests

5 participants