0

I am trying to use Spring to allow my Java classes to access a properties file. I have done quite a bit of googleing and there seems to be several ways of doing this. I have tried to use two of the different ways, and they are both failing.

Attempt 1
XML

<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    <property name="location" value=classpath:config.properties />
    <property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>

Java

public class App
{
    @Autowired
    private static Environment env;

    public static void main(String[] args)
    {
        System.out.println(env.getProperty("DatabaseName"));
    }
}

Attempt 2
XML

<util:properties id="myProperties" location="classpath:config.properties"/>

Java

public class App
{
    @Resource(name="myProperties")
    private static Properties myProperties;

    public static void main(String[] args)
    {
        System.out.println(myProperties.getProperty("DatabaseName"));
    }
}

In both cases I get a Null Pointer Exception when calling the "getProperty" method. I am new to Spring and am guessing I am missing something simple. In addition to getting these attempts to work, I would like to know what is the "best" way to expose a properties file with Spring.
Thank you in advance for any help.

Joe
  • 800
  • 4
  • 10
  • 26
  • Spring does not autowire static members. **Spring isn't even involved in what you are doing at all.** – Sotirios Delimanolis Dec 04 '13 at 15:01
  • Obviously I've gone down the wrong path. Can you please provide an example? – Joe Dec 04 '13 at 15:07
  • There are tons of examples on-line. The thing you have to understand is that Spring depends on its `ApplicationContext`. You haven't created or loaded an `ApplicationContext` anywhere. – Sotirios Delimanolis Dec 04 '13 at 15:09
  • I was under the impression that the Annotations loaded the Application Context behind the scenes. I have spent a lot of time searching online, but many of the example lack the Java side example code to help someone who is new to Spring. – Joe Dec 04 '13 at 15:12
  • 1
    Annotations are just metadata. They don't do anything on their own. You have to explicitly declare and instantiate an `ApplicationContext` implementation class. – Sotirios Delimanolis Dec 04 '13 at 15:14
  • The `ApplicationContext` is also called the IoC Container. It's all covered [here](http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-factory-instantiation) – Sotirios Delimanolis Dec 04 '13 at 15:15
  • @matsev This uses PropertyPlaceholderConfigurer which I believe is older method that has been replaced by PropertySourcesPlaceholderConfigurer – Joe Dec 04 '13 at 15:23
  • 2
    @Joe The use case is the same, just replace bean classes. – Sotirios Delimanolis Dec 04 '13 at 15:27
  • 1
    @Joe Correct, the `PropertySourcesPlaceholderConfigurer` is the preferred way as of Spring 3.1. However, the rest of my answer still applies, so you can copy relevant parts of my answer, and replace the `PropertyPlaceholderConfigurer` with the corresponding fully qualified name of `PropertySourcesPlaceholderConfigurer` in the bean declaration. – matsev Dec 04 '13 at 15:43

2 Answers2

1

==applicationContext.xml==

<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    <property name="location" value=classpath:config.properties />
    <property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>

<bean class="my.pckg.App">
  <property name="databaseName" value="${database.name}"/>
</bean>

==config.properties==

database.name=blah

==my.pckg.App==

public class App {

  private String databaseName;

  public void setDatabaseName(String databaseName) {
    this.databaseName = databaseName;
  }

  public String toString() {
    return "App (databaseName=" + databaseName + ")";
  }

}

==my.pckg.Main==

public class Main {
  public static void main(String [] args) {
    ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    App app = appContext.getBean(App.class);
    System.out.println(app);
  }
}
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
Pace
  • 41,875
  • 13
  • 113
  • 156
  • This is assuming that both config.properties and applicationContext.xml are at the root of the classpath. Also, I don't have an IDE handy so this is just freehand but it should give the gist. – Pace Dec 04 '13 at 15:11
  • Please add an explanation. – Sotirios Delimanolis Dec 04 '13 at 15:19
  • Thank you for the example, I see some of what I am missing. What I want to avoid is having to add more code for every property that I put in the properties file. If I add "database.username" I don't want to need to create a member variable in java and assign it individually with xml. – Joe Dec 04 '13 at 15:20
1

Here is your other way of doing it which seems to be what you want.

==applicationContext.xml==

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd">

    <util:properties id="myProperties" location="classpath:config.properties"/>

    <bean class="my.pckg.App">
        <property name="appProperties" ref="myProperties" />
    </bean>
</beans>

==config.properties==

database.name=blah

==my.pckg.App==

package my.pckg;

import java.util.Properties;

public class App {

      private Properties appProperties;

      public void setAppProperties(Properties appProperties) {
          this.appProperties = appProperties;
      }

      public String toString() {
        return "App (databaseName=" + appProperties.getProperty("database.name") + ")";
      }

}

==my.pckg.Main==

package my.pckg;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        App app = appContext.getBean(App.class);
        System.out.println(app);
    }
}
Pace
  • 41,875
  • 13
  • 113
  • 156
  • This is exactly what I was looking for. I've seen so many ways of getting the properties. Even though this is what I was looking for, is this a good method to continue to use in the future. Or are other methods considered "best practice"? – Joe Dec 04 '13 at 15:37
  • 1
    With this method you aren't really using Spring. This method could be useful if you are already using Spring or if you expect the location of the properties file to change. The upsides of the other approach are 1) Spring will parse and validate properties for you (e.g. integer properties). 2) You know exactly what properties the system uses with a glance at the app context. 3) Unit testing is much easier because you don't have to create fake properties files. 4) Your classes aren't even aware they're using a properties file and can focus on logic. – Pace Dec 04 '13 at 15:48