You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by da...@apache.org on 2016/08/04 16:07:44 UTC

svn commit: r1755199 - in /felix/trunk/converter/src: main/java/org/apache/felix/converter/impl/ConvertingImpl.java test/java/org/apache/felix/converter/impl/ConverterMapTest.java

Author: davidb
Date: Thu Aug  4 16:07:44 2016
New Revision: 1755199

URL: http://svn.apache.org/viewvc?rev=1755199&view=rev
Log:
Felix Converter Service - support for annotations.

Modified:
    felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java
    felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java

Modified: felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java?rev=1755199&r1=1755198&r2=1755199&view=diff
==============================================================================
--- felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java (original)
+++ felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java Thu Aug  4 16:07:44 2016
@@ -287,13 +287,24 @@ public class ConvertingImpl implements C
             new InvocationHandler() {
                 @Override
                 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-                    String propName = getAccessorPropertyName(method);
+                    String propName = getInterfacePropertyName(method);
                     if (propName == null)
                         return null;
 
                     Class<?> targetType = method.getReturnType();
 
-                    return converter.convert(m.get(propName)).to(targetType);
+                    Object val = m.get(propName);
+
+                    // If no value is available take the default if specified
+                    if (val == null) {
+                        if (targetCls.isAnnotation()) {
+                            val = method.getDefaultValue();
+                        }
+
+                        if (val == null && args != null && args.length == 1)
+                            val = args[0];
+                    }
+                    return converter.convert(val).to(targetType);
                 }
             });
     }
@@ -425,10 +436,25 @@ public class ConvertingImpl implements C
 
         Map result = new HashMap();
         for (Method md : obj.getClass().getDeclaredMethods()) {
-            handleMethod(obj, md, invokedMethods, result);
+            handleBeanMethod(obj, md, invokedMethods, result);
         }
         for (Method md : obj.getClass().getMethods()) {
-            handleMethod(obj, md, invokedMethods, result);
+            handleBeanMethod(obj, md, invokedMethods, result);
+        }
+
+        return result;
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static Map createMapFromInterface(Object obj) {
+        Set<String> invokedMethods = new HashSet<>();
+
+        Map result = new HashMap();
+        for (Method md : obj.getClass().getDeclaredMethods()) {
+            handleInterfaceMethod(obj, md, invokedMethods, result);
+        }
+        for (Method md : obj.getClass().getMethods()) {
+            handleInterfaceMethod(obj, md, invokedMethods, result);
         }
 
         return result;
@@ -482,8 +508,21 @@ public class ConvertingImpl implements C
         return propName.toString();
     }
 
+    private static String getInterfacePropertyName(Method md) {
+        if (md.getReturnType().equals(Void.class))
+            return null; // not an accessor
+
+        if (md.getParameterTypes().length > 1)
+            return null; // not an accessor
+
+        if (Object.class.equals(md.getDeclaringClass()))
+            return null; // do not use any methods on the Object class as a accessor
+
+        return md.getName().replace('_', '.'); // TODO support all the escaping mechanisms.
+    }
+
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    private static void handleMethod(Object obj, Method md, Set<String> invokedMethods, Map res) {
+    private static void handleBeanMethod(Object obj, Method md, Set<String> invokedMethods, Map res) {
         String mn = md.getName();
         if (invokedMethods.contains(mn))
             return; // method with this name already invoked
@@ -499,11 +538,30 @@ public class ConvertingImpl implements C
         }
     }
 
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private static void handleInterfaceMethod(Object obj, Method md, Set<String> invokedMethods, Map res) {
+        String mn = md.getName();
+        if (invokedMethods.contains(mn))
+            return; // method with this name already invoked
+
+        String propName = getInterfacePropertyName(md);
+        if (propName == null)
+            return;
+
+        try {
+            res.put(propName.toString(), md.invoke(obj));
+            invokedMethods.add(mn);
+        } catch (Exception e) {
+        }
+    }
+
     private static Map<?,?> mapView(Object obj) {
         if (obj instanceof Map)
             return (Map<?,?>) obj;
         else if (obj instanceof Dictionary)
             return null; // TODO
+        else if (obj.getClass().getInterfaces().length > 0)
+            return createMapFromInterface(obj);
         else
             return createMapFromBeanAccessors(obj);
     }

Modified: felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java?rev=1755199&r1=1755198&r2=1755199&view=diff
==============================================================================
--- felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java (original)
+++ felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java Thu Aug  4 16:07:44 2016
@@ -42,7 +42,7 @@ public class ConverterMapTest {
 
     @Before
     public void setUp() {
-        converter = new ConverterImpl();
+        converter = new ConverterService();
     }
 
     @After
@@ -117,52 +117,34 @@ public class ConverterMapTest {
 
     @Test
     public void testInterfaceToMap() {
-        Object obj = new Object();
         TestInterface impl = new TestInterface() {
             @Override
-            public String getFoo() {
+            public String foo() {
                 return "Chocolate!";
             }
 
             @Override
-            public int getBar() {
+            public int bar() {
                 return 76543;
             }
 
-            @SuppressWarnings("unused")
-            public long getL() {
-                return 1L;
+            @Override
+            public int bar(String def) {
+                return 0;
             }
 
-            @SuppressWarnings("unused")
-            public boolean isSomething() {
+            @Override
+            public Boolean za_za() {
                 return true;
             }
-
-            @SuppressWarnings("unused")
-            public Object getBlah() {
-                return obj;
-            }
-
-            @SuppressWarnings("unused")
-            private byte getByte() {
-                return (byte) 12;
-            }
-
-            @SuppressWarnings("unused")
-            public String getAlt(int arg) {
-                return "some value";
-            }
         };
 
         @SuppressWarnings("rawtypes")
         Map m = converter.convert(impl).to(Map.class);
-        assertEquals(5, m.size());
+        assertEquals(3, m.size());
         assertEquals("Chocolate!", m.get("foo"));
         assertEquals(76543, (int) m.get("bar"));
-        assertEquals(1L, (long) m.get("l"));
-        assertTrue((boolean) m.get("something"));
-        assertSame(obj, m.get("blah"));
+        assertEquals(true, (boolean) m.get("za.za"));
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
@@ -172,10 +154,12 @@ public class ConverterMapTest {
         m.put("foo", 12345);
         m.put("bar", "999");
         m.put("alt", "someval");
+        m.put("za.za", true);
 
         TestInterface ti = converter.convert(m).to(TestInterface.class);
-        assertEquals("12345", ti.getFoo());
-        assertEquals(999, ti.getBar());
+        assertEquals("12345", ti.foo());
+        assertEquals(999, ti.bar());
+        assertEquals(Boolean.TRUE, ti.za_za());
     }
 
     @SuppressWarnings("rawtypes")
@@ -184,8 +168,36 @@ public class ConverterMapTest {
         Map m = new HashMap<>();
 
         TestInterface ti = converter.convert(m).to(TestInterface.class);
-        assertNull(ti.getFoo());
-        assertEquals(0, ti.getBar());
+        assertNull(ti.foo());
+        assertEquals(999, ti.bar("999"));
+        assertNull(ti.za_za());
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Test
+    public void testMapToAnnotation1() {
+        Map m = new HashMap<>();
+        m.put("foo", 12345);
+        m.put("bar", "999");
+        m.put("alt", "someval");
+        m.put("za.za", true);
+
+        TestAnnotation ta = converter.convert(m).to(TestAnnotation.class);
+        assertEquals("12345", ta.foo());
+        assertEquals(999, ta.bar());
+        assertTrue(ta.za_za());
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Test
+    public void testMapToAnnotationDefaults() {
+        Map m = new HashMap<>();
+        m.put("alt", "someval");
+
+        TestAnnotation ta = converter.convert(m).to(TestAnnotation.class);
+        assertEquals("fooo!", ta.foo());
+        assertEquals(42, ta.bar());
+        assertFalse(ta.za_za());
     }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
@@ -200,7 +212,15 @@ public class ConverterMapTest {
     }
 
     interface TestInterface {
-        String getFoo();
-        int getBar();
+        String foo();
+        int bar();
+        int bar(String def);
+        Boolean za_za();
+    }
+
+    @interface TestAnnotation {
+        String foo() default "fooo!";
+        int bar() default 42;
+        boolean za_za();
     }
 }