Kallel Omar
Kallel Omar

Reputation: 1218

Read file properties using Spring annotations

I'm trying to learn how to read properties file using spring. After an internet searching I found that I can use @value and @PropertySource annotations to achieve that. I created a project which has the following structure and classes codes:

Structure of the project:

enter image description here

AppConfigMongoDB.java implementation:

package com.mongodb.properties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;


@PropertySource("classpath:config/config.properties")
public class AppConfigMongoDB {

@Value("#{mongodb.url}")
private String mongodbUrl;


@Value("#{mongodb.db}")
private String defaultDb;

public String getMongoDb()
{
    return defaultDb;
}

public String getMongoDbUrl()
{
    return mongodbUrl;
}
}

SpringConfiguration.java implementation:

 package com.mongodb.properties;

 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;

 @Configuration
 public class SpringConfiguration {
 @Bean
 public AppConfigMongoDB getAppConfigMongoDB(){
        return new AppConfigMongoDB();
  }
 }

Main.java

package com.mongodb.properties;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

public static void main(String[] args) {
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
    AppConfigMongoDB mongo = applicationContext.getBean(AppConfigMongoDB.class);
    System.out.println("db= "+mongo.getMongoDb());
    System.out.println("URL= "+mongo.getMongoDbUrl());
  }
}

The properties file that I'm reading from called config.properties, it contains the following lines:

mongodb.url=1.2.3.4
mongodb.db=dataBase

I tested this small project and I got a stack trace that contains the following exception:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'getAppConfigMongoDB': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.lang.String com.mongodb.properties.AppConfigMongoDB.mongodbUrl; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'mongodb' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public?
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1202)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84)
at com.mongodb.properties.Main.main(Main.java:9)

 Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'mongodb' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public?
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:226)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:93)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:81)
at org.springframework.expression.spel.ast.CompoundExpression.getValueRef(CompoundExpression.java:51)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:87)
at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:120)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:242)
at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:161)
... 18 more

Is it a problem of Spring calling beans? Or maybe is it a problem of properties file path or something else?

Upvotes: 11

Views: 62611

Answers (2)

Ayaskant
Ayaskant

Reputation: 569

Nice reply given by @Ian Sparkes . Adding some of my inputs here. Configuring the PropertySourcesPlaceholderConfigurer is not mandatory. I am able to get the value from my properties file and set it to the filed variable of my main Configuration class without it.

There is also another way to get the values of your keys in the properties file. Use org.springframework.core.env.Environment class . This class automatically loads all the key-value pairs in properties file that is in class path.

Example :

@Configuration
@ComponentScan(basePackages="com.easy.buy")
@PropertySource({"classpath:config.properties","classpath:props/db-${env}-config.properties", 
	"classpath:props/app-${env}-config.properties"})
public class CatalogServiceConfiguration {
	Logger logger = LoggerFactory.getLogger(CatalogServiceConfiguration.class);
	
	//This object loads & holds all the properties in it as key-pair values
	@Autowired
	private Environment env;
	
	/**
	 * Instantiate the DataSource bean & initialize it with db connection properties
	 * @return
	 */
	@Bean(name="basicDataSource")
	public BasicDataSource basicDataSource() {
		String dbUrl = env.getProperty("db.url");
		String dbUser = env.getProperty("db.user");
		String dbPwd = env.getProperty("db.pwd");
		String driver = env.getProperty("db.driver");
		
		logger.info("Initializing CatalogServiceConfiguration");
		logger.info("dbUrl=" + dbUrl);
		
		BasicDataSource ds = new BasicDataSource();
		ds.setDriverClassName(driver);
		ds.setUrl(dbUrl);
		ds.setUsername(dbUser);
		ds.setPassword(dbPwd);
		
		return ds;
	}
}

Upvotes: 0

ISparkes
ISparkes

Reputation: 1783

I can see several issues in the code.

1) Your place holders for values should be in the form ${mogodb.url}, not #{mongodb.url}. The "#" has a different meaning (See Spring Expressions).

2) You are going to need a PropertySourcesPlaceholderConfigurer bean to do the injection of the values

3) Sooner or later you are going to have a number of Beans floating around, and in I would use @ComponentScan to allow the context to know these without you having to mention them one by one

4) If you use ComponentScan to get the beans, you are going to have to provide AppConfigMongoDB bean once

I end up with these classes after doing all that:

Main.java

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

public static void main(String[] args) {
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
    AppConfigMongoDB mongo = applicationContext.getBean(AppConfigMongoDB.class);
    System.out.println("db= "+mongo.getMongoDb());
    System.out.println("URL= "+mongo.getMongoDbUrl());
  }
}

SpringConfiguration.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

@Configuration
@ComponentScan
public class SpringConfiguration {

  @Bean
  public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
    return new PropertySourcesPlaceholderConfigurer();
  }
}

AppConfigMongoDB.java

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource("classpath:config/config.properties")
public class AppConfigMongoDB {

  @Value("${mongodb.url}")
  private String mongodbUrl;

  @Value("${mongodb.db}")
  private String defaultDb;

  public String getMongoDb() {
    return defaultDb;
  }

  public String getMongoDbUrl() {
    return mongodbUrl;
  }
}

Upvotes: 26

Related Questions