4
votes

I'm trying to integrate spring boot with JSF in embedded tomcat with no luck, I tried with two approaches one with web.xml and other with Java config. In both cases xhtml pages are not getting rendered, instead a blank page is getting rendered. Below are configurations.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.kp.swasthik</groupId>
    <artifactId>kp-sb-jsf</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>kp-sb-jsf</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.0.M5</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
        <primefaces.version>5.2</primefaces.version>
        <!-- <jsf.version>2.2.8</jsf.version> -->
        <jsf.version>2.2.12</jsf.version>
        <jsf.extension.version>3.2.0</jsf.extension.version>
        <jsf.themes.version>1.0.10</jsf.themes.version>
        <spring.webflow.version>2.4.2.RELEASE</spring.webflow.version>
        <omnifaces.version>2.1</omnifaces.version>
        <wield.version>2.2.15.Final</wield.version>
    </properties>

    <dependencies>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.1</version>
    </dependency>

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

    <dependency>
        <groupId>org.glassfish.web</groupId>
        <artifactId>el-impl</artifactId>
        <version>2.2</version>
    </dependency>

       <!--
        <dependency>
            <groupId>org.omnifaces</groupId>
            <artifactId>omnifaces</artifactId>
            <version>${omnifaces.version}</version>
        </dependency>
       -->

        <dependency>
            <groupId>org.jboss.weld.servlet</groupId>
            <artifactId>weld-servlet</artifactId>
            <version>${wield.version}</version>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>


        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>primefaces</artifactId>
            <version>${primefaces.version}</version>
        </dependency>

        <dependency>
            <groupId>org.primefaces.extensions</groupId>
            <artifactId>primefaces-extensions</artifactId>
            <version>${jsf.extension.version}</version>
        </dependency>

        <dependency>
            <groupId>org.primefaces.themes</groupId>
            <artifactId>all-themes</artifactId>
            <version>${jsf.themes.version}</version>
        </dependency>

        <dependency>
            <groupId>org.primefaces.extensions</groupId>
            <artifactId>resources-optimizer-maven-plugin</artifactId>
            <version>2.0.0</version>
        </dependency>


        <!-- <dependency> <groupId>org.apache.myfaces.core</groupId> <artifactId>myfaces-impl</artifactId> 
            <version>${jsf.version}</version> </dependency> -->

        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>${jsf.version}</version>
        </dependency>

        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>${jsf.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.webflow</groupId>
            <artifactId>spring-faces</artifactId>
            <version>${spring.webflow.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.webflow</groupId>
            <artifactId>spring-webflow</artifactId>
            <version>${spring.webflow.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.webflow</groupId>
            <artifactId>spring-binding</artifactId>
            <version>${spring.webflow.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>prime-repo</id>
            <name>PrimeFaces Maven Repository</name>
            <url>http://repository.primefaces.org</url>
            <layout>default</layout>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>

</project>

faces.config in src/main/resources/META-INF directory

    <?xml version="1.0"?>
    <faces-config version="2.2" 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 http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd" metadata-complete="false" >

        <application>
            <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
            <!-- <resource-handler>org.omnifaces.resourcehandler.CombinedResourceHandler</resource-handler> -->
            <resource-handler>org.omnifaces.resourcehandler.UnmappedResourceHandler</resource-handler>


    </application>

    <lifecycle>
        <phase-listener>org.springframework.web.jsf.DelegatingPhaseListenerMulticaster</phase-listener>
    </lifecycle>

</faces-config>

context.xml for wield in src/main/webapp/META-INF

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <Resource name="BeanManager" auth="Container"
        type="javax.enterprise.inject.spi.BeanManager" factory="org.jboss.weld.resources.ManagerObjectFactory" />
</Context>

Index.html moved to src/main/resources/META-INF/resources index.xhtml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui"
    xmlns:pe="http://primefaces.org/ui/extensions">

<h:head>
</h:head>
<h:body>
    <p:panel>
         #{kpDisplay.hello}
     </p:panel>
</h:body>
</html>

@SpringBootApplication
@ComponentScan(basePackages={"com.kp.swasthik.bjsf"})
public class KpSbBjsfApplication extedns SpringBootServletInitializer{


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

     @Override
     protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(KpSbBjsfApplication.class);
  } 

  @Bean
public ServletRegistrationBean facesServletRegistration() {

    ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new FacesServlet(), "*.xhtml");
    servletRegistrationBean.addUrlMappings("/faces/*");
    servletRegistrationBean.setLoadOnStartup(1);
    return servletRegistrationBean;
}

@Bean
public ServletListenerRegistrationBean<ConfigureListener> jsfConfigureListener() {
    return new ServletListenerRegistrationBean<ConfigureListener>(new ConfigureListener());
}

@Bean
@ConditionalOnMissingBean
public RequestContextListener getRequestContextListener() {
    return new RequestContextListener();
}
}

And servlet context init class.

public class ServletCustmContextInitializer implements ServletContextInitializer {

    @Override
    public void onStartup(ServletContext jsfServlet) throws ServletException {
   jsfServlet.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString());
    jsfServlet.setInitParameter("javax.faces.PARTIAL_STATE_SAVING_METHOD", "true");
    jsfServlet.setInitParameter("javax.faces.PROJECT_STAGE", "Development");
    jsfServlet.setInitParameter("facelets.DEVELOPMENT", "true");
    jsfServlet.setInitParameter("javax.faces.FACELETS_REFRESH_PERIOD", "1");
    jsfServlet.setInitParameter("primefaces.CLIENT_SIDE_VALIDATION", "true");
    jsfServlet.setInitParameter("javax.faces.DEFAULT_SUFFIX", ".xhtml");
    jsfServlet.setInitParameter("primefaces.THEME", "bootstrap");

    }

}

I managed to bring up jsf-spring boot configuration but now JSF annotations does not work. If I add managed annotations manually to faces-config.xml the managed annotations do work. I even added metadata-complete="false" so the jsf scans for annotations sadly it doesn't work

1
What do your resource file URIs look like? You're mapping /faces/* and *.jsf resources only. Instead, the recommended mapping for a JSF 2.x application is *.xhtml (facelets). - Xtreme Biker
in web.xml approach you can find I've mapped *.xhtml. In Java conig appraoch also I've mapped *xhtml as parameter in constructor of Servletregistrationbean - Karthik Prasad
There's a bug with spring boot that requires the Jsf servlet to be declared both in web.xml and Java configuration. Try to do it and check if the servlet is being hit - Xtreme Biker
updated my question....... I did get this working but now jsf annotations do not work, can you point to the bug which you are refering - Karthik Prasad
Which namespace are you using for the annotations? - Xtreme Biker

1 Answers

1
votes

It just so happens that I wrote a tutorial on how to do exactly this. You can find it here along with a fully functional maven demo project on GitHub.

The key issue here is that Spring Boot is opinionated and prefers java-config, thus configuration is injected from java code whilst Tomcat requires the web.xml to be present simply as a comfort blanket; its not used.

Don’t use Omnifaces, it requires CDI and getting that to behave in embedded Tomcat seemed impossible in my attempts. There are other tools you can use which do work well, in my tutorial I have configured Rewrite as how to do that is not obvious.