Stuff that should just work…

Had one of those Maven/Eclipse experiences that was so infuriating, I need to record it here to make sure I can fix it easily next time.

Using STS 2.9.1 I created a “Dynamic Web Module” project. For the runtime I targeted tc Server / Tomcat 6. Then I proceeded to do some rudimentary JSP stuff, only to find that the JSTL taglibs were not resolving. It seems the expectation is that these would be provided by the container. Under JBoss they probably would be, but not under Tomcat. (I guess it makes sense… if you have multiple apps in the container, just let each one bundle the version desired – fewer container dependencies).

Fine; so I added the maven nature and the jstl.jar dependency. At some point I did Maven > Update project configuration. Suddenly the class that I had defined to back a form is not found. Also I’m getting this really annoying project error:

Dynamic Web Module 3.0 requires Java 1.6 or newer. [...] Maven WTP Configuration Problem
One or more constraints have not been satisfied.

WTF? Of course STS/Eclipse are configured to use Java 1.6… but my project apparently isn’t. So I go change that, but it doesn’t fix that error, and any time I update project config with Maven, it’s back to using JRE 1.5 and my Java source files are no longer on the build path as source files.

Turns out (took longer to find than to tell about it) the Maven compiler plugin doesn’t use Eclipse settings and just imposes its own defaults, i.e. Java 5, unless otherwise configured by a POM. And since a “Dynamic Web Project” uses Servlet 3.0 it requires Java 6. Boom.

Easy to fix, though annoying that I have to and there isn’t some Eclipse setting for this. Just add under the top-level POM:

<build>
    <plugins>
       <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>2.1</version>
          <configuration>
             <source>1.6</source>
             <target>1.6</target>
          </configuration>
       </plugin>
    </plugins>
 </build>

(Cripes, WordPress, can I get a “code” formatting/paste option already?? “Preformatted” most certainly isn’t.)

Then have Maven update project config again and 1.6 is in play. Oh, and instead of using the “src” directory for my source, I went ahead and changed to src/main/java as Maven expects, so that future “config update” will pick that up.

Advertisements

Checking out Hibernate with STS

I have cause to revisit my post about importing a git checkout into Eclipse. I need to take a look at the Hibernate code, which is on github at git://github.com/hibernate/hibernate-orm.git, and given the somewhat convoluted nature of this code, I need an IDE to help navigate it.

Now, I hear that with Eclipse Indigo (3.7), which is included with the latest STS 2.9 (which is what I use), the EGit plugin is included out of the box (which, for the purposes of this post, is what I’m doing – completely stock install). That’s helpful. See, previously, if you wanted to do something with git, you would find no evidence within Eclipse that it could. If you figured “there must be an extension for that” and searched for “git” from the extensions wizard, there would be no hits. Because what you needed to look for was “JGit” or “EGit” – you big dummy. An example of what I consider low discoverability that’s pervasive in Eclipse/STS. But I digress.

At least EGit has had a couple years to bake since my post. I went to File->Import->Git->Projects from Git and put in the URI above. This seems pretty straightforward:

Image

I’m not sure why it parses the URI into Host and Repository path here. Is there some reason you’d want to customize these?

In the next step, I pick the branches from the repo I want and proceed to the “local destination” dialog.

Image

These steps might be somewhat confusing to those who don’t know git and just want to take a look at some code. Since git is distributed, you don’t just get a point-in-time checkout from a repo, you get your own copy of the repo – or as much of it as you want. Basically it’s asking where I want my copy of the repository and checkout to go. The checkout (“initial branch” here) will go in the directory, and the repo will go in a .git subdirectory. “origin” is the name given to the repository I cloned this from, in case I want to sync with that later. That might be kind of obvious to someone familiar with git, but how about some tips for those who aren’t?

My question: why doesn’t this all simply default to being inside the workspace? What’s a workspace for, if not the project contents? As you can see, the default is to create a ~/git directory and checkout/clone the repo there.

Next step, three inscrutable options for how to deal with the resulting project(s) that have been checked out:

Image

OK. These seriously need some explanation. What do these do?

“Import existing projects” gets me nowhere in this case, as it requires Eclipse project descriptors to be included in the checkout, and they’re not. Arguably, they probably shouldn’t be. I just get the error “no projects found” if I try this. But that means I need to figure out myself how to get Eclipse/STS to interpret this checkout properly.

“Use the New Project wizard” is an option I don’t really understand. It just dumps you into the new project wizard you would get by clicking the new project button (generally the first button in the toolbar). This is also where you end up if you click “Finish” instead of “Next” anywhere along the way. I guess I could make use of the directory just created. I  also can’t go “back” and choose another option from here; cancel, and I’m back to square one. In general, I find the “New Project wizard” one of the most confusing things about Eclipse/STS, because there are so many options, many sounding similar yet meaning something completely different, and no explanations of what you can expect to get. Do I really have to go looking for doc that should be a click away? I digress.

“Import as general project” basically just creates a project with the given content and no organization. STS recognizes the different file types, of course, but there’s no concept of where the classpaths begin, how to build and test the project, anything like that – just plain directories with content. This won’t get me to my goal, which is to be able to look up class hierarchies, implementors of interfaces, etc. However, having done this, I can try to configure the project to get it to where STS understands these things.

I’m interested in the 3.6 branch of Hibernate, which is a Maven project (you can tell from the pom.xml – woe betide you in the Java world if you don’t recognize Maven when you see it. The “master” branch seems to be using Gradle). So I can right-click the project and Configure -> Convert to Maven Project.

By the way, let me point out something that didn’t work at all: creating a new project with the wizard “Maven -> Checkout Maven Projects from SCM”.

Image

This is apparently not aware of the EGit plugin, because there’s no SCM protocol listed here (the first box  is greyed out). If I click “Finish” here nothing happens except the dialog exits. I think it would probably work if I added a m2e SCM connector like the link suggests, but how would I know to do that?

Alright, so now I have a Maven project. Right away in the top-level pom.xml I get a “Project build error: Unresolveable build extension: Plugin org.jboss.maven.plugins:maven-jdocbook-style-plugin:2.0.0 or one of its dependencies could not be resolved: Could not find artifact org.jboss.maven.plugins:maven-jdocbook-style-plugin:jar:2.0.0 in central (http://repo1.maven.org/maven2)”. I happen to know what this is about because I know there are a bunch of JBoss dependencies not in Maven Central. How would I know that if I didn’t know? Google, I guess. Fortunately searching for that exact error message gets me right to a StackOverflow question about exactly the same thing, which someone has helpfully solved. I love SO, I just hate that it has to exist. Documentation is always about how to use something the right way, not what to do when something goes wrong. SO fills that gap.

So, add the repository information to the pom.xml – or, better, to my Maven settings.xml (which I had to create since STS is providing Maven in this setup) and on to the next problem. Two, actually (always seems to be the way of it – removing a build problem just uncovers more). These are related to “Missing artifact commons-logging”. A little Google sauce on that turns up this blog post (like the name, kinda like my blog!) about the death of the commons-logging dependency. Gotta love trying to support these old builds from a public ever-changing repo. Problem is, the Hibernate pom (actually the parent pom, which is in a subdirectory! huh?) uses the hack from that article, but the repo supplying the dummy dependencies seems to be down. So perhaps I should try the exclusions suggested by commentors in that blog? I found something that looks handy: in the pom dependency hierarchy, right-click and choose “Exclude Maven artifact”:

Image

Sadly, this doesn’t work:

Image

But here’s another StackOverflow suggestion. This seems to work, after removing the existing commons-logging dependencies and adding those ones in the parent pom, and (finally) right-clicking on the project, Maven -> Update project configuration. The errors are gone, and (I suspect) so is all the Maven-fu I can expect today.

Unfortunately I’m still not at my goal – I just have the Maven nature working now.

Turns out, this wasn’t quite the right path. What I’m looking at here are multiple Maven projects, with interdependencies. There’s no way I’m ever going to get anything useful from this in a single STS project. What I need to do is import these as multiple projects. In the meantime, delete the existing project (but leave the checkout) so it doesn’t get in the way.

So here’s what I do: File -> Import -> Existing Maven Projects and enter the path to my local checkout as the “Root Directory”:

If I select all the projects, they’ll all be created as interdependent workspace projects, each with build path and so forth configured according to Maven.

With lots of errors, of course… thousands, in fact. But let me start with the Maven problems, which are probably the source of the rest. Looks like all of the Maven errors are of the form “Plugin execution not covered by lifecycle configuration: org.jboss.maven.plugins:maven-injection-plugin:1.0.2:bytecode (execution: default, phase: compile)” – with a different plugin each time. I remember the import screen warned about some problems that would need to be resolved later – this seems to be what it was talking about.

Well, much later now, I think the Maven errors were mostly irrelevant. Those were due to the change to the m2eclipse plugin which broke the world for a lot of Maven users in Eclipse. Most of them were things that looked like it was safe to have m2eclipse “ignore” as recommended there. I went ahead and ran some of the goals that looked important (antrun:run and injection:bytecode in hibernate-entitymanager, the latter in hibernate-core) from the command line. Not sure they made much difference. I did Maven -> Update Project Configuration on everything changed and most of the red X’s went away.

I also ran into this problem and crashed a few times just by mousing over the “Window->Browser” menu before adding “-Dorg.eclipse.swt.browser.DefaultType=mozilla” to my STS.ini to avoid it.

At this point, the only problem seems to be that hibernate-entity has a ton of tests with imports like this:

import org.hibernate.ejb.metamodel.Customer_;
import org.hibernate.ejb.metamodel.Order;
import org.hibernate.ejb.metamodel.Order_;

… and then goes on to use these classes with underscores, which aren’t there. Evidently they’re supposed to be generated at some point, but I’m not sure how. I don’t really care about running these tests, just wanted to look at the framework code, so although STS reports 14382 Java problems, I can consider my work done here. Boy, that was easy!

One more note: I went back and added the git SCM connector for m2eclipse to try it out. It worked… but poorly. The way that worked was to select “git” for the scheme, then put in the git:// URI for the project, then wait for a popup to select the projects to import. If I reversed order or didn’t wait, I got either an error or nothing after hitting “Finish”. Hmm… hope that’s better in the next update. And, interestingly… the checkout/repo went into the workspace.

Trying out OrmLite by migrating LogMyLife #androiddev

In addition to ActiveAndroid I also took a look at OrmLite for Android. It’s a little larger than ActiveAndroid, but doesn’t dwarf my project like DB4O would. And the license is right for an open source dude like myself. Also it looks like it covers more functionality, also allowing you to get at the native DB connection (which doesn’t look possible with ActiveAndroid). And you aren’t required to subclass anything, though convenience base classes are provided. All good stuff.

When I tried out the demo project (which I also used in my TriDroid presentation), it looked reasonably straightforward. So just now I downloaded the JAR to take a look at what it would look like to convert LogMyLife to use OrmLite. What I didn’t notice is that the demo project is based on version 4.6, while the current version has jumped up to 4.10 a few days ago, which is apparently a significant release. I figured out things were different pretty quickly, though, because the first time I tried to annotate a DTO, the @DatabaseTable annotation couldn’t be found. I needed to download and link the ormlite-core JAR in addition to the ormlite-android JAR (which would be all that’s needed in previous releases). I suppose if I were using a maven POM to manage my build this would all be taken care of… but I haven’t gotten around to that.

I hope the docs are still reasonably accurate… I might be a little bit of a guinea pig for this release. We’ll see.

Bringing in the OrmLite helper

So I just went down a long rabbit trail about where exactly to put the OrmLite plumbing. The examples all have a helper that you have to keep track of per-Activity. But didn’t I just demonstrate for myself that an application-wide DB handle worked fine? So I’m thinking about just putting the plumbing in my Application subclass and seeing what happens. The complication seems to be multi-threading – the Google Group had a discussion pointing to this really interesting article on concurrent Sqlite access. I don’t really have multiple threads accessing the DB in LogMyLife, with the possible exception of my broadcast handlers – I’m not actually sure if they come in as a separate thread, or even a separate process, or what. That’s something for me to figure out soon. In the meantime, I guess I’ll go ahead with my scheme to try it in my Application class.

So first, I have to define a helper with callbacks for when I’m opening a connection and need to make sure the schema is in place, which needs to subclass OrmLiteSqliteOpenHelper (which subclasses the SqliteOpenHelper I’m used to) and define what to do in when the DB is being created or updated. Looks like it can also define some simple interactions for getting DAOs. This needs to be configured into the OpenHelperManager which is used to actually create my helper in context; the method of configuration is either to configure a string in my strings.xml and let magic happen behind the scenes, or to explicitly set a factory object on OHM that will return my helper. As it’s not much trouble and (I think) clearer, I do the latter.

Nuts and bolts

Soon I run into a little issue. OrmLite refers to SQLException all over the place, but it’s referring to java.sql.SQLException, generally used for JDBC, as opposed to the android.database.SQLException that’s usually used for Sqlite exceptions. It would be a nuisance just to have to be conscious of which is relevant. But the real difference is that the android.database.SQLException is a runtime exception, while java.sql.SQLException is a checked exception, so I have to deal with it somehow in any of my code that uses the DB. This forces me to re-think exception handling. Checked vs. un-checked exceptions is kind of an old argument, but I thought after all our experiences with Java the scales were starting to tip toward unchecked? As far as I know Java is the only major language using checked exceptions widely; the dynamic languages gaining popularity don’t really even have the ability to use them. So it’s kind of disheartening to see this throwback; although I imagine it arises from the JDBC nature of the rest of the OrmLite package.

Now I go to create a Dao by subclassing BaseDaoImpl, and I’m given a choice of four different constructors (but must include one). The most obvious-seeming one is evidently to be used with a DI container, so I look at the other ones. Eventually I realize that it’s probably best to use the one that’s like the generic DAO constructors, e.g. BaseDaoImpl.createDao(getConnectionSource(), Tracker.class).

While I’m working on the numerous errors Eclipse is reporting from my brutal refactoring, I realize that my BroadcastReceivers don’t have access to my Application subclass, so they have their own code for instantiating the DB connection. There’s no helper base class for them – reasonable, given they don’t really have a life-cycle. Suddenly just defining a string looks like a much nicer path for configuring the helper class.

An example query

And now I come up against one of my first query refactorings. I have a method like so in my existing domain code:

public Alert fetchNextAlert() {
 return fetchAlert(
  db_ALERT_ENABLED + " = 1 AND " + db_ALERT_SKIP_NEXT + " != 1 AND " +
  db_ALERT_NEXT_TIME + " > datetime('now', 'localtime')",
  null, null, null, db_ALERT_NEXT_TIME + " ASC", "1"
 );
}

fetchAlert takes these raw SQL constraints and turns them into a query for a single row from the Alerts table, then converts that row into an Alert DTO. It’s all fairly ugly code, to be sure. Here’s my first crack at a replacement in my OrmLite DAO:

public Alert fetchNextAlert() throws SQLException { 
 return queryForFirst(queryBuilder()
  .orderBy(C.db_ALERT_NEXT_TIME, true)
  .limit(1)
  .where().eq(C.db_ALERT_ENABLED, true)
  .and().ne(C.db_ALERT_SKIP_NEXT, true)
  .and().gt(C.db_ALERT_NEXT_TIME, new Date())
  .prepare());    
 }

Now this is reasonably clear and concise, and in line with how other ORM libraries work. But one thing troubles me: as far as I can tell, there’s no way to get raw SQL in as part of a where clause; I couldn’t duplicate the ” > datetime(‘now’, ‘localtime’)” constraint, and in my experience, when it comes to time, you want to speak the DB’s language. But perhaps I’m wrong this time – certainly the code above captures the intent. If absolutely needed, I could run a raw query to return the ID of the Alert I want, then just use standard DAO methods to turn that into an Alert DTO; two queries instead of one, though.

I have reasonably-sized swaths of code compiling at this point; time for a break.

Intercepting SimpleCursorAdapter data #androiddev

Normally when you create a SimpleCursorAdapter for a ListView, you specify a one-to-one mapping of the columns from the DB and the views where you want them to end up, and the adapter basically just does a toString() on your data and sticks it in the view.

You can, of course, modify this behavior by overriding setViewText, which lets you reformat the text or modify the view as you wish; but it doesn’t give you the DB cursor, just a String, so you can’t pull the data yourself or refer to other columns. But not to despair (or turn to the NotSoSimpleCursorAdapter)! You can modify anything you want by providing a ViewBinder to the adapter.

The main reason I’m talking about this is because I think the documentation on this is just a little vague:

An easy adapter to map columns from a cursor to TextViews or ImageViews defined in an XML file. You can specify which columns you want, which views you want to display the columns, and the XML file that defines the appearance of these views. Binding occurs in two phases. First, if a SimpleCursorAdapter.ViewBinder is available, setViewValue(android.view.View, android.database.Cursor, int) is invoked. If the returned value is true, binding has occured. If the returned value is false and the view to bind is a TextView, setViewText(TextView, String) is invoked. If the returned value is false and the view to bind is an ImageView, setViewImage(ImageView, String) is invoked. If no appropriate binding can be found, an IllegalStateException is thrown.

OK, great. This also promises that you can put any kind of data in any kind of view (not just a TextView). But I didn’t know what it meant by “if a SimpleCursorAdapter.ViewBinder is available.” Turns out it’s pretty simple:

  1. Implement the SimpleCursorAdapter.ViewBinder interface (it has only one method, setViewValue, which gives you the Cursor and the view to work with – and just return false to let the adapter’s default behavior handle the binding). I did this for LogCursorAdapter in an inner class.
  2. Instantiate your implementation and use setViewBinder on your SimpleCursorAdapter instance to set it up as the binder. This makes it “available” for the process described above.

This is arguably better than overriding setViewText because you wouldn’t even have to subclass the adapter to do it – or even create a class (it could be an anonymous implementation). And of course you can access all of the cursor columns in any way you please. Nice.

As far as my earlier data retrieval woes, this gave me the ability to pull data out the way I wanted. Sqlite seems to be storing plenty of precision in the NUMERIC column type; it was just a matter of it being retrieved as a String that caused truncation of precision. In this case the solution was just to pull it out as a Long or Double as appropriate and format it myself (I also learned about DecimalFormat which was very helpful).

It’s not the errors that make me scream about Java/Maven/Spring/Eclipse

What really gets me is that I always seem to come up against ones that are not only inscrutable, but seem to be unique to me. Google brings up nothing, or brings up only irrelevant results from five years ago and a different context. Here’s my latest. In a Spring configuration file, I have:

<jdbc:embedded-database id="dataSource">
    <jdbc:script location="classpath:rewards/testdb/schema.sql"/>
    <jdbc:script location="classpath:rewards/testdb/test-data.sql"/>
 </jdbc:embedded-database>

This gets me an error in Eclipse (STS actually): “No constructor with 1 argument defined in class ‘org.springframework.jdbc.config.SortedResourcesFactoryBean'”

Huh?

Google’s not helpful. Looking at the source of SortedResourcesFactoryBean doesn’t display any evident source for the problem. Guess I’ll ask on the Spring forum and see if I can find out anything. For all I know it’s an STS bug with 2.5.1; this exact same code and setup worked before, in an earlier version of STS. But it’s probably something related to the environment, perhaps the JARs I happen to have available via Maven.

Import/Export for LogMyLife #androiddev

Over the past few nights I whipped out an import/export capability for LogMyLife. Right now all it does is basically package up the database and a version file; later I expect I’ll include saving properties, which is why I’m including format version in the archive (I thought that was good foresight, as who knows what else might change). I wrapped it up in an activity you can call from the menu of the Main activity.

The implementation is reasonably straightforward, although I didn’t know a thing about handling files from Java. It’s predictably verbose but not too outrageous. I got a lot of help from this StackOverflow entry and this sun.com article. If you’re thinking of doing this you might check out how I did it for inspiration. I’d certainly encourage everyone to provide this capability so users can back up and transfer their app data!

I faced an odd little problem on importing: of course, it replaces the app’s DB. When I returned to the main activity, I returned a result code indicating this had happened, and had it close the database handle and reinitialize the components that displayed information from the database. But something seemed to be holding on to a database cursor and requerying it, and I couldn’t quite figure out why that was happening. Eventually I decided it would probably be simplest if I just have the activity restart itself from scratch. An answer on StackOverflow helped with how to do that – it’s not totally obvious; basically, just finish() the activity, and then (before exiting the same method) start it again.

Gingerbread is out, woo! And the Nexus S is coming; but I want a phone with a keyboard, dammit. Once my Nexus One gets 2.3 I’ll likely try to sell it in favor of the G2. Even though tethering is extra, which is wrong and bad and to be vehemently discouraged, but I don’t use tethering anyway.

Exploring ApiDemos; misc Android

Android 1.5 is down below 8% market share. If my wife’s Cliq ever gets an upgrade I’m dropping that platform like a hot potato. What’s interesting is that Eclair is actually still more common than Froyo (40%) – you’d think if they’ve done the work to get the device to 2.1, and seen how quickly versions change, it shouldn’t be too big a step to 2.2. Oh well.

I’ve been looking through ApiDemos to learn. While most of the demo classes seem well-commented, amusingly the ApiDemos.java file itself is not, and it does some non-obvious things involving searching the package manager for intents to dynamically create the lists being browsed. The upshot is it’s less than obvious how to find the sample code that matches the sample functionality you browse to – nothing tells you how to make the mapping, and it’s not always obvious. The actual mapping is between the label listed in the AndroidManifest.xml file for the activity (which is what you see in the app’s list browser, except that in many cases the actual text is in the strings.xml file) and the class name listed with it, e.g.:

<activity android:name=".view.Tabs1" android:label="Views/Tabs/Content By Id">

I would argue that the mapping between what you see (Views/Tabs/Content By Id – which again is often in strings.xml for no good reason I can see) and the class (com.example.android.apis.view.Tabs1) is far from obvious. Call me crazy, I think a README or at least a couple lines of comments in the main class would be in order. I should submit a patch.

Found a little nugget in ApiDemosApplication.java (which is otherwise empty):

PreferenceManager.setDefaultValues(this, R.xml.default_values, false);

This is a one-time setting of default prefs. Now of course, default_values.xml couldn’t be something simple like key-value pairs. It’s a PreferenceScreen like you would use for defining a PreferenceActivity. You wouldn’t know about those from the dev guide, unless you like decyphering reference docs. But as it happens I learned about these at some point and created a prefs screen with them in LogMyLife… which currently has no effect, so I need to do something about that.

I finally got around to gathering sources for the 2.2 platform to attach in Eclipse. I’ll have to update my article one of these days. Aside from the new sources, I should include the Apache license files in order to be proper.

I’m looking at migrating this blog to Blogspot. WordPress has neat themes but it deliberately blocks integration with tools like Adsense and Google Analytics. Also this editor drives me nuts. We’ll see.