Actually, I'm surprised that anything displays, since you aren't fetching row columns values, just column headers. I was thinking that unless there's at least one displayable row of data, the column headers didn't display.
I'm conflicted about your solution. One the one hand:
A) It works.
B) Oracle
does have samples of JSF on their official website mixing JSF and JSTL tags, so presumably there's at least some support (in other words, not a kludge that could break randomly when new versions of JSF are released).
On the other:
A) Mixing JSF and JSTL is not somethng I recommend, since despite Oracle's examples, in real life JSTL on JSF pages hasn't proven reliable. JSF View Templates are NOT JSPs, and JSTL was designed for JSPs.
B) Putting any sort of logical construct on a JSF View Template is not something I recommend either. People tend to blur the line between business logic (which should be on the backing bean) and display logic. And in cases where the logic is purely for the display (show/hide stuff
etc., I do recommend only simple EL expressions on the view template - no fancy function calls or complex conditionals. EL is a
to debug, so for a peaceful night's sleep, put the complex logic on the backing bean and have it return a simple boolean value for the EL to reference. A debugger can easily step through
Java logic on a backing bean. Stepping through logic on a View Template is much harder.
C) Core JSF does require such measures -as yours although as an alternative, you can dynamically build dataTable column definitions in Java logic in a backing bean using the UIComponent binding mechanism (it's not as arcane as it sounds). However, many of the third-party extension libraries such as PrimeFaces do have extended dataTable controls that support a variable list of columns without the need for JSTL or complex coding.
So, in short, I endorse your solution with reservations. If possible, use one of the native JSF solutions that the extension libraries offer. If that's not an option, then jSTL or UIComponent binding solutions are a reasonable alternative.
Not content with having passed a rain cloud over your parade, there's a couple of Best Practices, I should point out.
First, don't fetch or generate data within JSF backing bean "get" methods. A getter may be invoked 5 or 6 times in the process of rendering a JSF page, which multiplies the amount of work to be done and the time to do it. It's OK to generate the data on the first get, but cache it so that the 2nd-through 6th gets don't have to repeat all that effort. I know that this was just a simple sample, but it's always worth keeping in mind. Oh, and the other reason for caching is that "get" methods
MUST be idempotent - returning exactly the same results for each call. That won't happen if you're generating random numbers or querying a changing database on each call.
Secondly, I strongly recommend conservative bracketing. Only one late-night desperate attempt to debug something this way:
Will make you a confirmed believer in this style of coding: