Closed
Description
Denis Miorandi opened SPR-14684 and commented
Scenario description:
I've got a spring webapp like this
- webapp is main context + main classloader
- plugins are child contexts + child classloaders. Note that plugins read files from disk
(via custom classloader, not from jar)
this work fine in spring 3.2.x.
When migrated to spring 4.3.2 + spring boot 1.4, I've got an issue starting up.
In some cases it doesn't load file using the expected resourceLoader (classpath instead of expexted file)
The only changing is I've used a spring boot annotated class starting instead a web.xml one.
Issue:
If you look at attacched files (stack), it seems that spring scan two times
- On scan 1 spring use the webapp/plugin ResourceLoader, so that file are loaded as FileSystemResource as expected
- On scan 2 (ConfigurationClassParser one) spring use DefaultResourceLoader instead of the webapp/plugin one. In this case it recognize resource as classpath/jar and it fails (due to application logic). It seems that ConfigurationClassParser doesn't take in account main context
My ugly patch
Actually the only solution I found is to patch SimpleMetadataReaderFactory forcing my logic
{{ @Override
public MetadataReader getMetadataReader(String className) throws IOException {
String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;
Resource resource = this.resourceLoader.getResource(resourcePath);
// CLESIUS PATCH - BEGIN
// Load from disk instead of jar, otherwise crash
if(SingletonLoader.getInstance()!=null && className.startsWith("it.clesius")){
Class<?> cPlugin=SingletonLoader.getInstance().getClass(className);
if (cPlugin!=null){
try{
resourcePath=cPlugin.getClassLoader().getResource(ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX).toString().replace("file://", "//");
resource=new FileSystemResource(resourcePath);
}catch(Exception e){
System.out.println("CLESIUS PATCH - Error on spring clesius Patch");
}
}
}
// CLESIUS PATCH - END
if (!resource.exists()) {
// Maybe an inner class name using the dot name syntax? Need to use the dollar syntax here...
// ClassUtils.forName has an equivalent check for resolution into Class references later on.
int lastDotIndex = className.lastIndexOf('.');
if (lastDotIndex != -1) {
String innerClassName =
className.substring(0, lastDotIndex) + '$' + className.substring(lastDotIndex + 1);
String innerClassResourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(innerClassName) + ClassUtils.CLASS_FILE_SUFFIX;
Resource innerClassResource = this.resourceLoader.getResource(innerClassResourcePath);
if (innerClassResource.exists()) {
resource = innerClassResource;
}
}
}
return getMetadataReader(resource);
}
}}
Affects: 4.3.2
Attachments:
- scan1_right.png (188.25 kB)
- scan2_wrong(fail).png (183.84 kB)
Issue Links:
- Cache ASM metadata at the context level [SPR-14654] #19219 Cache ASM metadata at the context level
- Consistent *Aware callbacks for TypeFilters, ImportSelectors and ImportBeanDefinitionRegistrars [SPR-14686] #19250 Consistent *Aware callbacks for TypeFilters, ImportSelectors and ImportBeanDefinitionRegistrars