2

How to integrate Spring and JSF? I followed Spring documentation (which is sparse on this subject) and googled some more and currently I found two working ways:

  1. JSF Managed Bean will be Spring @Component / @Named (but there doesn't seem to work JSF scopes, but only Spring scopes):

    @Component
    @Scope("request")
    public class ItemController {
    
      @Autowired
      private ItemService itemService;
    
    }
    
  2. I will use @ManagedBean, JSF scopes work, but I cannot autowire Spring bean using @Autowired, the bean must contain setter and I'm not sure if this is best practice:

    @ManagedBean
    @RequestScoped
    public class ItemController {
    
      @ManagedProperty("#{itemService}")
      private ItemService itemService;
    
      public void setItemService(ItemService itemService) {
        this.itemService = itemService;
      }
    
    }
    
  3. Something else?

jirka.pinkas
  • 918
  • 6
  • 21
  • If you have Netbeans 8, there's a couple of good maven archetype you can go off of that integrate Spring-JSF-JPA. – Paul Samsotha Jun 22 '14 at 11:37
  • @peeskillet I seem to be blind, because I don't see any archetypes with Spring in NetBeans. Can you be more specific, please? – jirka.pinkas Jun 22 '14 at 15:34
  • If you go to New->Maven->ProjectFromAchetype->Next you'll see a dialog. In the search type in "jsf". There will be a `jsf2-spring4-jpa2-archetype` and a `spring-jsf-jpa-archetype` archetype you can choose from. The latter uses spring3 in a single pom project, while the former uses spring4, new jsf and jpa, and uses a modular pom project model. Pick your flavor. There's also some archetypes by AppFuse that use Hibernate, but I went through all of them and the Spring version they used is old. Keep in mind this is Netbeans 8. Haven't checked in earlier versions – Paul Samsotha Jun 22 '14 at 15:46
  • Thank you. For future reference: these archetypes are not NetBeans specific, they are from Maven Central Repository. Also they use my nr. 1 approach. – jirka.pinkas Jun 22 '14 at 18:34

4 Answers4

3

I would definitely go with way number 1 (and did so in quite some projects). It makes no real sense to mix JSF managed beans with Spring beans, unless you have a good reason to do so. With Spring managed beans, you have far more possibilities and you can use the full power of Spring even for your managed beans.

Theoretically, there is a third way: You could use CDI for the UI layer and Spring in the background. This might be an option if you don't want to use a full blown Java EE environment but still want to benefit from CDI and Myfaces CODI/Deltaspike in the UI layer. But in this case you would additionally need a CDI setup and a CDI to Spring bridge.

Michi
  • 1,595
  • 10
  • 11
  • Nr. 1 has one big problem, there's no view scope in Spring. – jirka.pinkas Jun 20 '14 at 05:42
  • Implementing the view scope in Spring is pretty straight-forward. If you download the code from our online JSF book http://jsfatwork.irian.at (German only at present) you'll find a basic implementation in example `mygourmet16-spring`. – Michi Jun 20 '14 at 05:46
  • @Michi Why it doesn't make sense ? You can use JSF Managed Bean for your view and service layer is configured as spring beans. – Avinash Singh Jun 20 '14 at 13:23
  • JSF managed beans have very limited functionality. If there is already Spring in the project why should you limit yourself. Spring offers high flexibility, AOP, proxies to inject beans with shorter scopes into beans with longer scopes and 100 additional things. – Michi Jun 20 '14 at 13:38
  • Finally I chose nr. 1 and implemented the view scope from your example. Thanks. – jirka.pinkas Jun 21 '14 at 07:49
1

I was having the same issue a while back.

Although there also is an option of a spring EL enhancement to lookup spring beans there, I still found the differences between JSF and spring to be too wide a gap to try to cross in a seamless manner.

My recommendation is therefore to make the gap explicit and not try to cross it.

In my case I ended up with a service locator pattern, gaining access to spring context and lookup there..

@ManagedBean
@ApplicationScoped
public class ServiceLocator {
   public <T> T getServiceByType(Class<T> serviceType) {
     getSpringContext().getBean(serviceType);
   }

   public ApplicationContext getSpringContext() {
     return FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
   }
}


@ManagedBean
@ViewScoped
public class ViewBean {

   @ManagedProperty("#{serviceLocator}")
   protected ServiceLocator serviceLocator;


   public void actionMethod() {
     serviceLocator.getService(BookingService.class).book(roomId, fromDate, toDate);
  }
}

Written from memory, but you might get the gist

Niels Bech Nielsen
  • 4,777
  • 1
  • 21
  • 44
  • interesting solution. Finally I chose Spring-specific solution, but in case I burn my fingers, I will revisit your solution. Thanks! – jirka.pinkas Jun 21 '14 at 07:52
1

You can use @AutowiredBean from JSF-Spring integration project to inject JSF managed beans into Spring beans:

@Component
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class JsfTest implements Serializable {
    private static final long serialVersionUID = 1L;

    @AutowiredBean
    private JsfBean jsfBean;

    ...
}

Add Maven artifact com.intersult:jsf-spring:2.2.0.1-SNAPSHOT to your project, see https://www.intersult.com/wiki/page/JSF%20Spring%20Integration (use translation button).

Tires
  • 1,529
  • 16
  • 27
  • 1
    As he seems to start a new project, I would not introduce something like this from the start. Unless you have old legacy stuff it usually brings absolutely no benefit to use JSF managed beans when you have Spring anyway. – Michi Jun 20 '14 at 12:16
  • Yes, should be used with care. – Tires Jun 24 '14 at 08:50
0

One approach is let Spring manage all your bean, definitely you need to use SpringBeanFacesELResolver in faces-config.xml

Bean:

@Component
@Scope("view")
public class UserBean

faces-config.xml:

<el-resolver>
    org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver>

Spring provides option to add your custom scope, you need to implement org.springframework.beans.factory.config.Scope interface. Use applicationcontext.xml for registration with Spring.

applicationcontext.xml on a custom 'view' scope implementation : [ViewScope is my implementation of Scope interface]

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
            <entry key="view">
                <bean class="com.org.common.ViewScope"/>
            </entry>
        </map>
    </property>
</bean>
Sam
  • 554
  • 1
  • 12
  • 23