JSF Conversion Oddities?

Posted on April 14, 2005 by Scott Leberknight

Suppose you have a web application with a field named "amount" on a form. Suppose also the field should convert its input to a number with at least 2 fractional digits. Ok, JSF provides a <f:convertNumber> tag that provides an attribute minFractionDigits. So far so good. We could put the following code in our JSF page:

<h:inputText id="amount" value="#{payment.amount}">
    <f:convertNumber minFractionDigits="2"/>
</h:inputText>

Makes some degree of sense. Whether I want to place this conversion directly in the view layer is debatable. Actually not really. I don't want to put it there but that's what JSF wants you to do, so for my example I did just that. Then I started playing around, submitting the form with various values. Entering valid numbers works fine, e.g. 75.00, 45, 21. So let's see what it does with something that is not a number. Entering 'abcd' produces a conversion error which gets output to the screen. The default error message is 'Conversion error occurred' and changing it to something like 'The amount could not be converted to a number' turns out to be exceedingly difficult in JSF on a per field basis, but that will have to wait for another blog. Ok, what about a mixture of numbers and letters? Entering '50xyz' produces...50.00. Um, wait a second. Apparently the invalid trailing letters are ignored. Last time I checked, if you try to feed that number to the standard factory method Double.valueOf() you get a NumberFormatException as you would expect. Why would JSF accept that value and convert it as a valid number? That just doesn't seem to make any sense at all.

Oh but wait. Before assuming this is purely the fault of JSF, I did a little more and wrote a JUnit test to test out parsing numbers using the NumberFormat.parse() class. The string "50xyz" is successfully parsed using this method. The JavaDoc for NumberFormat.parse() actually states "Parses text from the beginning of the given string to produce a number. The method may not use the entire text of the given string." That last sentence tells the story. The method doesn't necessarily use all of the input string, which I think is a bit odd. What if the input string were "50?75"? The parsed value is 50! This is not only odd, it seems just plain wrong to me. What if someone meant to type in "50.75" but typed "50?75" (since the "?" is next to "." on the keyboard? The parse does not flag an error and would then cause a wrong input value to be accepted. So apparently the culprit here is actually the JDK, not JSF. So this just illustrates that you need to thoroughly test your applications using many different forms of invalid data to ensure your application actually considers it invalid. But since JSF (apparently) uses NumberFormat during its conversion phase, this type of data will be converted successfully and not flagged as erroneous input.

Note that NumberFormat.parse() is not the only method with a lenient parse policy. The SimpleDateFormat.parse() method also does. For example, the string "4/2005edfnnas", when parsed with the pattern "MM/yyyy", is parsed successfully to the date 4/1/2005. And, the JSF <f:convertDateTime> tag probably uses SimpleDateFormat as well, since the above input string converts to "4/1/2005" in JSF. So if you are using JSF and its converter tags, be aware of the leniency during parsing.

onclick versus onchange in IE and Firefox

Posted on April 09, 2005 by Scott Leberknight

So I deployed one of the Core JSF examples to Tomcat and tested it out. In case anyone actually cares, it is the "Deleting Rows" example in chapter five. Anyway, since I normally use Firefox that is what I was using and the example worked as advertised. I have no idea why, but I opened up Internet Exploder and tried the example. It didn't work properly. The example basically has several checkboxes that, when changed as detected by a JavaScript onchange event, called submit() to submit the form. (Whether clicking a checkbox should cause a round trip to the server is a different matter altogether, but that is what this example does.)

So in Firefox this worked great. When a checkbox was clicked, the onchange even handler fired and submitted the form. but in IE what happened was quite different...nothing at all actually happened when I clicked the checkbox. That is, until the checkbox lost focus by tabbing away or mouse clicking somewhere else. The solution is relatively simple. Just change the onchange event handler to onclick. When a checkbox is clicked, the handler fires and the form is submitted. This works in both IE and Firefox.

My initial reaction was to praise Firefox and then to curse IE, but I wondered whether what the HTML specification said about onchange. Here's what the HTML 4.01 specification has to say about onchange event handlers:

"The onchange event occurs when a control loses the input focus and its value has been modified since gaining focus. This attribute applies to the following elements: INPUT, SELECT, and TEXTAREA."

Well, well, well. Apparently I needed to check (no pun intended) that initial reaction and in this case state that it is IE that is following the specification to the letter, not Firefox. IE does in fact wait until the checkbox has lost focus and that its value has changed. Prior to posting this, I submitted the "fix" of changing to use onclick to the Core JSF website. Using that method works in both IE and Firefox, and therefore probably Mozilla and Netscape as well. Anyway, the point here is simply that not everything is as it seems: in this case IE and Microsoft got it right, and Firefox has added extensions or at least "enhancements" to the way onchange is supposed to work.

Stuff like this is incredibly annoying, though; you cannot simply take the specification at face value because different vendors have slightly different implementations. This is one reason I dread having to test web applications in every single browser. And it goes to show why having specifications that are followed and that you can count on is very important. After all, how much time and money has been wasted over the years on getting web interfaces to work properly in all browsers, and even different versions of the same browser? Even on my current project at work we found a difference in the way Netscape 7 and IE 6 handle a certain thing in JavaScript and had to write different code for Netscape and IE. This should not be required but apparently is still an issue. Not as much as several years ago to be sure, but it is still not perfect.

Cuneiform or JSF?

Posted on April 05, 2005 by Scott Leberknight

So if JSF forms only permit POST requests, how would you go about creating a link to submit your form instead of a button? Whereas you use the <h:commandButton> tag to create an HTML submit button, you use <h:commandLink> to create a link that will submit your form. So far so good, right? Not so fast. Because JSF only permits forms to be POSTed, the JSF generates an HTML link with an onclick even handler that sets some hidden form variables and then submits the form. Lots of magic incantations going on here that are out of your control. Check out the following example code.

Suppose you have a form whose id is "registerForm." Also suppose you want to have several text fields and a "register" link to submit the form. In your JSF page, you write this code:

<h:commandLink value="register"/>

I deployed the JSF page containing this code to Tomcat and then viewed the generated source code. Here it is:

<a href="#" onclick="document.forms['registerForm']['registerForm:_idcl'].value='registerForm:_id6'; document.forms['registerForm'].submit(); return false;">register</a>

In addition to the above, a hidden field was added:

<input type="hidden" name="registerForm:_idcl" />

Is this the kind of code you want your web framework generating? I think I'll pass.

Another fun thing about JSF's generated HTML code is the way it names HTML form fields. It uses the format formName:componentName where formName is the name of the form and componentName is the name of the HTML form control. So in my "registerForm" the code <h:inputText id="password"/> generates the following:

<input id="registerForm:password" type="text" name="registerForm:password">

This code has the nice little side effect that it cannot be accessed in JavaScript in a simple manner. You cannot simply write document.forms.registerForm.password. Instead, due to the colon in the element name you are forced to write the following:

document.forms.registerForm["registerForm:password"].value

This seems par for the course so far while learning JSF. Every time you turn around there is some other gotcha or misuse of technology or artificial restriction being placed upon you the developer. Have fun!

No GET Requests! Are You Serious?

Posted on April 02, 2005 by Scott Leberknight

I managed to read a couple more pages of Core JavaServer Faces today and couldn't believe it when I read that JSF only supports POST requests for forms because apparently you can store session state on the client in a hidden field; this is apparently done automatically by JSF. Therefore since the contents of that field "can be quite large" you could possibly "overrun the buffer for request parameters." Are you serious? So for every form you create in JSF you must POST the submission? That is simply unbelievable. There is a reason there are both GET and POST requests - they are for different types of actions. Why in the world a framework would force you to (mis)use POST for every form submission is utterly beyond me. Then again, I suppose if you buy into the whole "JSF applications should be created using specific tools like Sun Studio Creator" model, then you probably either don't care what code is generated, wouldn't understand it anyway, or don't even realize there is a difference between GET and POST requests. If there weren't any difference, then why do Servlets have both doGet() and doPost() methods?

I would have thought the people designing JSF would know better than this. Spring MVC for example recognizes the distinction between GET and POST requests, and its AbstractController permits disabling GET and POST requests via a supportedMethods property, which by default supports HEAD, GET, and POST methods. In addition, Spring's AbstractFormController defines separate lifecycles for GET and POST requests, taking the viewpoint that GET requests typically correspond to "edit" operations while POST requests correspond to "save" or "delete" operations.

Finally, the fact that JSF doesn't even give the developer a choice just seems to be more evidence that it was designed for tools and not with developers in mind. And the implementation of storing client state in some gigantic hidden field seems ludicrous. That would mean you would need to have a form on every single page of a web application in order to carry that state around. To me that is just a poor design decision; it is certainly possible (and preferred) to design web applications with a minimum amount of session state. About the only things I ever store in session are User objects representing who the logged on user is. Sometimes I'll simply store the user's database id. Everything else that the view needs can be setup per request and set as request attributes. The only caveat is that I often store global data, e.g. for drop-down select lists and other rarely-changing reference data, in application scope. But seriously, is this really going to be the way the standard J2EE web framework works?

Raible Working for Microsoft

Posted on April 02, 2005 by Scott Leberknight

On April 1st I read how Matt Raible was going to work for Microsoft. Not thinking about the fact that it was April Fools Day, I completely bought it. What's even funnier is that today I saw his blog post about how it is not true and how CNET actually reported it in a story! I also feel a little stupid because tonight I told a couple of co-workers that Raible was going to work for Microsoft. :-)

First Real Python Script

Posted on April 01, 2005 by Scott Leberknight

Yesterday I completed my very first real, though very novice, Python script at work. We were creating a "commons" project for several projects past and present that I am working on that combines utility classes created over the pasts few years. We merged the codebase from the projects and needed to go through all the Java source files and modify headers, Javadoc tags, and footers to be consistent. I wrote a relatively short Python script to do this, and found it was pretty easy. Despite the fact that I have barely started to learn Python I was able to use the os module to work with files and directories, and to use the re module to use regular expressions to match various strings.

Definitely the coolest thing was the walk() function which (from the Python documentation) "generates the file names in a directory tree, by walking the tree either top down or bottom up. For each directory in the tree rooted at directory top (including top itself), it yields a 3-tuple (dirpath, dirnames, filenames)." For example, suppose you wanted to find all Windows .bat files starting from the c:\projects directory. The following script does just that. I am sure an expert Python developer could do it in fewer lines, but I am just starting out with Python so I'm sure it's not the best code.

import os
import re

for root, dirs, files in os.walk('c:\projects', topdown=False):
  for file in files:
    match = re.compile('.*bat$').match(file)
    if match != None:
      print 'Found file: ' + file + ' in dir ' + root

Pretty cool. I am not even going to bother seeing how many more lines of Java code this would take, but I'm sure it would be a lot more. Anyway, the way the walk() method returns a "3-tuple" is just plain cool, and it's even cooler how you can just define them in the for loop. I definitely plan to continue learning Python and keep this snake in my software tool garden. Ok, I cannot believe I just wrote that. Must be getting old if the cheesy and sucky jokes are starting already.

JSF Designed For Tool Support

Posted on April 01, 2005 by Scott Leberknight

After a month hiatus from blogging in which we took a week snowboarding at Whistler/Blackcomb and my time seemed to get sucked down the drain, I've started reading Core JavaServer Faces. Mind you, it is not because I am enthralled with JSF or that I really want to use it on any future projects. I am learning it because I am sure that in the near future I will have to explain to a client why I don't want to use it on a project right now.

I've read a lot of people's opinions on JSF on various places like TheServerSide, SYS-CON, IBM developerWorks, and another one at SYS-CON.

Obviously there's no shortage of opinions both ways. One of the things that annoys me is how JSF was designed for tools. There are some people who I've argued with and others whose articles I read who try to dispel this "myth" and say its not true. Well, it is true. In the preface to Core JSF, David Geary explains the JSF "framework was designed for tool support". Not designed with tools in mind, not designed so tool vendors can provide tooling, but designed purposely and specifically for tools. Now I am not against tools per se; in fact I use them all day long every day, e.g. IDEs, build tools, test tools, etc. But I am little skeptical of a framework designed and targeted for tools. Since David is a member of the JSF expert committee, and because I have now heard him say that in person and now in print, I believe it.

Yes, you can build JSF application by hand in vi if you like, but since JSF was designed for tools, it would be common sense to think that using a tool to build JSF applications would make it easier. One of the great things about the Java and open source worlds is that most things are first designed and used by people hand-coding everything, and then tools are built to support things that are tedious and repetitive. JSF inverts this by beginning with tools. Therefore from what I have seen (I'm only a 100 pages into the 600 pages of Core JSF) the JSF expert committee wasn't really too worried about those people who actually are more productive hand-coding or are experts and therefore can be slowed down by some tools.

Another thing about JSF is that it seems to force developers to build JSF applications, not HTML-based web applications or any other view technology. In other words, JSF strives to be completely agnostic of the specific view technology. That is fine in principle and might even work itself out to be a good choice, but for now it seems you have almost zero control over the HTML generated in your web application. Contrast the JSF style with all custom JSF tags with Spring which completely separates the view from the controller in its MVC framework, and does so with a minimal amount of coding and intrusion. It was designed for different view technologies to be plugged into the web framework, and actually supports multiple view technologies out of the box - JSP/JSTL, Velocity, Freemarker, XSLT, PDF, and Excel to name some. JSF on the other hand supports only JSP out of the box as a view technology. It seems that JSF pages are a morass of custom JSF tags, with very little HTML at all. Thus without a tool that explicitly supports JSF, a web developer who only knows things like HTML, CSS, graphics, etc. is going to have a tough time! In addition, this model makes it hard to customize the generated HTML since it is generated for you.

Having been to JavaOne the past two years where Sun has repeated how they want to make Java/J2EE development easier and lure masses of Visual Basic developers to Java. A noble goal but it could backfire if it actually succeeds. I say "backfire" because that means the Java world would all of a sudden have a group of developers who can use a tool, but have no idea what's going on underneath. That is always a recipe for problems, because there always are unique problems you run into during every single project you work on., and which require a deeper level of understanding than someone who only understands how to point-and-click. Anyway, I digress.

The point is I will get through Core JSF, building the sample applications by hand in Eclipse and UltraEdit, and perhaps I'll later blog about how I was wrong. But right now I'm not counting on that outcome; we'll see what happens. Perhaps as I go further with JSF I'll change my mind. Most times my first impression has been about right, but I definitely have misjudged things before. The worst one was my initial impression of Spring. After the first article I read, I wasn't really interested. But now I am a huge Spring user and advocate.