Skip to content

Commit 7c3402d

Browse files
committed
Remove bridge methods from interfaces, fixes #13
1 parent 97da651 commit 7c3402d

File tree

3 files changed

+54
-0
lines changed

3 files changed

+54
-0
lines changed

Diff for: README.md

+6
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ the lambda accesses an instance variable).
122122
Version History
123123
---------------
124124

125+
### Upcoming
126+
127+
- Removes from interfaces bridge methods which were generated by JDK 8 e.g.
128+
when an interface overrides a method and refines its return type
129+
([Issue #13](https://github.com/orfjackal/retrolambda/issues/13))
130+
125131
### Retrolambda 1.1.3 (2014-03-25)
126132

127133
- Fixed incompatibility with the Eclipse JDT compiler, version Kepler SR2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright © 2013-2014 Esko Luontola <www.orfjackal.net>
2+
// This software is released under the Apache License 2.0.
3+
// The license text is at http://www.apache.org/licenses/LICENSE-2.0
4+
5+
package net.orfjackal.retrolambda.test;
6+
7+
import org.junit.Test;
8+
9+
import static org.hamcrest.MatcherAssert.assertThat;
10+
import static org.hamcrest.Matchers.is;
11+
12+
public class DefaultMethodsTest {
13+
14+
/**
15+
* JDK 8 adds a bridge method to an interface when it overrides a method
16+
* from the parent interface and refines its return type. This uses Java 8's
17+
* default methods feature, which won't work on Java 7 and below, so we have
18+
* to remove it for it - this makes the bytecode same as what JDK 7 produces.
19+
*/
20+
@Test
21+
public void will_remove_non_abstract_methods_from_interfaces() {
22+
class Foo implements Child {
23+
@Override
24+
public String foo() {
25+
return "foo";
26+
}
27+
}
28+
assertThat(new Foo().foo(), is("foo"));
29+
}
30+
31+
public interface Parent {
32+
Object foo();
33+
}
34+
35+
public interface Child extends Parent {
36+
String foo(); // refined return type
37+
}
38+
}

Diff for: retrolambda/src/main/java/net/orfjackal/retrolambda/LambdaUsageBackporter.java

+10
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ private static void resetLambdaClassSequenceNumber() {
3636

3737
private static class MyClassVisitor extends ClassVisitor {
3838
private final int targetVersion;
39+
private int classAccess;
3940
private String className;
4041

4142
public MyClassVisitor(ClassWriter cw, int targetVersion) {
@@ -49,17 +50,26 @@ public void visit(int version, int access, String name, String signature, String
4950
version = targetVersion;
5051
}
5152
super.visit(version, access, name, signature, superName, interfaces);
53+
this.classAccess = access;
5254
this.className = name;
5355
}
5456

5557
@Override
5658
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
59+
if (isBridgeMethodOnInterface(access)) {
60+
return null;
61+
}
5762
if (LambdaNaming.LAMBDA_IMPL_METHOD.matcher(name).matches()) {
5863
access = Flags.makeNonPrivate(access);
5964
}
6065
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
6166
return new InvokeDynamicInsnConvertingMethodVisitor(api, mv, className);
6267
}
68+
69+
private boolean isBridgeMethodOnInterface(int methodAccess) {
70+
return Flags.hasFlag(classAccess, Opcodes.ACC_INTERFACE) &&
71+
Flags.hasFlag(methodAccess, Opcodes.ACC_BRIDGE);
72+
}
6373
}
6474

6575
private static class InvokeDynamicInsnConvertingMethodVisitor extends MethodVisitor {

0 commit comments

Comments
 (0)