This question already has answers here:
Spring JSF integration: how to inject a Spring component/service in JSF managed bean?
(4 answers)
Closed 6 years ago.
I have a webmodule with JSF 2 end Spring 4.3. In a backing bean I use #Autowired for DI of a service of a JAR. In EAR module there are WAR, JAR with #Service Spring and JAR with Spring configuration file.
Below a web.xml snippet:
<context-param>
<param-name>locatorFactorySelector</param-name>
<param-value>classpath:beanRefContext.xml</param-value>
</context-param>
<context-param>
<param-name>parentContextKey</param-name>
<param-value>sharedContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
applicationContext.xml:
<context:annotation-config />
<context:spring-configured />
<!-- package of #Service class in jar module in EAR-- >
<context:component-scan base-package="com.ipdb.service" />
beanRefContext.xml:
<bean id="sharedContext" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg>
<list>
<value>spring-ctx.xml</value>
</list>
</constructor-arg> </bean>
When I Use #Autowired(required=null) in a Backing Bean the value is null (there is not any exception). My JSF bean
#Component
#ManagedBean
#ViewScoped
public class PortfolioController {
#Autowired(required = true)
private PortfolioService portfolioService;
...
Can you help me, please.
PortfolioController is considered a JSF context bean adding #Component to #ManagedBean is totally wrong you can't mark same class as bean in two different contexts (JSF and Spring ).
Two solutions either make PortfolioController a spring bean thus remove the #ManagedBean and #ViewScoped or inject PortfolioController via JSF injection annotation #ManagedProperty
#ManagedProperty("#{portfolioService}")
private PortfolioService portfolioService;
if the applicationContext.xml is in your jar dependency, then you need to add asterisk after classpath:
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
With the asterisk spring search files applicationContext.xml anywhere in the classpath not only the current project.
Related
I am creating a war which is going to use a class from a jar file.
Now this jar file has a exposed a bean in its associationApplicationContext.xml which uses the #Required annotation on some of its properties for initialization.
associationApplicationContext.xml
e.g.
<!-- processes #Required annotations-->
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
<!-- The client bean to access the association rest web service -->
<bean id="associationClient" class="com.springtest.client.AssociationClientImpl">
<property name="associationRestClient" ref="associationServiceRestClient" />
</bean>
So inside the AssociationClient the property associationRestClient has #Required tag over its setter method.
#Required
public void setAssociationRestClient(final AssociationRestClient associationRestClient) {
this.associationRestClient= associationRestClient;
}
Now, as when I try to use this bean in my war file -
I have already put the jar dependency in pom.xml of war file
Already put the contextConfigLocation in web.xml as
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/associationApplicationContext.xml
</param-value>
</context-param>
Using the bean from inside the war file in another applicationcontext.xml file as
<import resource="classpath:/associationApplicationContext.xml"/>
<bean id="requestHandlerV1"
class="com.springtest.application.RequestHandlerV1">
<property name="associationClient" ref="associationClient"></property>
</bean>
Here the property associationClient is not getting initialized because it is not able to find the reference to bean associationRestClient which is associationServiceRestClient
I am getting
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'associationServiceRestClient' is defined
How can I get the object of associationClient initialized here ?
PS : I cannot change the implementation which uses #Required annotation
Assuming you have the following:
In web.xml:
<!-root application context-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:associationApplicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>JerseySpringWebApplication</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationcontext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!--URl for web service -->
<servlet-mapping>
<servlet-name>JerseySpringWebApplication</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
You don't have to import the associationApplicationContext.xml in applicationcontext.xml as now the root application beans will be visible in applicationcontext.xml. So application Context.xml will be like:
<mvc:annotation-config/>
<bean id="requestHandlerV1" class="com.springtest.application.RequestHandlerV1">
<property name="associationClient" ref="associationClient"></property>
</bean>
*Assuming you are invoking the controller through rest call.
If you still see issue with this, post your log.
I'm trying to integrate Spring with Vaadin, but I can't use the #Autowired annotation in my Vaadin classes.
Firstly, I created the followed maven structure
This is my web.xml
<web-app>
<display-name>Vaadin Web Application</display-name>
<context-param>
<description>Vaadin production mode</description>
<param-name>productionMode</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/application-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class> org.springframework.web.context.request.RequestContextListener </listener-class>
</listener>
<servlet>
<servlet-name>Vaadin Application Servlet</servlet-name>
<servlet-class>com.mycompany.config.AutowiringApplicationServlet</servlet-class>
<init-param>
<description>Vaadin UI to display</description>
<param-name>UI</param-name>
<param-value>com.mycompany.ui.MyUI</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Vaadin Application Servlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
This is my application-context.xml
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost/vaadin" />
<property name="username" value="postgres" />
<property name="password" value="tobbis" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="datasource"/>
<property name="persistenceUnitName" value="myUnit"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<jpa:repositories base-package="com.mycompany.repository"></jpa:repositories>
<context:annotation-config/>
<context:component-scan base-package="com.mycompany" />
Now I created my UserService that is within com.mycompany.services package
#Service
public class UserService {
public void saveUser(User user){
System.out.println("Test to Save");
}
}
And finally, I have my Panel where I want to inject the service
public class UserPanel extends VerticalLayout {
#Autowired
UserService service;
public UserPanel() {
// TODO Auto-generated constructor stub
Injector.inject(this);
service.saveUser();
}
}
but the result is always the same
Error creating bean with name 'com.mycompany.ui.UserPanel': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: com.mycompany.services.UserService com.mycompany.ui.UserPanel.service;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [com.aiem.services.UserService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Try to declare your UserService at applicationContext.xml
<bean name="userService" class="com.mycompany.services.UserService"></bean>
As far as I know,
Injector.inject(this);
is not something from Spring, you may be mixing it with another framework.
Instead, I would make UserPanel a prototype-scoped Spring component (meaning it can be instantiated and autowired by Spring, but you remain responsible for it's lifecycle).
#Component
#Scope(SCOPE_PROTOTYPE)
public class UserPanel extends VerticalLayout {
Note that a new instance will be created anytime UserPanel is retrieved from the context (e.g. autowired in another object). It could be best to control the creation of instances yourself by explicitly invoking
context.getBean(UserPanel.class)
at the right time.
AnnotationConfigWebApplicationContext is not meant to be used with XML config. It is supposed to be used with the #Configuration annotated classes.
Since you're using an xml file for Spring config, then you should instead remove these lines from web.xml:
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
And then by default Spring will use the XmlWebApplicationContext and pick up your xml file.
I have tried the same scenario than you. At the end, the solution is at the Vaadin documentation.
Seems that the problem is that we are using Vaadin context and not Spring context, and therefore we need to do the trick showed in the documentation (SpringHelper) to obtain any bean. Outside of the Spring context, the autowiring is not goint to work.
There is an addon for enabling autowiring via annotations: http://vaadin.xpoft.ru/.
Here is the link to the Vaadin site: http://vaadin.com/addon/springvaadinintegration. Hope it helps.
I have a question here, how beans defined in "applicationContext.xml" could be available to controllers defined in let's say "spring-servlet.xml", so i can skip this kind of errors i have.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name '/home' defined in ServletContext resource [/WEB-INF/mmapp-servlet.xml]: Cannot resolve reference to bean 'equipementService' while setting bean property 'equipementService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'equipementService' is defined
applicationContext.xml
<?xml version="1.0" ?>
<!DOCTYPE beans PUBLIC
"-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="equipementService"
class="mmapp.service.SimpleEquipementService" />
<bean name="equipement1"
class="mmapp.domain.Equipement" />
</beans>
mmapp-servlet.xml
<?xml version="1.0" ?>
<!DOCTYPE beans PUBLIC
"-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="/home" class="mmapp.web.HelloController">
<property name="equipementService" ref="equipementService" />
</bean>
</beans>
A Spring based web-application normally has multiple runtime Spring application contexts -
A root application context(which is loaded up during the start-up of the servlet container), here is where you normally put your beans for your services - the root application context is loaded up by using a ContextLoaderListener, typically using these entries in your web.xml file:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
One or more web application contexts, which is considered a child of the root application context, holding the beans related to the UI - controllers etc. This is configured by using a Dispatcher Servlet, a special servlet provided by Spring that knows to delegate the calls appropriately to the Spring Container. The beans in the root application context are visible to the beans defined here, BUT not the other way around - this way providing a level of separation between the UI layer and the services layer . This is a typical configuration entry in web.xml file:
<servlet>
<servlet-name>lovemytasks</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/mmapp-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
If you have defined the beans this way, the equipementService should be visible to your controller.
I'm not an expert and I'm not sure if this might be a problem, but I have a suggestion.
Could you post your web application descriptor (web.xml)? Does it contain the context-param?
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
UPDATED
I found an suspicious log entry:
org.springframework.beans.factory.wiring.BeanConfigurerSupport:
BeanFactory has not been set on BeanConfigurerSupport: Make sure this configurer runs in a Spring container.
Unable to configure bean of type [com.mycompany.projectname.App]. Proceeding without injection.
/UPDATED
I'm working on an Vaadin + Spring application and I wish to use JavaConfig.
According to some tutorial I built them up separately, but when I merge them I got the following (see the first codesnipet App.java - logger.info(">>mainWindow is null");)
app postconstruct ---------
mainWindow is null
I tried several variation of configs for example in applicationContext and so forth.
So my question is: how can I find out real problem ?
Thanks for your time and effort in advance.
Csaba
App.java
#Configurable
public class App extends Application
{
public MainWindow mainWindow;
public MainWindow getMainWindow(...
public void setMainWindow(Main....
#PostConstruct
public void init()
{
logger.info(">>app postconstruct --------- ");
if(mainWindow==null) logger.info(">>mainWindow is null");
else logger.info(">>mainWindow is not null");
}
AppConfig.java
#Configuration
public class AppConfig {
...
#Bean
public MainWindow mainWindow(){
return new MainWindow();
}
....
}
web.xml based on this !tutorial link!
...
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.mycompany.projectname.config.AppConfig</param-value>
</context-param>
...
<servlet>
<servlet-name>Vaadin Application Servlet</servlet-name>
<servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>
<init-param>
<description>Vaadin application class to start</description>
<param-name>application</param-name>
<param-value>com.mycompany.projectname.App</param-value>
</init-param>
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.mycompany.projectname.config.AppConfig</param-value>
</init-param>
</servlet>
Why are you using #Configurable? Do you mean to be using #Component instead?
#Configurable is typically used on domain objects (aka entities) that are not otherwise Spring-managed objects to allow them to receive dependency injection from the Spring container. This does not appear to be your goal. You should probably simply be wiring up your "App" class as another #Bean method, or otherwise marking it with #Component and picking it up via component-scanning (e.g. with #ComponentScan). Check out the related Javadoc and reference documentation for these annotations for more info.
Your annotations will not work if you didn't enabled them.
Do you have the following in your project spring context xml ?
<!-- Activate Spring annotation support -->
<context:spring-configured/>
<!-- Turn on #Autowired, #PostConstruct etc support -->
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<!-- Scans the classpath of this application for #Components to deploy as beans -->
<context:component-scan base-package="com.tc.poc.vaddinspring" />
Update: Look at this skeleton.
I use #Resource to annotate bean classes, #Autowired to autowire dependencies,
and in Spring configuration file these things:
context:component-scan base-package="package1,package2"
tx:annotation-driven
So, it works fine (tested). Spring scans package1, package2, classes with #Resource annotation
and then I can get them using getBean() IF TESTED FROM CONSOLE APPLICATION [say, with main() function].
But when I try to use next approach (to use Spring in container managed environment = with Tomcat):
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
compile a jar with all the bean classes and put this jar into WEB-INF/lib
then what I see? I cannot getBean() any of those #Resource annotated beans!
Spring simply cannot find them.
Still I can getBean() beans that are explicitly present in beans.xml.
Where's the problem?
Is missing <context:annotation-config/>?
<context:annotation-config/>
<context:component-scan base-package="package1"/>
<context:component-scan base-package="package2"/>
<tx:annotation-driven transaction-manager="transactionManager" />
or
<context:annotation-config/>
<context:component-scan base-package="package1, package2"/>
<tx:annotation-driven transaction-manager="transactionManager" />
I'm not sure how it's working in standalone mode, but the "" element in your Spring context allows the use "#Resource" annotations. Look at the Spring doc for more information.