Search code examples
springjsfcditomcat8myfaces

management sessions JSF 2.3 CDI


Having recently upgraded to JSF 2.3 from 2.2, I noticed that @ManagedBean was deprecated, and after some research found that I should be using CDI-2.0 managed beans and the @Named annotation. I also migrated @javax.faces.bean.SessionScoped to @javax.enterprise.context.SessionScoped.

However i noticed that my beans are created on the server's startup!

I login with an user 'X' and i change an attribute in my bean. after that i login with another browser and i expect to find null in my attribute but i have found the last update by the user 'X' in the other browser.

I'm using myFaces 2.3, omnifaces 3.1, i also installed CDI in my tomcat. i have referenced to some blogs and some responses stackoverflow like :

http://balusc.omnifaces.org/2013/10/how-to-install-cdi-in-tomcat.html

Migrate JSF managed beans to CDI managed beans

Here are my principal files :

beans.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
      http://java.sun.com/xml/ns/javaee
      http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

pom.xml:

.....
<dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>primefaces</artifactId>
            <version>${primefaces.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.primefaces.extensions</groupId>
            <artifactId>all-themes</artifactId>
            <version>${primefaces.all.themes}</version>
            <scope>compile</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.omnifaces/omnifaces -->
        <dependency>
            <groupId>org.omnifaces</groupId>
            <artifactId>omnifaces</artifactId>
            <version>3.1</version>
        </dependency>

        <dependency>
            <groupId>net.bootsfaces</groupId>
            <artifactId>bootsfaces</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.myfaces.core</groupId>
            <artifactId>myfaces-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.myfaces.core/myfaces-impl -->
        <dependency>
            <groupId>org.apache.myfaces.core</groupId>
            <artifactId>myfaces-impl</artifactId>
            <version>2.3.1</version>
        </dependency>

        <!-- Oracle jstl -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/javax.enterprise/cdi-api -->
        <dependency>
            <groupId>javax.enterprise</groupId>
            <artifactId>cdi-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>3.0.0</version>
            <scope>provided</scope>
        </dependency>
.....

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.webflow</groupId>
            <artifactId>spring-faces</artifactId>
            <version>2.4.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring.version}</version>
        </dependency>

Am i doing something wrong?


Solution

  • I found the problem and i implemented a solution, so i want to share it with you. The problem was the component-scan of spring framework and here my solution :

    XML:

    <context:component-scan base-package="com.example">  
        <context:exclude-filter type="aspectj" expression="com.example.beans.*" />  
    </context:component-scan> 
    

    Annotation:

    @SpringBootApplication
    @EnableAutoConfiguration
    @ComponentScan(basePackages = { "com.example" },
        excludeFilters = @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "com.example.beans.*"))
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }
    

    The second problem is about spring's bean injection into CDI bean so i create a bridge between Spring and CDI.

    I have to create a new annotation like this :

    @Qualifier
    @Inherited
    @Documented
    @Retention(RUNTIME)
    @Target({ FIELD, TYPE, METHOD, PARAMETER })
    public @interface SpringBean {
    
        String value() default "";
    }
    

    and a Producer :

    @SessionScoped
    public class CdiBeanFactoryPostProcessor implements Serializable {
    
        private static final long serialVersionUID = -44416514616012281L;
    
        @Produces
        public PropertyResourceBundle getBundle() {
            FacesContext context = FacesContext.getCurrentInstance();
            return context.getApplication().evaluateExpressionGet(context, "#{msg}", PropertyResourceBundle.class);
        }
    
        @Produces
        @SpringBean("example")
        public Example example(InjectionPoint injectionPoint) {
            return (Example) findBean(injectionPoint);
        }
    
    
        protected Object findBean(InjectionPoint injectionPoint) {
            Annotated annotated = injectionPoint.getAnnotated();
            SpringBean springBeanAnnotation = annotated.getAnnotation(SpringBean.class);
            ServletContext ctx = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
    
            String name = springBeanAnnotation.value();
    
            if(StringUtils.isNotBlank(name))
                return WebApplicationContextUtils.getRequiredWebApplicationContext(ctx).getBean(name);
            else 
                throw new NoSuchBeanDefinitionException(name, "not found in Context");
    
        }
    }
    

    And i inject it into my bean like that :

    @Named
    @SessionScoped
    public class ExampleBean extends AbstractManagedBean  implements Serializable {
    
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
    
        private static final Logger LOGGER = LogManager.getLogger(ExampleBean.class);
    
        @Inject
        @SpringBean("example")
        protected transient Example example;
    
        @Inject
        protected transient PropertyResourceBundle bundle;
    
    ..................
    
    }
    

    thank!