Thursday, July 22, 2010

Injecting enums with the Spring Framework

Today I needed to inject an Enum into a bean's constructor using Spring.

First I thought I'd need to write my own FactoryBean or 'better' a PropertyEditor.

Well no need, it is already nicely handled by the framework. After a bit of googling, I found the documentation in Appendix A of Spring's reference

And here is what actually works just fine. If I have the following enum:

public enum Language {
 EN, FR
}

And the following class that I need to instantiate with Spring:

public class LocalisedLogger {
 private final Language lang;
 public LocalisedLogger(Language lang) {
   this.lang = lang;
 }
}

Then I can just configure it like this:

<beans>
 <bean id="logger" class="org.leberrigaud.example.LocalisedLogger">
   <constructor-arg value="FR">
 </constructor-arg>
</bean>
</beans>

That'it! Spring does the rest…

Wednesday, July 21, 2010

Java versions on Snow Leopard

It seems I have a few issues with java and versionning theses days. This time I got bitten by Java's version on Snow Leopard. Indeed whatever version you think you're using it is Java 1.6!

What got me is the JDBC api and namely the new java.sql.Wrapper interface added in 1.6. Thank god for build boxes (running Linux ;-))

I now remember that I had to install manually Java 1.5 on my work machine, when I was in Sydney. I am now working on my laptop and forgot to do that. I couldn't remember the exact procedure but someone wrote it for me. Thanks to Ted Wise!

Tuesday, July 20, 2010

Java major.minor version

You're bound to see those errors at some point if you're a java developer, something that says Unsupported major.minor version 49.0, or similar.

I always forget which number corresponds to which version of Java, so there it is:

JDK 1.4
48.0
JDK 1.5
49.0
JDK 1.6
50.0

Monday, July 12, 2010

Initialising a git-svn repo from a given date

The issue is that git-svn only lets you specify a revision number from which to init a repository. So first you have to find out the revision number at which your repository was at a given date.

You need to use SVN for that, and it's log command:

svn log -r {2009-12-31}:{2010-01-01} http://svn.example.com/repo/trunk

This command will log all svn commits which happened between the 31st of December 2009 and the following day, 1st of January 2010.

Then from the logs just pick the commit from which you want to init your git-svn repository and there you go:

git svn clone -s -r72569:HEAD http://svn.example.com/repo/

Here the chosen revision is r72569

Monday, June 28, 2010

Using Git with SVN repositories

I've been using Git with SVN repositories for a while now. And for the most part it's good, really good.

If you want an introduction on where to start I suggest you read Emmanuel Bernard's entry on this exact topic. It's simple, to the point and will get you started in no time.

Today though I got bitten by some rather strange 'bug' of Git SVN. My master branch wasn't linked to remotes/trunk as I always expect. Apparently the branch that was last commited to (in SVN) is the one that gets linked to master.

Thankfully there is nothing that a quick Google search can't fix. And I found that one just has to issue the following command to fix that:

git reset --hard remotes/trunk

Thanks to Horst Gutmann for posting this before me.

Update:

A simple way to know what master is linked to is to issue the following command right after you cloned your SVN repository:

git svn dcommit

It will actually tell you where it is going to commit anything that should be.

Tuesday, January 26, 2010

Maven dependency heaven?

If you search Google for "maven dependency hell" you'll find many answers. It can be summarised to two types of root causes.

Transitive dependencies

The most usual one is a fact of transitive dependencies. Transitive dependencies are great but with them comes dependency resolution. Which in turns means that changing one declared dependency in your project can affect any part of your dependency tree. Most of the time this happens without the developers noticing at least until an issue comes up. This can be triggered by something as simple as changing a dependency's version.

Remote repositories

The other cause comes from a combination of inconsistent (remote) repositories and different build environments. If your different build environements, developement, continuous integration, release, talk to different repositories then you might get a different dependency tree. As a simple example, at work we have a repository where we deploy sources of libraries that don't provide them otherwise. This is great. However if someone deploys the source with a minimal POM depending on your build environment you might get the wrong POM. And this means a different dependency tree.

Continuous dependency management

I believe Continuous dependency management is the solution to this problem. Each time you build you have to know precisely what dependencies (all of them) are being used. This is why I developed the dependency tracker plugin. The existing dependency plugin offers a few goals – tree, analyze – to help with dependency management, but to me it fails short in two ways.

First it is difficult to assess what has changed from one tree to another. It is let up to the developers to do a mental diff. The dependency tracker plugin creates to this effect a text report that can and should be commited along side your project's source code. As it is a text report it is very easy to see changes between revisions using your VCS of choice or you IDE.

Second, it is a manual process. Developers have to actively use the plugin to understand and clean up their dependency tree. One idea of the dependency tracker is that it creates a text report that should commited alongside your source code. Then you can setup your project so that every build checks that its dependencies are the same as expected and fail if there is the slightest difference.

Using the plugin

The dependency tracker has three goals:

  • report
  • validate
  • checksum

The two first goals work together. I'll come back to the 'checksum' goal later. First you want to create a report. One report will be created for each module of your project in a dependencies.txt file. Its format is the following:

dependency|dependency trail|artifact checksum|pom checksum

Where dependency denotes the dependency we are talking about, the dependency trail is the information about how the dependency is reachable in the dependency tree and the checksums speak for themselves.

Then you just have to configure the plugin in your pom.xml to validate the report on each build. But don't forget to commit the report first.

<plugin>
  <groupId>com.atlassian.maven.plugins</groupId>
  <artifactId>maven-dependency-tracker-plugin</artifactId>
  <executions>
    <execution>
      <goals><goal>validate</goal></goals>
    </execution>
  </executions>
</plugin>

You're done. If any of your module's dependency changes unexpectidely, your build will fail.

The checksum is there to help calculate checksum of arbitrary files as done by the plugin in reports. Simply use that command:

mvn dependency-tracker:checksum -Dfile=/path/to/the/file

The plugin is available in Atlassian's public maven repository.

UPDATE

The source code of this plugin is now available on BitBucket at https://bitbucket.org/atlassian/maven-dependency-tracker-plugin. Feel free to fork…