'Properties file injection not working in spring

I am trying to use the properties file and inject it to my fields of a class, but I am getting null .

I have created a properties file called fortune.properties:

fortune1=Have a good day
fortune2=Have a bad day
fortune3=Have a medioccure day

Then I am loading it in the applicationContext.xml file:

<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
 
    <!-- Enable Component Scanning -->
    <context:component-scan base-package="com.luv2code.springdemo"></context:component-scan>
    <context:property-placeholder location="classpath:fortune.properties" />
</beans>

In the RandomFortuneClass, I am using value injection using @Value() annotation:

package com.luv2code.springdemo;
import java.util.Random;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component()
public class RandomFortuneService implements FortuneService {
    @Value("${fortune1}")
    private String fortune1;
    @Value("${fortune2}")
    private String fortune2;
    @Value("${fortune3}")
    private String fortune3;
    
    String[] fortunes = new String[] {fortune1, fortune2, fortune3};
    private Random random = new Random();
    
    @Override
    public String getFortune() {
        int index = random.nextInt(fortunes.length);
        return fortunes[index];
    }
}

Then I am declaring fortuneService in SwimCoach class using constructor injection:

package com.luv2code.springdemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component()
public class SwimCoach implements Coach {
    private FortuneService fortuneService;
    @Autowired
    SwimCoach(@Qualifier("randomFortuneService") FortuneService fs) {
        fortuneService = fs;
    }
    @Override
    public String getDailyWorkout() {
        System.out.println();
        return "Swim 5m everyday";
    }
    @Override
    public String getDailyFortune() {
        return fortuneService.getFortune();
    }
}

Now when I try to call the method getDailyFortune in the AnnotationDemoApp class, I always get null as output.

package com.luv2code.springdemo;
 
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class AnnotationDemoApp {
 
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Coach theCoach = context.getBean("swimCoach", Coach.class);
        System.out.println(theCoach.getDailyFortune());
        context.close();
    }
 
}

What is the error here?

Kindly comment if more information is needed.

Here is my file hierarchy:

spring_error

PS: I am following the spring & hibernate course for beginners by Chad Darby.



Solution 1:[1]

You simply need to move fortune.properties into /src/main/resources, but let me suggest a cleaner way...

First, drop the xml configuration, it's outdated by several years and everything you can do there can be done via java annotations.

Second, add your property files to src/main/resources.

Third, tell Spring where to resolve your properties from, you can do this by adding @PropertySources({@PropertySource("fortune.properties")}) to a configuration class like this (also note that I've added the @ComponentScan and @Configuration annotations here):

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;

@Configuration
@ComponentScan
@PropertySource("fortune.properties")
public class Config {

}

Fourth, in your main method, use the AnnotationConfigApplicationContext as opposed to the ClassPathXmlApplicationContext. I think you'll find it's much cleaner.

  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
    Coach theCoach = context.getBean("swimCoach", Coach.class);

    System.out.println(theCoach.getDailyFortune());
  }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 lane.maxwell