CDATA and NullPointerExceptions

Today was a perfect example of why I like to make mistakes in front of students. Yes, it’s sort of annoying when a student points out that I’m wrong. But it means that they’re paying attention and have learned enough of the content to correct me.

Plus, it almost always turns into a good teaching moment; like today.

Background…

Over the past few summers I’ve written an online autograder that I use in class. Students submit their code, it runs on the server, and they get their results. Behind the scenes there’s XML going between multiple servers to keep everything connected.

Since it’s student generated output the results are wrapped in a CDATA tag. That way I didn’t have to escape every > and <. And it worked flawlessly until we got to matrices. Turns out when junit tests for matrices fail there may be a ]]> in the results. ]] is the closing of the matrix and > is how junit wraps expected output.

The problem is that ]]> is also the closing tag for CDATA. By having ]]> inside CDATA the XML became invalid.

The fix, sort of

This is the line that was causing the problem.

out += "<message><![CDATA[" + f.getMessage() + "]]></message>\n";

The problem is when f.getMessage() returns a string that has ]]> in it. Invalid XML. What I came up with as a quick fix was to replace any ]]> in the message with ]] > with a space between the last two characters. Testing it, the XML was valid that way.

Here’s the fix I pushed last night.

out += "<message><![CDATA[" + f.getMessage().replace("]]>", "]] >") + "]]></message>\n";

For those of y’all playing at home, what happens when f.getMessage() returns null?

Today students started getting NullPointerException showing up, but it was in the test code, not theirs. Worked out to several pretty good discussions on NullPointerException and the idea that mistakes are helpful. Frustrating, but helpful.

The actual fix

Since I can’t, and don’t, work on my autograder from school I couldn’t do anything to get it working during the day. Fortunately students had enough other labs to work on that it didn’t cause too much disruption in class.

I ended up doing something pretty hacky and forcing a String. Ugly, but it appears to be working.

out += "<message><![CDATA[" + ("" + f.getMessage()).replace("]]>", "]] >") + "]]></message>\n";

The code now concatenates an empty string on the front of f.getMessage() before tacking on the replace method.

Next Step

I’m thinking that I should probably base64 encode the results before putting them into XML. Then it wouldn’t matter what characters there are. But that would take a lot more testing and I needed something that I could get working on when I got home last night. Maybe over the upcoming winter break I’ll get a better solution.

Or, even better would probably be to use an actual XML builder instead of just building it as a string. Anyone out there have any favorite Java libraries to build XML? Let me know in the comments.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *