Skip to content

ConfigurationClassParser does not use ApplicationContext's ResourceLoader for its MetadataReaderFactory [SPR-14684] #19248

Closed
@spring-projects-issues

Description

@spring-projects-issues

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

  1. On scan 1 spring use the webapp/plugin ResourceLoader, so that file are loaded as FileSystemResource as expected
  2. 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:

Issue Links:

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions