JSF2: Creating Custom Component [OutputObject]
JavaServerâ„¢ Faces - JSF - is the well-established standard for web-development frameworks in Java. The standard is based on the MVC paradigm, but is additionally to most web-frameworks also component-based and event-oriented. While JSF comes with a standard set of UI components, one of the most-publicized features is the easy addition of new components. Here, you will see just how easy it is to create new components that are fully functional and integrated into your web applications by creating a new component that takes a simple - with primative attributes only - java bean object as a value and his output will be the bean details printed in HTML table.
Example
A JSF page with the following code:
-
<html xmlns="http://www.w3.org/1999/xhtml"
-
xmlns:ui="http://java.sun.com/jsf/facelets"
-
xmlns:h="http://java.sun.com/jsf/html"
-
xmlns:f="http://java.sun.com/jsf/core"
-
xmlns:cc="http://myapplication.com/com">
-
<h:head></h:head>
-
<h:body>
-
<h1>User Bean</h1>
-
<cc:outputObject value="#{mybean.user}" />
-
<h1>Address Bean</h1>
-
<cc:outputObject value="#{mybean.address}" />
-
</h:body>
-
</html>
Where "mybean.user" and "mybean.address" will return beans of type User and Address, the result of these lines will be the following:

Creating the OutputObject custom component
Now lets start with creating the component in steps
Step 1: Creating the beans
The User bean:
-
package com.myapp.beans;
-
-
import java.net.URL;
-
import java.util.Date;
-
-
import com.myapp.components.outputoject.OutputObjectAttribute;
-
-
public class User {
-
-
private int id;
-
-
this.id = id;
-
this.username = username;
-
this.firstName = firstName;
-
this.lastName = lastName;
-
this.address = address;
-
this.birthDate = birthDate;
-
this.website = website;
-
}
-
-
public int getId() { return id; }
-
}
The Address bean:
-
package com.myapp.beans;
-
-
import com.myapp.components.outputoject.OutputObjectAttribute;
-
-
public class Address {
-
-
private int flatNo;
-
private int buildingNo;
-
-
this.flatNo = flatNo;
-
this.buildingNo = buildingNo;
-
this.address = address;
-
this.city = city;
-
}
-
-
public int getFlatNo() { return flatNo; }
-
public int getBuildingNo() { return buildingNo; }
-
}
Step 2: Creating the backing bean "mybean"
-
package com.myapp.backingbeans;
-
-
import java.net.MalformedURLException;
-
import java.net.URL;
-
import java.util.Date;
-
-
import javax.faces.bean.ManagedBean;
-
import javax.faces.bean.RequestScoped;
-
-
import com.myapp.beans.Address;
-
import com.myapp.beans.User;
-
-
@ManagedBean(name = "mybean")
-
@RequestScoped
-
public class MyBean {
-
-
private User user;
-
private Address address;
-
-
public User getUser() {
-
if (user == null) {
-
try {
-
user = new User(id, "Username Of Id [" + id + "]",
-
"First Name Of Id [" + id + "]", "Last Name Of Id ["
-
+ id + "]",
-
-
}
-
}
-
return user;
-
}
-
-
public Address getAddress() {
-
if (address == null) {
-
"Cairo");
-
}
-
return address;
-
}
-
}
What we want to do is a custom component that takes any object with primative attributes (User/Address) and prints the object details in an HTML table
Step 3: Creating the taglib and the component configuration
create a file with name "custom-taglib.xml" under location "WebContent/WEB-INF", the file contents will be:
-
<facelet-taglib xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
version="2.0"
-
<tag>
-
<tag-name>outputObject</tag-name>
-
<component>
-
<component-type>outputObject</component-type>
-
</component>
-
</tag>
-
</facelet-taglib>
That file define a new taglib called "http://myapplication.com/com" with 1 tag inside called "outputObject", the tag component type - will be used to refere to the tag component class - is "outputObject"
Step 4: Registering the taglib in web.xml file
in the web.xml file, add the following lines to register our custom taglib
-
<context-param>
-
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
-
<param-value>/WEB-INF/custom-taglib.xml</param-value>
-
</context-param>
These lines will tell our server to load the custom facelets library from location "/WEB-INF/custom-taglib.xml"
Step 5: Creating the "OutputObjectAttribute" annotation
Why we need such annotation, suppose you have a bean with 3 attributes "x", "y" and "z", when printing the bean details on the screen, you should use informative labels for "x", "y" and "z", also you should define the order of the attributes on the screen, print "z" then "x" and at the end print the value of "y". Our annotation will hold the needed information (label/order) of each attribute we want to be displayed on the screen.
-
package com.myapp.components.outputoject;
-
-
@java.lang.annotation.Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
-
@java.lang.annotation.Target(value={java.lang.annotation.ElementType.METHOD})
-
public @interface OutputObjectAttribute {
-
int order();
-
}
Step 6: Creating the component class
Our component class will simply do the following:
- Takes an object as a value
- Get all methods declared in the object class that are market with annotation OutputObjectAttribute
- Order all the methods with the value of OutputObjectAttribute.order
- Print a row for each method with the value of OutputObjectAttribute.label as the label column and the method return value as the value column
The class code:
-
package com.myapp.components.outputoject;
-
-
import java.io.IOException;
-
import java.lang.reflect.Method;
-
import java.net.URL;
-
import java.util.HashMap;
-
-
import javax.faces.component.FacesComponent;
-
import javax.faces.component.UIOutput;
-
import javax.faces.context.FacesContext;
-
import javax.faces.context.ResponseWriter;
-
-
@FacesComponent("outputObject")
-
public class HtmlOutputObject extends UIOutput {
-
@Override
-
ResponseWriter responseWriter = context.getResponseWriter();
-
responseWriter.startElement("div", null);
-
responseWriter.startElement("table", null);
-
responseWriter.writeAttribute("border", "1", "border");
-
responseWriter.writeAttribute("cellpadding", "5px", "cellpadding");
-
if (method.isAnnotationPresent(OutputObjectAttribute.class)) {
-
OutputObjectAttribute objectAttribute = method
-
.getAnnotation(OutputObjectAttribute.class);
-
methods.put(objectAttribute.order(), method);
-
}
-
}
-
for (int i = 1; i <= methods.size(); ++i) {
-
if (method.isAnnotationPresent(OutputObjectAttribute.class)) {
-
printObjectAttribute(object, responseWriter, method);
-
}
-
}
-
responseWriter.endElement("table");
-
responseWriter.endElement("div");
-
}
-
-
responseWriter.startElement("tr", null);
-
responseWriter.startElement("td", null);
-
OutputObjectAttribute objectAttribute = method
-
.getAnnotation(OutputObjectAttribute.class);
-
responseWriter.startElement("label", null);
-
responseWriter.write(objectAttribute.label());
-
responseWriter.endElement("label");
-
responseWriter.endElement("td");
-
responseWriter.startElement("td", null);
-
printObjectAttributeValue(responseWriter, object, method);
-
responseWriter.endElement("td");
-
responseWriter.endElement("tr");
-
}
-
-
private void printObjectAttributeValue(ResponseWriter responseWriter,
-
try {
-
value = "Exception Thrown";
-
}
-
responseWriter.startElement("a", null);
-
responseWriter.writeAttribute("href", value.toString(), "href");
-
responseWriter.write(value.toString());
-
responseWriter.endElement("a");
-
} else
-
responseWriter.write(value.toString());
-
}
-
}
The value "outputObject" in @FacesComponent("outputObject") should match the entry "
The component check on the attribute value type (method return value type), in case of "Integer, String..etc", it prints the value.toString(), in case of URL, the printed value will be an HTML A tag that refere (href) to the URL value
Step 7: Marking User/Address bean with the OutputObjectAttribute annotation
Our final step is to mark the beans User and Address with the annotatoin OutputObjectAttribute to define each attribute label and the order of the attribute in the resulted table
Our beans will be:
-
package com.myapp.beans;
-
-
import java.net.URL;
-
import java.util.Date;
-
-
import com.myapp.components.outputoject.OutputObjectAttribute;
-
-
public class User {
-
-
private int id;
-
-
this.id = id;
-
this.username = username;
-
this.firstName = firstName;
-
this.lastName = lastName;
-
this.address = address;
-
this.birthDate = birthDate;
-
this.website = website;
-
}
-
-
@OutputObjectAttribute(label = "User Id", order=1)
-
public int getId() { return id; }
-
@OutputObjectAttribute(label = "Username", order=2)
-
@OutputObjectAttribute(label = "First Name", order=3)
-
@OutputObjectAttribute(label = "Last Name", order=4)
-
@OutputObjectAttribute(label = "Address", order=5)
-
@OutputObjectAttribute(label = "Birth Date", order=6)
-
@OutputObjectAttribute(label = "Website", order=7)
-
}
The Address bean:
-
package com.myapp.beans;
-
-
import com.myapp.components.outputoject.OutputObjectAttribute;
-
-
public class Address {
-
-
private int flatNo;
-
private int buildingNo;
-
-
this.flatNo = flatNo;
-
this.buildingNo = buildingNo;
-
this.address = address;
-
this.city = city;
-
}
-
-
@OutputObjectAttribute(label = "Flat No.", order = 1)
-
public int getFlatNo() { return flatNo; }
-
@OutputObjectAttribute(label = "Building No.", order = 2)
-
public int getBuildingNo() { return buildingNo; }
-
@OutputObjectAttribute(label = "Street Address", order = 3)
-
@OutputObjectAttribute(label = "City", order = 4)
-
}
That's all for our OutputObject component, now our component is very simple one, but it holds the basics of creating other larger complex components
For an Eclipse project for the component tested with JBOSS AS 7.1, check the article attachements
- 3155 reads
Add new comment