Home > potd > POTD: bridge method injector

POTD: bridge method injector

August 7th, 2010

I was working on Hudson yesterday which led me to develop this little tool called Bridge method injector.

When you are writing a library, there are various restrictions about the kind of changes you can make, in order to maintain binary compatibility.

One such restriction is an inability to restrict the return type. Say in v1 of your library you had the following code:

public Foo getFoo() {
    return new Foo();
}

In v2, say if you introduce a subtype of called FooSubType, and you want to change the getFoo method to return FooSubType.

public FooSubType getFoo() {
    return new FooSubType();
}

But if you do this, you break the binary compatibility. The clients need to be recompiled to be able to work with the new signature. This is where this bridge method injector can help. By adding an annotation like the following:

@WithBridgeMethods(Foo.class)
public FooSubType getFoo() {
    return new FooSubType();
}

… and running the bytecode post processor, your class file will get the additional “bridge methods.” In pseudo-code, it’ll look like this:

// your original definition
@WithBridgeMethods(Foo.class)
public FooSubType getFoo() {
    return new FooSubType();
}

// added bridge method
public Foo getFoo() {
    invokevirtual this.getFoo()LFooSubType;
    areturn
}

Such code isn’t allowed in Java source files, but class files allow that. With this addition, existing clients will continue to function.

In this way, you can evolve your classes more easily without breaking backward compatibility.

For more about how to use it in your Maven project, the project website.

potd

  1. Michael B
    August 8th, 2010 at 08:31 | #1

    That is pretty awesome tbh.

  2. August 9th, 2010 at 08:00 | #2

    Nice. This can also be done by creating a new interface LegacyFoo with the original signature “Foo getFoo()” and having Foo implement LegacyFoo; then javac will inject the bridge method. But on a project where many classes are being refactored to narrow the return type, this is clearly nicer.

  3. Clinton Farleigh
    August 9th, 2010 at 13:07 | #3

    Neat trick, but changing the return type of a method in your public interface seems kind of crazy to me.

  4. August 10th, 2010 at 07:57 | #4

    Ian, Yes, if you can have all the references to Foo “upgraded” to new version of Foo, your approach works much better.

    In my case, I couldn’t do that.

  5. August 10th, 2010 at 07:59 | #5

    Clinton,

    Committing to backward compatibility often substantially reduces one’s ability to evolve code and avoid clutter. So any “crazy” tricks that improve this situation, I find them valuable.

    And this trick works :-)

  1. No trackbacks yet.