public MethodInfo getDefaultMethod (String uniqueName) {
MethodInfo mi = null;
- for (ClassInfo ci = this; ci != null; ci = ci.superClass){
- for (ClassInfo ciIfc : ci.interfaces){
- MethodInfo miIfc = ciIfc.getMethod(uniqueName, true);
- if (miIfc != null && !miIfc.isAbstract()){
- if (mi != null && !mi.equals(miIfc)){
+ for (ClassInfo ciIfc : this.getAllInterfaces()){
+ MethodInfo miIfc = ciIfc.getMethod(uniqueName, false);
+ if (miIfc != null && !miIfc.isAbstract() && !miIfc.isPrivate() && !miIfc.isStatic()){
+ if (mi != null && !mi.equals(miIfc)){
+ if(miIfc.getClassInfo().isSubInterfaceOf(mi.getClassInfo())) {
+ mi = miIfc;
+ } else if(mi.getClassInfo().isSubInterfaceOf(miIfc.getClassInfo())) {
+ continue;
+ } else {
// this has to throw a IncompatibleClassChangeError in the client since Java prohibits ambiguous default methods
String msg = "Conflicting default methods: " + mi.getFullName() + ", " + miIfc.getFullName();
throw new ClassChangeException(msg);
- } else {
- mi = miIfc;
}
+ } else {
+ mi = miIfc;
}
}
}
return mi;
}
+ private boolean isSubInterfaceOf(ClassInfo classInfo) {
+ assert this.isInterface() && classInfo.isInterface();
+ return this == classInfo || this.getAllInterfaces().contains(classInfo);
+ }
+
/**
* This retrieves the SAM from this functional interface. Note that this is only
* called on functional interface expecting to have a SAM. This shouldn't expect
o.bar();
}
}
+ // -- most specific implementations
+
+ public static interface Intf1 {
+ default int getInt() {
+ return 4;
+ }
+ }
+
+ public static interface Intf2 extends Intf1 {
+ @Override
+ default int getInt() {
+ return 3;
+ }
+ }
+ public static abstract class A implements Intf1 {
+
+ }
+
+ public static class B extends A implements Intf2 {
+ }
+
+ @Test
+ public void testMostSpecificImplementationResolution() {
+ if(verifyNoPropertyViolation()) {
+ B b = new B();
+ int x = b.getInt();
+ assertEquals(x, 3);
+ }
+ }
+ // --- inherited default methods
+
+ interface SuperIntf {
+ default String getString() {
+ return "Hello World";
+ }
+ }
+
+ interface SubIntf extends SuperIntf {
+ default int getZero() {
+ return 0;
+ }
+ }
+
+ public class ConcreteClass implements SubIntf {
+
+ }
+
+ @Test
+ public void testInheritedDefaultMethod() {
+ if(verifyNoPropertyViolation()) {
+ ConcreteClass cls = new ConcreteClass();
+ assertEquals(cls.getString(), "Hello World");
+ }
+ }
+
// <2do> how to test IncompatibleClassChangeError without explicit classfile restore?
}
+