Spring Boot and JSF/Primefaces/Richfaces

jsf, primefaces, spring, spring-boot

Solution

After seeing this question by louvelg about a different problem after setting up the FacesServlet with Spring Boot, I got it working with JSF/primefaces by adding a couple configuration files and also a ServletRegistrationBean from spring-web. The web.xml and faces-config.xml files kind of hurt Spring Boot's idea of minimal set up without tons of xml files, but this is the minimal set up I was able to find with JSF, if anyone knows of a better/cleaner way to do this, please let me know.

Here are the dependencies in my gradle.build file:

compile group: "org.springframework.boot", name: "spring-boot-starter"
compile group: "org.springframework", name: "spring-web", version: "4.0.2.RELEASE"

compile group: "org.apache.tomcat.embed", name: "tomcat-embed-core", version: tomcatVersion
compile group: "org.apache.tomcat.embed", name: "tomcat-embed-logging-juli", version: tomcatVersion
compile group: "org.apache.tomcat.embed", name: "tomcat-embed-jasper", version: tomcatVersion

compile group: "org.primefaces", name: "primefaces", version: "4.0"
compile group: "com.sun.faces", name: "jsf-api", version: "2.1.21"
compile group: "com.sun.faces", name: "jsf-impl", version: "2.1.21"

where `tomcatVersion` is "7.0.34". The key changes here are:

- Removing `spring-boot-starter-web`, which also includes Spring MVC as pointed out by M. Deinum

- Including `spring-boot-starter` (easier startup) and `spring-web`

- Explicitly including the tomcat-embed dependencies since `spring-boot-starter-web` is not here anymore.

Here are the new contents of my main class:

package com.hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import javax.faces.webapp.FacesServlet;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        FacesServlet servlet = new FacesServlet();
        return new ServletRegistrationBean(servlet, "*.xhtml");
    }
}

`@EnableAutoConfiguration` if you want Spring Boot to automatically set up Tomcat, and the ServletRegistrationBean mapping xhtml requests to your FacesServlet.

The WEB-INF/faces-config.xml file in my webapp directory:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
              version="2.2">
    <application>
        <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
    </application>
</faces-config>

and the web.xml file also in webapp/WEB-INF:

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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/web-app_2_5.xsd"
           version="2.5">

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
</web-app>

The servlet definitions seem redundant, but for some reason if I remove them either from the web.xml file or the servlet registration bean, rendering of xhtml pages doesn't work as expected or not at all. EDIT: turns out the servlet mapping isn't necessary in the web.xml file, it was just an IDE problem, in my case Intellij Idea doesn't know about the servlet mapping being defined in the servlet registration bean, so it was complaining about missing mappings for the expected servlet, but the application runs without problems nevertheless.

Thanks to all who contributed.

Problem

I have been in contact with Spring for just a few months now and recently came upon Spring Boot while browsing the guides section. The guides were very easy to complete and made for a good initial grasp of the projects's basic (and awesome) idea, which is to be able to build and deploy enterprise-level applications with minimal configuration while upholding to a wide array of Spring's/JEE's good practices. I am really interested in using Spring Boot for test projects since with it they are so much easier and faster to set up and run and still be very close to my production environment. I am currently trying to build a project with Spring Boot and Primefaces as my view technology of choice, but this setup apparently isn't ready out-of-the-box as is the case with Thymeleaf, for which having its binary in the classpath is enough. I tried including the folowing gradle/maven artifacts, with no success: - primefaces - jsf-api - jsf-impl - el-api Spring Boot's embedded Tomcat server starts with no apparent errors, but after trying to open a page such as /view in a browser, the embedded server displays the following error message: `HTTP Status 500 - Circular view path: would dispatch back to the current handler URL again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)` After searching in several different places, I still fail to locate any resources/tutorials on how to set up such a project. Here are the contents of my build.gradle file: ``` buildscript { repositories { maven { url "http://repo.spring.io/libs-snapshot" } } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.0.0.RC4") } } apply plugin: 'java' apply plugin: 'idea' apply plugin: 'spring-boot' idea { module { downloadJavadoc = true } } group = 'com.hello' version = '0.0.1-SNAPSHOT' repositories { mavenCentral() mavenLocal() maven { url "http://repository.primefaces.org" } } dependencies { compile("org.springframework.boot:spring-boot-starter-web") // compile ("org.thymeleaf:thymeleaf-spring4") compile group: 'org.primefaces', name: 'primefaces', version: '4.0' compile group: 'com.sun.faces', name: 'jsf-api', version: '2.2.2' compile group: 'com.sun.faces', name: 'jsf-impl', version: '2.2.2' compile group: 'javax.el', name: 'el-api', version: '1.0' } task wrapper(type: Wrapper) { gradleVersion=1.10 } ``` My main class: ``` package com.hello; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @EnableAutoConfiguration @ComponentScan @Configuration public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` and my implementation of WebMvcConfigurerAdapter: ``` package com.hello; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration public class MvcConfig extends WebMvcConfigurerAdapter { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("view"); registry.addViewController("/view").setViewName("view"); } } ``` Along with my view.html file (I also tried view.xhtml), these are all the files I created for this project as I'm trying for the minimal setup. If anyone can see what I'm doing wrong (or not doing at all), help would be much appreciated. Do I need extra files/beans for JSF configuration in this case? If so, where and how should put such files? This question has also been posted in the official Spring forums: http://forum.spring.io/forum/spring-projects/boot/746552-spring-boot-and-jsf-primefaces-richfaces EDIT: After including M. Deinum's configuration bean for JSF and removing the WebMvcConfigurerAdapter definition (related to Spring MVC), Spring Boot seems to map requests to the FacesServlet instance, now I get the following error message: `HTTP Status 500 - Servlet.init() for servlet FacesServlet threw exception` root cause: ``` java.lang.IllegalStateException: Could not find backup for factory javax.faces.context.FacesContextFactory ``` The code for the new JsfConfig bean: ``` package com.hello; import com.sun.faces.config.ConfigureListener; import org.springframework.boot.context.embedded.ServletListenerRegistrationBean; import org.springframework.boot.context.embedded.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver; import javax.faces.webapp.FacesServlet; @Configuration public class JsfConfig { @Bean public FacesServlet facesServlet() { return new FacesServlet(); } @Bean public ServletRegistrationBean facesServletRegistration() { ServletRegistrationBean registration = new ServletRegistrationBean(facesServlet(), "*.xhtml"); registration.setName("FacesServlet"); return registration; } @Bean public ServletListenerRegistrationBean<ConfigureListener> jsfConfigureListener() { return new ServletListenerRegistrationBean<ConfigureListener>(new ConfigureListener()); } @Bean public ViewResolver getViewResolver(){ InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/templates/"); resolver.setSuffix(".xhtml"); return resolver; } } ```

Original source

Related problems