I use an old fashion JSP scriptlet code and I have decided to give Facelets a try and migrate my application. I already dislike some things (like the extra work of having to change some of the HTML5 tags that a designer gives me, close them, etc) but the benefits seem worth it. I am finding some problems in the migration, basically I am trying to define a composite component
and pass over a List<T extends BasicData>
to be displayed.
I am using Netbeans 8.0.2
, Apache Tomcat 8.0.3.0
(J2EE 7), JDK 1.8
. I am reading Java Server Faces - Introduction by example to get help and examples.
1) I am not sure I have included the right dependencies in Maven, or if I included duplicated functionality with the libraries. Is this the minimum set? (considering I might use some JSTL)
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.faces</groupId>
<artifactId>javax.faces-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<!-- This is the Mojarra Implementation of JSF -->
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>2.2.8-02</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.1.0-b03</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.1.0-b03</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>com.sun.el</groupId>
<artifactId>el-ri</artifactId>
<version>1.0</version>
</dependency>
2) Since JSF 2.0, I am not supposed to need the following fragment in the web.xml
. However, when I omit it I don't get the JSF rendered and I only obtain the untreated XML. What am I doing wrong?
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<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>/faces/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
3) Now the main problem is that my bean doesn't seem to get instantiated. Everything renders fine except that the bean is passed is always null
. In fact I can pass any data type (for example a String
instead of a List
) and it never complains (since whatever I pass is always null
and Netbeans apparently does not detect it at compilation time).
index.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:util="http://java.sun.com/jsf/composite/util"
template="template.xhtml">
<ui:define name="content">
<util:visualisationList
elementList="#{visualisationListController.elements}"/>
</ui:define>
</ui:composition>
visualisationListController.java
@Named(value = "visualisationListController")
@Dependent
public class VisualisationListController <T extends BasicData> implements Serializable {
private List<T> elements;
/**
* Creates a new instance of visualisationList
*/
public VisualisationListController() {
// This is for testing, eventually I would like to get this information from a DB
System.out.println("constructor");
elements = new ArrayList<>();
ComplexData cd = new ComplexData(); // ComplexData EXTENDS BasicData
cd.setName("ELEMENT 1");
elements.add((T)cd);
cd = new ComplexData();
cd.setName("ELEMENT 2");
elements.add((T)cd);
}
public List<T> getElements() {
return elements;
}
public void setElements(List<T> elements) {
this.elements = elements;
}
}
visualisationList.xhtml
(This renders, but the list is null
so nothing is printed)
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<!-- INTERFACE -->
<cc:interface>
<cc:attribute name="elementList" type="java.util.List" required="true" shortDescription="The list of objects to be displayed"/>
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<ul>
<c:forEach items="#{cc.attrs.elementList}" var="element">
<li>
#{element.name}
</li>
</c:forEach>
</ul>
</cc:implementation>
</html>
I never read I need a beans.xml
as suggested here, and this post does not give me clues either. The bean is supposed to be automatically instantiated. To do some further testing, I have tried the first simple example from the aforementioned book and my bean doesn't get instantiated either. I understand from the book text that the object should be automatically instantiated.
In case there is an error on the way I treat or create the List
, I have also tried to use a less complex data (just a String
), use @SessionScoped
and remove the c:forEach
, and it does not work either.
EDIT
The problem is fixed thanks to (once again) BalusC
pointer. I had to get information from different sources, so, for convenience, I have compiled the steps I took below. However, it is still not clear my question (1):
According to the JSF info page, I only need to include one Maven dependency. But when doing so, I get the following error message:
An Error Occurred:
Could not get component metadata for visualisationList.xhtml. Did you forget to specify <composite:interface>?
viewId=/index.xhtml
location= ...
I have tried several things, including steps in here, unsuccessfully. If I include certain libraries I get:
javax.servlet.ServletException
javax.faces.webapp.FacesServlet.service(FacesServlet.java:606)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
root cause
java.lang.NullPointerException
java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1011)
java.util.concurrent.ConcurrentHashMap.putIfAbsent(ConcurrentHashMap.java:1535)
The only thing that worked for me, although I am not sure why, is to include the dependency:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>2.2.8-02</version>
<scope>runtime</scope>
</dependency>
(Together with the javaee-web-api 6.0 of course)
Only then, I get the result I was expecting from the beginning. However, I don't understand why this dependency has to be included, if TomEE was suppossed to provide it all. Also, I am not sure it means I will use v.2.2 when I have read that EE 6 should only run up to 2.1. Finally, I had to create a beans.xml
for this to work, and I am not sure why - Is this only for JSF version <= 2.1?
STEPS I TOOK TO CHANGE TOMCAT TO TOMEE ON NETBEANS
- Download TomEE. Install and configure it in Netbeans servers section. (Source)
- Edit TomEE server.xml and changed all ports to avoid collision with my old Tomcat.
In server.xml, remove the
xpoweredBy
andserver
attributes from the connector:(Source)
Then, in
bin/catalina.bat
change::noJuliConfig set "JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%" ... :noJuliManager set "JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%"
to:
:noJuliConfig set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG% ... :noJuliManager set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%
(Source)
Then right click on project - Properties - Run. Change server to TomEE and Java EE version to "Java EE 6 Web" (since the current version of TomEE only accepts JEE 1.6). Dependencies in
pom.xml
have to be changed accordingly, to version 6:<dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>6.0</version> <!-- 7.0 (JSF 2.2) or 6.0 (JSF 2.0/2.1) --> <scope>provided</scope> </dependency> .... <artifactItem> <groupId>javax</groupId> <artifactId>javaee-endorsed-api</artifactId> <version>6.0</version> <type>jar</type> </artifactItem>
....
Now TomEE should work and run the application from Netbeans.