I have a large Spring application that I am trying to convert to a single OSGi bundle for deployment into JBoss (AS 7.0.2). Initially I am trying to minimize code changes and deploy the application as-is, but I am running into issues with Spring resource loading. I've created a relatively simple application as a reproducer. The application is an OSGi bundle with a few simple Spring beans using ClassPathXmlApplicationContext. I am building the bundle with maven-bundle-plugin and embeding transitive dependencies including Spring 3.0.6 JARs.
When I use a simple configuration location such as "classpath:spring/applicationContext.xml" everything works fine. However, the real application has several different locations using combinations of "classpath*:" and location patterns such as "classpath:spring/*Context.xml". These locations with patterns are causing problems.
Despite Spring's support for VFS it is not being used in these cases. Within the OSGi context Spring is getting resource URLs with a "bundle:" protocol and doesn't know what to do with them. So it falls back to assuming they are files, and the resource loading fails:
22:05:18,264 WARN [org.springframework.core.io.support.PathMatchingResourcePatternResolver] (MSC service thread 1-4) Cannot search for matching files underneath class path resource [spring/] because it does not correspond to a directory in the file system: java.io.FileNotFoundException: class path resource [spring/] cannot be resolved to absolute file path because it does not reside in the file system: bundle://com.tendril.test.spring.osgi-23-0-0/spring/
After some research I found Snowdrop and am hoping it can help. I am embedding snowdrop-vfs 2.0.0.Final in my bundle, I have switched to using VFSClassPathXmlApplicationContext, and I have configured OSGi to use these VFS modules:
<module identifier="org.jboss.vfs"/> <module identifier="org.jboss.osgi.vfs" startlevel="1"/>
However, using a location with patterns such as "classpath:spring/*Context.xml" does not seem to work; none of my beans are found:
22:19:35,672 INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory] (MSC service thread 1-1) Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@8a70e3a: defining beans ; root of factory hierarchy
Interestingly, using a patternless location that works with ClassPathXmlApplicationContext (classpath:spring/applicationContext.xml) does not work with VFSClassPathXmlApplicationContext:
Caused by: java.io.FileNotFoundException: /spring/applicationContext.xml (No such file or directory) at java.io.FileInputStream.open(Native Method) [:1.6.0_26] at java.io.FileInputStream.<init>(FileInputStream.java:120) [:1.6.0_26] at org.jboss.vfs.spi.RootFileSystem.openInputStream(RootFileSystem.java:55) at org.jboss.vfs.VirtualFile.openStream(VirtualFile.java:238) [jboss-vfs-3.0.1.GA.jar:3.0.1.GA]
My simple reproducer project is attached.
spring-jboss-osgi.zip 4.9 K
Let me look into this. The VFSClassPathXmlApplicationContext should work, I believe that for a reason or another it's picking up the wrong classloader, but I'm not sure.
regarding "classpath:spring/*Context.xml" - this is always a tricky resource location spec - usually the best form is "classpath*:spring/*Context.xml" because the former will try to resolve *Context.xml from the first 'spring/' location found on the CP - may or may not be the one you want. So, try this too.
But as I said, I'll try looking into this.
There is one thing I've found w.r.t. classloaders - the thread context classloader doesn't seem to be able to resolve resources in embedded JARs within the bundle. I've filed an issue on this, but I'm not really sure if it's a defect or expected behavior: AS7-2165. My repro project has some workaround code for this issue, but with or without the workaround I'm still seeing the problem.
Thanks for suggesting "classpath*". In my real application this is indeed being used, so I've added it as another case in my repro project. But as you can probably guess I still can't resolve resources using it with either ClassPathXmlApplicationContext or VFSClassPathXmlApplicationContext.