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 2017/02/17 16:21:15 UTC

svn commit: r1783423 - in /felix/trunk/converter/converter/src: main/java/org/apache/felix/converter/impl/ test/java/org/apache/felix/converter/impl/

Author: davidb
Date: Fri Feb 17 16:21:15 2017
New Revision: 1783423

URL: http://svn.apache.org/viewvc?rev=1783423&view=rev
Log:
Felix Converter: allow the specification of an error handler with a converter Rule

Modified:
    felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java
    felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java
    felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/InternalConverter.java
    felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterTest.java

Modified: felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java?rev=1783423&r1=1783422&r2=1783423&view=diff
==============================================================================
--- felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java (original)
+++ felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java Fri Feb 17 16:21:15 2017
@@ -180,45 +180,59 @@ public class AdapterImpl implements Inte
         @SuppressWarnings("unchecked")
         @Override
         public Object to(Type type) {
-            if (object != null) {
-                Set<Type> fromTypes = assignableTypes(treatAsClass != null ? treatAsClass : object.getClass());
-                Set<Type> toTypes = assignableTypes(type);
+            List<ConvertFunction<Object, Object>> converters = new ArrayList<>();
+            try {
+                if (object != null) {
+                    Set<Type> fromTypes = assignableTypes(treatAsClass != null ? treatAsClass : object.getClass());
+                    Set<Type> toTypes = assignableTypes(type);
 
-                List<ConvertFunction<Object, Object>> converters = new ArrayList<>();
-                for (Type fromType : fromTypes) {
+                    for (Type fromType : fromTypes) {
+                        for (Type toType : toTypes) {
+                            // TODO what exactly do we use as order here?
+                            converters.add(classRules.get(new TypePair(fromType, Util.primitiveToBoxed(toType))));
+                        }
+                    }
+                    for (Type fromType : fromTypes) {
+                        converters.add(classRules.get(new TypePair(fromType, Object.class)));
+                    }
                     for (Type toType : toTypes) {
-                        // TODO what exactly do we use as order here?
-                        converters.add(classRules.get(new TypePair(fromType, Util.primitiveToBoxed(toType))));
+                        converters.add(classRules.get(new TypePair(Object.class, Util.primitiveToBoxed(toType))));
                     }
-                }
-                for (Type fromType : fromTypes) {
-                    converters.add(classRules.get(new TypePair(fromType, Object.class)));
-                }
-                for (Type toType : toTypes) {
-                    converters.add(classRules.get(new TypePair(Object.class, Util.primitiveToBoxed(toType))));
-                }
 
-                for (Iterator<ConvertFunction<Object, Object>> it = converters.iterator(); it.hasNext(); ) {
-                    ConvertFunction<Object, Object> func = it.next();
-                    it.remove();
-                    if (func == null)
-                        continue;
+                    for (Iterator<ConvertFunction<Object, Object>> it = converters.iterator(); it.hasNext(); ) {
+                        // remove null values
+                        ConvertFunction<Object, Object> func = it.next();
+                        if (func == null)
+                            it.remove();
+                    }
 
-                    try {
-                        Object res = func.convert(object, type, root, keys.toArray());
-                        if (res != null) {
-                            return res;
+                    for (ConvertFunction<Object,Object> cf : converters) {
+                        try {
+                            Object res = cf.convert(object, type, root, keys.toArray());
+                            if (res != null) {
+                                return res;
+                            }
+                        } catch (Exception ex) {
+                            if (hasDefault)
+                                // TODO override this too!
+                                return defaultValue;
+                            else
+                                throw new ConversionException("Cannot convert " + object + " to " + type, ex);
                         }
-                    } catch (Exception ex) {
-                        if (hasDefault)
-                            return defaultValue;
-                        else
-                            throw new ConversionException("Cannot convert " + object + " to " + type, ex);
                     }
                 }
-            }
 
-            return del.to(type);
+                return del.to(type);
+            } catch (Exception ex) {
+                // do custom error handling
+                for (ConvertFunction<Object, Object> cf : converters) {
+                    Object eh = cf.handleError(object, type, root, keys.toArray());
+                    if (eh != null)
+                        return eh;
+                }
+                // No error handler, throw the original exception
+                throw ex;
+            }
         }
 
         @Override

Modified: felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java?rev=1783423&r1=1783422&r2=1783423&view=diff
==============================================================================
--- felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java (original)
+++ felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java Fri Feb 17 16:21:15 2017
@@ -481,14 +481,19 @@ public class ConvertingImpl implements C
                     Object val = m.get(propName);
 
                     // If no value is available take the default if specified
+                    boolean defaultUsed = false; // TODO maybe we don't need this...
                     if (val == null) {
                         if (targetCls.isAnnotation()) {
                             val = method.getDefaultValue();
+                            defaultUsed = true;
                         }
 
-                        if (val == null && args != null && args.length == 1)
+                        if (val == null && args != null && args.length == 1) {
                             val = args[0];
+                            defaultUsed = true;
+                        }
                     }
+
                     return converter.convert(val).to(targetType);
                 }
             });

Modified: felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/InternalConverter.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/InternalConverter.java?rev=1783423&r1=1783422&r2=1783423&view=diff
==============================================================================
--- felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/InternalConverter.java (original)
+++ felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/InternalConverter.java Fri Feb 17 16:21:15 2017
@@ -19,5 +19,5 @@ package org.apache.felix.converter.impl;
 import org.osgi.util.converter.Converter;
 
 public interface InternalConverter extends Converter {
-    public InternalConverting convert(Object obj);
+    InternalConverting convert(Object obj);
 }

Modified: felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterTest.java?rev=1783423&r1=1783422&r2=1783423&view=diff
==============================================================================
--- felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterTest.java (original)
+++ felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterTest.java Fri Feb 17 16:21:15 2017
@@ -56,8 +56,10 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.osgi.util.converter.ConversionException;
+import org.osgi.util.converter.ConvertFunction;
 import org.osgi.util.converter.Converter;
 import org.osgi.util.converter.ConverterBuilder;
+import org.osgi.util.converter.Rule;
 import org.osgi.util.converter.StandardConverter;
 import org.osgi.util.converter.TypeReference;
 
@@ -342,9 +344,74 @@ public class ConverterTest {
         int[] ia = {1, 2};
         assertEquals("1,2", adapted.convert(ia).to(String.class));
         assertArrayEquals(ia, adapted.convert("1,2").to(int[].class));
+    }
+
+    @Test
+    public void testCustomErrorHandling() {
+        ConvertFunction<String,Integer> func = new ConvertFunction<String,Integer>() {
+            @Override
+            public Integer convert(String obj, Type targetType, Object root, Object[] keyPath) throws Exception {
+                return null;
+            }
+
+            @Override
+            public Integer handleError(String obj, Type targetType, Object root, Object[] keyPath) {
+                if ("hello".equals(obj)) {
+                    return -1;
+                }
+                return null;
+            }
+        };
 
+        ConverterBuilder cb = converter.newConverterBuilder();
+        cb.rule(new Rule<>(String.class, Integer.class, func));
+        Converter adapted = cb.build();
+
+        assertEquals(new Integer(12), adapted.convert("12").to(Integer.class));
+        assertEquals(new Integer(-1), adapted.convert("hello").to(Integer.class));
+
+        // This is with the non-adapted converter
+        try {
+            converter.convert("hello").to(Integer.class);
+            fail("Should have thrown a Conversion Exception when converting 'hello' to a number");
+        } catch (ConversionException ce) {
+            // good
+        }
     }
 
+    /*
+    @Test
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public void testCustomDefaultHandling() {
+        // TODO re-enable
+        Map<String, String> m = new HashMap<>();
+//        MyAnnotation ann = converter.convert(m).to(MyAnnotation.class);
+//        assertEquals(17, ann.value());
+
+        // Now register a custom default handler
+        ConvertFunction<Map,MyAnnotation> func = new ConvertFunction<Map,MyAnnotation>() {
+            @Override
+            public MyAnnotation convert(Map obj, Type targetType, Object root, Object[] keyPath) throws Exception {
+                return null;
+            }
+
+            @Override
+            public MyAnnotation handleDefault(Map obj, Class<?> targetType, Object root, Object[] keyPath) {
+                return 42;
+            }
+        };
+
+        ConverterBuilder cb = converter.newConverterBuilder();
+        Rule r = new Rule(Map.class, MyAnnotation.class, func);
+        cb.rule(r);
+        Converter adapted = cb.build();
+
+        MyAnnotation ann2 = adapted.convert(m).to(MyAnnotation.class);
+        assertEquals("The default value from the annotation should have been overridden by the default handler",
+                42, ann2.value());
+    }
+    */
+
     @Test
     public void testUUIDConversion() {
         UUID uuid = UUID.randomUUID();
@@ -889,5 +956,9 @@ public class ConverterTest {
         }
     }
 
+    static @interface MyAnnotation {
+        int value() default 17;
+    }
+
     enum SomeEnum { VALUE, GETVALUE };
 }