Archive for the ‘Java’ Category

JSF, Iterating with tomahawk radio buttons, t:datalist, a4j:repeat

The standard JSF radio buttons h:selectOneRadio render a load of old school html (i.e. they use table tags to do layout, (all a bit 1996)).

e.g. JSF h:selectOneRadio tag

<h:selectOneRadio id="aRadio">
	<f:selectItems value="#{radioOptions.items}" />
</h:selectOneRadio>

Code for #{radioOptions}

import java.util.ArrayList;
import java.util.List;

import javax.faces.model.SelectItem;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;

@Name("radioOptions")
@Scope(ScopeType.APPLICATION)
public class RadioOptions
{
	public List<SelectItem> items = new ArrayList<SelectItem>();

	public RadioOptions()
	{
		items.add(new SelectItem("1", "label 1"));
		items.add(new SelectItem("2", "label 2"));
		items.add(new SelectItem("3", "label 3"));
	}

	public List<SelectItem> getItems()
	{
		return items;
	}

	public void setItems(List<SelectItem> items)
	{
		this.items = items;
	}
}

Note: I’m using jboss seam in the example above, but you could easily remove the seam annotations and define the bean in using jsf managed beans or faces config etc. Also the examples here are a bit mickey mouse and could be better.

Under JSF 1.2 will be rendered as

<table id="myForm:aRadio">
	<tr>
		<td>
			<input type="radio" name="myForm:aRadio" id="myForm:aRadio:0" value="1" />
			<label for="myForm:aRadio:0">Label 1</label>
		</td>
		<td>
			<input type="radio" name="myForm:aRadio" id="myForm:aRadio:1" value="2" />
			<label for="myForm:aRadio:1">Label 2</label>
		</td>
		<td>
			<input type="radio" name="myForm:aRadio" id="myForm:aRadio:2" value="3" />
			<label for="myForm:aRadio:2">Label 3</label>
		</td>
	</tr>
</table>

Anyway this limitation is well known and as a result we’ve been using the apache tomahawk t:selectOneRadio (using the layout=”spread” attribute) and t:radio tags to provide more flexible layouts which can be styled by css.

Iterating through a list of select items

There are times when I want to render the radio buttons in a flexible fashion (offered by t:radio) using a loop tag such as t:dataList or a4j:repeat e.g.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<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:fn="http://java.sun.com/jsp/jstl/functions" xmlns:c="http://java.sun.com/jstl/core" xmlns:t="http://myfaces.apache.org/tomahawk" xmlns:a4j="https://ajax4jsf.dev.java.net/ajax">
<f:view>
<h:form id="myForm">
	<!-- radio button, layout spread  -->
	<t:selectOneRadio id="myRadio" forceId="true" layout="spread">
		<f:selectItems value="#{radioOptions.items}" />
	</t:selectOneRadio>

	<!-- data list, loops through all the radio button options -->
	<t:dataList var="helper" value="#{radioOptions.items}" rowIndexVar="idx">
		<!-- example html, not constrained to table layout -->
		<h1>Heading</h1>
		<t:radio for="myRadio" index="#{idx}"/>
		<h1>Another Heading</h1>
	</t:dataList>
</h:form>
</f:view>
</html>

Unfortunately this doesn’t work and throws:

java.lang.IllegalStateException: Could not find component 'myRadio' (calling findComponent on component 'myForm:j_id3:0:j_id5')

The Fix:

I almost always forget this which is why im blogging about it,

<t:radio for="myRadio" index="#{idx}"/>

needs to be replaced with

<t:radio for=":myForm:myRadio" index="#{idx}"/>

The tomahawk t:radio component must have the fully qualified component name of the t:selectOneRadio name otherwise it cannot find it.

Since the form is defined as:

<h:form id="myForm">

:myForm needs to be prefixed to the for attribute of the t:radio giving :myForm:myRadio

I take absolutely no credit for this because its explained here and on the Myfaces wiki this article is merely a note to self.

Btw, the above works with a4j:repeat as well as t:datalist

Currently tomahawk isn’t working in JSF 2.0 which is a shame as we are looking to upgrade very soon. Hopefully a decent radio button will become part of JSF 2 at some point.

Update: Fully Qualified JSF Name

A bit of searching around on the web took me to Lincoln Baxter’s blog where he mentions rendering components outside of the form and explains that the first “:” tells JSF to start looking from the very top of the JSF View Root. Thanks for that!

Maven site generation error: DTDDVFactoryImpl does not extend from DTDDVFactory

When generating a site with Maven, we encountered the following exception when a particular reporting plugin was executed:

org.apache.xerces.impl.dv.DVFactoryException:
DTD factory class org.apache.xerces.impl.dv.dtd.DTDDVFactoryImpl does not extend from DTDDVFactory.

This basically meant that an incompatible version of xerces was trying to be run. We have everything set to use Java 1.6, which ships with its own version of xerces. After some debugging, it was tracked down to the maven-site-plugin which we had recently upgraded to use version 2.1 of the plugin by specifying it in our pom file like so:

<pluginManagement>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-site-plugin</artifactId>
			<version>2.1</version>
		</plugin>
	</plugins>
</pluginManagement>

The maven-site-site plugin has the following dependency structure:

  • org.apache.maven.plugins:maven-site-plugin:maven-plugin:2.1
    • org.apache.maven.doxia:doxia-module-xhtml:jar:1.1.2 (compile)
      • org.apache.maven.doxia:doxia-core:jar:1.1.2 (compile)
        • xerces:xercesImpl:jar:2.8.1 (compile)

It is the dependency of the xercesImpl jar 2.8.1 that is the problem. To get around this issue, you can tell the maven-site-plugin to exclude a particular dependency. This can be done like so:

<pluginManagement>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-site-plugin</artifactId>
			<version>2.1</version>
			<dependencies>
				<dependency>
					<groupId>org.apache.maven.doxia</groupId>
					<artifactId>doxia-core</artifactId>
					<version>1.1.2</version>
					<exclusions>
						<exclusion>
							<groupId>xerces</groupId>
							<artifactId>xercesImpl</artifactId>
						</exclusion>
					</exclusions>
				</dependency>
			</dependencies>
		</plugin>
	</plugins>
</pluginManagement>

There are a couple of maven reporting plugins that we found produced this exception when run with maven-site-plugin 2.1. These plugins are:

If you use an older version of the maven-site-plugin then the above mentioned reporting plugins should work ok. It is only when specifying a version of 2.1 or above that the exception occurs.

Some of the solutions suggested on the net didn’t work for us, like adding the xercesImpl jar as a dependency to the actual reporting plugin in question, so hopefully the solution mentioned in this post is helpful.

Suppress logging in java unit tests

Here are a couple of different ways of suppressing logging when running unit tests. If you are using apache commons logging then you can suppress logging with the following code:

LogFactory.getFactory().setAttribute(
                "org.apache.commons.logging.Log",
                "org.apache.commons.logging.impl.NoOpLog");

If running your unit tests with JUnit, it is probably best to put this code in the setUp() method. However, if you only wanted it suppressed on particular tests, it could go at the top of the test method instead. Bear in mind that if the logger is a static in the class you are testing, you  may need to then reset the attribute at the end of the test method, otherwise, any tests being run after that one will also have their logging suppressed.

If you run your unit tests within an IDE, you may want to see the logging, but not see the logging when you actually run the build of your project with something like Maven. Thankfully, there is a very simple answer to this if you are using Maven. The maven-surefire-plugin is responsible for running the tests and there is a configuration option which needs to be specified to redirect all the test output to file instead of to the console. This keeps your build reports much cleaner as you aren’t interested in seeing the logging messages. As a bonus, since all output is saved to file, exceptions will also be output to file, so whenever exceptions are thrown in the methods being tested, the stack trace wont show up in the build report.

The configuration option that needs specifying is <redirectTestOutputToFile> and this needs to be set to true, as shown below.

<plugin>
	<artifactId>maven-surefire-plugin</artifactId>
	<configuration>
		<redirectTestOutputToFile>true</redirectTestOutputToFile>
	</configuration>
</plugin>