Tuesday, 19 May 2009

DbUnit and nullable columns

We use DbUnit for our database integration tests and this works very well allowing us to populate the database with test data specific for the test at hand.

I have had a problem for the last few hours that has driven me to distraction. I was populating a table with a row and the tests using this data were all OK.

I then added an extra row that also wanted to populate an extra nullable column. The test failed because the test thought this column was null. I stopped the test in the debugger and yes the code was correct, the column was null. What could be wrong ?

My DbUnit XML looked like this:
<dataset>
<MY_TABLE
ID="1"
MANDATORY_COL="This column must have data"
/>

<MY_TABLE
ID="2"
MANDATORY_COL="This column must have data"
NULLABLE_COL="This column is nullable"
/>
</dataset>


The problem appears to be that DbUnit builds its list of columns from the first occurrance of each table. Any optional columns listed in subsequent entries are simply ignored.

There are two solutions. Either reverse the order of the two items in the XML file, or set the column to null in the rows where the nullable column is not required.

Friday, 15 May 2009

TDD Testing of Dependancy Injection in Spring

Spring relies very heavily on dependancy injection and when writing integration tests the first thing that must work before you even try to connect to things like your database is that all your beans must be correctly injected.

So before I get all excited and start writing tests that read or write to the database I write a very simple test to check that everything has been injected correctly.

public class FooServiceIntegrationTest extends BaseIntegrationTester{
private FooService fooService;

public void setFooService(BulkUploadService aFooService){
fooService = aFooService;
}

public void testInjection() throws Exception{
assertNotNull("FooService not injected", fooService);
}
}

Strictly speaking this test testInjection is not needed at this stage because the test will fail if the injection of this primary bean fails.

Ok so I need to create the bean.

<bean id="fooService" name="fooService" class="uk.co.foo.FooServiceImpl">
</bean>

The test will now pass.

The test now gets more useful as I now extend the test to see if FooService has its beans injected successfully.

public class FooServiceIntegrationTest extends BaseIntegrationTester{
private FooService fooService;

public void setFooService(BulkUploadService aFooService){
fooService = aFooService;
}

public void testInjection() throws Exception{
assertNotNull("FooService not injected", fooService);
assertNotNull("FooService not injected", fooService.getBarDao());
}
}

Now this will not compile at first as fooService.getBarDao() does not exist.
I add this to the interface and implement the method and re-run the test,

The test fails as we have not set the property on the bean so lets do that.

<bean id="fooService" name="fooService" class="uk.co.foo.FooServiceImpl">
<property name="barDao" ref="barDao" />
</bean>

Assuming barDao has also been configured then the test will now pass.

Possibly others do this, I do not know but I have found this little test invaluable as a precursor to grander integration tests later on.

BTW BaseIntegration tester does little more than extend AbstractTransactionalDataSourceSpringContextTests and implement the method getConfigLocations()

Thursday, 14 May 2009

Eclipse Hot Keys and the language bar on Windows

I like to use Eclipse Hot Keys and two of my favourites are Ctrl+Shift+R (open a resource) and the very similar Ctrl+Shift+T.

Sometimes when in eclipse I would do something and suddenly find the double quote and '@' keys (among others) had swopped.

I sussed out that somehow I was changing my keyboard settings from English UK to English US. I left it at that now I knew I could fix it.

Today I sussed out why and how to stop it happening again.

The hot keys to change the language is Ctrl+Shift and I must have been missing off the R or T.

So assuming you do not want to change the keyboard from one to the other at all or not too often you have two options:
a) disable the hot keys
b) remove the language you do not want.

To do this go to: Contol Panel->Regional & Language options->Languages->Details.

If you want to disable the hot keys select Key Settings->'Change Key Sequence'.
If you want to remove one of the languages, select one and then select 'remove'

Thursday, 9 April 2009

Spring User Group in the North West

Last night was the inaugrial North West Spring User Group.

There were two speakers, Jan Machacek of Cake Solutions and a joint author of Pro Spring 2.5 and Rob Harrop from SpringSource and also joint author with Jan on the original 'Pro Spring' book

Jan gave an excellent worked example of a small web application using Spring 3.0 and Rob also ran a worked example on REST development in Spring. Rob's talk was particularly interesting and brave in that he was willing to show the REST development at the cutting edge and show and admit to its weaknesses with it being only at milestone release.

There will be future meetings and you can follow them at the Linkedin User group

Tuesday, 24 March 2009

KeePass - Secure password and data storage

For a while I have wanted some form of secure password and data storage and I came across KeePass.

This tool appears to do everything I want.

I can run it standalone from a USB device without installing any software or registry changes on the PC.

I can store passwords as well as custom information.

There is a wealth of plugins for things like backups and browser integration.

And its free.

Tuesday, 17 March 2009

org.hibernate.DuplicateMappingException and tomcat

There are probably many reasons why you might get a DuplicateMappingException from an application using hibernate. Not least because you have a mapping defined twice.

However I have just found this reason and it is new to me.

In the tomcat logs I found this:
Caused by: org.hibernate.DuplicateMappingException: Duplicate class/entity mapping uk.co.formfill.dfcommon.domain.dfwv.Action
at org.hibernate.cfg.Mappings.addClass(Mappings.java:118)
at org.hibernate.cfg.HbmBinder.bindRoot(HbmBinder.java:154)
at org.hibernate.cfg.Configuration.add(Configuration.java:386)
at org.hibernate.cfg.Configuration.addInputStream(Configuration.java:427)
at org.hibernate.cfg.Configuration.addFile(Configuration.java:267)

Looking further up the tomcat logs to just before the first Exception stack trace there was this:
17-03-2009 10:44:22 [Thread-1] INFO  - Reading mappings from file: D:\apache-tomcat-6.0.14\work\Catalina\localhost\dfweb\loader\uk\co\formfill\dfcommon\hibernate\mappings\dfwv\actions.hbm.xml
17-03-2009 10:44:22 [Thread-1] INFO - duplicate import: uk.co.formfill.dfcommon.domain.dfwv.Action->uk.co.formfill.dfcommon.domain.dfwv.Action
17-03-2009 10:44:22 [Thread-1] INFO - duplicate import: uk.co.formfill.dfcommon.domain.dfwv.Action->Action
17-03-2009 10:44:22 [Thread-1] INFO - Mapping class: uk.co.formfill.dfcommon.domain.dfwv.Action -> ACTIONS

So I looked in D:\apache-tomcat-6.0.14\work\Catalina\localhost\dfweb and that was empty. Strange.

The same war worked fine on a different installation and the cause was in the tomcat configuration.

The offending line was in tomcat's context.xml with the problem being the overriding of the antiJARLocking property which had been done beacuse of some historical apps..
<Context antiJARLocking="true">

Removing this and all is fine. Looking at the tomcat documentation I can not see why this problem might occurr but hey ho, it is fixed.

Thursday, 26 February 2009

Pretty printing Java classpaths using Ant's pathconvert task

This is a blatent reproduction from a friend of mines blog Andrew Beacock for two reasons.

1. I can never find it.
2. A kind sole by the name of Remke provided a very nice enhancement using a macro

Here is the echopath macro


<!-- = = = = = = = = = = = = = = = = =
macrodef: echopath
= = = = = = = = = = = = = = = = = -->
<macrodef name="echopath">
<attribute name="pathid" />
<sequential>
<property name="line.pathprefix" value="| |-- " />
<!-- get given path in a printable form -->
<pathconvert pathsep="${line.separator}${line.pathprefix}"
property="echo.@{pathid}" refid="@{pathid}">
</pathconvert>
<echo>
Path @{pathid}
${line.pathprefix}${echo.@{pathid}}
</echo>
</sequential>
</macrodef>


Call the macro like this:
<path id="quick_test_classpath">
<path refid="test.classpath" />
<pathelement location="${instrumented.classes.dir.dev}"/>
<pathelement location ="${classes.dir.dev}" />
<pathelement location ="${test.config.dir.dev}" />
<pathelement location ="${dfcommon.dir.dev}" />
</path>

<target name="display_my_classpath" >
<echopath pathid="quick_test_classpath"/>
</target>


This will produce some output like:
[echo]
[echo] Path quick_test_classpath
[echo] | |-- C:\projects\foo\bar\test\lib\ant-junit.jar
[echo] | |-- C:\projects\foo\bar\test\lib\dbunit-2.3.0.jar
[echo] | |-- C:\projects\foo\bar\WebRoot\WEB-INF\lib\commons-beanutils.jar
[echo] | |-- C:\projects\foo\bar\WebRoot\WEB-INF\lib\commons-codec-1.3.jar
[echo] | |-- C:\projects\foo\bar\WebRoot\WEB-INF\lib\commons-collections-3.2.1.jar
[echo] | |-- C:\projects\foo\bar\WebRoot\WEB-INF\lib\commons-dbcp-1.2.1.jar
[echo]


Andrew's original bog post can be found here