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