Hi,

We are heavily relying on the ResourceLoader and more specifically the org.springframework.core.io.support.PathMatchingResourcePatternResolver. In a legacy codebase that we own, we are using this call very often: applicationContext.getResources("classpath*:**/some-file-pattern.xml") or any other type of pattern.

Since version 6.2.4 we clearly see a difference in behavior here. Compared to version 6.2.3 we observe that now nothing is returned while it was returning the expected resources in the previous version.

We also see a difference in behavior when running locally from IntelliJ compared to running the final WAR. Running locally in IntelliJ (which is obviously more 'File based' scanning than 'Jar based' scanning) everything works. Running in the final WAR, everything fails. As it only occurs in the final runtime, it is very difficult to analyze the Spring code to pinpoint where the difference in behavior is caused. We do see changes in org.springframework.core.io.support.PathMatchingResourcePatternResolver as of 6.2.x and a small Exception change in 6.2.4, but we couldn't point to that 100% as being the root cause.

Can you help us out here? What could have caused this difference in behavior ?

Comment From: sdeleuze

Could you please provide a minimal reproducer as an attached project or a link to a repository allowing to see change of behavior?

Comment From: kristofdepypere

That's hard. As mentioned, locally running the project will not give any insights, it only happens when running the real deal and connecting through remote debugging. The code will simply be the line shown above, the setup is highly manual anyway.

Comment From: jhoeller

Could you try to debug through PathMatchingResourcePatternResolver.findPathMatchingResources a bit and see what happens (that is, whether it backs out of certain root paths to analyze or the like)?

Between 6.2.3 and 6.2.4, we only had one defensive change in terms of jar entries caching (#34446) which I don't see as immediately related. Maybe that specific part if worth debugging though, just in case we were missing a side effect there: see PathMatchingResourcePatternResolver.doFindPathMatchingJarResources (line 810 ff).

To be clear, PathMatchingResourcePatternResolver got quite heavily revised in 6.2 for internal jar caching. A general side effect from that effort could still be lurking here, in particular since you only experience it for war/jar scenarios, and I'd be happy to fix that for 6.2.5 based on your analysis.

Comment From: kristofdepypere

I'll try, I already did, but I'll try more. A lot is happening there and indeed, caching is probably impacting behavior, so I only get to dive in once per application restart.

Comment From: jhoeller

If that is easier to do for a start, let's double-check the behavioral difference between 6.2.3 and 6.2.4: There is just that one change in PathMatchingResourcePatternResolver mentioned above, and it'd be great to know whether that specifically causes the regression that you are experiencing, or whether the regression is somehow triggered by the general 6.2 revision before and not immediately related to that 6.2.4 change.

Aside from downgrading to 6.2.3, you could also manually patch PathMatchingResourcePatternResolver to undo that change but otherwise stay on spring-core in version 6.2.4 (since such specific patching would isolate the effect even better).

Comment From: jhoeller

Potentially, this regression could also be caused by #34528 - a change in AbstractFileResolvingResource (line 87) which is called from PathMatchingResourcePatternResolver.addAllClassLoaderJarRoots (line 487). If the latter is relied on to build the initial jar roots for your scenario (that's not the common path but can happen in some scenarios), this could break the recognition of a valid jar root.

If this is the case in your scenario, we'd need to debug AbstractFileResolvingResource.exists specifically: why getInputStream() apparently fails then while the former getContentLengthLong call in 6.2.3 returned >0. This actually looks like a more likely cause to me than the PathMatchingResourcePatternResolver change mentioned above, so maybe we should investigate this one first.

Again, you could manually patch AbstractFileResolvingResource to undo that change in line 87 but otherwise stay on spring-core in version 6.2.4.

Comment From: jhoeller

I'm pretty sure it's a side effect from #34528. Locally reproducing it, I got a revision that makes both the original #34528 as well as the assumed .exists() check for jar roots as used in addAllClassLoaderJarRoots pass. I'll bring this into a 6.2.5 snapshot ASAP.

Comment From: kristofdepypere

@jhoeller I can confirm your hunch is correct. I tested by patching spring-core 6.2.4 with the before and after of the change in #34528 in AbstractFileResolvingResource.exists and everything works when reverting the line change.

Comment From: jhoeller

Alright, thanks for double-checking! The change is pushed in the meantime, to be available in the upcoming 6.2.5-SNAPSHOT in a few minutes. Please give the snapshot a try, this is a different implementation aiming to accommodate all of the requirements.

Since this is a painful regression in the scenarios affected, we intend to release 6.2.5 out-of-cycle: this Thursday along with Boot 3.4.4. It'd be great to confirm that everything is in order before that follow-up release, so integration testing is highly appreciated.