Unable to load classpath resource without leading slash

1,270 views
Skip to first unread message

Brian Lalor

unread,
Aug 12, 2012, 10:32:15 PM8/12/12
to ve...@googlegroups.com
I'm working on a busmod that uses Spring. In the busmod's start() method, I create a AnnotationConfigApplicationContext instance and pass it a reference to the class that contains my configuration:
ctx = new AnnotationConfigApplicationContext(AppConfig.class);
This works fine except when running as a busmod. I can create a new *instance* of AppConfig, but Spring does something funny (in my opinion) and wants to examine the actual .class file. When I create the context from within my busmod, I get an exception:

Caused by: java.io.FileNotFoundException: class path resource [my/package/AppConfig.class] cannot be opened because it does not exist
at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:157)


I don't understand the intricacies of resource loading, but I was able to determine that I could get a URL to the resource by prefixing a leading slash to the resource name. So
AppConfig.class.getResource("/my/package/AppConfig.class")
finds the .class file in the correct jar, while
AppConfig.class.getResource("my/package/AppConfig.class")
returns null.

I'm wondering if an additional method needs to be overridden in ParentLastURLClassLoader but I honestly have no idea where to start. Does anyone have any clues?

Thanks,
Brian

Dmitry Sklyut

unread,
Aug 12, 2012, 11:19:53 PM8/12/12
to ve...@googlegroups.com
If you are using spring already, might as well use spring Resource abstraction. Just use ClassPathResource and make sure to pass this.getClass().getClassloader. This way you will use proper classloder and will not have to worry with path separators.

Brian Lalor

unread,
Aug 12, 2012, 11:24:00 PM8/12/12
to ve...@googlegroups.com
On Aug 12, 2012, at 11:19 PM, Dmitry Sklyut <dmi...@dsklyut.com> wrote:

> If you are using spring already, might as well use spring Resource abstraction. Just use ClassPathResource and make sure to pass this.getClass().getClassloader. This way you will use proper classloder and will not have to worry with path separators.

That's where the problem lies, actually. I was trying to reduce the problem to something that could be understood by someone without Spring knowledge.

Not sure if this matters, but this is happening in a worker verticle, which appears to use ParentLastURLClassLoader.

The full stack trace is here: http://pastebin.com/myFHyYLc

Brian Lalor

unread,
Aug 12, 2012, 11:41:52 PM8/12/12
to ve...@googlegroups.com
For what it's worth, I tried providing a specific DefaultResourceLoader with the Verticle's class loader, but to no avail:

appCtx = new AnnotationConfigApplicationContext();
appCtx.registerShutdownHook(); // just in case

((AnnotationConfigApplicationContext) appCtx).setResourceLoader(new DefaultResourceLoader(getClass().getClassLoader()));
((AnnotationConfigApplicationContext) appCtx).register(AppConfig.class);

appCtx.refresh(); // <- blows up here

Tim Fox

unread,
Aug 13, 2012, 2:05:58 AM8/13/12
to ve...@googlegroups.com
Where did you put the Spring jar? In the module lib directory?

Brian Lalor

unread,
Aug 13, 2012, 5:49:01 AM8/13/12
to ve...@googlegroups.com
On Aug 13, 2012, at 2:05 AM, Tim Fox <timv...@gmail.com> wrote:

> Where did you put the Spring jar? In the module lib directory?

Yes. The jar that contains AppConfig.class also lives in the lib directory.

Brian Lalor

unread,
Aug 13, 2012, 4:53:04 PM8/13/12
to ve...@googlegroups.com
On Aug 12, 2012, at 11:24 PM, Brian Lalor <bla...@bravo5.org> wrote:

I think the problem may be that Spring is using Thread.currentThread().getContextClassLoader(), and I don't believe Vert.x is setting the thread's context class loader.

Brian Lalor

unread,
Aug 13, 2012, 10:36:49 PM8/13/12
to ve...@googlegroups.com
On Aug 13, 2012, at 4:53 PM, Brian Lalor <bla...@bravo5.org> wrote:

> I think the problem may be that Spring is using Thread.currentThread().getContextClassLoader(), and I don't believe Vert.x is setting the thread's context class loader.

Calling
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());

in my start() method seems to have solved the problem. This should work fine for my worker busmod, but what affect does it have on standard verticles that are run via an NioWorker? I see that setContextClassLoader() is called for the Rhino and Python verticles, but I still wonder about the possibility of conflicts with multiple verticles setting the contextClassLoader, since they (could) share the same thread.

Tim Fox

unread,
Aug 14, 2012, 4:22:12 AM8/14/12
to ve...@googlegroups.com
This is a known issue with Vert.x -it's been discussed on several other
threads on this group, and there is a github issue for it.

--
Tim Fox

Vert.x - effortless polyglot asynchronous application development
http://vertx.io
twitter:@timfox

Tim Fox

unread,
Aug 14, 2012, 4:23:08 AM8/14/12
to ve...@googlegroups.com
Yes, there are lots of other entry points into verticles where it needs
to be set to. This is why the github issue has been around for so long
and not quickly fixed :(

Brian Lalor

unread,
Aug 14, 2012, 6:38:12 AM8/14/12
to ve...@googlegroups.com
Would it make sense to consider a security manager or configuring a policy file to exclude (well, apparently just not grant) permission to get the thread context class loader? This will cause the Groovy verticle to fail, I think, but maybe that can be worked around.

--
Brian Lalor
bla...@bravo5.org
> --
> You received this message because you are subscribed to the Google Groups "vert.x" group.
> To post to this group, send an email to ve...@googlegroups.com.
> To unsubscribe from this group, send email to vertx+un...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/vertx?hl=en-GB.
>
Reply all
Reply to author
Forward
0 new messages