i18n in Tomcat and JSTL

Okay, so I didn't *fix* the problem, but I figured out what it was and worked around it. Two things: First, Jasper predicts the JSP's encoding based on the markup on the page and tries to help with the encoding (ignoring the page directive), and second, the JSTL formatDate tag wacks the whole page's encoding no matter what.

Serves me right that the day after I praise Tomcat's goodness, it kicks me in the nads again.

Everything I did in the past two hours was trial and error. My HTML web pages were working, my XML feed pages were not. They seemed identical in terms of the logic. So after trying all the ways you can think of to get the encodings to work, I made copies of both pages and started stripping away tags and directives until the index.jsp and the rss.jsp pages were identical. And guess what? The rss JSP was still outputting garbage. WTF? So then I started adding stuff from the index page to the rss page to see if there was something special that it needed to work, and when I got to the meta tag in the html header with the UTF-8 declaration, the rss page finally worked. But I took the meta tag back out again and *it still worked*. WTF!?!?!

It turns out that once you *break* a page, it stays broken until you can convince it otherwise with something like that meta header. Why this is the case is something for the Jasper developers to explain, but I'm sure if you try it yourself you'll be able to reproduce it easily. So frustrating.

Okay, after I finally got to the point where I could test other tags and directives, I figured out quickly that using fmt:formatDate from JSTL is the killer. I read something like this in a Java.net post by Simon Brown but I wasn't using the fmt:setLocale tag like he was. Just the presence of one formatDate tag wacks the entire pages character encoding for good. Here's what it looked like:

<c:catch><fmt:formatDate value="${created}" timeZone="${tz}" pattern="EE, dd MMM yyyy HH:mm:ss Z"/></c:catch>

So - the solution (for now) is to pull the date encoding back into MySQL like this:

select *, date_format(created, '%a, %d %b %Y %T PDT') as posted
from entry
order by created desc 
limit 30

See the problem? I'm embedding the timezone because MySQL doesn't have any concept of them. Urgh. What would be better is to figure out a way for the JSTL tags not to break the pages but for now I'm happy to have pinpointed the problem.

Make sure to *take out* the the encoding from the page directive. Just use: contentType="application/xml" and it seems to do the right thing. It seems you can't use both the fmt:formatDate tag *and* encode the page at the same time.

Wow, what a PITA. The formatDate stuff in JSTL is really not done well at all, so I'm not surprised that it's become a problem. Unlike the other tags which will fail quietly (a *good* thing on markup pages), the formatDate tag actually throws errors so you have to surround it with catch tags, which is just ridiculous.

If anyone who knows a way of using the formatDate tag and not have the pages die, I'd be ever so grateful.


UPDATE: I've edited this page like three times and I still don't really know the problem, but the above works, that I can say. Don't use the fmt:formatDate tags and don't put the page encoding and it works. I think. Maybe.

< Previous         Next >