Wednesday 12 August 2009

Cannot call an overloaded constructor (in a Java class) from Groovy (1.6.3)

So I have a Java class with two constructors. If I "call" one of them from Groovy, the code compiles but the constructor is never called. Nice.

Thursday 6 August 2009

Hibernate - could be a bit brighter

I love Hibernate - I think it is great. I have seen, and made some hideous applications with Hibernate that run like a dog. With three legs. Two of which are broken, but in pretty much every case, the inefficiency has been down to the use of Hibernate, rather than Hibernate itself. I have no time for people who bash Hibernate because "it is slow". It isn't. It is a tool which needs to be used properly. Almost all the projects I have worked on that have used Hibernate have also included custom JDBC. Anyway, just occasionally, Hibernate wants to make me rip my hair out in frustration. The latest example... I issue the following hql:
select session.id from Session session where session.mask is null or session.mask.id=8013
and I get back no results. Strange, I look in the DB and there are plenty of Sessions with null masks. Hibernate generates the following SQL:
  select
      session0_.id as col_0_0_
 from
      t_session session0_,
      t_mask mask2_
  where
     session0_.mask_id=mask2_.id
      and (
          session0_.mask_id is null
          or mask2_.stream_id=8013
      )
  order by
      session0_.start_date
1 prize for spotting the *stupid stupid stupid* assumption that hibernate made. The solution is to issue the following hql:
select session.id from Session session left outer join session.mask sessionMask where sessionMask is null or sessionMask.id=8013
which issues:
  select
      session0_.id as col_0_0_
  from
      t_session session0_
  left outer join
      t_mask mask1_
          on session0_.mask_id=mask1_.id,
      t_resource resource2_
  where
          mask1_.id is null
          or mask1_.stream_id=8013
  order by
      session0_.start_date
I am sure the manual warns you about this, but really. Hibernate, come on.

Thursday 11 June 2009

Apple/itunes/iphone - fantastic when it works, horrific when it doesn't

Update: DO NOT DO THIS! This process kept the photos, but lost the music :(

My wife's laptop crashed so we found a spare computer for her. Being the optimistic sort I installed itunes and plugged in her iphone thinking "it will just copy the music/photo collection from the iphone". Does it my rear end!

I cannot believe Apple make it so hard, Apple make it impossible - there is just no way to update your computer from your iphone. Syncing offers to wipe out your iphone! How hard can it be! I am just speechless.

At least there is no way to do it *officially*.

Long story short you need to:

- use itunes to backup the iphone (it will do this even if you haven't synced it - right click on the phone under devices and choose "Back Up") - jailbreak your iphone (which luckily I had done on a previous iphone) - install ftp - copy all the data manually onto the new computer - sync

Lame lame lame.

And yes, jailbreaking does prevent the iphone being upgraded to v3.0 when it rolls out, but I don't really care because co-incidentally a shiny new one will be arriving tomorrow courtesy of the fact it was dropped last week and the 7 or 8£ a month I pay to o2 insurance :)

Wednesday 10 June 2009

NO! O2 - I (might) hate you!

I love the iphone.  Yeah, I know, sad but true.  I purchased the first generation, and then the iphone3g when it came.  I also bought one for my wife.

I didn't mind paying the mega bucks as I knew that early adopters usually got the chance to upgrade to the next gen.  Not so with the iphone 3G S it appears, at least not according to <a href="http://www.phonesreview.co.uk/2009/06/09/o2-customers-furious-at-iphone-3g-s-upgrade-costs/">this link</a>.

Really?  Are O2 that short sighted - I won't be upgrading on principal (I don't really need the new model, just the new OS), so what incentive is there for me to spend mega bucks? 

O2 really need to understand that people like me don't mind spending money, we do mind not feeling special.  I just want to know that I am getting some sort of loyalty discount.

The <a href="http://shop.o2.co.uk/update/paymonth.html">pay monthly cost</a> has also increased - I pay ~£35/month and didn't pay for my handset, now for the same monthly cost I will need to spend an extra £184.98!!!  OK, the disk space has doubled, but I don't need any more disk space!

Sigh.

When the iphone came out it was exciting for two reasons:

 - it was a fantastic piece of kit in itself (both the hardware and OS).  It was a paradigm shift from a phone with a few extra apps to a mini computer with a phone
 - it set a new level for the competition

I would hope the competition has had time to react and respond with alternatives.  Maybe I will start checking them out.

Monday 8 June 2009

Apache Tomcat service fails if running on a 64bit JVM

Our deployment platform is Windows 200x, 64 bit. Don't ask why - I too am a Linux fan boy. Anyway, installing tomcat as a service works, but trying to start said service fails. Turns out that unless you want to jump through a few hoops you need to install the 32bit JDK. (don't forget to update the windows environment variable and then open a new console to pick up the new environment variable ;))

Wednesday 27 May 2009

Javascript plus and minus operator gotchas

So I am using the joy that is jquery to ajaxify our web application, and we have a calendar component.

The component has a "next" and "previous" which lets you move between weeks. So I had the following code:
/**
 * Calendar functions
 */
function addEventHandlersToCalendarComponent() {
    $('#previousWeekButton').click(function() {
        $("#calendarViewInMs").val($('#calendarViewInMs').val() - MILLISECONDS_IN_A_WEEK);
        refreshCalendar();
        return false;
    });

    $('#nextWeekButton').click(function() {
       $("#calendarViewInMs").val($('#calendarViewInMs').val() + MILLISECONDS_IN_A_WEEK);

        refreshCalendar();
        return false;
    });

    $('#calendarDateGoButton').click(function() {
        refreshCalendar();
        return false;
    });
}
The previous week worked perfectly, but clicking the next week broke with the server saying it couldn't parse the number.

Hmm.

After thinking about, and seeing the actual value being sent to the server, it was obvious: "-" operators convert both operands into a number, the "+" operator however, does no such goodness, it simple does a string concatenation. The solution was simple, to use the parseInt to coerce the result of the "val()" method into an actual int.

Friday 15 May 2009

Importing data from SQLServer 2005 into SQLServer 2000

We found ourselves in the less than ideal situation of developing against a database with a different version than the production one; we were developing against SQLServer 2005 but it was going to be deployed on SQLServer 2000.

I think this is a big no-no; the closer your development environment, the more valuable it is.

So anyways, we ended up having almost a fairly large (500+MB) SQLServer 2005 which we needed to get into SQLServer 2000 SP4. Restoring the backup didn't work, which isn't too much of a suprise. I certainly wasn't going to export each table into CSV and import it individually!

Google to the rescue. Google came up with this article which worked a treat.

I ended up creating the single SQL file which came out at 1.6GB, then compressed it down to a much more manageable 60MB, moved it across the world to the remote machine and hey bisto - it worked.

Thursday 14 May 2009

FreeMarker an iterating a map

We use FreeMarker to render our views in our web tier. It is a really powerful, fairly extensible (would love to easily add/override builtins!!!), but there are a couple of pain points.

The first is iterating maps. Without going into too much detail, you may expect to be able to do the following:
<#list map as entry>
  Hi there ${entry.key}, this is your value ${entry.value}
</#list>
but you can't.

Neither can you do:
<#list map.entrySet() as entry>
  ...
</#list>


Neither can you do:
<#list map.keySet() as key>
  ${map[key]} or ${map.key} or ${map.(key)} or ${map.[key]}
</#list>

Instead, you need to do the following:

Neither can you do:
<#list map?keys as key>
  ${map.values[key_index]}
</#list>
Nice.

Yeah.
Our latest web application can run in an environment that allows javascript, which means we can make our application much more dynamic.

Our UI consultant decided to use JSON and build up the UI dynamically. Other than the initial html page, the server doesn't return any other HTML.

This has a number of pros and cons, which I will blog about at a later date, but for now, it is off to learn the magic that is jQuery. This is almost certainly going to remind me once more why I always define myself as a "server side web developer" ;)

Groovy bug in 1.6.2 - Spring Transactions are ignored when called from groovy code

http://jira.codehaus.org/browse/GROOVY-3480
My colleague Rich Evans noticed this one. He noticed that our Spring transactional annotations were being ignored if the code invoking the proxy was groovy. Assume we have the following:
public interface MyService {
    boolean isThisWithinATransaction();
}

public final class DefaultMyService implements MyService {
    @Transactional
    public boolean isThisWithinATransaction();
         return TransactionAspectSupport.currentTransactionInfo().hasTransaction()
    }
}
If we dependency inject that service into a groovy class (using groovy 1.6.2) then the method returns false, if it dependency inject it into a Java class, then it returns true.

Note: the actual bug is not specific to Spring's Transactional annotations - it is broader than that - Spring AOP proxies just don't work as expected in groovy 1.6.2. Given how much Spring uses proxies, this is pretty painful!

I am not entirely sure what is involved in this issue - something to do with the fact that the method that the Spring proxy invokes doesn't have the Spring Transaction annotation on it, as it is actually one of Groovy's dispatching methods that gets called. The transactional interceptor is still in the call chain, as the decision to whether the method *could* be transactional is done from static analysis, the problem only exhibits itself during runtime.

I keep meaning to blog about my lessons learnt regarding testing strategies. One of those lessons is the further away your code is from the production environment, the less valuable those tests are. We were hit by this. All our production code (Controllers and services etc.) are written in groovy, but our tests are written using Java. This meant our integration tests passed but our production code failed.

Nothing beats those system level, black box tests. We use selenium for this, but just haven't got there yet.

Saturday 9 May 2009

Two good discussion tools

Nice article: two good discussion tools

I have an ongoing dilema on how to facilitate good discussion. I am opinionated and to the point, but I am also open to discussion. I have no issue stating a fact and being proven wrong. Within the right context, this can lead to some excellent discussions, but I can also feel like a great big hammer crushing other people and their opinions. Which I hate, and never, ever intend.

I am very luck to work along side two other colleagues who are like minded, but rather more polished and refined than me (they know words like Oort and latin and everything ;)).

Anyway, the above article has two simple, and I think very effective tools that I will start adopting.

Hopefully this will be an end to my wife's (who I love dearly) "It isn't what you say, it is the way that you say it" record. If they could manage to use the material that record is made of in engineering, things would last for ever - I know that particular record has ;) :)

Friday 8 May 2009

Leopard TimeMachine saved my bacon

Had to hard boot my leopard MacBook Pro 17".  When it came back, everything was wrong - loads of corrupted files etc.

Time for reboot I thought - I had everything backed up using Time Machine and spideroak.  Or so I thought :)

So an hour (ish) later I had a fresh virgin installation.  I could have chosen to restore from Time Machine during the update, but I wanted a bit more control (:)) than that, so I didn't.

I created the exact same username/password (not sure if that is relevant), and logged in.  Clicked on the Time Machine icon and there it was - a beauty to behold - restoring was slightly unintuitive - I expected to be able to right click and restore, but no, I needed to select the ones and then click the Restore icon.

So, no more than 3 hours and I am back up and running.

(yeah yeah, I know, if I had done an entire system image it would have been even quicker).

Didn't have to use spideroak this time, but I will be using it to synchronise mine, and my wife's photo galleries.  Rock on.

Logback defaults to DEBUG level

In our project we are using logback for our logging. One really nice feature is that you don't need to do the whole
if (logger.isDebugEnabled()) {
  logger.debug("hi there " + person + ".");
}
You can simply do:
logger.debug("Hi there {}.", person);
A nice, and obvious use of variable argument lists (introduced in JDK 5.0). OK, arguably publicising logback is reason enough for a post, but the real reason I am posting is to point out something that might catch other developers who don't have time to read the entire manual :) Logback has it's own configuration, but if you manage to get it wrong, and it cannot find that configuration it uses it's own default. This default configuration (from the manual):
is hardwired to attaching a ConsoleAppender to the root logger. The output is formatted using a PatternLayout set to the pattern %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n. Moreover, by default the root logger is assigned to the DEBUG level.
So, if you start using it and wonder why you get a whole load of debug, now you know. In fact, you know at least two things:
  1. Logback isn't picking up your configuration (which you might not have)
  2. You need to read the manual, in particular the section on configuration
Go on, be honest, how many people are going to simply read the configuration section and skip the rest, or even better - how many are going to google-paste (google for a configuration and copy and paste it into your own code :)). You know who you are!

ScribeFire and Blogspot and Token Invalid 401

This is my first post from scribefire, which seems to work quite nicely.

To get it to work, I did the following:

  • Install the firefox plugin 
  • Start it up (I configure it to open in a new window)
  • Click on the "Blogs" tab at the top right
  • Click on the Wizard button
  • Enter the URL (colin.yates.blogspot.com)
  • Click Next
  • Enter my username/password (username is your full gmail email account!)
  • Click Next
and that was it!

Do note, however, sometimes it didn't recognise the blogging platform and asked me to choose one.  Unfortunately, blogger wasn't in the drop down, so I cancelled and restarted the wizard.  It took maybe 3 or 4 attempts before it work.  Now it works fantastically - must do, otherwise you wouldn't be reading this.

Thursday 7 May 2009

Convenient directive for iterating lists in freemarker

We are seeing the same pattern of iterating lists within freemarker appearing:
<#list items as item>
  <#if item_has_next>,</#if>
<#list>

this is quite verbose, and error prone so I have added a new directive called 'iterate', which automatically appends a separator (default is comma) if required.
<@iterate items ; item>
  whatever I want to do with the ${item}.
<@iterate>

The directive:
<#macro iterate items separator=','>
<#list items as item>
  <#nested item/>
  <#if item_has_next>${separator}<!--#if-->
<#list>
<#macro>

To use, this you need to put it into a file (i.e. mystuff.ftl) and then include it within all the templates from which you want to use the new directive (i.e. all of them ;)).
My freemarker fu sucks a bit at this point. We have a web app so I included it in /WEB-INF/views/includes/mystuff.ftl (of course I didn't call it that!). Unfortunately I needed to specify the relative path as I couldn't figure out the fully qualified one - /WEB-INF/views/includes/mystuff.ftl and /views/includes/mystuff.ftl don't work.
So, if my template is /WEB-INF/views/people/list.ftl then I need to do the following:
<#include ../includes/mystuff.ftl>

<@iterate people ; person> Person ${person_index}: ${person.name} <@iterate>

We are using Spring to configure Freemarker, which means using FreeMarkerConfigurer. Unfortunately, I don't think this supports the ability to specify automatic includes (similar to JSP preludes and codas), so I might need to write my own. No biggies.
Hi, world,

My name is Colin Yates and I am a Software Engineer. I am primarily interested in doing software engineering better. Why do we have such a dismal success rate. Successes are more often than not accidents, or at least unexpected ;) Why is that? Why is software so hard to do well? Technologies/processes I am interested in: spring, gradle, groovy, pragmatic development, testing and so on.

This blog will be a dumping ground for pretty much anything I think about that might be worth sharing. Or not.

One warning - I sometimes talk utter tosh, but just occasionally there are little nuggets in there as well. Good luck finding them! To be fair, I will try and separate my posts with a consistent set of tags.