ROME and custom Generator elements

The majority of the articles I’ve seen on using ROME to create Atom and RSS feeds don’t show you how to customize the optional ‘generator’ element that both Atom and RSS support. It’s really easy. I’m assuming that you’ve already created and populated a SyndFeed instance:

SyndFeed feed = ..
WireFeedOutput feedOutput = new WireFeedOutput();
WireFeed wireFeed = feed.createWireFeed();
if (wireFeed.getFeedType().startsWith("atom")) {
  Feed atomFeed = (Feed)wireFeed;
  Generator gen = new Generator();
  gen.setUrl("http://yoursite.com/");
  gen.setValue("Your Site");
  gen.setVersion("1.0");
  atomFeed.setGenerator(gen);
  feedOutput.output(atomFeed, ...);
} else {
  Channel rssFeed = (Channel)wireFeed;
  rssFeed.setGenerator("Your Site 1.0 (http://yoursite.com/)");
  feedOutput.output(rssFeed, ...);
}

Make a decision about which feed you’re going to produce, cast to the appropriate implementation of WireFeed (Channel for RSS and Feed for Atom), and then use the appropriate setters on each of those respective classes.

Links: 1-9-2007

Firefox mimeTypes.rdf corruption

Came across another interesting bug today involving Firefox and mime types. Firefox uses a file called mimeTypes.rdf (stored in your profile folder) to keep track of a) what application should be opening the file you’re downloading and b) what kind of file it should tell a server it’s sending when you upload a file. And it works … for the most part. See, if you download a PDF file from a server that (incorrectly) states that the content-type of the file is ‘application/unknown’, choose to open it using Adobe Acrobat and then check the box that says ‘Do this automatically from now on’, Firefox will store that bit of knowledge away in mimeTypes.rdf. Now go and use a web application that you upload files to and which analyzes the content-type of the files you’re uploading and upload a PDF file. If you’re using LiveHTTPHeaders, you’ll notice that you’re not sending ‘application/pdf’ but instead ‘application/x-download’.

It looks like this bug was filed in bugzilla a couple times and even acknowledged in their documentation, but has yet to be fixed. You can ‘fix’ the problem by deleting your mimeTypes.rdf file and restarting Firefox.

Five Things

My friend and ex-roommate David tagged me with the five things meme, so here are five things about me you probably don’t know:

  1. My parents tell me that the doctor dropped me on the floor when I was born.
  2. I lettered in soccer and baseball in high school.
  3. I got my first computer (a Color Classic) in college. I remember playing Maelstrom while listening to Tribe Called Quest with my roommate for hours.
  4. I worked at Fuddruckers during my college summers, gaining a ‘Guest Service Representative’ certification. I’m not sure if my certification expired, but if you buy me lunch, I’ll be happy to refill your drink.
  5. I’ve seen Major League Baseball games at the following parks:
    • Dodger Stadium
    • Angel Stadium
    • Jack Murphy Stadium
    • PETCO Park
    • Candlestick Park
    • Bank One Ballpark
    • Coors Field
    • Shea Stadium
    • McAfee Coliseum
    • Kingdome
    • Fenway Park
    • Skydome*
    • Camden Yards
    • Yankee Stadium

I’ll tag Joe, John, Ryan, Erik and Mike.

* The visit to the Skydome probably shouldn’t count, I didn’t actually see a game there because I was in Toronto in November. I think there was a Canadian Aboriginal festival happening that day.

OGNL: getter and setter types must match

Yesterday I ran into a interesting bug with the WebWork application I spend my waking hours working on, at least initially I thought it was a WebWork bug. I had a WebWork action with a getter / setter combination that looked like this:

public void setUser(String username) {
...
}
public User getUser() {
...
}

The thinking here was that if I invoked the action using a request like this:

/myaction.jspa?user=aaron

then the action would look up the user based on the given username and populate a User object, which would then be returned by the getUser() method (populating the user instance using a custom IOC interceptor would have also worked but would have been overkill in this particular case). The problem was that the setUser(String username) method was never getting called. After checking and double checking the method names and the parameter being passed, I googled around and found this email thread which discusses the very issue, saying that the problem was in fact not with WebWork, nor with it’s underlying expression engine OGNL, but rather the ‘Java reflection API semantics’. In the thread, Laurie Harper, a Struts committer, says that the:

… restriction (where getter and setter have to be of the same type) comes from the Java relection API semantics, not OGNL. A property can only have one type, so it makes sense that the getter and setter for a JavaBean property must agree on that type.

I didn’t doubt what he said, but I needed to see it with my own eyes, so I dove into the deep sea that is OGNL, reflection and JavaBeans. First I read the JavaBeans specification, which seems to back up his story: page 55 of the PDF says this:

By default, we use design patterns to locate properties by looking for methods of the form:
public <PropertyType> get<PropertyName>();
public void set<PropertyName>(<PropertyType> a);
If we discover a matching pair of “get<PropertyName>” and “set<PropertyName>” methods
that take and return the same type, then we regard these methods as defining a read-write property whose name will be “<propertyName>”.

So the JavaBeans specification requires the getter and setter to be of the same type, but how does OGNL figure out that the I’m trying to trick it with two different types?

I found the answer by digging pretty deep: the OgnlRuntime class looks up a PropertyDescriptor for the given class (in my case the WebWork action) and then calls the getWriteMethod() on the PropertyDescriptor instance. The documentation for that method mentions that it may return null if the property can’t be written but the documentation doesn’t mention why that might happen. If you grab the source for the PropertyDescriptor class, you’ll see that the getWriteMethod() method invokes a private method findPropertyType(), which is where I finally found the culprit. It compares the return type of the getter and the parameter type of the setter and throws an IntrospectionException if the types don’t match (line 602), which the getWriteMethod() catches and then returns null, which leaves the OgnlRuntime with no method to call.

So it sounds to me like this is really a JavaBean specification requirement, not a Java reflection API semantic, but then I guess it’s all just semantics anyway right?