Im-a build me some Spring samples (Part 1: petcare) #fail

Just more examples of commonplace Eclipse/Java things that drive me nuts. I should say up front that the version of Eclipse I’m using is actually SpringSource Tool Suite (STS) version 2.3.2.RELEASE, running on the 1.6.0_20 64-bit Sun HotSpot JVM on Fedora 13.

There’s a trove of Spring sample projects over at https://src.springframework.org/svn/spring-samples/ – very helpful. So I had Eclipse check some out and import them as projects. Funny thing, there seem to be a lot of complaints about XML. I’m getting a little more savvy, let’s see if I can resolve these.

Pet Care

spring-petcare-3.0.xsd

From petcare’s servlet-context.xml, we get the good old “Referenced file contains errors (http://www.springframework.org/schema/petcare/spring-petcare-3.0.xsd).” OK – I’m pretty familiar with that. If you try to go to the URL given, SpringSource’s server redirects you to the home page. Seems the “petcare” schema just didn’t quite make the list with the rest of the framework – I can understand that. But what URL should we use instead?

Well, not surprisingly, the petcare projects contains its own XSD; it’s in /src/main/resources/org/springframework/samples/petcare/util/config/ – so how do I use that as the URL? Well, one way is to use the svn tree from the website; then the schemaLocation is https://src.springframework.org/svn/spring-samples/petcare/trunk/src/main/resources/org/springframework/samples/petcare/util/config/spring-petcare-3.0.xsd. Would have been nice if the project just did that, wouldn’t it? I would think that, distrusting SpringSource not to move/change it again, you could refer to it relative to src/main/resources/META-INF/spring/appServlet/servlet-context.xml as ../../../org/springframework/samples/petcare/util/config/spring-petcare-3.0.xsd (feeling the pain yet?) or copy it to the same directory and just refer to it as spring-petcare-3.0.xsd – but neither of these seems to work on deploy, while the web URL does. There’s a file META-INF/spring/spring.schemas that appears to be intended to specify where to look in the project for the schema, but I’m not sure how it’s supposed to be referred to in Eclipse to make this work.

Here’s a really great error Eclipse has on one of the XML elements that refers to the schema: “- schema_reference.4: Failed to read schema document ‘spring-petcare-3.0.xsd’, because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.” So which is it? Good grief. Would it really be hard to make messages like this actually useful? This is so frustrating.

Amazingly enough, if you try to deploy and you haven’t cleaned this up, Tomcat goes and tries to download the XSD as well and fails if it comes out wrong. So there you have it: your ability to deploy seems to depend on whether the right web sites are up at the right time. I imagine there’s a Tomcat or context.xml setting to disable this behavior.

Spring NamespaceHandler for petcare:resources

OK. So now I’m pointing at the right XSD, but I still have problems with servlet-context.xml. Actually it’s only a warning, but: “Unable to locate Spring NamespaceHandler for element ‘petcare:resources’ of schema namespace ‘http://www.springframework.org/schema/petcare'&#8221; – again with the “Unable to locate” business. That crap sure gets old. Why don’t you give me some kind of clue? Where did you look, where should I look? Actually I think I understand this and it’s trying to say there’s no “resources” element defined in the XSD. But there certainly is, so I don’t really know what this is on about. It seems to work anyway on deploy so I’ll ignore for now.

root-context.xml: Build path is incomplete

On to root-context.xml, another Spring bean file. This has three errors listed. The first two are really confusing: Next to line 22 which looks like this:

<!-- Embedded H2 Database -->

I have the error “Build path is incomplete. Cannot find class file for org.springframework.samples.petcare.users.PetcareAuthenticationFailureHandler”. Next to line 24 which looks like this:

<jdbc:script location="classpath:schema.sql" />

I have the error “Build path is incomplete. Cannot find class file for org.springframework.samples.petcare.users.PetcareUserService”. WTF? Actually Eclipse helpfully gave me a clue below on line 56, which looks like this:

<import resource="security.xml" />

This has the warning “Validation warning occured in imported configuration file ‘src/main/resources/META-INF/spring/security.xml'”. Yes, as it turns out that file has errors on lines 22 and 24, where¬† they make a lot more sense. But they’re not reported in security.xml; they’re reported against irrelevant lines in root-context.xml, which just includes it. Truly mind-boggling.

Now from this, plus the “Build path is incomplete. Cannot find class file for org.springframework.samples.petcare.util.templating.DefaultStringTemplateFactory” on line 29, I gather the build path is incomplete. But all those files look to be provided by this project and the build paths seem to be set up fine. So what the heck is going on?

At this point I checked my system and noticed that after installing some unrelated things, Fedora has chosen java-1.5.0-gcj as my compiler. I don’t think Eclipse is using this, and theoretically it shouldn’t matter anyway, but I shut down Eclipse, reconfigure alternatives so the Sun JDK is again providing the default javac, restart Eclipse, and clean the project. Somewhere in there, the complaints went away.

page.jsp Type mismatch

Now I’m left with just one actual error in src/main/webapp/WEB-INF/layouts/page.jsp. Only, when I open that file, Eclipse doesn’t list any errors. I have to go down to the “Markers” tab to find it:

page.jsp line 62 Type mismatch: cannot convert from boolean to String

Line 62 is a completely innocuous HTML div. Eclipse is just bonkers. I delete the marker and now my petcare project is free of red Xes. I deploy and it works. That might be enough for some people… but now, what about all those warnings?

Unresolvable warnings

Our old friend servlet-context.xml still has a warning next to <petcare:resources> that says “Unable to locate Spring NamespaceHandler for element ‘petcare:resources’ of schema namespace ‘http://www.springframework.org/schema/petcare'&#8221;. I feel I’ve been as clear as possible about the petcare schema so I really don’t know what more there is to say. So let’s leave that (or delete it).

Under src/main/resources, log4j.xml complains “The file cannot be validated as the XML Schema “/home/luke/Documents/workspace-sts-2.3.2.RELEASE/petcare/src/main/java/log4j.dtd (No such file or directory)” that is specified as describing the syntax of the file cannot be located.” This seems to be universally ignored – as I recall, I saw some bogus explanation as to why it was bad to specify a URL for this DTD. You would think Eclipse could just supply the DTD itself, or find it somewhere in the log4j JAR in my Maven dependencies. I don’t have a clue what to do about this so I leave it.

The final warnings are in src/main/webapp/WEB-INF/views/appointments/calendar.jsp, where Eclipse is complaining about data-* attributes on some HTML tags. As I recall these attribute “extensions” are part of the HTML standard so I don’t know why Eclipse is complaining. No way to shut it up without disabling validation entirely, so again let’s leave it. And that’s it for petcare.

Memory (classloader) leak

BTW, petcare has a big fat memory leak in it somewhere, because after you’ve re-deployed a few times, you get a PermGen error. Nice going. I can use this to hone my memory-leak-debugging skills soon.

This sort of thing makes me so mad I could spit

Often projects have external dependencies. Sometimes their whole job is to resolve external dependencies. Maven, yum, rubygems, heck CPAN!

These projects should be built as if their dependencies are trying to deliberately sabotage them. Reminds me of the talk I saw at Uberconf that drove home that point: stuff goes wrong, so you gotta protect yourself at all of the integration points.

When it comes to external dependencies, if something goes wrong, you really need to point the user in the right direction. You need to say “here’s what I was looking for, and here’s why I was looking for it, and here’s where I looked, and here’s what I got, and here’s what’s in my cache, and here’s the problem, and here’s what you can do once you’ve figured out why I got the wrong answer.” Then the user has some idea what to pursue. When they get an error like “Could not resolve dependency xyz” then guess where they end up? Posting desperately on some forum somewhere. Or Googling for that forum post.

Which brings me to today’s offender: Eclipse. Oh, Eclipse. Despite copious (even overwhelming) feedback to the user, how rarely you succeed in producing useful diagnostics. It’s bad enough when you’re installing a plugin and one of the dependencies in some repo is missing. Then you at least have a fighting chance of realizing that it was a dependency and who might be to blame. But Eclipse also validates XML against the stated DTD, and guess what? That’s an external dependency. And guess what happens when something goes wrong with that dependency?

Evidently Eclipse caches the broken DTD and refers to that to declare your XML invalid with the useful error message: Referenced file contains errors (http://tuckey.org/res/dtds/urlrewrite3.0.dtd). For more information, right click on the message in the Problems View and select "Show Details..."

Now that I look at the error, it’s actually better than I first read. It does blame the DTD, and it does say where it got it. At first I read this more like “Your file has errors.” (Helpful! Also what someone would see if they didn’t know what a DTD was for.) OK. Once I downloaded that file myself, I could see that it was broken. Actually tuckey.org seems to be sporadically serving that file wrong.The second time I downloaded it, it was fine. That’s going to happen, though, see? That’s sabotage. The really broken part here was that Eclipse actually cached that broken DTD after downloading it. You’d think that having detected it was broken, it might retry the download each time a validation was needed. It might provide you a mechanism to request a new download. It might actually inform you that the file is cached, for those of us not familiar with Eclipse internals.

A helpful error message would have been something like: “Eclipse tried to validate this XML file’s schema with the DTD downloaded from http://tuckey.org/res/dtds/urlrewrite3.0.dtd (as specified in the file) and cached at the location /some/path/urlrewrite3.0.dtd. This DTD file has errors; please check the DTD URL specified and the cached file to determine the source of the errors. To clear the cache and try the same URL again, (follow these instructions).”

things are looking up

Creating menus in XML was pretty easy. Now looking for how to use the stock icons – in code you can refer to them as android.R.drawable.ic_menu_* but I’m not sure how to specify this in the XML and docs aren’t being helpful. Trial and error determines that an icon like “@android:drawable/ic_menu_add” will succeed (at least in this case the builder helpfully tells me when I have it wrong). The available icons can be found by having Eclipse autocomplete android.R.drawable.<Ctrl-Space> or by opening up the R class in the JAR and looking through the definitions.

Actually got WhenDidI app reasonably wired up. Creating a new item on the list works (still need to do this when they press the back button, and store members when activity is paused) and has a working layout. Created a list editor that shows list of lists. Created a row layout for the main screen that is what I want. Menus have icons and send the user to the right place if possible. Feels like I did a lot.