Bytecode Hacks

Bridger and Seven2Six

Presentation Prepared By:
David M. Lloyd <david.lloyd@redhat.com>

Bridger: The Problem

  • You need to retain binary compatibility, but...
    • You have a method whose return type you want to narrow or broaden
    • You want to change the return type of a method to something completely different
      • For example, changing a void method to support call chaining
    • You want to remove a deprecated method

Bridger: The Solution

  • Bridger executes a name transformation on all methods containing the string "$$bridge" in their name
  • The "$$bridge" string (and everything after) is dropped
  • The method is marked ACC_BRIDGE and ACC_SYNTHETIC
    • This means that javac won't see it
    • But code compiled against that signature will still link against it at runtime
  • Thus all the aforementioned problems can be easily solved

Bridger: Example 1


    /**
     * This method returned Object in a previous version.
     */
    public String getValue() {
        return blah.toString();
    }

    /**
     * This gets changed to "getValue()" and is hidden from javac.
     * But, classes compiled against the old version will link against
     * this one instead at run time.
     */
    public Object getValue$$bridge() {
        return getValue();
    }

Bridger: Example 2


    /**
     * This method returned void in a previous version.
     */
    public Builder setName(String name) {
        this.name = name;
        return this;
    }

    /**
     * This gets changed to "setName()" and is hidden from javac.
     * But, classes compiled against the void-returning old version
     * will link against this one instead at run time.
     */
    public void setName$$bridge(String name) {
        this.name = name;
    }

Seven2Six: The Problem

  • Someone gave you a PR riddled with diamond operators but you need to backport it to your Java 6 branch
  • You need to support Java 6 but you really want String switch, try-with-resources, etc.

Seven2Six: The Solution

  • Translates Java 7 bytecode to Java 6
  • Fully supports:
    • Diamond operator
    • String switch
    • Improved type inference
    • New numeric literals (binary constants, underscore separators)
  • Mostly supports:
    • Try-with-resources (suppressed exceptions are dropped when running on Java 6, but work as expected on Java 7)
    • Multi-catch blocks (with one caveat)
      • If the compiler detects a common superclass of more than one of the exception options, it will silently link against it
      • If that class is missing when running Java 6, you will get errors at run time
  • Does not support:
    • The invokedynamic instruction
    • Any JDK 7-specific APIs

Get this stuff

  • Get bridger from GitHub or Maven as a plugin (org.jboss.bridger:bridger:1.0.Final)
  • Get seven2six from GitHub or Maven as a plugin (org.jboss.seven2six:seven2six:1.1.Final)

That's it!