0

Let me tell you my story, and in between I will ask questions

I am working in a project I have to use JSF, there is not really other choice. Coming from the wonderful Spring world in the last years, I really wanted to use some features like Spring Data, Spring singleton beans, Autowire beans into other beans, etc.

So I thought initially everything would be smooth, JSF (backing beans) will be managed by CDI container and @Service, @Respostory and database connection Entity manager by spring container. I want to make my application independent from a Java EE container, but just for information I am using Wildfly 9. In Wildfly, I create a datasource (connection to an oracle database) to bind later to my application.

So my first difficulty was, Some years ago, I code some JSF and I knew about @ManagedBean anotations and JSF scopes, all even though has not changed, there seems to be another aproach, and acording to what I read it is recommendable to use @Named and so on (CDI annotations) instead of the JSF annotations. So I wanted to follow those advices and somehow forces me to introduce CDI container into my application.

1st Question: Is that true ? Isn´t it recommendable to use old JSF annotations ?

My JSF beans look like this:

import java.io.Serializable;
import java.util.Locale;

import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.validation.constraints.NotNull;

import co.com.psl.connectnetwork.service.AuthenticationService;
import lombok.Data;


@Named
@SessionScoped
@Data
public class LoginBean implements Serializable {
}

My first issue, is that as I mentioned before, I wanted to introduce Spring, so I had in my application context xml file

<context:annotation-config />
<context:component-scan base-package="co.com.package" />

That was causing me problems because it seemed that Spring scanned my JSF managed beans , and treated them as Spring beans, which I don´t have any issue with that, but in practice those beans were singleton !!! , so terrible for an application which manages some state among logged users.

So I solved it by excluding JSF beans from spring container, I did it by introducing this:

<context:component-scan base-package="co.com.scannedpackage" >
    <context:exclude-filter type="regex" expression="co.excludedpackage.*Bean"  />
</context:component-scan>

So It did not seem to me so terrible , and as it seems to be some imcompatibility I though It was better that JSF beans will not be managed by Spring.

2nd Question: Do you agree?

As I said, I will have some @Service (Spring annotations) beans which I will eventually have to inject into the JSF managed beans . Initially I used @Inject to inject the service bean into the JSF bean , and it worked perfectly , the only issue is that when the JSF bean was using javax.enterprise.context.SessionScoped , it forced that all attributes are Serializable, so I made the @Service Spring bean implement the Serializable interface, which I dont think it is nice , even if it works, it seems to me a contradiction and a spring singleton bean (stateless) is forced to be serialized. So I tried to use the @Autowired anotation in the JSF managed bean , but the bean was not been injected and I got a null reference. Basically I guess the error I think it was, to use @Autowired in a bean which is not managed by spring.

3rd Question: How can I make it work ? I really think it is better to use @Autowired than to have spring beans serializable .If the ApplicationScope/viewScope/SessionScope JSF bean is passivated, will the Spring bean be injected again?, I don´t think so. If @ManagedBean is used, will it work ?

Another issue I am having, is that if my JSF beans are managed by CDI, It seems that javax.faces.bean.ViewScoped does not work well with CDI

4th Question: Is that so? Do you recommend me to use @ManagedBean instead of @Named? If I use @ManagedBean, how do I inject Spring dependencies? Is there any other CDI scope I could use instead of ViewScoped?

Now moving from JSF to Spring, I really want to use Spring in my applications, Features like Spring-Data, Spring-Security and others, the advantages of Spring singleton beans over EJB Stateless beans, are things I don´t want to miss. In my application, I will have a datasource created in the Java EE server or Java EE container. Then, I will bind that datasource internally in my application. So in my applicationContext.xml, I have:

<?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:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd">

<bean id="datasource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:/jndi-spring"/>
    <property name="lookupOnStartup" value="true"/>
    <property name="proxyInterface" value="javax.sql.DataSource"/>
</bean>
<!-- <jee:jndi-lookup id="datasource" jndi-name="java:/ConnectNetworkDS"/> -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="datasource" />
    <property name="persistenceUnitName" value="persistenceUnit2" />
    <property name="packagesToScan" value="co.com.packagestoscan" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    </property>

    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
        </props>
    </property>
</bean>
<jpa:repositories base-package="co.com.packagewhererepositoriearelocated"  />
</beans>

Please note that I am using Spring data and this line

<jpa:repositories base-package="co.com.packagewhererepositoriearelocated"  />

is to indicate the interfaces annotated with @org.springframework.stereotype.Repository.Resository

Unfortunately, when I deploy my application, I get:

ERROR [org.jboss.msc.service.fail] (MSC service thread 1-1) MSC000001: Failed to start service jboss.deployment.unit."deployedwar.war".WeldStartService: org.jboss.msc.service.StartException in service jboss.deployment.unit."deployedwar.war".WeldStartService: Failed to start service

So I was doing so internet research, and I included :

  • persistence.xml
  • CdiConfig class

The content of persistence.xml is: http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" version="2.1">

<persistence-unit name="persistenceUnit">
        <class>co.com.entityClass1</class>
    <class>co.com.entityClass2</class>
    <jta-data-source>java:/jndi-string</jta-data-source>
    <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
            <property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider" />
        </properties>
</persistence-unit>

</persistence>

And CdiConfig class:

import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

public class CdiConfig {  

    @Produces  
    @Dependent  
    @PersistenceContext  
    private EntityManager entityManager;

}

5th Question: Can somebody please tell me why this is required ? Shouldn´t spring be able to inject the enntityManager into the @Repository Spring beans ? Why a persistence.xml is necessary ? Why does it seems that injection into @Repository Spring beans have to be done by Spring ? I think this somehow is redundant

Arjan Tijms
  • 36,666
  • 12
  • 105
  • 134
Deibys
  • 531
  • 1
  • 8
  • 18
  • A very personal opinion is that Spring in latest versions of Java EE is useless. It is replaced by CDI for IoC. Dealing with 2 containers trying to achieve the same thing is a waste of time. For Spring data, you have the possibility of using delta-spike (data module) which are a set of CDI portable extensions. Unfortunately you have to work with JSF which I consider the only weak brick in the current JEE bundle. I have personally replaced this one with a combination of JAX-RS & AngularJs. – Franck Sep 02 '15 at 19:12
  • I really Spring has some advantages over CDI. As far as I know, transactionality is not implemented in CDI – Deibys Sep 02 '15 at 21:10
  • Please ask one question per Question. As to transaction management, that part is done by EJB+JTA. Spring competes Java EE (CDI, EJB, JTA, JSF, etc), not alone CDI. Here are some related/duplicate questions already individually asked and answered: http://stackoverflow.com/q/18369356, http://stackoverflow.com/a/4347707, http://stackoverflow.com/q/18387993, http://stackoverflow.com/q/30639785 – BalusC Sep 02 '15 at 21:22
  • Also pojo transaction http://docs.oracle.com/javaee/7/api/javax/transaction/Transactional.html – Franck Sep 02 '15 at 21:25
  • 5th Question: Spring Data expects a `EntityManager` bean but is not opinionated where it comes from. You're responsible to provide the `EntityManager` and you do this by providing the producer field as shown above. – mp911de Sep 03 '15 at 08:08
  • 1
    And in general: You should not mix the Spring container with the CDI container. Two DI's are considered harmful. Spring Data itself has CDI support, so you're not required to maintain an additional Spring context. – mp911de Sep 03 '15 at 08:10

1 Answers1

0

Isn´t it recommendable to use old JSF annotations?

That's true. In JSF we're moving away from the JSF native beans and injection in favor of CDI. Although still not officially so, @ManagedBean and friends should be considered effectively deprecated.

@ViewScoped should work fine with CDI, but make sure you're importing the right one. The old one does not work, the newer one does. The one you need is:

javax.faces.view.ViewScoped

See CDI compatible @ViewScoped

Arjan Tijms
  • 36,666
  • 12
  • 105
  • 134