Skip to content

Commit

Permalink
Remove bridge methods from interfaces, fixes #13
Browse files Browse the repository at this point in the history
  • Loading branch information
luontola committed Mar 28, 2014
1 parent 97da651 commit 7c3402d
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 0 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ the lambda accesses an instance variable).
Version History
---------------

### Upcoming

- Removes from interfaces bridge methods which were generated by JDK 8 e.g.
when an interface overrides a method and refines its return type
([Issue #13](https://github.com/orfjackal/retrolambda/issues/13))

### Retrolambda 1.1.3 (2014-03-25)

- Fixed incompatibility with the Eclipse JDT compiler, version Kepler SR2
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright © 2013-2014 Esko Luontola <www.orfjackal.net>
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0

package net.orfjackal.retrolambda.test;

import org.junit.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;

public class DefaultMethodsTest {

/**
* JDK 8 adds a bridge method to an interface when it overrides a method
* from the parent interface and refines its return type. This uses Java 8's
* default methods feature, which won't work on Java 7 and below, so we have
* to remove it for it - this makes the bytecode same as what JDK 7 produces.
*/
@Test
public void will_remove_non_abstract_methods_from_interfaces() {
class Foo implements Child {
@Override
public String foo() {
return "foo";
}
}
assertThat(new Foo().foo(), is("foo"));
}

public interface Parent {
Object foo();
}

public interface Child extends Parent {
String foo(); // refined return type
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ private static void resetLambdaClassSequenceNumber() {

private static class MyClassVisitor extends ClassVisitor {
private final int targetVersion;
private int classAccess;
private String className;

public MyClassVisitor(ClassWriter cw, int targetVersion) {
Expand All @@ -49,17 +50,26 @@ public void visit(int version, int access, String name, String signature, String
version = targetVersion;
}
super.visit(version, access, name, signature, superName, interfaces);
this.classAccess = access;
this.className = name;
}

@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (isBridgeMethodOnInterface(access)) {
return null;
}
if (LambdaNaming.LAMBDA_IMPL_METHOD.matcher(name).matches()) {
access = Flags.makeNonPrivate(access);
}
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
return new InvokeDynamicInsnConvertingMethodVisitor(api, mv, className);
}

private boolean isBridgeMethodOnInterface(int methodAccess) {
return Flags.hasFlag(classAccess, Opcodes.ACC_INTERFACE) &&
Flags.hasFlag(methodAccess, Opcodes.ACC_BRIDGE);
}
}

private static class InvokeDynamicInsnConvertingMethodVisitor extends MethodVisitor {
Expand Down

0 comments on commit 7c3402d

Please sign in to comment.