Wednesday, April 28, 2010

Guicing your jars

Through the magic of ServiceLoader you can automate the wiring of your classpath components:

public static void main(final String... args) {
    final Injector injector = Guice.createInjector(
            ServiceLoader.load(Module.class).iterator());
    // Use injector here, etc.
}

For each jar or classpath component, include a META-INF/services/com.google.inject.Module file containing the class name of a Guice module which can configure the jar, e.g., hm.binkley.rice.MobModule.

This makes your jars auto-configuring. Merely including them in the classpath is sufficient to be injected into your application. You will find multibindings useful for each jar to provide a well-known list of services without them colliding.

Monday, April 26, 2010

Raw types make my head hurt

This compiles:

public static void main(final String... args) {
    final Fred fred = new Fred();
    final Integer i = fred.get(Integer.class);
}

public interface Bob {
    <T> T get(final Class<T> type);
}

public static class Fred implements Bob {
    @Override
    public <T> T get(final Class<T> type) {
        return type.cast(null);
    }
}

This does not:

public static void main(final String... args) {
    final Fred fred = new Fred();
    final Integer i = fred.get(Integer.class);
}

public interface Bob {
    <T> T get(final Class<T> type);
}

public static class Fred<Q> implements Bob {
    @Override
    public <T> T get(final Class<T> type) {
        return type.cast(null);
    }
}

But this does:

public static void main(final String... args) {
    final Fred<?> fred = new Fred();
    final Integer i = fred.get(Integer.class);
}

public interface Bob {
    <T> T get(final Class<T> type);
}

public static class Fred<Q> implements Bob {
    @Override
    public <T> T get(final Class<T> type) {
        return type.cast(null);
    }
}

And this does:

public static void main(final String... args) {
    final Fred fred = new Fred();
    final Integer i = ((Bob) fred).get(Integer.class);
}

public interface Bob {
    <T> T get(final Class<T> type);
}

public static class Fred<Q> implements Bob {
    @Override
    public <T> T get(final Class<T> type) {
        return type.cast(null);
    }
}

What is going on here?

UPDATE: Thanks to Bob Lee in the comments, I see what is going on. Using a class-level raw type results in the methods of that class also being treated as raw types, even though the type parameters of the class and method are separate. (NB — this does not apply to static methods, only instance methods.)

Thursday, April 01, 2010

readlink for better scripting

Fritz Thomas solves a common shell scripting problem for me: finding where your script lives. This script saved as ~/bin/x:

#!/bin/bash
echo "$0"
readlink -f "$0"

With ~/bin in PATH produces:

$ cd ~/bin; ./x
./x
/home/where/the/heart/is/bin/x
$ cd; x
/home/where/the/heart/is/bin/x
/home/where/the/heart/is/bin/x

Just what I need! (Yes, quite an odd home directory.)

Do note the caveats for readlink(1).