4

I have a Java webapp WAR file that depends on multiple jars in it's WEB-INF\lib directory. One of these JARS needs to load some config files by doing class.getClassLoader().getResourceAsStream(...). However the InputStream resturns null. Is there a problem with taking this approach when the JAR is inside a WAR? The app is deployed on Tomcat6.

EDIT MORE INFO:

I'm tring to load in SQL queries from files so I can run them. These are located in a separate DAO jar within the web app's WAR, under WEB-INF/lib

mywebapp.war
        -- WEB-INF
          -- lib
             -- mydao.jar
               ---- com/companyname/queries
                   -- query1.sql
                   -- query2.sql
                   -- query3.sql
                   ...

CODE USING TO LOAD CLASSES

public class QueryLoader {

 private static final Logger LOGGER = Logger.getLogger(QueryLoader.class.getName());

public String loadQuery(String fileName) {
  final String newline = "\n";

  BufferedReader reader = new BufferedReader(new InputStreamReader(         
        QueryLoader.class.getClassLoader().getResourceAsStream(
              "/com/companyname/queries/" + fileName)));
  StringBuilder sb = new StringBuilder();
  String line;
  try {
     while ((line = reader.readLine()) != null) {
        sb.append(line);
        sb.append(newline);
     }
  } catch (IOException e) {
     LOGGER.error(e);
  }

I have also tried changing the getResourceAsStream line to

Thread.currentThread().getContextClassLoader().getResourceAsStream(

without success.

My development environment is MS Windows Vista and but I encounter the same error when running it on this environment and on Ubuntu.

Tarski
  • 5,360
  • 4
  • 38
  • 47

3 Answers3

3

Assuming you're not making the rookie mistake of putting QueryLoader in a different JAR, the only problem I can see is that you're using File.separator yet appear (from your use of \) to be using Windows. When using getResourceAsStream, the separator is always a forward slash (/) just as if you're using a URL.

If I change that I get this:

QueryLoader.class.getClassLoader().getResourceAsStream(
          "/com/companyname/queries/" + fileName)

Of course, if QueryLoader is in the com.companyname.queries package (along with the queries themselves) then you should simply do this:

QueryLoader.class.getResourceAsStream(fileName)

Simple as that. (It's documented that Class.getResourceAsStream qualifies relative filenames with the name of the containing package.)

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
3

Managed to get it to work by using Spring's resource loader instead

public String loadQuery(String fileName) {
  final String newline = "\n";

  ApplicationContext ctx = new ClassPathXmlApplicationContext();
  Resource res = ctx.getResource("classpath:/com/msi/queries/" + fileName);
  BufferedReader reader;
  StringBuilder sb = new StringBuilder();
  try {
     reader = new BufferedReader(new InputStreamReader(res.getInputStream()));
     String line;

     while ((line = reader.readLine()) != null) {
        sb.append(line);
        sb.append(newline);
     }
  } catch (IOException e) {
     LOGGER.error(e);
  }

  return sb.toString();

}

Tarski
  • 5,360
  • 4
  • 38
  • 47
2

It should work, but you need to take care that you use the correct class loader.

Ralph
  • 118,862
  • 56
  • 287
  • 383
  • I have had trouble with the class loader in a old project, since that used a ClassX.class.getClassLoader() - (Where ClassX is most, but not nessesary, within the specific jar) since than i do not have had the problem anymore - But this is only how it worked for me. – Ralph Nov 26 '10 at 10:12
  • You can ensure a correct classloader by getting the classloader from some class that you know is in the same JAR file as the resource you want to load. – Neeme Praks Nov 26 '10 at 10:28
  • @Neeme Praks, yes that's what I've got at the moment but unfortunately it doesn't work – Tarski Nov 26 '10 at 10:30
  • 1
    are you sure there are no other copies of that class somewhere, in some other JAR? if yes, then could you describe a bit more about the specific configuration you have - where is the resource located, what else is located in that JAR, how are you reading that resource (code sample), etc. Add that extra description to original question, not to the comments here. – Neeme Praks Nov 26 '10 at 10:40
  • I think that it isn't whether it is the correct classloader, but what it is being asked to load. With the wrong slashes, it just won't work. – Donal Fellows Nov 26 '10 at 11:16