I'm somewhat new to Spring (using 3.0), so I'm hoping there is a simple answer. If I have a controller that is annotated with #Controller and #RequestMapping and I want to set a property via dependency injection, how do I go about doing that? The controller class doesn't have to appear in the Spring configuration file because it gets picked up automatically because of the #Controller annotation.
Example Controller class:
package gov.wi.dnr.wh.web.spring;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
public class RehabHomeController {
private String xxx;
#RequestMapping(value="/rehab/home", method = RequestMethod.GET)
public String get() {
return "whdb.rehabhome";
}
public String getXxx() {
return xxx;
}
public void setXxx(String xxx) {
this.xxx = xxx;
}
}
Spring 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: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-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<context:component-scan base-package="gov.wi.dnr.wh.web.spring"/>
<mvc:annotation-driven />
</beans>
This works as is, but I would like to inject the "xxx" property. How do I go about doing that?
#Autowired
private YourService yourServiceBean;
(you can also use #Inject)
Of course, YourService has to be declared as a bean - either in applicationContext.xml, or by annotations (#Service for example)
If you want to inject string properties, you can use the #Value annotation:
#Value("${propName}")
private String str;
(For that you will need a PropertyPlaceholderConfigurer)
Related
I have a simple app which is contains xml config, 1 spring session bean, controller. Everything works fine with an annotations, but looks like spring cannot see xml config because it cannot find Person bean?!
The question is how can i autowire beans through xml only?
Exception message:
No qualifying bean of type 'com.spring_beans_scope.beans.Person' available: expected at least 1 bean which qualifies as autowire candidate
<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" xmlns:aop="http://www.springframework.org/schema/aop" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="id1" class="com.spring_beans_scope.beans.WelcomeBean" scope="prototype">
<!--<property name="message" value="Welcome to spring" />-->
</bean>
<bean id="person" class="com.spring_beans_scope.beans.Person" scope="session">
<property name="name" value="Raj" />
<aop:scoped-proxy proxy-target-class="true" />
</bean>
<context:component-scan base-package="com.spring_beans_scope" />
<context:annotation-config />
</beans>
Bean
//#Service("person")
//#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Person {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
The head of the controller
#Controller
public class HelloController {
#Autowired
private Person person;
This answer is based on your comment that you want to know how to do it without the use of annotations.
You can do it without annotations. You need to use the autowire attribute on your bean declaration.
autowire="byName"
This may be a bit trickier as the #Controller annotation is not configured from xml but this stack overflow post helps explain how you can configure your controller to do so.
This tutorial helps explain the different ways you can autowire from the context file directly.
I have a profiles.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:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
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/util
http://www.springframework.org/schema/util/spring-util.xsd">
<!-- Local -->
<beans profile="local">
<util:properties id="localProperties">
<prop key="property">localProperty</prop>
</util:properties>
<context:property-placeholder properties-ref="localProperties" ignore-unresolvable="true" />
</beans>
<!-- Dev -->
<beans profile="dev">
<util:properties id="devProperties">
<prop key="property">devProperty</prop>
</util:properties>
<context:property-placeholder properties-ref="devProperties" ignore-unresolvable="true" />
</beans>
</beans>
and I have a org.springframework.ws.client.support.interceptor.ClientInterceptor that I want to use values from profiles.xml:
#Component
public class HeaderInjector implements ClientInterceptor {
#Value("${property}")
private static String someProperty;
#Override
public boolean handleRequest(MessageContext messageContext)
throws WebServiceClientException {
//want to use someProperty here based on value from profiles.xml
}
}
How can I do this? I tried adding #ImportResource("profiles.xml") at the top of the class like
#Component
#ImportResource("profiles.xml")
public class SoapLeadPipeHeaderInjector implements ClientInterceptor {
but someProperty never gets set.
First of all there is nothing about Spring Integration in your question, so be careful with choosing tags for questions.
#ImportResource("profiles.xml") can be applied on the #Configuration class if you start application context from annotations.
If your main entry point is XML configuration, your #Component must be scanned via <context:component-scan base-package="..."/> then.
See more info in the Spring Framework Reference Manual.
Is there anyway to get beans loaded via <context:component-scan/> in a xml file to be proxy'ed by an #Coniguration annotated class which has #EnableCaching and declares the SimpleCacheManager? This would be the easiest route for the large applicaiton I'm working with, my ultimate preference would be to convert it all over to a Configuration class, but that is a lot more work and there are next to no unit tests for this application -.- , something would totally break. The other option is to declare the Cache's in the xml which works fine but I feel like is a step backwards.
NOTE: The <context:annotation-config/> is declared in a separate xml file 'integration.xml' I put it back in the applicationContext.xml but it didn't affect anything.
The declaration of the caches and the enabling of the caching via #EnableCaching was moved to the below java class some time ago and I don't think anyone noticed that it stopped working. So I would like to get it working again in the best way.
Application Context (edited for brevity)
<?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:task="http://www.springframework.org/schema/task"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:cache="http://www.springframework.org/schema/cache"
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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
"
>
<util:properties id="properties" location="classpath:config.properties"/>
<context:property-placeholder properties-ref="properties"/>
<!-- TODO: Replace this with MethodInvokingBean - we don't actually *want* a ConfigFactory instance -->
<bean id="configFactory" class="net.adl.service.ConfigFactory">
<property name="properties" ref="properties" />
</bean>
<!-- Enable Caching -->
<cache:annotation-driven proxy-target-class="true"/>
<!-- Declaring the cache manager and caches here works, but I feel is a step backwards to put them back in the XML config -->
<context:component-scan base-package="
net.adl.quartz,
net.adl.config,
net.adl.dao,
net.adl.service,
net.adl.audit,
net.adl.diagnostic,
net.adl.loader,
net.adl.loader"/>
<!-- add support for #Scheduled -->
<task:scheduler id="taskScheduler" pool-size="10"/>
<task:executor id="taskExecutor" pool-size="10"/>
<!-- Used for real time monitoring of folders for data loads -->
<task:executor id="realTimeAutoLoaderExecutor" pool-size="1"/>
<task:annotation-driven scheduler="taskScheduler" executor="taskExecutor"/>
<!-- enable #Transactional annotations -->
<bean id="transactionAdvice" class="net.adl.aop.TransactionAdvice"/>
<!--<bean id="profiler" class="net.adl.util.Profiler"/>-->
<aop:aspectj-autoproxy proxy-target-class="true">
<aop:include name="transactionAdvice"/>
<!--<aop:include name="profiler"/>-->
</aop:aspectj-autoproxy>
<!-- set system properties -->
<bean id="systemPrereqs" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<!--
"systemProperties" is predefined; see:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html#expressions-beandef-xml-based
-->
<property name="targetObject" value="#{#systemProperties}"/>
<property name="targetMethod" value="putAll"/>
<property name="arguments">
<util:properties>
<prop key="net.sf.ehcache.skipUpdateCheck">true</prop>
<prop key="org.terracotta.quartz.skipUpdateCheck">true</prop>
</util:properties>
</property>
</bean>
<!-- Exception translation bean post processor -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean class="org.springframework.orm.hibernate4.HibernateExceptionTranslator"/>
<bean id="versionInfo" class="net.adl.util.VersionInfo">
<property name="versionFilePath" value="${labmatrix.home}/version-info.txt"/>
</bean>
<!-- Here is where we call in the <context:annotation-config/>, not sure why its done in a separate file -->
<import resource="resources/spring/integration.xml"/>
</beans>
Integration.xml -- I think the idea is more deployment specific config options can go in this one
<?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-3.1.xsd
"
>
<context:annotation-config/>
</beans>
MethodCachingConfiguration Class
package net.adl.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.support.NoOpCacheManager;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
#Configuration
#EnableCaching
public class MethodCacheConfiguration {
public static final String STUDY_CONFIG = "config.studies";
public static final String ACCESS_CONFIG = "config.access";
public static final String WORKFLOW_CONFIG = "config.workflows";
public static final String PROCESS_CONFIG = "config.processes";
public static final String QUERY_CONFIG = "config.queries";
public static final String AUTOLOADER_CONFIG = "config.autoloader";
public static final String LOCALIZATION = "localization";
public static final String FACTORY_CONFIG = "config.factories";
/**
* Configures the cacheManager bean for #Cacheable annotation support
*/
#Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(
new ConcurrentMapCache(STUDY_CONFIG),
new ConcurrentMapCache(ACCESS_CONFIG),
new ConcurrentMapCache(WORKFLOW_CONFIG),
new ConcurrentMapCache(PROCESS_CONFIG),
new ConcurrentMapCache(QUERY_CONFIG),
new ConcurrentMapCache(AUTOLOADER_CONFIG),
new ConcurrentMapCache(LOCALIZATION),
new ConcurrentMapCache(FACTORY_CONFIG)
));
return cacheManager;
}
}
EDIT: Fixed copy paste reformat typos
<cache:annotation-driven /> and #EnableCaching are equal you can have only one (maybe it can be source of your trouble) Can you provide example of code where you are actually using caching? Which bean should use cache feature.
Answer provided by chalimartines
When I access a bean from spring bean configuration file using BeanFactory like this:
public class Person {
private String id,address;
#Autowired
private Customer customer;
//setters & getters
}
and bean configuration file
<bean name="person" class="com.ram.spring.model.Person"></bean>
<bean class="com.ram.spring.model.Customer">
<property name="email" value="ram#adp.com"></property>
<property name="name" value="Ram"></property>
</bean>
here is the executor class
public class PersonExecutor {
public static void main(String[] args) {
BeanFactory context = new XmlBeanFactory(new ClassPathResource("Spring.xml"));
Person person = (Person)context.getBean("person");
System.out.println(person.getCustomer());
}
}
when I execute this, I got null.is BeanFactory not supported for annotations?? any ideas??
Approach 1: Include below code in your xml
<beans xmlns="http://www.springframework.org/schema/beans"
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-3.0.xsd">
<context:annotation-config />
<!-- Remaining bean declaration -->
</beans>
Approach 2: Remove #Autowired and inject customer in your xml file only.
<bean name="person" class="com.ram.spring.model.Person">
<property name="customer" ref="customer"></property>
</bean>
<bean name="customer" class="com.ram.spring.model.Customer">
<property name="email" value="ram#adp.com"></property>
<property name="name" value="Ram"></property>
</bean>
You have to use AnnotationConfigApplicationContext or
you have to add to yor Spring.xml to activate the annotation scan.
As #jens suggested
you should active annotation scan
<context:component-scan base-package="package_path">
</context:component-scan>
<context:annotation-config />
hope that helped
Why doesn't it work?
When using Spring with an XML context, using annotations is not activated by default. This means #Autowired, #Transactional, #PostConstruct and any other annotation you will use will simply not be exploited.
How do I fix it?
To make Spring aware of annotations, you need to add the following line:
<context:annotation-config />
Thus, Spring will search for annotations in the beans it creates and process them accordingly.
This requires activating the context namespace. At the top of your context, make sure you have all context related links and arguments1:
<beans xmlns="http://www.springframework.org/schema/beans"
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-3.0.xsd">
<context:annotation-config />
<!-- Your context -->
</beans>
You do not need <context:component-scan /> in your case. This would be useful if you used full-annotation context (e.g. classes annotated with #Component). See the difference between <context:annotation-config /> and <context:component-scan /> in this answer.
Alternate solution
As Naman Gala suggested, you could also drop #Autowired completely and inject all dependencies in XML. See the related answer for more details.
1 This includes the xmlns:context attribute (xmlns = XML NameSpace) and two URLs in xsi:schemaLocation.
I'm trying to run some tests for my controller but somehow the #Autowire annotation is not working.
Here is what I'm trying to do:
#WebAppConfiguration
#ContextConfiguration("/WEB-INF/spring/app-config.xml")
public class ClientsTest {
private Client client = new Cliente();
#Test
public void test() {
BindingResult result = mock(BindingResult.class);
ClientController clientController = new ClientController();
ModelAndView model = clientController.regClient(client, result);
Assert.assertEquals("success", model.getViewName());
}
}
#Controller
public class ClientController {
#Autowired private ClientService clientService;
#RequestMapping(value="/regClient.html", method = RequestMethod.POST)
public ModelAndView regClient(#ModelAttribute("client") #Valid Client client, BindingResult result){
ModelAndView model = new ModelAndView();
if(result.hasErrors())
{
model.setViewName("error");
}
else
{
model = clientService.regClient(client);
model.setViewName("success");
}
return model;
}
}
<?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"
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/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">
<!-- Scans the classpath of this application for #Components to deploy as beans -->
<context:component-scan base-package="com.app.app_v2.web" />
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>client</value>
</list>
</property>
</bean>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<ref bean="clientFormatter"/>
</set>
</property>
</bean>
<bean id="clientFormatter" class="com.app.app_v2.spring.ClientFormatter"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<bean id="clientService" class="com.app.app_v2.services.ClientService"/>
</beans>
As far as I know the clientService is null and this is why I'm getting the exception.
Because I don't know much about running test I'm asking for your help.
Your immediate problem about #Autowire not working is related to the fact that you're explicitly instantiating the clientController, and not through Spring framework. If you want the class to be a Spring bean you need to let the Spring framework manage its lifecycle, only than the dependency injection will kick-in, and all the spring beans annotated with #Autowire will be injected. Moreover, the test should be run with spring runner SpringJUnit4ClassRunner
Note that this is not necessary, cause with your test you can go two ways. More towards unit testing, by mocking your clientService e.g. via EasyMock or Mockito. Your currently posted test looks more geared towards that way. To learn how to complete your test take a look at this blog post
On the other hand, you can go for an integration test. Since version 3.2 Spring MVC offers test module which should really be the way to write integration test against Spring MVC. You can follow a great blog series backed with source code to learn how to do it.