2

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.

  • While I still don't know why this works in unit test but not on the command line, @ptomli pointed me at [a thread](https://stackoverflow.com/a/29539977/8635259) with an alternative approach that is more compact. `Resource[] xsdFiles = resourceResolver.getResources("classpath:/xml/*.xsd");` then iterate over `xsdFiles`. – Ryan Elliott Oct 10 '17 at 19:55

2 Answers2

1
org.apache.commons.io.IOUtils.toString(getClass().getResourceAsStream("/csv/test.csv"), Charset.forName("UTF-8")))

This is example how to get access to internal source in jar file.

It is tricky, what is root path for the resource. In IDE you can mark some folder (e.g. webapp/recource) as resource folder. And when you build jar file, resource folder content will be in the root. So if you start your resource path from /, it means root of jar (i.e. root of resource folder).

I do not use relative paths, so you could look at open resource with relative path in java to get more info about it.

Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35
  • Thanks for your suggestion, but I'm trying to discover the resources available at a particular path (/xml). I'm able to load the resources in that path once I know their names, but I can't get a list of the resources that exist there. – Ryan Elliott Oct 10 '17 at 19:17
0

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

ptomli
  • 11,730
  • 4
  • 40
  • 68
  • I tried `Thread.currentThread().getContextClassLoader().getResourceAsStream("/xml")` and this returned a null pointer for me. I also tried the [Spring resolver suggestion](https://stackoverflow.com/a/29539977/8635259) , but IIRC it complained that "/xml" was an invalid path. I'll try again. – Ryan Elliott Oct 10 '17 at 18:53
  • My recollection was incorrect. Using Spring's `ResourceLoader.getResource().getInputStream()` gave me the same result as `getClass().getResourceAsStream`. Specifically, it gave an empty stream for resource path, but loaded the xsd file just fine. – Ryan Elliott Oct 10 '17 at 19:21
  • I was able to get the Spring ResourceLoader approach to work once I stopped trying to use it like Class.getResourceAsStream(). thanks! – Ryan Elliott Oct 10 '17 at 19:50