Page 1 of 2 12 LastLast
Results 1 to 10 of 17

Thread: Classpath Resource Loading : different behavior in standalone or web application...

  1. #1

    Default Classpath Resource Loading : different behavior in standalone or web application...

    Hi folks,

    I'm using Spring's ApplicationContext.getResource() in order to retrieve some class files at application start-up and do stuff...

    The code is very easy, I simply construct a query and passes it to the context, and iterate on the results :

    Code:
    String query = "classpath*:" + pkgBase + "/**/*.class";
    logger.info("Scanning CLASSPATH entries : " + query);
    Resource[] resources;
    try {
    	resources = springContext.getResources(query);				
    } catch(IOException e) {
    	...
    }
    for (int i = 0; i < resources.length; i++) {
    	...
    }
    This code is used in two different "contexts" :
    1/ in a web app, using Spring Context Loader ;
    2/ in a standalone Swing app, where I create the App Context myself.

    1/ works fine : the resources are fetched when the .class are exploded (in WEB-INF/classes) and also when they're packaged (in a jar in WEB-INF/lib) ;
    2/ doesn't work when .class are packaged in a jar : it only works if I have the .class files in a folder that's in my CLASSPATH... Since this app is a webstart, it's a pretty big issue :-/

    As far as I see, only the way the Spring Application Context is created differs : in 1/ I have a WebApplicationContext created by the loader, in 2/ I do it myself by instanciating a ClassPathXmlApplicationContext...

    I've been through the API docs :
    http://static.springframework.org/sp...nResolver.html

    And found a warning there :

    WARNING: Note that "classpath*:" will only work reliably with at least one root directory before the pattern starts, unless the actual target files reside in the file system. This means that a pattern like "classpath*:*.xml" will not retrieve files from the root of jar files but rather only from the root of expanded directories.
    As far as I understand it, this should not affect me (I always have a base package), but since I have this problem...
    Maybe I'm not using PathMatchingResourcePatternResolver when creating the ClassPathXmlCtx myself ?
    Shall I use GenericAppCtx instead ?

    Many thanks in advance for any information !

    Have fun,

    Remi

  2. #2
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    The classpath resource uses the underlying classloader to resolve various resources and that's why when moving between different environments the behavior might differ.
    I'm not sure how things are on webstart but I would recommend trying a very simple test using Class.getClassloader.getResource() to understand in what manner the classloader resolves resources.
    In webapps, the classloader usually unpacks the jars somewhere in a temporary folder so doing a pattern matching works since the folder structure is in place; I suspect that this is not the case with webstart which means that when the pattern matcher starts, it will not find the files on the disk.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  3. #3

    Default

    Hi Costin,

    Thanks a lot for the reply ! Comments below...

    Quote Originally Posted by Costin Leau View Post
    I'm not sure how things are on webstart but I would recommend trying a very simple test using Class.getClassloader.getResource() to understand in what manner the classloader resolves resources.
    The problem is not only with webstart. Actually AppCtx.getResources("classpath:..."); does not find the classes inside a jar file even when I launch it from the command-line :

    java -jar MyJar.jar

    AFAIK, everything in the jar is loaded by the SystemClassLoader then, so I don't see why it fails !

    I've checked with a non signed jar from cmd line, wondering if it was because I'm signing those jars, but no success : classes aren't returned :-/

    Are you sure that ClassPathApplicationContext.getResources() and WebApplicationContext.getResources() have the exact same behavior ? That's, AFAIK, the only difference in my code...

    In webapps, the classloader usually unpacks the jars somewhere in a temporary folder so doing a pattern matching works since the folder structure is in place; I suspect that this is not the case with webstart which means that when the pattern matcher starts, it will not find the files on the disk.
    Really ? You mean that my jars in WEB-INF/lib are "exploded" at some point ???
    In that case, AppCtx.getResources() would never work in "standalone" apps that has jars ? This would really suck :-/

    Thanks a lot for the help !

    Have fun,

    Remi

  4. #4
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    Really ? You mean that my jars in WEB-INF/lib are "exploded" at some point ???
    In that case, AppCtx.getResources() would never work in "standalone" apps that has jars ? This would really suck :-/
    I haven't worked with Spring and standalone apps too much so I can't say exactly what's the problem in this case. Note that inside a webapp, the jar can be exploded virtually (i.e. no unpacking occurs but the classloader is smart enough to recognize a jar and traverse it).
    If you look at the sources you'll notice that the behavior is the same just that a different ResourceLoader is used - the first one uses the classpath while the second one relies on the webcontext.

    As I said, try doing some simple tests by using class.getClassLoader().getResource()/getResources() to see what you can look for.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  5. #5

    Default

    Quote Originally Posted by Costin Leau View Post
    I haven't worked with Spring and standalone apps too much so I can't say exactly what's the problem in this case. Note that inside a webapp, the jar can be exploded virtually (i.e. no unpacking occurs but the classloader is smart enough to recognize a jar and traverse it).
    OK, get it. This would explain why it also works when you launch the standalone application from inside eclipse (there's no jar yet : it uses eclipse's output folder which contains raw .class files) !
    Sucky classloaders !!! Looks like they always end up right in my way ;-P

    If you look at the sources you'll notice that the behavior is the same just that a different ResourceLoader is used - the first one uses the classpath while the second one relies on the webcontext.
    Damnit !
    So I guess I'm stuck then ? :-/

    Hopefully, my stuff has 2 different ways of working (I don't *have* to use classpath scanning, it's an option that allows to get rid of an XML config file by using annotations actually).

    As I said, try doing some simple tests by using class.getClassLoader().getResource()/getResources() to see what you can look for.
    I'll do this.
    Do you consider this as a bug in Spring ???
    I mean, from the docos it says that AppCtx.getResources(...) fecthes stuff from the CLASSPATH, I don't remember anything mentionning that stuff in jars (but in the CLASSPATH) would not work when using the ClassPathXmlApplicationContext !

    Thanks for the help !

    Cheers

    Remi

  6. #6
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    Sucky classloaders !!! Looks like they always end up right in my way ;-P
    Classloaders are very powerful - they can make your life easier but can also yield unexpected results.

    I'll do this.
    Do you consider this as a bug in Spring ???
    I mean, from the docos it says that AppCtx.getResources(...) fecthes stuff from the CLASSPATH, I don't remember anything mentionning that stuff in jars (but in the CLASSPATH) would not work when using the ClassPathXmlApplicationContext !
    From the information that you gave me, no, I don't think there is a bug in spring. The classpath is assembled at runtime and depending on the classloader used, resource resolution might different.
    There have been some discussions in the past and there isn't much that Spring can improve. If the classloader doesn't want to return a resource, it might be that you are not allowed to see it (security measure). Spring adheres to the classloading contract so in the end, it's up to the implementation what resources get returned or not.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  7. #7

    Default

    Quote Originally Posted by Costin Leau View Post
    Classloaders are very powerful - they can make your life easier but can also yield unexpected results.
    Apparently they're not that powerful : they can't find a class in a jar !
    And anyway I've had previous bad experiences with ClassLoaders and dynamic code swapping, I still have nightmares about it today ;-P

    no, I don't think there is a bug in spring. The classpath is assembled at runtime and depending on the classloader used, resource resolution might different.
    Well, in this situation it clearly does not ! I mean, I'm doing this :

    java -jar MyJar.jar

    and the AppCtx.getResources("classpath:*...") code inside does NOT find some classes which ARE in the classpath (otherwise I don't see how my app can work !!!).

    java -jar MyClass.jar adds all resources and classes to the System Class Loader. Class.forName() should work inside that code for classes defined in MyJar.jar.

    So, if Spring's really looking into the CLASSPATH, it should find them too, don't you think ?

    From what I read in ResourcePatterResolver's javadocs :
    "
    This interface also suggests a new resource prefix "classpath*" for all matching resources from the class path. Note that the resource location is expected to be a path without placeholders in this case (e.g. "/beans.xml"); JAR files or classes directories can contain multiple files of the same name.
    "

    JAR files !!!
    :-)

    Sorry to bother, but to me, it looks like a bug :-/
    I'm even thinking about filing it, I'd be happy in more comments from you before I do so...

    Thanks again for the great support (and the excellent framework btw) !

    Cheers

    Remi

  8. #8
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    Sorry to bother, but to me, it looks like a bug :-/
    I'm even thinking about filing it, I'd be happy in more comments from you before I do so...

    Thanks again for the great support (and the excellent framework btw) !
    Remi, if you think this is a bug then please create a small test which proves it and upload it to JIRA.
    Thanks.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  9. #9

    Default

    Quote Originally Posted by Costin Leau View Post
    Remi, if you think this is a bug then please create a small test which proves it and upload it to JIRA.
    Thanks.
    You're right, it's the best way to go. I clearly don't want to pollute the JIRA since I'm not a deep Spring expert !

    I'll try to roll the following test : in a main(), create a new ClassPathXmlApplicationContext (by getting the XML beans definitions from CLASSPATH), and try to locate stuff in the classpath using AppCtx.getResources().

    Then, I'll try to launch this with exploded classes, and with everything inside a jar.

    If I'm right, the code should work in both contexts ?

    Cheers

    Remi

  10. #10
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    I'll try to roll the following test : in a main(), create a new ClassPathXmlApplicationContext (by getting the XML beans definitions from CLASSPATH), and try to locate stuff in the classpath using AppCtx.getResources().

    Then, I'll try to launch this with exploded classes, and with everything inside a jar.

    If I'm right, the code should work in both contexts ?
    The best tests are the simplest ones. In your case, create a simple JUnit and create an appCtx which doesn't find the resource while your code which searches the classpath, can find the resource just fine.
    Please make sure the test runs fine from ant since inside an IDE such as Eclipse or IntelliJ, the classpath depends on various factors and is not really portable.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •