0
votes

I'm new with Spring MVC and I'm doing some tests. I was trying to find some answers about this issues, but most of them make references to Spring 3.11 and I'm using the last release: 4.1.6.

I want to load a ".properties" file when the application starts, and use the information in it to create a bean to access it in all the context of the app.

So far, I reach to load the file in the servlet-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd 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">
  ...
  <context:property-placeholder location="classpath*:resources/Resources.properties" />
</beans:beans>

I think (not really sure) that I correctly declared the bean in the root-context.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  <!-- Root Context: defines shared resources visible to all other web components -->
  <bean id="Resources" class="ar.com.violenciaesmentir.blog.resources.ResourcesDB"/>
</beans>

And I also think I made the bean correctly, but I don't really know if the annotations are right:

package ar.com.violenciaesmentir.blog.resources;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class ResourcesDB {
  @Value("DB.NAME")
  private String name;

  @Value("DB.TYPE")
  private String type;

  @Value("DB.USER")
  private String user;

  @Value("DB.PASS")
  private String pass;

  @Value("DB.DRIVER")
  private String driver;

  @Value("DB.URL")
  private String url;

  @Value("DB.MAXACTIVE")
  private String maxActive;

  @Value("DB.MAXIDLE")
  private String maxIdle;

  @Value("DB.MAXWAIT")
  private String maxWait;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getType() {
    return type;
  }

  public void setType(String type) {
    this.type = type;
  }

  public String getUser() {
    return user;
  }

  public void setUser(String user) {
    this.user = user;
  }

  public String getPass() {
    return pass;
  }

  public void setPass(String pass) {
    this.pass = pass;
  }

  public String getDriver() {
    return driver;
  }

  public void setDriver(String driver) {
    this.driver = driver;
  }

  public String getUrl() {
    return url;
  }

  public void setUrl(String url) {
    this.url = url;
  }

  public String getMaxActive() {
    return maxActive;
  }

  public void setMaxActive(String maxActive) {
    this.maxActive = maxActive;
  }

  public String getMaxIdle() {
    return maxIdle;
  }

  public void setMaxIdle(String maxIdle) {
    this.maxIdle = maxIdle;
  }

  public String getMaxWait() {
    return maxWait;
  }

  public void setMaxWait(String maxWait) {
    this.maxWait = maxWait;
  }
}

My ".properties" file:

DB.NAME = jdbc/Blog
DB.TYPE = javax.sql.DataSource
DB.USER = blog
DB.PASS = blog
DB.DRIVER = oracle.jdbc.driver.OracleDriver
DB.URL = jdbc:oracle:thin:@localhost:1521:xe
DB.MAXACTIVE = 20
DB.MAXIDLE = 5
DB.MAXWAIT = 10000

I think the reference is ok because it gave me troubles when starting the server, saying that it couldn't find the property for "name", but I was doing the annotation wrong and then I fixed.

What I want is to have that bean initialized and be avaible to have an attribute in the DB class like:

@ManagedAttribute
private ResourcesDB resources;
...
public void foo() {
  String dbName = resources.getName();
}

When I try it, resources is null. What I'm doing wrong?

-----UPDATE-----
Ok, I could solve the problem doing some try&fail with the answers given. First of all, I corrected the @Value like ("${DB.NAME}") and added a value to the service annotation @Service(value="Resources").

Then, the only change I got to do was in the servlet-context.xml. Instead of:

<context:property-placeholder location="classpath*:resources/Resources.properties" />

I used:

<beans:bean id="configuracion" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <beans:property name="location" value="classpath:Resources.properties"/>
</beans:bean>

And used @Autowire instead of @ManagedBean to access the bean.

2
look for PropertyPlaceholderConfigurer, and you should use "${db.user}"Marged
You should look into Spring Boot and @ConfigurationProperties.chrylis -cautiouslyoptimistic-

2 Answers

0
votes

There are 2 things flawed in your code.

  1. Your @Value expressions are wrong
  2. Your <context:property-placeholder /> must be in the same context as the beans

When using @Value you have to use placeholders, by default ${property name} you are just using a name. So update your annotations to reflect that. I.e. @Value("${DB.NAME}.

Next you have defined <context:property-placeholder /> in the context loaded by the DispatcherServlet whereas your beans are loaded by the ContextLoaderListener. The property placeholder bean is a BeanFactoryPostProcessor and it will only operate on bean definitions loaded in the same context. Basically your bean definition are in the parent context and your placeholder in the child context.

To fix move <context:property-placeholder /> to the same context where you bean is defined in.

Instead of @ManagedAttribute which is a JSF annotation use @Autowired or @Inject. And if you don't have a <context:component-scan /> add a <context:annotation-driven />.

0
votes

Your @Value syntax is incorrect. It should be @Value("${DB.NAME}").

You might also need to add this to your XML config:

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:resources/Resources.properties" />
</bean> 

The value on the location may vary, not sure on how you are structuring and building your artifacts.