2

I have Two projects, CarpoolDB and Carpool.

CarpoolDB : contains backend stuff and has

carpool-application-context.xml

<context:annotation-config />
<context:component-scan base-package="com.onmobile" />
<context:property-placeholder location="classpath:server.properties" />

server.properties

cm.db.driverClassName=com.mysql.jdbc.Driver
cm.db.url=jdbc:mysql://localhost:3306/carpool1
cm.db.username=abc
cm.db.password=xyz

I make a jar of carpoolDB and place in Carpool Application

Carpool: contains UI thing and for backend contact carpoolDB jar and has

carpool-application-context1.xml

<import resource="classpath:carpool-application-context.xml"/>
<context:annotation-config />
<context:component-scan base-package="com.onmobile.carpool.authentication" />

spring-servlet.xml

<context:property-placeholder location="classpath:carpool.properties" /> 

<context:annotation-config />
<context:component-scan base-package="com.onmobile.carpool.controller, com.onmobile.carpool.util" />

carpool.properties

cm.email.sender.mail.smtp.host=mail.on.com

Now, I have one class com.onmobile.carpool.util.EmailSender, it has one property smtpHost and want the value to get injected by Spring using @Value but it is not getting injected.

@Controller
public class EmailSender {

    public static final Log logger = LogFactory.getLog(EmailSender.class);

    @Value("${cm.email.sender.mail.smtp.host}")
    private String smtpHost;

}

I am getting error as

java.lang.IllegalArgumentException: Could not resolve placeholder 'cm.email.sender.mail.smtp.host'

carpool.properties is present in src folder.

Why it is not picking the cm.email.sender.mail.smtp.host from carpool.properties file. is there any relation with properties file present in jar file.

Actually properties file is loaded as I can't see in logs like file not found but field is not getting autowired.



Posting updated complete configuration files after removing import

web.xml

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
            /WEB-INF/carpool-application-context1.xml
            /WEB-INF/applicationContext-security.xml
        </param-value>
  </context-param>
  <filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>
            org.springframework.web.filter.DelegatingFilterProxy
        </filter-class>
  </filter>
  <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>/jsp/*</url-pattern>
  </servlet-mapping>
  <listener>
    <listener-class>
    org.springframework.web.context.ContextLoaderListener
    </listener-class>
  </listener>
  <listener>
    <listener-class>
        org.springframework.security.web.session.HttpSessionEventPublisher
        </listener-class>
  </listener>

carpool-application-context1.xml

<!-- Configure annotated beans --> 
<context:annotation-config />
<context:component-scan base-package="com.onmobile.carpooldb.db" />
<context:property-placeholder location="classpath:carpool.properties" />


   <beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <beans:property name="driverClassName"><beans:value>${cm.db.driverClassName}</beans:value></beans:property>
        <beans:property name="url"><beans:value>${cm.db.url}</beans:value></beans:property>
        <beans:property name="username"><beans:value>${cm.db.username}</beans:value></beans:property>
        <beans:property name="password"><beans:value>${cm.db.password}</beans:value></beans:property>
        <beans:property name="testOnBorrow"><beans:value>true</beans:value></beans:property>
        <beans:property name="testOnReturn"><beans:value>true</beans:value></beans:property>
        <beans:property name="validationQuery"><beans:value>select 1</beans:value></beans:property>
        <beans:property name="maxIdle"><beans:value>-1</beans:value></beans:property>
        <beans:property name="maxActive"><beans:value>-1</beans:value></beans:property>
        <beans:property name="maxOpenPreparedStatements"><beans:value>-1</beans:value></beans:property>
        <beans:property name="maxWait"><beans:value>30000</beans:value></beans:property>
    </beans:bean>

    //session factory bean and other configuration 

spring-servlet.xml

<context:property-placeholder location="classpath:carpool.properties" />

<context:annotation-config />
<context:component-scan base-package="com.onmobile.carpool.authentication, com.onmobile.carpool.controller, com.onmobile.carpool.util" />


<!-- Declare a view resolver -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />

<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

    <!-- one of the properties available; the maximum file size in bytes -->
    <property name="maxUploadSize" value="100000"/>
</bean>

carpool.properties

cm.db.driverClassName=com.mysql.jdbc.Driver
cm.db.url=jdbc:mysql://localhost:3306/carpool
cm.db.username=abc
cm.db.password=xyz

user.profile.pic.base.folder=D:\\carpoolRepository\\carpoolProfilePicUpload
google.places.autocomplete.response.xml.base.folder=D:\\carpoolRepository\\googleMapXML

#EMAIL - FORGOT PASSWORD 
cm.email.sender.mail.smtp.host=mail.on.com

I am trying to inject value of cm.email.sender.mail.smtp.host in EmailSender "smtpHost" property way mentioned above, when i read it it says null. other properties like cm.db.driverClassName etc get properly injected in carpool-application-context1.xml.

I am attaching the snap containing location for configuration filesenter image description here

Jayesh
  • 6,047
  • 13
  • 49
  • 81

1 Answers1

3

You have <context:component-scan base-package="com.onmobile" /> in the carpool-application-context.xml which is imported from carpool-application-context1.xml so that forces your controller to be created in the root web app context, because "com.onmobile" includes "com.onmobile.carpool.controller", and there is no property-placeholder config for the root context.

You have a property placeholder configurer in the servlet context(spring-servlet.xml). Property placeholder configurers(defined by the context:property-placeholder tag) are bean postprocessors and work on per container basis, so they can't modify the bean definitions of context they are not defined in. So it can't modify the bean definition of controller instance declared in the root context(carpool-application-context.xml, carpool-application-context1.xml). So because of the double scanning your controller is created twice - both in root and servlet context, and only one is processed by the correct placeholder configurer.

As a fix, you can use filter expressions in component-scan to pick up @Controller annotated classes only only in the spring-servlet.xml, and exclude it from carpool-application-context.xml/carpool-application-context1.xml

See @Service are constructed twice for examples of filters

Please keep your Spring configuration simple, your configuration is very puzzling.

update you are confusing controllers (which are annotated with @Controller and I think should be better put into aaa.bbb.controllers package) with services which should be annotated with @Service in the util package. My advice is to move your services to the root web app context(carpool-application-context1.xml) and put the property placeholder configurer declaration there.

Community
  • 1
  • 1
Boris Treukhov
  • 17,493
  • 9
  • 70
  • 91
  • _"Please keep your Spring configuration simple, your configuration is very puzzling."_ +1 to that. – ach Jan 31 '13 at 15:30
  • Hey Boris, Thanks for explaining and pointing to references which helped in getting the problem but still i am not very clear. can you please elaborate your first paragraph....please it will be lot helpful...thanks – Jayesh Jan 31 '13 at 16:07
  • It seems that the tag has been swallowed by the markdown, I'll fix it when I get to PC. The problem is that the first configuration file scans "com.onmobile" and that includes your controller class that has value annotation. Configurer is not defined in the root context(which processes appcontext and appcontext1 files), the situation is the similar as in the first link of the answer. No placeholder configurer in the root context, the configurer in servlet context can't do anything with the controller mistakingly created in the root context because postprocessors work on per app context basis. – Boris Treukhov Jan 31 '13 at 16:28
  • Hey Boris, really appreciated for your quick reply.I have restructured my app and now i have only carpool-application-context1.xml with data and spring-servlet.xml with data – Jayesh Jan 31 '13 at 17:43
  • still I am facing issue of @Value not working. what i should do to make it work. – Jayesh Jan 31 '13 at 17:46
  • You need to have the property placeholder configurer in the same app context where the controller declared. – Boris Treukhov Jan 31 '13 at 17:49
  • Are you sure that carpool-application-context.xml is out of the game? – Boris Treukhov Jan 31 '13 at 17:59