PropertyPlaceholderConfigurer not loading programmatically - spring

I have a custom ApplicationContext class where I'm trying to programmatically load a PropertyPlaceholderConfigurer, then use the placeholders in my XML config file.
I've tried three different approaches so far, and each time I get an error like this:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named '${domain}.testId' is defined
What I am doing wrong?
Context class
public class MyApplicationContext extends GenericApplicationContext {
public MyApplicationContext (String... locations) throws IOException {
// method one
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this);
scanner.scan("com.my.package");
// method two
new MyPropertyPlaceholderConfigurer().postProcessBeanFactory(getBeanFactory());
// method three
getBeanFactory().registerSingleton("propertyPlaceholderConfigurer", new MyPropertyPlaceholderConfigurer());
// load XML config files
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(this);
for (String location : locations) {
xmlReader.loadBeanDefinitions(location);
}
}
}
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"
xmlns:aop="http://www.springframework.org/schema/aop"
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/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="test.testId" class="java.lang.String">
<constructor-arg value="this is the test value" />
</bean>
<bean id="prod.testId" class="java.lang.String">
<constructor-arg value="this is the prod value" />
</bean>
<alias name="${domain}.testId" alias="testId" />
</beans>
Usage
MyApplicationContext context = new MyApplicationContext(
new String[] { "test.xml" });
Assert.assertEquals("this is the test value", context.getBean("testId"));

I appreciate the answers on how to define the bean, but it turns out the problem was much simpler. I was loading the bean just fine, but I wasn't properly initializing my context after loading all the beans. A simple call to refresh() did the trick.
MyApplicationContext context = new MyApplicationContext(
new String[] { "test.xml" });
context.refresh(); // this runs BeanFactoryPostProcessors like
// MyPropertyPlaceholderConfigurer, among other things
Assert.assertEquals("this is the test value", context.getBean("testId"));

If you just want to use your own custom MyPropertyPlaceholderConfigurer (assuming it extends PropertyPlaceholderConfigurer, then all you need to do is to put it as a bean in your application context, it'll do all the rest for you:
<bean class="my.pkg.MyPropertyPlaceholderConfigurer" />

This is standard way how make your properties accessible in configuration file.
<util:list id="locations">
<value>classpath:appconfig.properties</value>
<value>classpath:jdbc.properties</value>
</util:list>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:ignoreResourceNotFound="true"
p:locations-ref="locations" />
<!-- bean that uses properties -->
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
p:driverClass="${jdbc.driver}"
p:jdbcUrl="${jdbc.url}"
p:user="${jdbc.user}"
p:password="${jdbc.pw}"
p:initialPoolSize="5"
p:minPoolSize="5"
p:maxPoolSize="50"
p:idleConnectionTestPeriod="5" />
Another quite useful way how to "inject" properties in your configuration file on ANY place is using maven: you use same syntax ${property-name} but values are supplied earlier during maven build process - this is relevant part of maven configuration:
<properties>
<jdbc.url>jdbc:mysql://localhost:3306/dummyuserdb</jdbc.url>
<jdbc.user>root</jdbc.user>
<jdbc.pw>admin</jdbc.pw>
</properties>
and you have to include your spring's configuration directory in maven filtered resources:
<build>
<resources>
<resource>
<directory>${basedir}/src/main/webapp/WEB-INF/spring-config</directory>
<filtering>true</filtering>
</resource>
</resources>
Or if you prefer java configuration:
#Configuration
#PropertySource(value = "config/jdbc.properties")
public class BaseWebConfig {
#Autowired Environment env;
#Bean
public MyBean myBean() {
MyBean myBean = new MyBean();
String propertyValue = env.getProperty("my-property-name");
// do something with myBean and propertyValue
return myBean;
}
}
}

Related

Having to use deprecated classes with Spring MVC

Have been trial Spring Web MVC (4.2.5) and have his a number of issues trying to use a DispatcherServlet and
<mvc:annotation-driven />
Have setup a simple #Controller class and wanted to use the POJO to JSON mapping. The docu said that if Jackson was detected on the class path it would be used automatically, however this didn't work for me and I was forced to use the 'deprecated' AnnotationMethodHandlerAdapter
<bean name="mappingJackson2HttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" >
<property name="messageConverters" ref="mappingJackson2HttpMessageConverter"/>
</bean>
which then worked fine.
Equally, tried to create a #ControllerAdvice class for handling all exceptions, but only got an #ExceptionHandler method working on the same controller class, and that was only when I added the (again) deprecated AnnotationMethodHandlerExceptionResolver to the context.
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver" />
Having to instantiate two deprecated classes suggests I am doing something wrong, especially when all the tutorials seem to suggest this should all 'just work', but I cannot see what (and indeed nosing through the Spring source I cannot see how the default and recommended handlers would work anyway)
There are no errors, the annotation simply aren't detected. The fill context xml is
please find the entire context XML below (is very simple)
<?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:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven enable-matrix-variables="true"/>
<bean name="mappingJackson2HttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" >
<property name="messageConverters" ref="mappingJackson2HttpMessageConverter"/>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver" />
<context:component-scan base-package="com.domain.datastore.dao"/>
<context:component-scan base-package="com.domain.service"/>
<context:component-scan base-package="com.domain.uiapi"/>
</beans>
An example controller is
#RestController("/place/*")
public class PlaceController {
private PlaceService placeService;
#Autowired
public PlaceController(PlaceService placeService) {
this.placeService = placeService;
}
#RequestMapping(path="/{id}", method = RequestMethod.GET)
public #ResponseBody Place getPlace(#PathVariable("id") long id, Model model) {
return placeService.getPlace(id);
}
}
and the cross-cutting exception handler is
#ControllerAdvice
public class GlobalExceptionController {
public GlobalExceptionController() {
System.out.println("GlobalExceptionController");
}
#ResponseStatus(HttpStatus.NOT_FOUND)
#ExceptionHandler(NotFoundException.class)
public ModelAndView handleCustomException(NotFoundException ex) {
return null;
}
}
The issue was that Spring MVC was matching the path in
#RestController("/place/*")
And as such passing the instance of PlaceController around as the handler. The ExceptionHandlerExceptionResolver expects a HandlerMethod and so was unable to process the exception.
As such dropping the path from the class annotation and putting the full path in the method got it all working and I dropped all the deprecated beans.
#RestController
public class PlaceController {
#RequestMapping(path="/place/{id}", method = RequestMethod.GET)
public #ResponseBody Place getPlace(#PathVariable("id") long id, Model model)
What I am not sure is if this is a bug. Shouldn't it be possible to put the 'base' path in the RestController annotation and the subpath in the RequestMapping?
As far as I can understand you don't want to use a deprecated class. AnnotationMethodHandlerAdapter is indeed Deprecated. As doc suggest you should use RequestMappingHandlerAdapter instead.
See here for the details.
And instead of AnnotationMethodHandlerExceptionResolver you can use ExceptionHandlerExceptionResolver.

Spring property place holder is not resolving in jaxws:client (cxf) address property

Environment:
Spring MVC : 4.1.7.RELEASE
CXF: 3.0.0
java: 1.8
web.xml --- loads appContext.xml (spring cofigs) & cxfContext.xml (configs for cxf)
spring-servlet.xml --- loading the spring mvc configs.
I'm using the below way to load the properties file.
#Configuration
#PropertySource(value = { "classpath:config.properties" })
public class Configuration {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Properties are getting resolved and no issues except in one case.
I'm using CXF for webservices and the address property is not getting resolved when "${addressVal}" is used. All other properties inside the xml are gettign loaded except for "jaxws:client".
<jaxws:client id="port"
serviceClass="com.service.Myclass"
address="${addressVal}" />
Where is the problem. What I'm doing wrong.
Problem with servlet context / application context loading ?
Please advice.
I am having the same problem. Sadly no solution found yet. However, for anyone finding this question, a workaround is using the JaxWsProxyFactoryBean.
Example:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schema/jaxws.xsd">
<bean id="client" class="demo.spring.service.HelloWorld" factory-bean="clientFactory" factory-method="create"/>
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="demo.spring.service.HelloWorld"/>
<property name="address" value="${some.property.value}"/>
</bean>
It is not as nice, becuase you have to inject the factory, call create() and cast, but at least it works.
#Autowired
#Qualifier("clientFactory")
private JaxWsProxyFactoryBean factory;
public void callService() {
HelloWorld helloWorld = (demo.spring.service.HelloWorld)factory.create();
}
You can also add the following to your spring config to create a specific bean, but that did not work for me. Trying to inject that bean failed, which is why I settled on the method described above.
<bean id="client" class="demo.spring.service.HelloWorld" factory-bean="clientFactory" factory-method="create"/>
See also http://cxf.apache.org/docs/writing-a-service-with-spring.html at the bottom of the page

Unitils: How can it obtain database properties from Spring

I am using Unitils with Spring for unit testing. I've configured Spring with datasource using a properties file.
My question is how can I use the same datasource or the same properties for Unitils?
Unitils expects a file in the classpath unitils.properties with database configuration parameters like url, user, password and driver.
I've tried to configure Unitils using the properties used in the Spring configuration as below but it is not working.
database.driverClassName=${jdbc.driver.class}
Thanks,
Adi
One potential solution... You could have your Spring configuration read its datasource parameters from the unitils.properties, instead of the other way around. Probably not ideal.
I believe unitils is using spring under the covers, so you might also try adding your datasource context in your unitils tests by using #SpringApplicationContext. If you could figure out the name of the datasource bean setup by unitils when it starts up, you could override it in your context (assuming the unitils datasource bean is created before the other spring beans are which may/may not be true.)
e.g.
#SpringApplicationContext({"correctDataSourceContext.xml"})
EDIT: Another option that will definitely work: https://stackoverflow.com/a/6561782/411229
Basically instantiate Unitils yourself and set the properties manually.
Ryan answer is correct and helpful as well though I've used different approach.
I extended the class PropertiesDataSourceFactory ro override the methods as follows:
public class UnitilsDataSourceFactory extends PropertiesDataSourceFactory {
#Override
public void init(Properties configuration) {
try {
String[] configFiles = new String[] { "applicationContext-test.xml" };
BeanFactory factory = new ClassPathXmlApplicationContext(configFiles);
SystemPropertiesReader systemPropertiesReader = (SystemPropertiesReader) factory.getBean("systemPropertiesReader");
Properties loadProperties = systemPropertiesReader.loadProperties();
super.init(loadProperties);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public DataSource createDataSource() {
DataSource dataSource = super.createDataSource();
return dataSource;
}
}
and also wrote a SystemPropertiesReader as:
public class SystemPropertiesReader {
private Collection<Resource> resources;
public void setResources(final Collection<Resource> resources) {
this.resources = resources;
}
public void setResource(final Resource resource) {
resources = Collections.singleton(resource);
}
#PostConstruct
public Properties loadProperties() throws Exception {
final Properties systemProperties = System.getProperties();
for (final Resource resource : resources) {
final InputStream inputStream = resource.getInputStream();
try {
systemProperties.load(inputStream);
} finally {
//
}
}
return systemProperties;
}
}
and added a bean with the properties file:
<bean id="systemPropertiesReader" class="uk.co.friendslife.eventmanager.domain.dao.SystemPropertiesReader">
<property name="resource">
<value>classpath:/META-INF/em/config/eventmanager_${database_name_lower}.properties</value>
</property>
</bean>
add the following to unitils.properties:
org.unitils.database.config.DataSourceFactory.implClassName=x.y.UnitilsDataSourceFactory
Just want to add some idea and im not sure if it is a best practice or not so correct me if theres something wrong.
MYPROJECT
-src
--TestPackage
---BaseServiceTest.class
---BlogspotServiceTest.class
--hibernate.cfg.xml
-web
--WEB-INF
---blogspot-servlet-test.xml
---jdbc-test.properties
in my case I used my blogspot-servlet-test.xml to call or to create the datasource
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
.... some bean configuration
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="file:web/WEB-INF/jdbc.properties"/>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- DAO'S -->
<bean id="blogspotDAO" class="package.BlogspotDAOImpl"/>
<!-- SERVICES -->
<bean id="blogspotService" class="package.BlogspotServiceImpl"/>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
MY jdbc-test.properties file
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.dialect=org.hibernate.dialect.MySQL5Dialect
jdbc.databaseurl=jdbc:mysql://127.0.0.1:3306/dbspringminiblogtest
jdbc.username=root
jdbc.password=
For hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd//hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping class="somePackage.entity.Author"/>
<!-- Other Entity Class to be mapped -->
</session-factory>
</hibernate-configuration>
and i created BaseClass for me to lessen creating of multiple #SpringApplicationContext annotation and it is also use to configure common configuration needed in testing other class, just extends it.
#SpringApplicationContext({"file:web/WEB-INF/blogspot-servlet-test.xml"})
public class BaseServiceTest extends UnitilsJUnit4 {
}
i used #SpringApplicationContext to load the datasource and other bean configurations on my BaseClass and this is how i implement it.
Below : see Spring-Unitils Tutorial
for more details
public class BlogspotServiceTest extends BaseServiceTest{
#Mock
#InjectInto(property = "blogspotDAO")
#SpringBean("blogspotDAO")
private BlogspotDAO blogspotDAOMock;
#TestedObject
#SpringBean("blogspotService")
private BlogspotService blogspotServiceMock;
#Test
public void testAddBlogSpot() {
assertNotNull("BlogspotService Not null",blogspotServiceMock);
}
}
NOTE: please create unitils.properties and unitils-local.properties inside TestPackage to be able to run the program.
For #SpringBean explanation and other annotation please read :
Unitils-EasyMock

Spring and auto-wiring: NullPointerException

I'm trying to get a grip on auto-wiring in Spring, but I can't seem to properly instantiate the bean (a DocumentBuilder). I have created a custom JSP tag as such:
public class MyTag extends SimpleTagSupport {
#Autowired
private DocumentBuilder documentBuilder;
public void setBuilder(DocumentBuilder builder) {
this.documentBuilder = builder;
}
#Override
public void doTag() throws IOException {
// documentBuilder is null in here!
}
}
This is the servlet configuration:
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Scan for HTTP/REST controllers -->
<context:component-scan base-package="the.right.package" />
<context:annotation-config/>
<bean id="documentBuilderFactory"
class="javax.xml.parsers.DocumentBuilderFactory"
factory-method="newInstance">
<property name="validating" value="false" />
<property name="ignoringElementContentWhitespace" value="true" />
</bean>
<bean id="documentBuilder" class="javax.xml.parsers.DocumentBuilder"
factory-bean="documentBuilderFactory"
factory-method="newDocumentBuilder">
</bean>
</beans>
Any ideas?
You can only inject in spring beans! But Jsp-Tags are no Spring Beans, so the Autowird annotation will be completely ignored, and therefore the field is null.
There are two solution:
use the #Configurable Support. -- But that requires real AspectJ. (I have never tried it for Tags, but I guess it will work for tags like for every other normal class). #see Spring Reference: Chapter 7.8.1 Using AspectJ to dependency inject domain objects with Spring
Extend your tag from the abstract Spring class RequestContextAwareTag. This provides access to the WebApplicationContext via getRequestContext().getWebApplicationContext(). Then you can use the WebApplicationContext to obtain the required beans programmatic.
Try to modify the code like this
public class MyTag extends SimpleTagSupport {
private DocumentBuilder documentBuilder;
#Autowired
public void setBuilder(DocumentBuilder builder) {
this.documentBuilder = builder;
}
#Override
public void doTag() throws IOException {
// documentBuilder is null in here!
}
}
You can use #Autowired if you mark your tag class as Spring bean. But it's stupid, because simple tags not caching by container. Each request creates own tag instance, but wiring happend only conteiner starts.

Spring Autowire Fundamentals

I am a newbie in Spring and am trying to understand the below concept.
Assume that accountDAO is a dependency of AccountService.
Scenario 1:
<bean id="accServiceRef" class="com.service.AccountService">
<property name="accountDAO " ref="accDAORef"/>
</bean>
<bean id="accDAORef" class="com.dao.AccountDAO"/>
Scenario 2:
<bean id="accServiceRef" class="com.service.AccountService" autowire="byName"/>
<bean id="accDAORef" class="com.dao.AccountDAO"/>
In AccountService Class:
public class AccountService {
AccountDAO accountDAO;
....
....
}
In the second scenario, How is the dependency injected ? When we say it is autowired by Name , how exactly is it being done. Which name is matched while injecing the dependency?
Thanks in advance!
Use #Component and #Autowire, it's the Spring 3.0 way
#Component
public class AccountService {
#Autowired
private AccountDAO accountDAO;
/* ... */
}
Put a component scan in your app context rather than declare the beans directly.
<?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">
<context:component-scan base-package="com"/>
</beans>
<bean id="accServiceRef" class="com.service.accountService" autowire="byName">
</bean>
<bean id="accDAORef" class="com.dao.accountDAO">
</bean>
and
public class AccountService {
AccountDAO accountDAO;
/* more stuff */
}
When spring finds the autowire property inside accServiceRef bean, it will scan the instance variables inside the AccountService class for a matching name. If any of the instance variable name matches the bean name in the xml file, that bean will be injected into the AccountService class. In this case, a match is found for accountDAO.
Hope it makes sense.

Resources