Author: davidb
Date: Mon Mar 20 09:23:03 2017
New Revision: 1787694

URL: http://svn.apache.org/viewvc?rev=1787694&view=rev
Log:
Felix Converter - update to support latest Rule API.

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/ConverterBuilderImpl.java
    
felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConverterImpl.java
    
felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java
    
felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterBuilderTest.java
    
felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.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=1787694&r1=1787693&r2=1787694&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
 Mon Mar 20 09:23:03 2017
@@ -18,35 +18,26 @@ package org.apache.felix.converter.impl;
 
 import java.lang.reflect.Type;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 
 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.Converting;
-import org.osgi.util.converter.Rule;
 import org.osgi.util.converter.TypeReference;
-import org.osgi.util.function.Function;
 
 public class AdapterImpl implements InternalConverter {
     private final InternalConverter delegate;
-    private final Map<TypePair, ConvertFunction<Object, Object>> classRules =
-            new ConcurrentHashMap<>();
+    private final Map<Type, List<ConvertFunction<?>>> typeRules;
+    private final List<ConvertFunction<?>> allRules;
 
-    AdapterImpl(InternalConverter converter, List<Rule<?,?>> rules) {
-        this.delegate = converter;
-        for (Rule<?,?> r : rules) {
-            rule(r);
-        }
+    AdapterImpl(InternalConverter converter, Map<Type, 
List<ConvertFunction<?>>> rules, List<ConvertFunction<?>> catchAllRules) {
+        delegate = converter;
+        typeRules = rules;
+        allRules = catchAllRules;
     }
 
     @Override
@@ -61,26 +52,10 @@ public class AdapterImpl implements Inte
         return new ConverterBuilderImpl(this);
     }
 
-    @SuppressWarnings("unchecked")
-    private <F, T> AdapterImpl rule(Rule<F, T> rule) {
-        ConvertFunction<F, T> toFun = rule.getToFunction();
-        if (toFun != null)
-            classRules.put(new TypePair(rule.getSourceType(), 
rule.getTargetType()),
-                (ConvertFunction<Object, Object>) toFun);
-
-
-        ConvertFunction<T, F> fromFun = rule.getBackFunction();
-        if (fromFun != null)
-            classRules.put(new TypePair(rule.getTargetType(), 
rule.getSourceType()),
-                (ConvertFunction<Object, Object>) fromFun);
-        return this;
-    }
-
     private class ConvertingWrapper implements InternalConverting {
         private final InternalConverting del;
         private final Object object;
         private volatile Object defaultValue;
-        private volatile Class<?> treatAsClass;
         private volatile boolean hasDefault;
 
         ConvertingWrapper(Object obj, InternalConverting c) {
@@ -109,7 +84,6 @@ public class AdapterImpl implements Inte
 
         @Override
         public Converting sourceAs(Class<?> type) {
-            treatAsClass = type;
             del.sourceAs(type);
             return this;
         }
@@ -134,7 +108,7 @@ public class AdapterImpl implements Inte
 
         @Override
         public Converting targetAsBean() {
-            // TODO not yet implemented
+            del.targetAsBean();
             return this;
         }
 
@@ -160,33 +134,16 @@ public class AdapterImpl implements Inte
         @SuppressWarnings("unchecked")
         @Override
         public Object to(Type type) {
-            List<ConvertFunction<Object, Object>> converters = new 
ArrayList<>();
+            List<ConvertFunction<?>> tr = 
typeRules.get(Util.primitiveToBoxed(type));
+            if (tr == null)
+                tr = Collections.emptyList();
+            List<ConvertFunction<?>> converters = new ArrayList<>(tr.size() + 
allRules.size());
+            converters.addAll(tr);
+            converters.addAll(allRules);
+
             try {
                 if (object != null) {
-                    Set<Type> fromTypes = assignableTypes(treatAsClass != null 
? treatAsClass : object.getClass());
-                    Set<Type> toTypes = assignableTypes(type);
-
-                    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) {
-                        converters.add(classRules.get(new 
TypePair(Object.class, Util.primitiveToBoxed(toType))));
-                    }
-
-                    for (Iterator<ConvertFunction<Object, Object>> it = 
converters.iterator(); it.hasNext(); ) {
-                        // remove null values
-                        ConvertFunction<Object, Object> func = it.next();
-                        if (func == null)
-                            it.remove();
-                    }
-
-                    for (ConvertFunction<Object,Object> cf : converters) {
+                    for (ConvertFunction<?> cf : converters) {
                         try {
                             Object res = cf.convert(object, type);
                             if (res != null) {
@@ -194,7 +151,6 @@ public class AdapterImpl implements Inte
                             }
                         } catch (Exception ex) {
                             if (hasDefault)
-                                // TODO override this too!
                                 return defaultValue;
                             else
                                 throw new ConversionException("Cannot convert 
" + object + " to " + type, ex);
@@ -205,7 +161,7 @@ public class AdapterImpl implements Inte
                 return del.to(type);
             } catch (Exception ex) {
                 // do custom error handling
-                for (ConvertFunction<Object, Object> cf : converters) {
+                for (ConvertFunction<?> cf : converters) {
                     Object eh = cf.handleError(object, type);
                     if (eh != null)
                         return eh;
@@ -220,59 +176,4 @@ public class AdapterImpl implements Inte
             return to(String.class);
         }
     }
-
-    private static Set<Type> assignableTypes(Type mostSpecialized) {
-        if (!(mostSpecialized instanceof Class))
-            return Collections.singleton(mostSpecialized);
-
-        Class<?> curClass = (Class<?>) mostSpecialized;
-        Set<Type> lookupTypes = new LinkedHashSet<>(); // Iteration order 
matters!
-        while((curClass != null) && (!(Object.class.equals(curClass)))) {
-            lookupTypes.add(curClass);
-            lookupTypes.addAll(Arrays.asList(curClass.getInterfaces()));
-            curClass = curClass.getSuperclass();
-        }
-        lookupTypes.add(Object.class); // Object is the superclass of any type
-        return lookupTypes;
-    }
-
-    static class TypePair {
-        private final Type from;
-        private final Type to;
-
-        TypePair(Type from, Type to) {
-            this.from = from;
-            this.to = to;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(from, to);
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj == this)
-                return true;
-            if (!(obj instanceof TypePair))
-                return false;
-
-            TypePair o = (TypePair) obj;
-            return Objects.equals(from, o.from) &&
-                    Objects.equals(to, o.to);
-        }
-    }
-
-    static class ConvertFunctionImpl<F, T> implements ConvertFunction<F, T> {
-        private final Function<F, T> function;
-
-        public ConvertFunctionImpl(Function<F, T> function) {
-            this.function = function;
-        }
-
-        @Override
-        public T convert(F obj, Type targetType) throws Exception {
-            return function.apply(obj);
-        }
-    }
 }

Modified: 
felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConverterBuilderImpl.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConverterBuilderImpl.java?rev=1787694&r1=1787693&r2=1787694&view=diff
==============================================================================
--- 
felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConverterBuilderImpl.java
 (original)
+++ 
felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConverterBuilderImpl.java
 Mon Mar 20 09:23:03 2017
@@ -18,17 +18,18 @@ package org.apache.felix.converter.impl;
 
 import java.lang.reflect.Type;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
-import org.apache.felix.converter.impl.AdapterImpl.ConvertFunctionImpl;
+import org.osgi.util.converter.ConvertFunction;
 import org.osgi.util.converter.ConverterBuilder;
-import org.osgi.util.converter.Rule;
-import org.osgi.util.converter.TypeReference;
-import org.osgi.util.function.Function;
+import org.osgi.util.converter.TargetRule;
 
 public class ConverterBuilderImpl implements ConverterBuilder {
     private final InternalConverter adapter;
-    private final List<Rule<?,?>> rules = new ArrayList<>();
+    private final Map<Type, List<ConvertFunction<?>>> rules = new HashMap<>();
+    private final List<ConvertFunction<?>> catchAllRules = new ArrayList<>();
 
     public ConverterBuilderImpl(InternalConverter a) {
         this.adapter = a;
@@ -36,31 +37,34 @@ public class ConverterBuilderImpl implem
 
     @Override
     public InternalConverter build() {
-        return new AdapterImpl(adapter, rules);
+        return new AdapterImpl(adapter, rules, catchAllRules);
     }
 
     @Override
-    public <F, T> ConverterBuilder rule(Rule<F, T> rule) {
-        rules.add(rule);
+    public <T> ConverterBuilder rule(ConvertFunction<T> func) {
+       catchAllRules.add(func);
         return this;
     }
 
     @Override
-    public <F, T> ConverterBuilder rule(Class<F> fromCls, Class<T> toCls, 
Function<F, T> toFun, Function<T, F> fromFun) {
-        rules.add(new Rule<F, T>(fromCls, toCls, new 
ConvertFunctionImpl<>(toFun), new ConvertFunctionImpl<>(fromFun)));
-        return this;
+    public <T> ConverterBuilder rule(Type t, ConvertFunction<T> func) {
+       getRulesList(t).add(func);
+       return this;
     }
 
     @Override
-    public <F, T> ConverterBuilder rule(TypeReference<F> fromRef, 
TypeReference<T> toRef, Function<F, T> toFun,
-            Function<T, F> fromFun) {
-        // TODO Auto-generated method stub
-        return null;
+    public <T> ConverterBuilder rule(TargetRule<T> rule) {
+       Type type = rule.getTargetType();
+       getRulesList(type).add(rule.getFunction());
+        return this;
     }
 
-    @Override
-    public <F, T> ConverterBuilder rule(Type fromType, Type toType, 
Function<F, T> toFun, Function<T, F> fromFun) {
-        // TODO Auto-generated method stub
-        return null;
+    private List<ConvertFunction<?>> getRulesList(Type type) {
+        List<ConvertFunction<?>> l = rules.get(type);
+       if (l == null) {
+               l = new ArrayList<>();
+               rules.put(type, l);
+       }
+        return l;
     }
 }

Modified: 
felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConverterImpl.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConverterImpl.java?rev=1787694&r1=1787693&r2=1787694&view=diff
==============================================================================
--- 
felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConverterImpl.java
 (original)
+++ 
felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConverterImpl.java
 Mon Mar 20 09:23:03 2017
@@ -29,6 +29,7 @@ import java.util.UUID;
 import java.util.regex.Pattern;
 
 import org.osgi.util.converter.ConverterBuilder;
+import org.osgi.util.converter.Rule;
 
 public class ConverterImpl implements InternalConverter {
     @Override
@@ -37,35 +38,30 @@ public class ConverterImpl implements In
     }
 
     public void addStandardRules(ConverterBuilder cb) {
-        cb.rule(Byte.class, String.class, v -> v.toString(), Byte::parseByte);
-        cb.rule(Calendar.class, String.class, v -> 
v.getTime().toInstant().toString(),
-                v -> {
-                    Calendar cc = Calendar.getInstance();
-                    cc.setTime(Date.from(Instant.parse(v)));
-                    return cc;
-                });
-        cb.rule(Character.class, Boolean.class, v -> v.charValue() != 0,
-                v -> v.booleanValue() ? (char) 1 : (char) 0);
-        cb.rule(Character.class, String.class, v -> v.toString(),
-                v -> v.length() > 0 ? v.charAt(0) : 0);
-        cb.rule(Class.class, String.class, Class::toString,
-                this::loadClassUnchecked);
-        cb.rule(Date.class, Long.class, d -> d.getTime(), l -> new Date(l));
-        cb.rule(Date.class, String.class, v -> v.toInstant().toString(),
-                v -> Date.from(Instant.parse(v)));
-        cb.rule(Double.class, String.class, v -> v.toString(), 
Double::parseDouble);
-        cb.rule(Float.class, String.class, v -> v.toString(), 
Float::parseFloat);
-        cb.rule(Integer.class, String.class, v -> v.toString(), 
Integer::parseInt);
-        cb.rule(LocalDateTime.class, String.class, LocalDateTime::toString, 
LocalDateTime::parse);
-        cb.rule(LocalDate.class, String.class, LocalDate::toString, 
LocalDate::parse);
-        cb.rule(LocalTime.class, String.class, LocalTime::toString, 
LocalTime::parse);
-        cb.rule(Long.class, String.class, v -> v.toString(), Long::parseLong);
-        cb.rule(OffsetDateTime.class, String.class, OffsetDateTime::toString, 
OffsetDateTime::parse);
-        cb.rule(OffsetTime.class, String.class, OffsetTime::toString, 
OffsetTime::parse);
-        cb.rule(Pattern.class, String.class, Pattern::toString, 
Pattern::compile);
-        cb.rule(Short.class, String.class, v -> v.toString(), 
Short::parseShort);
-        cb.rule(UUID.class, String.class, UUID::toString, UUID::fromString);
-        cb.rule(ZonedDateTime.class, String.class, ZonedDateTime::toString, 
ZonedDateTime::parse);
+        cb.rule(new Rule<Calendar, String>(f -> 
f.getTime().toInstant().toString()) {});
+        cb.rule(new Rule<String, Calendar>(f -> {
+            Calendar cc = Calendar.getInstance();
+            cc.setTime(Date.from(Instant.parse(f)));
+            return cc;
+        }) {});
+        cb.rule(new Rule<Calendar,Long>(f -> f.getTime().getTime()) {});
+        cb.rule(new Rule<Long,Calendar>(f -> new 
Calendar.Builder().setInstant(f).build()) {});
+        cb.rule(new Rule<Character,Boolean>(c -> c.charValue() != 0) {});
+        cb.rule(new Rule<Boolean,Character>(b -> b.booleanValue() ? (char) 1 : 
(char) 0) {});
+        cb.rule(new Rule<String,Character>(f -> f.length() > 0 ? f.charAt(0) : 
0) {});
+        cb.rule(new Rule<String,Class<?>>(this::loadClassUnchecked) {});
+        cb.rule(new Rule<Date,Long>(Date::getTime) {});
+        cb.rule(new Rule<Long,Date>(f -> new Date(f)) {});
+        cb.rule(new Rule<Date,String>(f -> f.toInstant().toString()) {});
+        cb.rule(new Rule<String,Date>(f -> Date.from(Instant.parse(f))) {});
+        cb.rule(new Rule<String, LocalDateTime>(LocalDateTime::parse) {});
+        cb.rule(new Rule<String, LocalDate>(LocalDate::parse) {});
+        cb.rule(new Rule<String, LocalTime>(LocalTime::parse) {});
+        cb.rule(new Rule<String, OffsetDateTime>(OffsetDateTime::parse) {});
+        cb.rule(new Rule<String, OffsetTime>(OffsetTime::parse) {});
+        cb.rule(new Rule<String, Pattern>(Pattern::compile) {});
+        cb.rule(new Rule<String, UUID>(UUID::fromString) {});
+        cb.rule(new Rule<String, ZonedDateTime>(ZonedDateTime::parse) {});
     }
 
     private Class<?> loadClassUnchecked(String className) {

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=1787694&r1=1787693&r2=1787694&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
 Mon Mar 20 09:23:03 2017
@@ -48,14 +48,18 @@ import org.osgi.util.converter.Convertin
 import org.osgi.util.converter.TypeReference;
 
 public class ConvertingImpl implements Converting, InternalConverting {
-    private static final Map<Class<?>, Class<?>> interfaceImplementations;
+    private static final Map<Class<?>, Class<?>> INTERFACE_IMPLS;
     static {
         Map<Class<?>, Class<?>> m = new HashMap<>();
         m.put(Collection.class, ArrayList.class);
         m.put(List.class, ArrayList.class);
         m.put(Set.class, LinkedHashSet.class); // preserves insertion order
         m.put(Map.class, LinkedHashMap.class); // preserves insertion order
-        interfaceImplementations = Collections.unmodifiableMap(m);
+        INTERFACE_IMPLS = Collections.unmodifiableMap(m);
+    }
+    private static final Collection<Class<?>> NO_MAP_VIEW_TYPES;
+    static {
+        NO_MAP_VIEW_TYPES = Arrays.asList(String.class);
     }
 
     volatile InternalConverter converter;
@@ -69,7 +73,6 @@ public class ConvertingImpl implements C
     volatile Type[] typeArguments;
     private volatile boolean forceCopy = false;
     private volatile boolean sourceAsJavaBean = false;
-    @SuppressWarnings( "unused" )
     private volatile boolean targetAsJavaBean = false;
     private volatile boolean sourceAsDTO = false;
     private volatile boolean targetAsDTO = false;
@@ -218,7 +221,7 @@ public class ConvertingImpl implements C
             if (defaultValue != null)
                 return 
converter.convert(defaultValue).sourceAs(sourceAsClass).targetAs(targetAsClass).to(targetClass);
             else
-                return null;
+                throw new ConversionException("Cannot convert " + object + " 
to " + targetAsClass);
         }
     }
 
@@ -263,7 +266,7 @@ public class ConvertingImpl implements C
             targetElementType = (Class<?>) typeArguments[0];
         }
 
-        Class<?> ctrCls = interfaceImplementations.get(targetAsClass);
+        Class<?> ctrCls = INTERFACE_IMPLS.get(targetAsClass);
         Class<?>targetCls;
         if (ctrCls != null)
             targetCls = ctrCls;
@@ -328,7 +331,7 @@ public class ConvertingImpl implements C
         if (m == null)
             return null;
 
-        Class<?> ctrCls = interfaceImplementations.get(targetClass);
+        Class<?> ctrCls = INTERFACE_IMPLS.get(targetClass);
         if (ctrCls == null)
             ctrCls = targetClass;
 
@@ -454,16 +457,13 @@ 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) {
                             val = args[0];
-                            defaultUsed = true;
                         }
                     }
 
@@ -478,6 +478,11 @@ public class ConvertingImpl implements C
 
         Class<?> boxed = Util.primitiveToBoxed(cls);
         if (boxed.equals(cls)) {
+            if (cls.isArray()) {
+                return new Object[] {};
+            } else if (Collection.class.isAssignableFrom(cls)) {
+                return converter.convert(Collections.emptyList()).to(cls);
+            }
             // This is not a primitive, just return null
             return null;
         }
@@ -487,9 +492,9 @@ public class ConvertingImpl implements C
             return 0L;
         } else if (cls.equals(double.class) ) {
             return 0.0;
-        } else {
-            return 0;
         }
+
+        return 0;
     }
 
     private static boolean isDTOType(Class<?> cls) {
@@ -571,6 +576,20 @@ public class ConvertingImpl implements C
         } else if (Number.class.isAssignableFrom(targetAsClass)) {
             if (object instanceof Boolean) {
                 return ((Boolean) object).booleanValue() ? 1 : 0;
+            } else if (object instanceof Number) {
+                if (Byte.class.isAssignableFrom(targetAsClass)) {
+                    return ((Number) object).byteValue();
+                } else if (Short.class.isAssignableFrom(targetAsClass)) {
+                    return ((Number) object).shortValue();
+                } else if (Integer.class.isAssignableFrom(targetAsClass)) {
+                    return ((Number) object).intValue();
+                } else if (Long.class.isAssignableFrom(targetAsClass)) {
+                    return ((Number) object).longValue();
+                } else if (Float.class.isAssignableFrom(targetAsClass)) {
+                    return ((Number) object).floatValue();
+                } else if (Double.class.isAssignableFrom(targetAsClass)) {
+                    return ((Number) object).doubleValue();
+                }
             }
         } else if (Class.class.equals(targetAsClass)) {
             if (object instanceof Collection && ((Collection<?>) 
object).size() == 0) {
@@ -731,7 +750,7 @@ public class ConvertingImpl implements C
                 }
             }
             for (Class<?> intf : cls.getInterfaces()) {
-                Class<?> impl = interfaceImplementations.get(intf);
+                Class<?> impl = INTERFACE_IMPLS.get(intf);
                 if (impl != null)
                     return impl;
             }
@@ -804,16 +823,20 @@ public class ConvertingImpl implements C
             return null; // TODO
         else if (isDTOType(sourceCls) || sourceAsDTO)
             return createMapFromDTO(obj, converter);
-        else {
-            if (sourceAsJavaBean) {
-                Map<?,?> m = createMapFromBeanAccessors(obj, sourceCls);
-                if (m.size() > 0)
-                    return m;
-            }
-        }
+        else if (sourceAsJavaBean) {
+            Map<?,?> m = createMapFromBeanAccessors(obj, sourceCls);
+            if (m.size() > 0)
+                return m;
+        } else if (typeProhibitedFromMapView(sourceCls))
+            throw new ConversionException("No map view for " + obj);
+
         return createMapFromInterface(obj);
     }
 
+    private boolean typeProhibitedFromMapView(Class<?> sourceCls) {
+        return NO_MAP_VIEW_TYPES.contains(sourceCls);
+    }
+
     private static boolean isCopyRequiredType(Class<?> cls) {
         if (cls.isEnum())
             return false;

Modified: 
felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterBuilderTest.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterBuilderTest.java?rev=1787694&r1=1787693&r2=1787694&view=diff
==============================================================================
--- 
felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterBuilderTest.java
 (original)
+++ 
felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterBuilderTest.java
 Mon Mar 20 09:23:03 2017
@@ -19,27 +19,27 @@ package org.apache.felix.converter.impl;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 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.TypeReference;
+import org.osgi.util.converter.TypeRule;
+import org.osgi.util.function.Function;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
 
 public class ConverterBuilderTest {
     private Converter converter;
@@ -57,9 +57,12 @@ public class ConverterBuilderTest {
     @Test
     public void testStringArrayToStringAdapter() {
         ConverterBuilder cb = converter.newConverterBuilder();
-        Converter ca = cb.rule(String[].class, String.class,
-                v -> Stream.of(v).collect(Collectors.joining(",")),
-                v -> v.split(",")).build();
+        Converter ca = cb.
+                rule(new TypeRule<String[],String>(String[].class, 
String.class,
+                        v -> Stream.of(v).collect(Collectors.joining(",")))).
+                rule(new TypeRule<String,String[]>(String.class, 
String[].class,
+                        v -> v.split(","))).
+                build();
 
         assertEquals("A", converter.convert(new String[] {"A", 
"B"}).to(String.class));
         assertEquals("A,B", ca.convert(new String[] {"A", 
"B"}).to(String.class));
@@ -81,18 +84,9 @@ public class ConverterBuilderTest {
     @Test
     public void testSecondLevelAdapter() {
         ConverterBuilder cb = converter.newConverterBuilder();
-
-        cb.rule(char[].class, String.class, 
ConverterBuilderTest::convertToString, null);
-        cb.rule(new Rule<String, Number>(String.class, Number.class, new 
ConvertFunction<String, Number>() {
-            @Override
-            public Number convert(String obj, Type targetType) throws 
Exception {
-                if (Integer.class.equals(targetType))
-                    return Integer.valueOf(-1);
-                else if (Long.class.equals(targetType))
-                    return Long.valueOf(-1);
-                return null;
-            }
-        }));
+        cb.rule(new TypeRule<>(char[].class, String.class, 
ConverterBuilderTest::convertToString));
+        cb.rule(Integer.class, (f,t) -> -1);
+        cb.rule(Long.class, (f,t) -> -1L);
         Converter ca = cb.build();
 
         assertEquals("hi", ca.convert(new char[] {'h', 'i'}).to(String.class));
@@ -100,7 +94,8 @@ public class ConverterBuilderTest {
         assertEquals(Long.valueOf(-1), ca.convert("Hello").to(Long.class));
 
         // Shadow the Integer variant but keep Long going to the Number 
variant.
-        Converter ca2 = ca.newConverterBuilder().rule(String.class, 
Integer.class, v -> v.length(), null).build();
+        Converter ca2 = ca.newConverterBuilder().rule(
+                new TypeRule<String,Integer>(String.class, Integer.class, s -> 
s.length())).build();
         assertEquals(5, (int) ca2.convert("Hello").to(Integer.class));
         assertEquals(Long.valueOf(-1), ca2.convert("Hello").to(Long.class));
     }
@@ -108,14 +103,15 @@ public class ConverterBuilderTest {
     @Test
     public void testCannotHandleSpecific() {
         Converter ca = converter.newConverterBuilder().rule(
-                new Rule<Integer, Long>(Integer.class, Long.class, new 
ConvertFunction<Integer,Long>() {
-            @Override
-            public Long convert(Integer obj, Type targetType) throws Exception 
{
-                if (obj.intValue() != 1)
-                    return new Long(-obj.intValue());
-                return null;
-            }
-        })).build();
+            new TypeRule<>(Integer.class, Long.class, new 
Function<Integer,Long>() {
+                @Override
+                public Long apply(Integer obj) {
+                    if (obj.intValue() != 1)
+                        return new Long(-obj.intValue());
+                    return null;
+                }
+            })).build();
+
 
         assertEquals(Long.valueOf(-2), 
ca.convert(Integer.valueOf(2)).to(Long.class));
 
@@ -123,11 +119,15 @@ public class ConverterBuilderTest {
         assertEquals(Long.valueOf(1), 
ca.convert(Integer.valueOf(1)).to(Long.class));
     }
 
-    @Test @SuppressWarnings("rawtypes")
+    @Test
     public void testWildcardAdapter() {
-        ConvertFunction<List, Object> foo = new ConvertFunction<List, 
Object>() {
+        ConvertFunction<Object> foo = new ConvertFunction<Object>() {
             @Override
-            public Object convert(List t, Type type) throws Exception {
+            public Object convert(Object obj, Type type) throws Exception {
+                if (!(obj instanceof List))
+                    return null;
+
+                List<?> t = (List<?>) obj;
                 if (type instanceof Class) {
                     if (Number.class.isAssignableFrom((Class<?>) type))
                         return converter.convert(t.size()).to(type);
@@ -136,13 +136,9 @@ public class ConverterBuilderTest {
             }
         };
 
-        Rule<List, Object> r = new Rule<>(List.class, Object.class, foo);
-        Rule<Object, Object> allCatch = new Rule<>(Object.class, Object.class,
-                (v,t) -> v.toString());
-
         ConverterBuilder cb = converter.newConverterBuilder();
-        cb.rule(r);
-        cb.rule(allCatch);
+        cb.rule(foo);
+        cb.rule((v,t) -> v.toString());
         Converter ca = cb.build();
 
         assertEquals(3L, (long) ca.convert(Arrays.asList("a", "b", 
"c")).to(Long.class));
@@ -150,106 +146,66 @@ public class ConverterBuilderTest {
         assertEquals("[a, b, c]", ca.convert(Arrays.asList("a", "b", 
"c")).to(String.class));
     }
 
-    @Test @SuppressWarnings("rawtypes")
-    public void testWildcardAdapter2() {
-        Map<Object, Object> snooped = new HashMap<>();
-        Rule<Object, ArrayList> r = new Rule<>(Object.class, ArrayList.class,
-                (v,t) -> null,
-                (v,t) -> "arraylist");
-        Rule<Object, List> r2 = new Rule<>(Object.class, List.class,
-                (v,t) -> null,
-                (v,t) -> "list");
-        Rule<Object, Object> allCatch = new Rule<>(Object.class, Object.class,
-                (v,t) -> {snooped.put(v,t); return null;}, null);
+    @Test
+    public void testWildcardAdapter1() {
+        ConvertFunction<Object> foo = new ConvertFunction<Object>() {
+            @Override
+            public Object convert(Object obj, Type type) throws Exception {
+                if (!(obj instanceof List))
+                    return null;
+
+                List<?> t = (List<?>) obj;
+                if (type instanceof Class) {
+                    if (Number.class.isAssignableFrom((Class<?>) type))
+                        return converter.convert(t.size()).to(type);
+                }
+                return null;
+            }
+        };
 
         ConverterBuilder cb = converter.newConverterBuilder();
-        cb.rule(r);
-        cb.rule(r2);
-        cb.rule(allCatch);
+        cb.rule((v,t) -> converter.convert(1).to(t));
+        cb.rule(foo);
         Converter ca = cb.build();
 
-        assertEquals("Precondition", 0, snooped.size());
-        assertEquals("arraylist", ca.convert(
-                new ArrayList<String>(Arrays.asList("a", "b", 
"c"))).to(String.class));
-        assertEquals("Precondition", 0, snooped.size());
-        assertEquals("list",ca.convert(
-                new LinkedList<String>(Arrays.asList("a", "b", 
"c"))).to(String.class));
-        assertEquals("Precondition", 0, snooped.size());
-        assertEquals("a", ca.convert(
-                new HashSet<String>(Arrays.asList("a", "b", 
"c"))).to(String.class));
-        assertEquals(String.class, snooped.get(new 
HashSet<String>(Arrays.asList("a", "b", "c"))));
+        // The catchall converter should be called always because it can 
handle all and was registered first
+        assertEquals(1L, (long) ca.convert(Arrays.asList("a", "b", 
"c")).to(Long.class));
+        assertEquals(1, (int) ca.convert(Arrays.asList("a", "b", 
"c")).to(Integer.class));
+        assertEquals("1", ca.convert(Arrays.asList("a", "b", 
"c")).to(String.class));
     }
 
     @Test
-    public void testConvertAs() {
-        ConverterBuilder cb = converter.newConverterBuilder();
-        cb.rule(new Rule<>(MyIntf.class, MyCustomDTO.class,
-                (i, t) -> { MyCustomDTO dto = new MyCustomDTO(); dto.field = 
"" + i.value(); return dto; }));
-        cb.rule(new Rule<>(MyBean.class, MyCustomDTO.class,
-                (b, t) -> { MyCustomDTO dto = new MyCustomDTO(); dto.field = 
b.getValue(); return dto; }));
-        Converter cc = cb.build();
-
-        MyBean mb = new MyBean();
-        mb.intfVal = 17;
-        mb.beanVal = "Hello";
-
-        assertNull(converter.convert(mb).to(MyCustomDTO.class).field);
-        
assertNull(converter.convert(mb).sourceAs(MyIntf.class).to(MyCustomDTO.class).field);
-        assertEquals("Hello", cc.convert(mb).to(MyCustomDTO.class).field);
-        assertEquals("17", 
cc.convert(mb).sourceAs(MyIntf.class).to(MyCustomDTO.class).field);
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Test @Ignore("This test assumes that the all the embedded objects are 
also converted to maps, but they aren't")
-    public void testConvertWithKeysDeep() {
-        MyDTO6 subsubDTO1 = new MyDTO6();
-        subsubDTO1.chars = Arrays.asList('a', 'b', 'c');
-        MyDTO6 subsubDTO2 = new MyDTO6();
-        subsubDTO2.chars = Arrays.asList('z', 'z', 'z', 'z');
-        MyDTO6 subsubDTO3 = new MyDTO6();
-        subsubDTO3.chars = Arrays.asList('8');
-        MyDTO6 subsubDTO4 = new MyDTO6();
-        subsubDTO4.chars = Arrays.asList(' ');
-        MyDTO5 subDTO1 = new MyDTO5();
-        subDTO1.subsub1 = subsubDTO1;
-        subDTO1.subsub2 = subsubDTO2;
-        MyDTO5 subDTO2 = new MyDTO5();
-        subDTO2.subsub1 = subsubDTO3;
-        subDTO2.subsub2 = subsubDTO4;
-        MyDTO4 dto = new MyDTO4();
-        dto.sub1 = subDTO1;
-        dto.sub2 = subDTO2;
-
+    public void testWildcardAdapter2() {
+        Map<Object, Object> snooped = new HashMap<>();
         ConverterBuilder cb = converter.newConverterBuilder();
-        ConvertFunction<MyDTO6, Map> fun = new ConvertFunction<MyDTO6, Map>() {
-            @Override @SuppressWarnings("unchecked")
-            public Map convert(MyDTO6 obj, Type targetType) throws Exception {
-                StringBuilder sb = new StringBuilder();
-                for (Character c : obj.chars) {
-                    sb.append(c);
-                }
+        cb.rule(new Rule<String[],ArrayList<String>>(v -> {
+                Arrays.sort(v, Collections.reverseOrder());
+                return new ArrayList<>(Arrays.asList(v));
+            }) {});
+        cb.rule(new Rule<String[],List<String>>(v -> {
+                Arrays.sort(v, Collections.reverseOrder());
+                return new CopyOnWriteArrayList<>(Arrays.asList(v));
+            }) {});
+        cb.rule((v,t) -> { snooped.put(v,t); return null;});
+        Converter ca = cb.build();
 
-                Map m = new HashMap();
-                m.put("chars", sb.toString());
-                return m;
-            }
-        };
-        cb.rule(new Rule<MyDTO6, Map>(new TypeReference<MyDTO6>() {},
-                new TypeReference<Map>() {}, fun));
-        Converter c = cb.build();
-
-        Map m = c.convert(dto).to(Map.class);
-        assertEquals(2, m.size());
-        Map m1 = (Map) m.get("sub1");
-        Map m2 = (Map) m.get("sub2");
-        Map m11 = (Map) m1.get("subsub1");
-        assertEquals("abc", m11.get("chars"));
-        Map m12 = (Map) m1.get("subsub2");
-        assertEquals("zzzz", m12.get("chars"));
-        Map m21 = (Map) m2.get("subsub1");
-        assertEquals("String should be doubled by special converter rule", 
"88", m21.get("chars"));
-        Map m22 = (Map) m2.get("subsub2");
-        assertEquals(" ", m22.get("chars"));
+        assertEquals(new ArrayList<>(Arrays.asList("c", "b", "a")), ca.convert(
+                new String [] {"a", "b", "c"}).to(ArrayList.class));
+        assertEquals("Precondition", 0, snooped.size());
+        String[] sa0 = new String [] {"a", "b", "c"};
+        assertEquals(new LinkedList<>(Arrays.asList("a", "b", "c")), 
ca.convert(
+                sa0).to(LinkedList.class));
+        assertEquals(1, snooped.size());
+        assertEquals(LinkedList.class, snooped.get(sa0));
+        assertEquals(new CopyOnWriteArrayList<>(Arrays.asList("c", "b", "a")), 
ca.convert(
+                new String [] {"a", "b", "c"}).to(List.class));
+
+        snooped.clear();
+        String[] sa = new String [] {"a", "b", "c"};
+        assertEquals(new CopyOnWriteArrayList<>(Arrays.asList("a", "b", "c")), 
ca.convert(
+                sa).to(CopyOnWriteArrayList.class));
+        assertEquals(1, snooped.size());
+        assertEquals(CopyOnWriteArrayList.class, snooped.get(sa));
     }
 
     static interface MyIntf {

Modified: 
felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java?rev=1787694&r1=1787693&r2=1787694&view=diff
==============================================================================
--- 
felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java
 (original)
+++ 
felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java
 Mon Mar 20 09:23:03 2017
@@ -18,7 +18,6 @@ package org.apache.felix.converter.impl;
 
 import java.math.BigInteger;
 import java.net.URL;
-import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Collections;
 import java.util.Date;
@@ -32,6 +31,7 @@ import org.junit.Ignore;
 import org.junit.Test;
 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;
 
@@ -105,13 +105,14 @@ public class ConverterMapTest {
         mb.setEnabled(true);
 
         ConverterBuilder cb = new StandardConverter().newConverterBuilder();
-        cb.rule(Date.class, String.class, v -> sdf.format(v), v -> {
+        cb.rule(new Rule<Date,String>(v -> sdf.format(v)) {});
+        cb.rule(new Rule<String,Date>(v -> {
             try {
                 return sdf.parse(v);
-            } catch (ParseException e) {
-                throw new RuntimeException(e);
+            } catch (Exception ex) {
+                return null;
             }
-        });
+        }) {});
         Converter ca = cb.build();
         Map<String, String> m = ca.convert(mb).sourceAsBean().to(new 
TypeReference<Map<String, String>>(){});
         assertEquals("true", m.get("enabled"));

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=1787694&r1=1787693&r2=1787694&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
 Mon Mar 20 09:23:03 2017
@@ -301,7 +301,7 @@ public class ConverterTest {
     @Test
     public void testExceptionDefaultValue() {
         assertEquals(42, (int) 
converter.convert("haha").defaultValue(42).to(int.class));
-        assertNull(converter.convert("haha").defaultValue(null).to(int.class));
+        assertEquals(999, (int) 
converter.convert("haha").defaultValue(999).to(int.class));
         try {
             converter.convert("haha").to(int.class);
             fail("Should have thrown an exception");
@@ -323,9 +323,9 @@ public class ConverterTest {
     @Test
     public void testCustomStringArrayConversion() {
         ConverterBuilder cb = converter.newConverterBuilder();
-        cb.rule(String[].class, String.class,
-                v -> Stream.of(v).collect(Collectors.joining(",")),
-                v -> v.split(","));
+        cb.rule(new Rule<String[],String>(v -> 
Stream.of(v).collect(Collectors.joining(","))){});
+        cb.rule(new Rule<String,String[]>(v -> v.split(",")){});
+
         Converter adapted = cb.build();
 
         String[] sa = {"A", "B"};
@@ -336,9 +336,8 @@ public class ConverterTest {
     @Test
     public void testCustomIntArrayConversion() {
         ConverterBuilder cb = converter.newConverterBuilder();
-        cb.rule(int[].class, String.class,
-                v -> 
Arrays.stream(v).mapToObj(Integer::toString).collect(Collectors.joining(",")),
-                v -> 
Arrays.stream(v.split(",")).mapToInt(Integer::parseInt).toArray());
+        cb.rule(String.class, (f,t) -> f instanceof int[] ? Arrays.stream((int 
[]) f).mapToObj(Integer::toString).collect(Collectors.joining(",")) : null);
+        cb.rule(int[].class, (f,t) -> f instanceof String ? 
Arrays.stream(((String) f).split(",")).mapToInt(Integer::parseInt).toArray() : 
null);
         Converter adapted = cb.build();
 
         int[] ia = {1, 2};
@@ -348,14 +347,14 @@ public class ConverterTest {
 
     @Test
     public void testCustomErrorHandling() {
-        ConvertFunction<String,Integer> func = new 
ConvertFunction<String,Integer>() {
+        ConvertFunction<Integer> func = new ConvertFunction<Integer>() {
             @Override
-            public Integer convert(String obj, Type targetType) throws 
Exception {
+            public Integer convert(Object obj, Type targetType) throws 
Exception {
                 return null;
             }
 
             @Override
-            public Integer handleError(String obj, Type targetType) {
+            public Integer handleError(Object obj, Type targetType) {
                 if ("hello".equals(obj)) {
                     return -1;
                 }
@@ -364,8 +363,7 @@ public class ConverterTest {
         };
 
         ConverterBuilder cb = converter.newConverterBuilder();
-        cb.rule(new Rule<>(String.class, Integer.class, func));
-        Converter adapted = cb.build();
+        Converter adapted = cb.rule(Integer.class, func).build();
 
         assertEquals(new Integer(12), adapted.convert("12").to(Integer.class));
         assertEquals(new Integer(-1), 
adapted.convert("hello").to(Integer.class));


Reply via email to