How to use Spring services in JSF-managed beans? - spring

JSF is very popular technology in Java world, however, cooperation with Spring is still painfull and requires 'nasty' hacks. I have currently the problem with one of this 'hacks'.
Spring services are injected using the SpringBeanFacesELResolver. It is configured in faces-config.xml:
<application>
<el-resolver>
org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver>
</application>
The injection of Spring services is very ugly, but it is working:
#ManagedProperty(value="#{customerService}")
CustomerService customerService;
But there are issues. JSF requires from me that the managed bean should be serializable. That means, that the Spring service must also be serializable, or the field should be transient. When the field is transient, the injection is not working (I have null in that field). And making Spring services serializable is in my opinion not a good idea and a potential performance issues - what should happen with Hibernate context, data sources, which all are injected into Spring service?
So, what is the correct and less painfull way of using Spring services withing JSF managed beans?

I experienced a lot of issues with org.springframework.web.jsf.el.SpringBeanFacesELResolver, too. Mostly related to unmatching object scopes (Spring has no equivalent to JSF's view scope and conversation scope). Some people also complain about serialization problems.
I successfully applied the solution proposed in this article: http://www.beyondjava.net/blog/integrate-jsf-2-spring-3-nicely/.
In my case, serialization, was not a problem and I was only concerned with bean scopes. I wished JSF to fully manage the backing beans lifecycle without interference with Spring beans lifecycle.
I made JSF managed beans to load the Spring context and autowire themselves to access Spring-managed beans from the JSF context.
I developed the following JSF bean superclass:
public abstract class AutowireableManagedBean {
protected AutowireCapableBeanFactory ctx;
#PostConstruct
protected void init() {
logger.debug("init");
ctx = WebApplicationContextUtils
.getWebApplicationContext(
(ServletContext) FacesContext.getCurrentInstance()
.getExternalContext().getContext())
.getAutowireCapableBeanFactory();
// The following line does the magic
ctx.autowireBean(this);
}
...
}
Then, my concrete JSF backing beans looked like this (I was able to use view scope without problems):
#ManagedBean
#ViewScoped
public class MyBackingBean extends AutowireableManagedBean {
#Autowired
private MyDao myDao;

Related

After registering SpringBeanFacesELResolver, #Named #RequestScoped behaves like Spring singleton

I am creating new JSF 2.2 application and found this issue:
I have:
1) EL Resolver
<application>
<locale-config>
<default-locale>ru</default-locale>
</locale-config>
<resource-bundle>
<base-name>i18n.messages</base-name>
<var>msg</var>
</resource-bundle>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
<!--<variable-resolver>org.springframework.web.jsf.WebApplicationContextVariableResolver</variable-resolver>-->
</application>
2) Faces Bean
#Named("SubscriberBalance")
#RequestScoped
public class SubscriberBalance extends AbstractManagedBean {
private static final long serialVersionUID = -7018658511320101002L;
private SupportService supportService;
private SubscriberBalanceWrapper subscriberBalance;
private Long subscriberId;
private Integer subscriberType;
private Integer months;
3) Spring4+Hibernate4
And after that,my bean shares data between all users. It behaves like spring singleton. It seems like it ignore JSF scopes and process only Spring scopes. So #Scope("request") is working, but #RequestScope doesnt. How to do it correctly? And why it happening? Thank you
I think I figured out this issue and may be it will be helpful for someone.
So we have:
1) CDI - feature of Java EE 6
2) Spring framework
3) JSF
First of all, Spring never interact with CDI in my case. CDI #Named annotation is JSR 330 annotation. But since spring 3.0, Spring also scans those annotations. So that`s why in my case #Named works.
The second, #Named is full equivalent to #Component. So I could use #Component there as well.
#RequestScope and other JSF annotations will not work because its not JSF context, but Spring context. If we need to use JSF context, we need to use #ManagedBean, etc.
#Scope annotation works because its Spring-managed bean, because I have package-scan enabled for my bean.
So approaches are:
1) Use pure JSF with #ManagedBean annotations. I dont prefer this way. Disadvantages are: poor DI integration, much handy work, etc
2) Use CDI. I dont like it as we have Spring
3) Use Spring everywhere. I love this way as it gives me one-way control on all parts of my system. I will not have to think about JSF specific annotations until I really need them.
So in JSF backend bean should be:
#Controller
#Scope(...)
Please see this article
Thank you

How to inject service in JSF managed bean without using Spring IOC

Typically if I have to inject a service in Spring I use
<bean id="mycontroller" class="com.MyController">
<property name="myService" ref="myService" />
and
<bean id="myService" class="com.MyService"></bean>
How to do the same when using JSF? I dont want to use two IOC containers for the beans and rather keep it in faces context itself. I have seen links such as
JSF 2 inject Spring bean/service with #ManagedProperty and no xml
and A problem about injecting spring bean into jsf bean . They talk about injecting Spring managed bean into JSF context.
What I am trying to do must be really simple but am not able to find any relevant info. Am a newbie and will appreciate any help.
I think you may be confused by the word "bean".
The thing is, the "service" you are talking about is also a Spring bean, right?
You probably have it as a service cause it has some additional features (probably transaction management) added by Spring, according to your configuration.
The JSF IoC container is very simplistic, it does not allow you to configure its lifecycle to include transaction management, AOP and things like that. Those things you have to do with Spring (or EJB, in a Java EE environment).
So, when using JSF with Spring, you usually have two choices:
Either you put the backing beans for the JSF pages in the JSF container, annotating them with #ManagedBean, #RequestScoped, #ViewScoped, etc; and injecting any necessary Spring bean with #ManagedProperty in a property (a setter is required)
Or skip the JSF container and put the backing beans along with all others in the Spring container, and use the Spring scopes of request/session, annotating them with Spring's annotations #Component, #Scope("request"), #Scope("session") and injecting with #Autowired, #Qualifier and the like.
Personally, faced with that choice I'd go with the first choice, cause it gives you #ViewScoped and some other niceties. It's true it makes use of two IoC containers but then, which Java EE app does not?
If you want to go the second route anyway, you may also add a view scope for Spring beans, backed by JSF viewMap.
What Spring calls a "Service" is in Java EE terms an "EJB". EJB is out the box available in Java EE web profile containers like Glassfish, JBossAS and TomEE.
To create a stateless EJB service, just use #Stateless on the class:
#Stateless
public class SomeService {
public void doSomething() {
// ...
}
}
And to inject it in a JSF managed bean, just use #EJB on the property-to-be-injected:
#ManagedBean
#ViewScoped
public class SomeController {
#EJB
private SomeService service;
}
That's it. No getter/setter necessary. No XML boilerplate necessary.

jsf 2.0 spring 3 scope request not working

I am trying to use spring to provide managed beans to jsf. I assume that #ManagedBean will be picked up by JSF container to link the EL in JSF to managed bean even when I use spring by configuring spring usage in faces-config.xml.
Spring shall provide the beans but now who manages scope of the beans?
I have tried following annotation on beans to have it become Request scope but they do not work.
#ManagedBean(name="helloBean") //meant for JSF
#RequestScoped //meant for JSF
#Scope(value="request") //meant for spring
#Controller //meant for spring
public class HelloBean implements Serializable {
Actually earlier I was using plain JSF and #ManagedBean and #RequestScoped were working well. Now as I tried to integrate using spring the scope are not working.
I have even tried setting bean scope in spring config but they work as expected in context of spring (singleton and prototype) but not web request context.
I was trying to avoid having to use above #Scope and #Controller annotation hoping that JSF will manage scope but do not seem like.
Below are my files snippet for spring config and MyHelloBean which probably will help communicate better.
<bean id="helloBean" class="com.mkyong.common.HelloBean" init-method="init" />
<bean id="myHelloBean" class="com.mkyong.common.MyHelloBean" init-method="init" >
<property name="helloBean" ref="helloBean"></property>
</bean>
#ManagedBean
#RequestScoped
#Scope(value="request")
#Controller
public class MyHelloBean implements Serializable {
private static final long serialVersionUID = 1L;
//#ManagedProperty(value = "#{helloBean}")
private HelloBean helloBean;
see in above MyHelloBean I am using spring DI to set helloBean which gets set by spring fine. I have commented out #ManagedBean which I think I can leave it in there as it will be ignored by spring any ways and JSF is not going to process it I guess but to be safe I commented it out for JSF to not process it.
To complete I use below in faces-config to activate spring usage.
<el-resolver>
org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver>
Regards,
Miten.
Our team faced similar problems integrating JSF and Spring beans, including problems with their scopes. And here I am to share our knowledge.
Scopes
Basically now, when you defined in your application context, that Spring will be managing your beans, thus scopes. Spring will map JSF scope annotations to his native scope annotations.
Example when both Spring and JSF support provided scope:
#RequestScoped annotation will be mapped to #Scope("request") Spring's annotation, etc with other supported scopes.
Example when Spring does not support JSF's provided scope:
#ViewScoped is not defined in Spring's native scope annotations, thus (not sure) it will use Spring's default scope, which is singleton, or request scope (not sure).
Bean Injection
In JSF2 you used #ManagedProperty annotations for injection, while Spring uses #Autowired annotation. What are the differences and which to choose?
Injecting Spring beans with #ManagedProperty:
Spring component you wish to inject must have a value which will match jsf injection annotation's value: #Component(value = "valueMatches") injected with #ManagedProperty(value = "valueMatches").
Injecting Spring beans with #Autowired:
Spring component you wish to inject must does not require a custom value to distinguish, if it is the only implementation of the bean you are injecting: #Component injected with #Autowired.
Our way
We used Spring's annotations for defining Beans, Scopes and Injection.
We marked JSF beans with #Scope(value = "desiredScope"), #Controller(value = "beanName") and #Qualifier(value = "beanName") annotations. Later which could be accessed from JSF context with help of in faces-config.xml via "beanName" value defined in the #Controller annotation.
We marked Spring services with #Service annotation.
We injected Spring services and JSF beans with #Autowired annotation.
We found ViewScope and FlashScope custom implemetations on the web and used them for our beans. Thus we did not lose any of JSF2 scopes and even added new one.
Hope this helps.
Your approach is a bit confusing in the sense that it seems that you're mixing Spring XML configuration and Spring Annotation-based configuration. As described as an example here, if you're using annotated configuration then you should have:
<context:component-scan base-package="com.yourcom.package" />
to order Spring scan for the annotations. Otherwise, if you're using XML configuration then you should have:
<bean id="helloBean" class="com.mkyong.common.HelloBean" init-method="init" scope="request" />
as by default the scope for a Spring bean is singleton.

Clean way to inject a Spring 3 bean into a JSF 2 managed bean?

I'm migrating our current solution from JSF 1.2 to JSF 2. As I need to use the new View scope I'm using JSF 2 annotations. That forced me to inject the Spring beans using the JSF #ManagedProperty annotation instead of Spring's #Autowired
Before it was something like this:
#Autowired private OneService oneService
And now it's like:
#ManagedProperty(value="#{oneServiceImpl}")
private OneService oneService
Do you know if is there a way to annotate the managed properties without needing to state their bean name?
Thanks!
No, there isn't. JSF makes use of Expression Language (EL) to determine which class you refer by name. Using a class called ELResolver he takes the String passed, interprets and makes the appropriate reference. The class SpringBeanFacesELResolver provides integration between the two frameworks intercepts the request and passing it to the context of Spring, which handles the dependencies required to provide the ManagedBeans, who then passes it to the JSF's own ELResolver. So JSF needs the name of the bean to know what to inject.
You can still use Spring with JSF 2. Just create a custom Spring scope which can then be used as the view scope for your beans.
#Named #Scope("view")
public class MyBean {
#Inject
private MyManagedProperty oneService;
//...
}
Steal the implementation of the View scope here: http://cagataycivici.wordpress.com/2010/02/17/port-jsf-2-0s-viewscope-to-spring-3-0/

How to inject a Spring 3 Bean into a JSF 2 Converter

I am trying to #javax.naming.Inject a Spring 3 Bean called WtvrBean into a JSF 2 #FacesConverter.
Both the Bean and the Converter are on the same package. And, in my spring's applicationContext.xml, I am scanning this package:
<context:component-scan base-package="my-package" />
But this is not working. For sure, the JSF 2 internal class that uses the converter is
definitely not in my-package.
For instance, if I remove the #ManagedBean from a JSF 2 ManagedBean, and replace it to #org.springframework.stereotype.Component or #Controller, the WtvrBean can be #Injected on this ManagedBean, by using Spring WebFlow.
Well, as far as I know, there is no such thing as a #Converter stereotype in Spring.
I know I can use
FacesContextUtils.getWebApplicationContext(context).getBean("WtvrBean")
But, with that approach, the coupling between the web app and the spring is getting more tight. (annotations are metadata, and are not even considered dependency by some authors).
I am using FacesContextUtils so far, if there is no better solution.
Any ideas?
If you want to inject beans into instances of a class, these instances have to be spring-managed. I.e. spring has to instantiate them. And this is not happening, so - no, you can't inject there.
But this is because you register the converter within jsf. You can skip that:
#Component("myConverter")
public class MyConverter implements Converter { .. }
And then, if you are using the spring <el-resolver>:
converter="#{myConverter}"
So that will do it. It has worked for me.
(A workaround worth mentioning is that you can do it by using aspectj weaving and #Configurable, but I'd prefer your FacesContextUtils approach. The weaving modifies classes so that they become spring managed even if they are not instantiated by spring.)
#FacesConverter(value = "examTypeConverter")
#Named
Simple answer.
hey i was facing the same problem that spring beans are not getting injected in the JSF Converter.
then by googling about it i found the answers that after JSF 2.2 we can make converters as jsf managed bean. and then we can inject the spring dependency.
it solved my problem.
#ManagedBean
#RequestScoped
public class CustomerByName implements Converter {
#ManagedProperty(value = "#{customerDao}")
private CustomerDao customerDao;
and in your jsf page use it like a managed bean
converter="#{customerByName}"
Add #Scope annotation (eg with "request" parameter) to your managed bean.
#ManagedBean
#Scope("request")
public class MyBean {
....
}

Resources