daydreamer
daydreamer

Reputation: 92019

Spring: How to inject values with @Value annotation by reading from external properties file?

I have following situation
- Have a MongoService class, which reads host, port, database from file

xml configuration

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>file:///storage/local.properties</value>
            </list>
        </property>
    </bean>
</beans>  

The local.properties looks like

### === MongoDB interaction === ###
host="127.0.0.1"
port=27017
database=contract

and MongoService Class as

@Service
public class MongoService {

    private final Mongo mongo;
    private final String database;
    private static final Logger LOGGER = LoggerFactory.getLogger(MongoService.class);

    public MongoService(@Nonnull final @Value("#{ systemProperties['host']}") String host, @Nonnull final @Value("#{ systemProperties['port']}") int port, @Nonnull final @Value("#{ systemProperties['database']}") String db) throws UnknownHostException {
        LOGGER.info("host=" + host + ", port=" + port + ", database=" + db);
        mongo = new Mongo(host, port);
        database = db;
    }
}

When I want to test that bean is fine, I do the following in
MongoServiceTest.java

public class MongoServiceTest {

    @Autowired
    private MongoService mongoService;

}

It complains saying that can not identify bean for MongoService .

Then I add the following to above xml

<bean id="mongoService" class="com.business.persist.MongoService"></bean>

Then it complains saying "No Matching Constructor found"

What I want to do

a.) MongoService should be @Autowired and reads configuration params from <value>file:///storage/local.properties</value>

Question

a.) Is accessing values in constructor are correct? (file name is local.properties and I am using @Value("#{ systemProperties['host']}") syntax)

b.) What is that I need to make it work so that @Autowired private MongoService mongoService loads correctly and reads value off local.properties file.

P.S. I am very new to Spring and don't really know how to make this work

Thanks much for your help in advance

Upvotes: 3

Views: 4170

Answers (2)

nayakam
nayakam

Reputation: 4249

I think , You have to add constructor-arg to config xml as follows.

<bean id="mongoService" class="com.business.persist.MongoService">

        <constructor-arg type="java.lang.String">
            <value>host</value>
        </constructor-arg>

        <constructor-arg type="int">
            <value>port</value>
        </constructor-arg>

        <constructor-arg type="java.lang.String">
            <value>database</value>
        </constructor-arg>

    </bean>

I am not sure,Bst way could be adding java based bean config. Remove the bean definition from xml and add java-based congfig as follows

@Service
public class MongoService {

    private final Mongo mongo;
    private final String database;
    private static final Logger LOGGER = LoggerFactory.getLogger(MongoService.class);

@bean
    public MongoService(@Nonnull final @Value("#{ systemProperties['host']}") String host, @Nonnull final @Value("#{ systemProperties['port']}") int port, @Nonnull final @Value("#{ systemProperties['database']}") String db) throws UnknownHostException {
        LOGGER.info("host=" + host + ", port=" + port + ", database=" + db);
        mongo = new Mongo(host, port);
        database = db;
    }
}

HTH

Upvotes: 2

Jesse Webb
Jesse Webb

Reputation: 45253

By default, Spring instantiates objects using the default constructor (with no args) and then uses the setter methods to set all the properies. If you don't want to (or can't) use the setters or define a default construtor, you have to tell spring what to pass in as constructor args.

Here is a blog post explaining how it can be done:
http://www.javalobby.org/java/forums/t18396.html

The basic syntax looks like this:

<bean name="MyBean" class="com.example.BeanClass">
  <constructor-arg index="0"><ref bean="OtherBeanName"/></constructor-arg>
</bean>

The index attribute is optional but it requires you to order the XML constructor-arg elements in the same order as the params to the constructor.

Upvotes: 0

Related Questions