Merge pull request #10 from stbischof/conv_def_method

[converter] handle default methods - FELIX-6239
diff --git a/converter/converter/src/main/java/org/osgi/util/converter/ConvertingImpl.java b/converter/converter/src/main/java/org/osgi/util/converter/ConvertingImpl.java
index c9e3722..0733060 100644
--- a/converter/converter/src/main/java/org/osgi/util/converter/ConvertingImpl.java
+++ b/converter/converter/src/main/java/org/osgi/util/converter/ConvertingImpl.java
@@ -17,6 +17,9 @@
 package org.osgi.util.converter;
 
 import java.lang.annotation.Annotation;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.reflect.Array;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
@@ -810,6 +813,32 @@
 					if (cls.isAnnotation()) {
 						val = method.getDefaultValue();
 					}
+					else if (method.isDefault())
+					{
+						double javaVersion = Double.parseDouble(
+							System.getProperty("java.class.version"));
+						double java8 = 52.0;
+						if (javaVersion > java8)
+						{
+							val = MethodHandles.lookup().findSpecial(
+								method.getDeclaringClass(), method.getName(),
+								MethodType.methodType(method.getReturnType(),
+									new Class[] {}),
+								method.getDeclaringClass()).bindTo(
+									proxy).invokeWithArguments(args);
+						}
+						else
+						{
+							Constructor<Lookup> c = Lookup.class.getDeclaredConstructor(
+								Class.class);
+							if (!c.isAccessible())
+							{
+								c.setAccessible(true);
+							}
+							val = c.newInstance(cls).in(cls).unreflectSpecial(method,
+								cls).bindTo(proxy).invokeWithArguments(args);
+						}
+					}
 
 					if (val == null) {
 						if (args != null && args.length == 1) {
diff --git a/converter/converter/src/test/java/org/osgi/util/converter/ConverterTest.java b/converter/converter/src/test/java/org/osgi/util/converter/ConverterTest.java
index ef00c13..166b9c9 100644
--- a/converter/converter/src/test/java/org/osgi/util/converter/ConverterTest.java
+++ b/converter/converter/src/test/java/org/osgi/util/converter/ConverterTest.java
@@ -1465,6 +1465,14 @@
         assertNotNull(k);
     }
 
+    @Test
+    public void testDefaultInterfaceMethod() throws Throwable
+    {
+        Class<?> clazz = InterfaceWithDefaultMethod.class;
+        InterfaceWithDefaultMethod i = (InterfaceWithDefaultMethod) Converters.standardConverter().convert(
+            new HashMap<String, Object>()).to(clazz);
+        assertEquals(InterfaceWithDefaultMethod.RESULT, i.defaultMethod());
+    }
     static interface MyIntf2 {
         String code();
         Integer value();
diff --git a/converter/converter/src/test/java/org/osgi/util/converter/InterfaceWithDefaultMethod.java b/converter/converter/src/test/java/org/osgi/util/converter/InterfaceWithDefaultMethod.java
new file mode 100644
index 0000000..c8a42ff
--- /dev/null
+++ b/converter/converter/src/test/java/org/osgi/util/converter/InterfaceWithDefaultMethod.java
@@ -0,0 +1,11 @@
+package org.osgi.util.converter;
+
+public interface InterfaceWithDefaultMethod
+{
+    public static final String RESULT = "r";
+
+    public default String defaultMethod()
+    {
+        return RESULT;
+    }
+}
\ No newline at end of file