Reputation: 6111
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 files
Upvotes: 2
Views: 10733
Reputation: 17774
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.
Upvotes: 3