26

Properties file location is WEB-INF/classes/auth.properties.

I cannot use JSF-specific ways (with ExternalContext) because I need properties file in a service module which doesn't have a dependency on a web-module.

I've already tried

MyService.class.getClassLoader().getResourceAsStream("/WEB-INF/classes/auth.properties");

but it returns null.

I've also tried to read it with FileInputStream but it requires the full path what is unacceptable.

Any ideas?

Roman
  • 59,060
  • 84
  • 230
  • 322

3 Answers3

53

Several notes:

  1. You should prefer the ClassLoader as returned by Thread#getContextClassLoader().

    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    

    This returns the parentmost classloader which has access to all resources. The Class#getClassLoader() will only return the (child) classloader of the class in question which may not per se have access to the desired resource. It will always work in environments with a single classloader, but not always in environments with a complex hierarchy of classloaders like webapps.

  2. The /WEB-INF folder is not in the root of the classpath. The /WEB-INF/classes folder is. So you need to load the properties files relative to that.

    classLoader.getResourceAsStream("/auth.properties");
    

    If you opt for using the Thread#getContextClassLoader(), remove the leading /.

The JSF-specific ExternalContext#getResourceAsStream() which uses ServletContext#getResourceAsStream() "under the hoods" only returns resources from the webcontent (there where the /WEB-INF folder is sitting), not from the classpath.

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • 1
    @unbeli: good luck when you distribute it as JAR then :) – BalusC Jul 01 '10 at 18:51
  • @BalusC you edited your answer, before it recommended only to use the context class loader. It is obvious, that the issue is not the wrong classloader, but the wrong path. – unbeli Jul 01 '10 at 19:01
  • Besides that: if the resource belongs to the class and is not an external configuration, you should use *only* Class#getResource() / getResourceAsStream(). Class#getClassLoader() won't return any child class loaders. Context class loader does not have access to *all* resources. – unbeli Jul 01 '10 at 19:04
  • @unbeli: you misunderstood me. I was saying like that using `ClassLoader#getResourceAsStream()` is more recommend than using `ExternalContext#getResourceAsStream()`. Also see the edit history. I removed it because the OP mentioned that it was not an option at any way (which I overlooked). I'd appreciate if you remove the downvote. – BalusC Jul 01 '10 at 19:05
  • @unbeli: it's however useful if you want to externalize the resource and/or want to be able to override it without rebuilding/redeploying the whole webapp on every edit of the file. – BalusC Jul 01 '10 at 19:08
8

Try this:

MyService.class.getClassLoader().getResourceAsStream("/auth.properties");

Reading files with getResourceAsStream looks on the classpath to find the resource to load. Since the classes directory is in the classpath for your webapp, referring to the file as /auth.properties should work.

Jesper
  • 186,095
  • 42
  • 296
  • 332
5

ResourceBundle (http://download.oracle.com/javase/6/docs/api/java/util/ResourceBundle.html) resolve most of the problems with a relative/absotule path for Properties Files.

It uses the the Resource class and point it to a Dummy Class to make reference to a properties file.

For example:

  1. You a have file called MAINProperties.properties and inside it there is a property: mail.host=foo.example.com
  2. Create a Dummy Class called MAINProperties without nothing.
  3. Use the following code:

    ResourceBundle.getBundle("com.example.com.MAINProperties").getProperty("mail.host")

And That's it. No InputStreams Required.

P.D. Apache Commons has a Library Called Apache Commons Configuration that has a lot of capabilities (reloadable files, multiple domain types) that could be used in combination of the above.

Gelvis
  • 189
  • 1
  • 6