Wednesday, November 19, 2014

Metaprogramming Trap with Interfaces in Java 8

Consider the following little example:
package prv.rli.codetest;

import java.lang.reflect.Method;

public class BreakingInterfaces  {
    interface Base {
        BaseFoo foo();
        interface BaseFoo {           
        }
    }
   
    interface Derived extends Base {
        DerivedFoo foo();
        interface DerivedFoo extends BaseFoo {
           
        }
    }
   
    public static void main(String[] args) {       
        dumpDeclaredMethods(Derived.class);
    }

    private static void dumpDeclaredMethods(Class<?> class1) {
        System.out.println("---" + class1.getSimpleName() + "---");
        Method[] methods = class1.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("----------");
    }
}
What would you expect to be the output? We have a derived Interface which overrides the only method of its base interface in a covariant way. So one method only.

If you compile the above examplt with jdk1.7.0.55 the output is indeed:
 ---Derived---
public abstract BreakingInterfaces$Derived$DerivedFoo BreakingInterfaces$Derived.foo()
----------
But when using jdk1.8.0.25 the output is:
---Derived---
public abstract prv.rli.codetest.BreakingInterfaces$Derived$DerivedFoo prv.rli.codetest.BreakingInterfaces$Derived.foo()
public default prv.rli.codetest.BreakingInterfaces$Base$BaseFoo prv.rli.codetest.BreakingInterfaces$Derived.foo()
----------
 For reasons unknown to me, the base class method resurfaces here which may lead to unwanted behaviour when using reflection.