1

My PC's operating system is Windows 7 64-bit.

I created a very simple Dynamic Web Project app in Eclipse:

I have a app.properties file in WEB-INF/classes directory with these properties:

DefaultMaximumBatchSize=1000
DAOFactory=MSSQLSERVER

I have a class AppProperties which reads the above file into a Properties object at startup using getResourceAsStream:

public class AppProperties {
   private static final Properties APP_PROPERTIES;
   static {
      InputStream inputStream = null;

      APP_PROPERTIES = new Properties();

      try {
         inputStream = AppProperties.class.getResourceAsStream("/WEB-INF/classes/app.properties");
         System.out.println("AppProperties: inputStream=" + inputStream);

         if (inputStream != null) {
            APP_PROPERTIES.load(inputStream);
         }
      } catch (Exception e) {
         System.out.println("AppProperties: Exception occured; e=" + e);
      }
   }

   public static String getValue(String propertyName) {
      if (propertyName == null || propertyName.equalsIgnoreCase(""))
         return null;
      else
         return APP_PROPERTIES.getProperty(propertyName);
   }
}

I have a listener class AppContextListener:

public class AppContextListener implements ServletContextListener {

    public AppContextListener() {
    }

    public void contextInitialized(ServletContextEvent arg0) {
        String defaultMaxBatchSize = AppProperties.getValue("DefaultMaximumBatchSize");
        System.out.println("AppContextListener: contextInitialized(ServletContextEvent): defaultMaxBatchSize=" + defaultMaxBatchSize);
    }

    public void contextDestroyed(ServletContextEvent arg0) {
    }

}

I deployed the app to JBoss 4.2.3, run the JBoss 4.2.3 and I get this output in server.log:

AppProperties: inputStream=java.io.FileInputStream@1adde645
AppContextListener: contextInitialized(ServletContextEvent): defaultMaxBatchSize=1000

Perfect.

I then deployed the same app to WildFly 8.2.1, run the WildFly 8.2.1 and I get this output in server.log:

AppProperties: inputStream=null
AppContextListener: contextInitialized(ServletContextEvent): defaultMaxBatchSize=null

What happened? What is the correct way to read properties file in WildFly from WEB-INF/classes directory?

srh
  • 1,661
  • 4
  • 30
  • 57

3 Answers3

4

Class.getResourceAsStream() looks for a resource in all of the directories and jars that constitute the classpath of the application.

So, if you start a java program with

java -cp foo;bar.jar com.baz.Main

And you use SomeClass.class.getResourceAsStream("/blabla/app.properties"), The classloader will look for the app.properties file under foo/blabla, and in the blabla directory of bar.jar.

Now, in a webapp, what constitutes the classpath of the webapp is

  • the directory WEB-INF/classes
  • all the jar files under WEB-INF/lib

So, if you call

AppProperties.class.getResourceAsStream("/WEB-INF/classes/app.properties")

the classloader will look for app.properties in

  • /WEB-INF/classes/WEB-INF/classes
  • <all the jar files of WEB-INF/lib>/WEB-INF/classes

The conclusion is that, to load an app.properties file located in WEB-INF/classes, what you need is

AppProperties.class.getResourceAsStream("app.properties")
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Thanks for very detailed answer as always. `/app.properties` worked in WildFly 8.2.1 and it also worked in JBoss 4.2.3. Why `/WEB-INF/classes/app.properties` worked in JBoss 4.2.3? Does JBoss 4.2.3 uses different classloader algorithm than WildFly 8.2.1? – srh Sep 03 '15 at 14:04
  • The classpath of a webapp is not a JBoss/Wildfly thing. It's a standard, specified in the Java EE spec. I have no idea why it worked in JBoss. – JB Nizet Sep 03 '15 at 14:06
  • I printed out the context ClassLoader `Thread.currentThread().getContextClassLoader()` and JBoss 4.2.3 gives the output `WebappClassLoader delegate: false repositories: /WEB-INF/classes/ ----------> Parent Classloader: java.net.FactoryURLClassLoader@e77d77b` while WildFly 8.2.1 gives the output `ModuleClassLoader for Module "deployment.TestWebReadPropertiesFile.war:main" from Service Module Loader`. TestWebReadPropertiesFile.war is the application deployed. What is that means? – srh Sep 03 '15 at 14:23
  • No idea. I don't know the internals of Wildfly. – JB Nizet Sep 03 '15 at 14:26
  • ok. Thanks. I just have to justify to my manager that we need to change the code to upgrade from JBoss 4.2.3. to WildFly 8.2.1 and that's why I was enquiring – srh Sep 03 '15 at 14:29
3

JBoss shouldn't have worked.

Class.getResourceAsStream retrieves the resource from the classpath and the webapp root folder is not in the classpath.

The WEB-INF/classes folder is. Use getResourceAsStream("/app.properties"), and remember to close the stream:

 private static final Properties APP_PROPERTIES = new Properties();
 static {
   try (InputStream inputStream = AppProperties.class.getResourceAsStream("/app.properties")) {
      System.out.println("AppProperties: inputStream=" + inputStream);
      if (inputStream != null)
         APP_PROPERTIES.load(inputStream);
   } catch (Exception e) {
      System.out.println("AppProperties: Exception occured; e=" + e);
   }
}

Now, if app.properties is always next to AppProperties.class, instead of at the root, make the name unqualified (remove the /). This will work even when your class is in a package (and it is in a package, right?).

Andreas
  • 154,647
  • 11
  • 152
  • 247
  • Thanks. `/app.properties` worked in WildFly 8.2.1 and it also worked in JBoss 4.2.3. Why `/WEB-INF/classes/app.properties` worked in JBoss 4.2.3? Does JBoss 4.2.3 uses different classloader algorithm than WildFly 8.2.1? – srh Sep 03 '15 at 14:03
  • @srh Correct. JBoss uses a different classloader strategy that's not conformant with the Servlet specification. You *can* configure it to be, but the default setup is different. At least it used to be. I think AS7 changed things. – Andreas Sep 03 '15 at 15:50
-1

Try

InputStream inputStream =
    this.getClass().getClassLoader().getResourceAsStream("/my.properties");`
Leistungsabfall
  • 6,368
  • 7
  • 33
  • 41
redMist
  • 219
  • 2
  • 12
  • why downvote? my answer is correct – redMist Sep 02 '15 at 22:46
  • No, it's not. `ClassLoader.getResourceAsStream()` expects a path without a leading slash. It also doesn't explain anything to the OP. And trying to load "my.properties" when the file is named "app.properties" certainly won't help. – JB Nizet Sep 03 '15 at 06:02
  • @JB Nizet it doesn expect path without leadin slash check [here](http://stackoverflow.com/questions/3160691/how-to-read-properties-file-in-web-application) or [here](http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getResourceAsStream%28java.lang.String%29), also this is just example OP can replace name of file with whatever he needs. and I didn't explain because answer can be easily found on google. If anything you should downvote OP question. – redMist Sep 03 '15 at 12:09
  • Almost every question asked here can find its answer on google. That's not a reason to not explain answers. And you pointed me to the javadoc of Class.getResourceAsStream(), which can take a path with a leading slash. Not the same as ClassLoader.getResourceAsStream(). – JB Nizet Sep 03 '15 at 12:50