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

<context:component-scan> Classloader problem [SPR-3815] #8495

Closed
spring-issuemaster opened this Issue Aug 29, 2007 · 12 comments

Comments

Projects
None yet
1 participant
@spring-issuemaster
Copy link
Collaborator

spring-issuemaster commented Aug 29, 2007

Leonardo Pinho opened SPR-3815 and commented

I've tried to use context:component-scan in a web application which depends on some local component (.jar) that contains some classes registered into Spring Container using @Component annotation.

However those classes are not found by ClassPathBeanDefinitionScanner class although t the base-package property is set up corretly. It is problably an issue with PathMatchingResourcePatternResolver as can be figure out in the testcase attached.

The full description of the problem and an use case is described at spring core forum:
http://forum.springframework.org/showthread.php?t=43234


Affects: 2.1 M3, 2.1 M4

Attachments:

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 29, 2007

Leonardo Pinho commented

Test case example

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 29, 2007

Dave Syer commented

I think maybe this is related to #8174. Plus (I'm not 100% clear here) it looks like the example on the forum uses two @Components in the same package, but in different file system resources (a jar file and a local class in WEB-INF/classes)? Could it be that a SimpleClassReaderFactory would fail to resolve the dependency because it uses classpath: to construct a Resource path, and that will pick one or the other of the package locations but not both?

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 30, 2007

Leonardo Pinho commented

No, the packages are differents (see below). Only the base-package (root) is the same.

  • WEB-INF/lib/springmoduletest.jar :

    • bizservices/springmoduletest/core/MyModuleManager.class
    • bizservices/springmoduletest/core/impl/MyModuleManagerImpl.class
  • WEB-INF/classes:

    • bizservices/springtest/core/MyManager.class
    • bizservices/springtest/core/impl/MyManagerImpl.class

The resources are different as well: "WEB-INF/lib/springmoduletest.jar" and "WEB-INF/classes". But PathMatchingResourcePatternResolver resolves the pattern: "classpath*:bizservices/**/*.class" to:

[main] DEBUG PathMatchingResourcePatternResolver - Resolved location pattern [classpath*:bizservices/**/*.class] to resources [file [C:...\WEB-INF\classes\bizservices\springtest\core\impl\MyManagerImpl.class], file [C:...\WEB-INF\classes\bizservices\springtest\core\MyManager.class]]

I've attached a respective web app example. The source code for springmoduletest.jar is at WEB-INF/lib/springmoduletest-source.jar.

Thanks for helping!!

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 30, 2007

Leonardo Pinho commented

Web app example

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 30, 2007

Marten Deinum commented

I think that Dave has a point here, although the package is different I think that the main difference is the resource that it is loaded from. One from a local (WEB-INF/classes) resource and one from a jar resource. It is also something you can easily test with the supplied testcase, change the package so that it is the same and still it will fail.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 31, 2007

Mark Fisher commented

This appears to be a much lower-level issue. I started from the provided testcase that focused on PathMatchingResourcePatternResolver, and after a bit of debugging I realized I was able to narrow the failing testcase down much further:

public class JarResourceLoadingTests extends TestCase {
public void testJarResourceLoading() {
ClassLoader cl = getClass().getClassLoader();
assertNotNull(cl.getResource("bizservices/springmoduletest"));
}
}

That test failed...
I then re-assembled the JAR file providing my own (minimal) manifest:

Manifest-Version: 1.0
Created-By: Test
Extension-Name: bizservices

After that, the test passed. At least for my environment, it seems like the "Extension-Name" is crucial for getResource() to return a URL for the paths inside the JAR.

Leonardo, can you try replacing the manifest and see if you get the same results.... in the local test case as well as your web app?

Mark

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 31, 2007

Leonardo Pinho commented

Hi Mark,

I've replaced the manifest and I got exactly the same results as you. The test case and the web app have worked perfectly!

Weird not? Because PathMatchingResourcePatternResolveTests (/test/org/springframework/core/io/support/) has a similar test:

public void testClasspathStartWithPatternInJar() throws IOException {
	Resource[] resources = resolver.getResources("classpath*:org/aopalliance/**/*.class");
	assertProtocolAndFilenames(resources, "jar", CLASSES_IN_AOPALLIANCE);
}

And this test case works well, doesn't it?

Well, at least we have got a work around until now :)

Thanks,
Leonardo

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Sep 1, 2007

Mark Fisher commented

Ok - it looks like I jumped to a conclusion with regards to 'Extension-Name'. I was just emulating another jar that I had been testing against successfully.

I am actually able to get the test case to pass by simply unpacking and recreating the JAR:
jar xf springmoduletest.jar
jar cf newjar.jar bizservices

So... it has nothing to do with 'Extension-Name' (sorry). My current MANIFEST.MF looks like this:
Manifest-Version: 1.0
Created-By: 1.5.0_07 (Apple Computer, Inc.)

...and the test passes.

I have investigated the existing JAR to see what might be the problem but yet to discover what it is.

Mark

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Sep 1, 2007

Leonardo Pinho commented

Yeah, I guess the problem is not related to Manifest.mf because I get the manifest.mf from the original jar and generated it again using winzip and it worked.

So I guess it is a issue with jar generation from Eclipse because I built the orginal jar using it and I did the same generation again and the test case failed.

Therefore I think you can close this bug because it is not related to Spring and it is a very specific problem.

Thank you very much for your help!!

Regards,
Leonardo

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Sep 1, 2007

Mark Fisher commented

Leonardo,

Thanks for that information. I must admit that I don't typically export JAR files from within eclipse but rather just command-line 'jar'. So, I did try it out and had the same results as you (the JAR exported by Eclipse caused my TestCase to fail).

However, I then discovered that the Export->"Java"->"JAR file" wizard has some 'options' at the bottom, and one of the checkboxes (unchecked by default) is "Add directory entries". If you make sure to select that option, then the Eclipse-exported JAR file will also work with getResource("packagename")... and therefore it will also work with Spring's path-matching and the ant-path wildcards of your original example.

Mark

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Sep 1, 2007

Mark Fisher commented

This pretty much summarizes the difference. Notice that the second JAR (created with "Add directory entries" selected) actually contains directories in addition to the classes:

jar tf springmoduletest.jar
META-INF/MANIFEST.MF
bizservices/springmoduletest/core/MyModuleManager.class
bizservices/springmoduletest/core/OtherModuleManager.class
bizservices/springmoduletest/core/impl/OtherModuleManagerImpl.class
bizservices/springmoduletest/core/impl/MyModuleManagerImpl.class

jar tf springmoduletest-with-directories.jar
META-INF/
META-INF/MANIFEST.MF
bizservices/
bizservices/springmoduletest/
bizservices/springmoduletest/core/
bizservices/springmoduletest/core/impl/
bizservices/springmoduletest/core/impl/MyModuleManagerImpl.class
bizservices/springmoduletest/core/impl/OtherModuleManagerImpl.class
bizservices/springmoduletest/core/MyModuleManager.class
bizservices/springmoduletest/core/OtherModuleManager.class

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Jan 27, 2011

Radha Spencer commented

Thank you very much for your research and post. I have been stumped for the past day and a half on this issue. Much appreciation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.