Adrian J George III opened SPR-15245 and commented

When using a ClassPathBeanDefinitionScanner with a different class loader than the attached context, ConfigurationClassParser.asSourcreClass abandons the provided classloader and uses the context's loader instead. This leads to the class not being found and a failure of the context to initialize.

This line https://github.com/spring-projects/spring-framework/blob/5b98a54c9b9f8c2f4332734ee23cd483b7df0d22/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java#L627 calls through to https://github.com/spring-projects/spring-framework/blob/5b98a54c9b9f8c2f4332734ee23cd483b7df0d22/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java#L659 which uses the local class loader.

The problem can be reproduced here https://github.com/adrianjgeorge/classloading-poc


Affects: 4.3.6

Issue Links: - #14977 ConfigurationClassParser needs to load annotations through source class loader

Comment From: spring-projects-issues

Juergen Hoeller commented

We have a rather fundamental assumption that the context-level ClassLoader can see all the classes of the context's bean definitions, at least to the degree that it needs to introspect them and to generate proxy classes for them. This does not just apply to ConfigurationClassParser but to DefaultListableBeanFactory and GenericApplicationContext in general.

Even if we revised the factory to generally preserve the ClassLoader that a particular scanner uses for each scanned bean definition, you might still run into failures when creating proxies later on. There are several spots in the framework where we're making such general assumptions about the context-level ClassLoader.

Could you possibly configure your ApplicationContext with a synthetic ClassLoader which is actually able to see all affected classes?

Comment From: spring-projects-issues

Adrian J George III commented

In this case the ClassLoader is sitting in front of an ear and providing dependency seperation, so i could get everything into one ClassLoader but that would defeat my purpose by allowing dependency bleedthrough and potentially causing failures.

Maybe it will help if I explain my use case. You have three beans A, B, and C. B needs to be injected with A. C needs to be injected with A and B. A is the only one known at compile time, and the only one baked into my artifact. B and C are each in their own ear with their (potentially clashing) dependencies which are discovered at runtime. I need them all to live happily together in the same context, because I can't tell what order if any they could be built hierarchically since i don't control the artifacts with B and C.

Did that make sense?

Comment From: snicoll

I unfortunately don't see how we can make this consistent. As @jhoeller indicates, there is a fundamental requirement that the context class loader can see the classes that it needs to handle. This seems also a very specific arrangement of yours that we'd like to support if we can but this could easily become a rabbit hole. Thanks for the suggestion, in any case.