Search code examples
javaembedded-resource

Listing files with getResourceAsStream() is empty when run on command line


I'm trying to list the files at a particular path in my application's jar file. It works when I build using "mvn clean package", but when I run on the command line with "java -jar target/myproject_1.0.jar" the file list is empty. Based on this suggestion, I am reading the directory contents with this code

    boolean failed = true;
    String schemaLocation = "/xml";
    System.out.println("Scanning folder "+schemaLocation);
    InputStream dirStream = getClass().getResourceAsStream(schemaLocation);
    BufferedReader dirReader = new BufferedReader(new InputStreamReader( dirStream ));
    try{
        String filename = dirReader.readLine();
        while( filename != null ){
            failed = false;
            if( filename.endsWith(".xsd")){
                String fullname = schemaLocation+"/"+filename;
                System.out.println("Loading schema file "+fullname );
                InputStream in = getClass().getResourceAsStream(schemaLocation+"/"+filename);
                readAndProcessSchema(in);
            }
            filename = dirReader.readLine();
        }
    }catch(IOException ex){
        ex.printStackTrace();
    }
    if(failed){
        System.out.println("Fallback enabled.");
        InputStream in = getClass().getResourceAsStream(schemaLocation+"/schema_v1.0.xsd");
        readAndProcessSchema(in);
    }

Note that the stream is not null, just empty. And only the path listing logic fails, because the fallback code at the end of the code sample (which reads the hard-coded xsd filename) works even on the command line. I have also tried MyClass.class.getResourceAsStream("/xml") (based on this suggestion) with the same results.

One other note that may be relevant is that the contents of the xml path are coming from one of my project's dependencies, and I can't predict what additional files they may add in the future (hence my need to scan that path). To pull in those dependencies, I'm using the suggestion from this post, and I believe it is working because the jar files table-of-contents appears to include everything:

 $ jar -tvf target/myproject-1.0.jar | grep xml
      0 Tue Oct 10 10:02:28 PDT 2017 xml/
   1999 Tue Oct 10 10:02:28 PDT 2017 xml/schema_v1.0.xsd
   4474 Tue Oct 10 10:02:28 PDT 2017 xml/schema_v2.0.xsd
   5757 Fri Oct 06 16:07:48 PDT 2017 META-INF/maven/com.mycompany/myproject/pom.xml

It might also be worth mentioning that this is running as a Spring Boot application, built using their spring-boot-maven-plugin "repackage" goal. I would like to know not only now to fix this, but also why the classpath works differently in Maven unit tests than on the command line.


Solution

  • Your code is using Class#getResourceAsStream, which will use the class loader of the class. This might work in your IDE or Maven, but may not in other situations.

    In effect you should probably try using the thread context class loader Thread.currentThread().getContextClassLoader() and fall back if that fails.

    There is a similar question Get a list of resources from classpath directory

    Of course, as suggested there, you could use a Spring tool, PathMatchingResourcePatternResolver