Thursday, March 13, 2008

Facelets and XSD-converted TLDs for Eclipse

JavaServer Faces builds on JSPs with the goal of simplifying the building of user interfaces. Facelets aims for further improvement by extending JavaServer Faces, but uses XHTML to define the views, removing the dependency on JSPs and some of the associated issues.

There is a very informative review of Facelets on IBM developerWorks, "Facelets fits JSF like a glove" (Richard Hightower, 2006-02-21). Unfortunately, Richard is currently quite correct in that "IDE support for Facelets is minimal".

Why Facelets works differently in your IDE

The biggest shortcoming I see is that when using JSPs with or without Faces, many IDEs including Eclipse use the same Tag Library Descriptors (TLDs) that are used by the JSP container. While the JSP container uses these files for validation, the IDEs use the information to provide syntax and code completion, as well as pop-up documentation for tags and attributes. Since Facelets uses XHTML files for the views instead of JSPs, at least in Eclipse, the IDE support is lost.

Part of the lost support is due to the fact that instead of declaring tag libraries with a special taglib declaration as in JSP, they are instead declared as XML namespaces, as described in the Facelets documentation. Additionally, since the views seem to be more XML than HTML, an IDE's XML editor seems to be a much better pick than an HTML/JSP editor, which may initially seem to be an odd move.

The benefit of an XML editor, such as the one available with Eclipse and Eclipse-based products, is that XML features similar to to the previous HTML and JSP features are available, including content assist and pop-up documentation. However, this is largely dependent on having a valid XML Schema (XSD) - and all Faces provides are TLDs.

The outline to a solution

I then realized that a TLD file is just XML. There is even a complete XSD for TLD files. Why not write an XSLT to convert the desired TLDs into XSDs? Surprisingly, expecting that someone else would have already done this, I was unable to find any such accomplishments. I then wrote my own transformation, and am making my solution available here for your use on http://ziesemer.java.net: facelets-xsd.jar.

Included in this .jar file is:

  • My TaglibToXSD.xslt XSL transformation.
  • XSD versions of the latest Faces TLDs (html_basic.tld and jsf_core.tld from Sun's Reference Implementation (RI), Mojarra (1.2._08), transformed using the above XSLT.
  • A manually written facelets.xsd file, representing the "UI" components from the "http://java.sun.com/jsf/facelets" namespace, as described in the Facelets developer docs. (Note that I was unable to find a TLD, XSD, or any other form of compiled documentation for these tags outside of the linked referenced documentation.)

Note that in at least the Eclipse-based IDEs, the built-in documentation support for XML does not seem as rich as the support provided for JavaDocs. HTML tags are stripped, leaving only the raw text, compared to having rendered/formatted HTML with the JavaDocs. Additionally, Eclipse doesn't appear to provide any ability to expand the displayed documentation beyond the relatively-small pop-up window, and without even any scrollbars, there is currently no easy way to view the complete text in longer descriptions. (The JavaDoc viewer provides an F2 option to expand the view.) As such, I recommend that you keep the HTML versions of the documentation handy: Faces and Facelets.

Configuring Eclipse

While these XSDs should work with practically any IDE or other XML editor that supports XSD, here I'm going to focus on Eclipse 3.3.

(Note that "Eclipse Classic" does not come bundled with the XML editor, though it can be easily installed through the Update Manager. The "Eclipse IDE for Java Developers" does come bundled with the XML editor. Also be certain to use a recent version of the Java JRE to run Eclipse (1.5 or higher), otherwise the XML features will appear to be missing.)

Eclipse comes with a nice feature called the XML Catalog. (See also the wiki page.) In summary, the catalog allows Eclipse to automatically associate a schema or DTD with any open XML document, whether or not a valid or accessible schema location is provided within the XML. This is what I used to have Eclipse associate my generated XSD files with my Faces files. It can even reference the files inside my provided .jar file without the need to extract them.

There are 3 XSDs that can be linked from my provided .jar file, as shown in the table below. Just replace <folder> with the location where you have the .jar file saved, and use forward-slashes (/) for the path. View Eclipse's default entries for examples. Alternatively, you can extract and link to the extracted files, which will also allow Eclipse to automatically populate the Key field. (For more detailed step-by-step type instructions, refer to the referenced links above.)

LocationNamespace Key
jar:file:<folder>!/html_basic.xsd http://java.sun.com/jsf/html
jar:file:<folder>!/jsf_core.xsd http://java.sun.com/jsf/core
jar:file:<folder>!/facelets.xsd http://java.sun.com/jsf/facelets

If you were to store your Facelets views as *.xml files, this should be it. However, *.xhtml is a probably the most common, and a content type should be configured for it within Eclipse. (Without it, the XML features won't work properly, even when a file is opened with the XML editor.)

  1. Choose Window, Preferences.
  2. From the outline at the left, expand General, click Content Types.
  3. From the upper window pane at the right, expand Text, then select XML.
  4. From the lower pane, click Add, enter *.xhtml, click OK, then OK again.

You may then wish to make the XML editor the default for *.xhtml files:

  1. Choose Window, Preferences (again).
  2. From the outline at the left, expand General, Editors, then click File Associations.
  3. From the upper window pane at the right, select *.xhtml.
  4. From the lower pane, select "XML Editor", click Default, then OK.

The last option to note is when the XML editor is open, "Turn Grammar Constraints On/Off" from the XML menu. (This is described in more detail in the Eclipse Help.) As XHTML (and the TLDs/XSDs) aren't configured to allow "unknown" children, this option usually works best when turned Off, allowing content assist to provide completion options even when the parent schema doesn't allow it (an issue that is outside the scope of this post).

11 comments:

Ryan said...

Exactly what I've been looking for. Most annoying not having content assist available in the various editors in Eclipse.

You should consider submitting this to the facelets project. They really should have an XSD as part of the distribution.

Mark A. Ziesemer said...

Ryan - I'm glad to hear that someone else was able to make use of this!

I had thought about submitting this to Facelets, and maybe I'll still drop them a note.

Unfortunately, I'm realizing that this method isn't really compatible with some of the "limitations" of XHTML. (While it works great for the Eclipse features, the XHTML specification causes validation errors for any non-XHTML content.) I was planning on writing a 2nd post about these issues shortly...

Hugo said...

To get completion working for .xhtml Facelets files in Eclipse 3.3, you can also install JbossTools plugin, and use JbossTools HTML Editor !

Mark A. Ziesemer said...

Thanks for the tip, Hugo. I'll definitely look into it!

theschles said...

Confused - I added the three .xsd files to my XML Catalog, yet I still see errors in Eclipse 3.4 for my xmlns declarations:

Code pasted here

Help?

Edi said...

I use Eclipse 3.4, and i dose not work. It dose not autocomplete my code, help plase

Mark A. Ziesemer said...

theschles and Edi - I don't believe I've actually tried this again under Eclipse 3.4 or since making this post.

For now, I'd actually recommend against the approach, partially for the same reason I explained to Ryan above.

I've actually had better luck just using Eclipse's JSP editor, which does recognize the taglibs, and doesn't share any of the above XHTML issues. Just make sure *.xhtml or whatever extension you're using is added to the file associations under General / Content Types / Text / JSP in Eclipse.

Steven said...

Did you ever get a chance to submit a second post to resolve some of the xhtml issues?

neocygnus said...

Excelent Work Mark

Dou you have xsd files for mojarra 2.0?

https://javaserverfaces.dev.java.net/servlets/ProjectDocumentList?folderID=11965&expandFolder=11965&folderID=
i could´t use your XSLT transformation

belz said...

I'd love to see those transformations for mojarra too. Downloaded Helios as i saw some resolved bug reports on adding support for h:link etc. but couldn't get it working and don't have too much time left :-)

Anonymous said...

Does this work for JSF 2.x? Using MyFaces 2.1 and Eclipse Indigo.