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/11/16 23:32:55 UTC
svn commit: r1815525 - in /felix/trunk/converter/converter/src:
main/java/org/osgi/util/converter/ConvertingImpl.java
test/java/org/osgi/util/converter/ConverterTest.java
Author: davidb
Date: Thu Nov 16 23:32:55 2017
New Revision: 1815525
URL: http://svn.apache.org/viewvc?rev=1815525&view=rev
Log:
Support additional collection interfaces in the converter.
Modified:
felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/ConvertingImpl.java
felix/trunk/converter/converter/src/test/java/org/osgi/util/converter/ConverterTest.java
Modified: felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/ConvertingImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/ConvertingImpl.java?rev=1815525&r1=1815524&r2=1815525&view=diff
==============================================================================
--- felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/ConvertingImpl.java (original)
+++ felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/ConvertingImpl.java Thu Nov 16 23:32:55 2017
@@ -29,6 +29,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Deque;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
@@ -36,22 +37,47 @@ import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.Queue;
import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentNavigableMap;
+import java.util.concurrent.ConcurrentSkipListMap;
/**
- * @author $Id: d83ff45e4ee09ebafe6704e71cc66c53d75583dd $
+ * @author $Id: 6f9d6ee446aafb1de4c8f52537248a3180965f54 $
*/
class ConvertingImpl extends AbstractSpecifying<Converting> implements Converting, InternalConverting {
private static final Map<Class<?>, Class<?>> INTERFACE_IMPLS;
static {
Map<Class<?>, Class<?>> m = new HashMap<>();
m.put(Collection.class, ArrayList.class);
+ // Lists
m.put(List.class, ArrayList.class);
+ // Sets
m.put(Set.class, LinkedHashSet.class); // preserves insertion order
+ m.put(NavigableSet.class, TreeSet.class);
+ m.put(SortedSet.class, TreeSet.class);
+ // Maps
m.put(Map.class, LinkedHashMap.class); // preserves insertion order
+ m.put(ConcurrentMap.class, ConcurrentHashMap.class);
+ m.put(ConcurrentNavigableMap.class, ConcurrentSkipListMap.class);
+ m.put(NavigableMap.class, TreeMap.class);
+ m.put(SortedMap.class, TreeMap.class);
+ // Queues
+ m.put(Queue.class, LinkedList.class);
+ m.put(Deque.class, LinkedList.class);
+
INTERFACE_IMPLS = Collections.unmodifiableMap(m);
}
private static final Collection<Class<?>> NO_MAP_VIEW_TYPES;
@@ -332,6 +358,7 @@ class ConvertingImpl extends AbstractSpe
for (Map.Entry entry : (Set<Entry>) m.entrySet()) {
Object key = entry.getKey();
Object value = entry.getValue();
+ key = convertMapKey(key);
value = convertMapValue(value);
instance.put(key, value);
}
@@ -339,39 +366,39 @@ class ConvertingImpl extends AbstractSpe
return instance;
}
- Object convertMapKey(Object key) {
- return convertMapElement(key, 0);
- }
+ Object convertMapKey(Object key) {
+ return convertMapElement(key, 0);
+ }
Object convertMapValue(Object value) {
- return convertMapElement(value, 1);
- }
+ return convertMapElement(value, 1);
+ }
+
+ private Object convertMapElement(Object element, int typeIdx) {
+ Type targetType = null;
+ if (typeArguments != null && typeArguments.length > typeIdx) {
+ targetType = typeArguments[typeIdx];
+ }
+
+ if (element != null) {
+ if (targetType != null) {
+ element = converter.convert(element).to(targetType);
+ } else {
+ Class< ? > cls = element.getClass();
+ if (isCopyRequiredType(cls)) {
+ cls = getConstructableType(cls);
+ }
- private Object convertMapElement(Object element, int typeIdx) {
- Type targetType = null;
- if (typeArguments != null && typeArguments.length > typeIdx) {
- targetType = typeArguments[typeIdx];
- }
-
- if (element != null) {
- if (targetType != null) {
- element = converter.convert(element).to(targetType);
- } else {
- Class< ? > cls = element.getClass();
- if (isCopyRequiredType(cls)) {
- cls = getConstructableType(cls);
- }
-
- if (sourceAsDTO || DTOUtil.isDTOType(cls))
- element = converter.convert(element).sourceAsDTO().to(cls);
- else
- element = converter.convert(element).to(cls);
- }
- }
- return element;
- }
+ if (sourceAsDTO || DTOUtil.isDTOType(cls))
+ element = converter.convert(element).sourceAsDTO().to(cls);
+ else
+ element = converter.convert(element).to(cls);
+ }
+ }
+ return element;
+ }
- @SuppressWarnings({ "unchecked", "rawtypes" })
+ @SuppressWarnings({ "unchecked", "rawtypes" })
private Map convertToMapDelegate() {
if (Map.class.isAssignableFrom(sourceClass)) {
return MapDelegate.forMap((Map) object, this);
@@ -386,7 +413,10 @@ class ConvertingImpl extends AbstractSpe
}
// Assume it's an interface
- return MapDelegate.forInterface(object, this);
+ if (object.getClass().getInterfaces().length > 0) {
+ return MapDelegate.forInterface(object, this);
+ }
+ return null;
}
@SuppressWarnings("rawtypes")
@@ -456,7 +486,8 @@ class ConvertingImpl extends AbstractSpe
final Map m = mapView(object, sourceCls, converter);
return Proxy.newProxyInstance(targetCls.getClassLoader(), new Class[] {targetCls},
new InvocationHandler() {
- @Override
+ @SuppressWarnings("boxing")
+ @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Class<?> mdDecl = method.getDeclaringClass();
if (mdDecl.equals(Object.class))
@@ -512,7 +543,8 @@ class ConvertingImpl extends AbstractSpe
});
}
- private Object handleNull(Class<?> cls) {
+ @SuppressWarnings("boxing")
+ private Object handleNull(Class< ? > cls) {
if (hasDefault)
return converter.convert(defaultValue).to(cls);
@@ -544,6 +576,7 @@ class ConvertingImpl extends AbstractSpe
return Dictionary.class.isAssignableFrom(cls);
}
+ @SuppressWarnings("boxing")
private Object trySpecialCases() {
if (Boolean.class.equals(targetAsClass)) {
if (object instanceof Collection && ((Collection<?>) object).size() == 0) {
@@ -610,6 +643,7 @@ class ConvertingImpl extends AbstractSpe
Constructor<?> ctr = targetAsClass.getConstructor(String.class);
return (T) ctr.newInstance(object.toString());
} catch (Exception e2) {
+ // Ignore
}
}
return null;
@@ -662,16 +696,16 @@ class ConvertingImpl extends AbstractSpe
}
@SuppressWarnings("rawtypes")
- private Map createMapFromDTO(Object obj, InternalConverter converter) {
+ private Map createMapFromDTO(Object obj, InternalConverter ic) {
Set<String> handledFields = new HashSet<>();
Map result = new HashMap();
// Do we need 'declaredfields'? We only need to look at the public ones...
for (Field f : obj.getClass().getDeclaredFields()) {
- handleDTOField(obj, f, handledFields, result, converter);
+ handleDTOField(obj, f, handledFields, result, ic);
}
for (Field f : obj.getClass().getFields()) {
- handleDTOField(obj, f, handledFields, result, converter);
+ handleDTOField(obj, f, handledFields, result, ic);
}
return result;
}
@@ -689,7 +723,9 @@ class ConvertingImpl extends AbstractSpe
throw new ConversionException("Cannot be converted to map: " + obj);
}
- private static Object createMapOrCollection(Class<?> cls, int initialSize) {
+ @SuppressWarnings("boxing")
+ private static Object createMapOrCollection(Class< ? > cls,
+ int initialSize) {
try {
Constructor<?> ctor = cls.getConstructor(int.class);
return ctor.newInstance(initialSize);
@@ -735,7 +771,7 @@ class ConvertingImpl extends AbstractSpe
@SuppressWarnings({ "rawtypes", "unchecked" })
private void handleDTOField(Object obj, Field field, Set<String> handledFields, Map result,
- InternalConverter converter) {
+ InternalConverter ic) {
String fn = Util.getDTOKey(field);
if (fn == null)
return;
@@ -748,6 +784,7 @@ class ConvertingImpl extends AbstractSpe
result.put(fn, fVal);
handledFields.add(fn);
} catch (Exception e) {
+ // Ignore
}
}
@@ -764,6 +801,7 @@ class ConvertingImpl extends AbstractSpe
res.put(bp, md.invoke(obj));
invokedMethods.add(bp);
} catch (Exception e) {
+ // Ignore
}
}
@@ -785,16 +823,17 @@ class ConvertingImpl extends AbstractSpe
res.put(propName, r);
invokedMethods.add(mn);
} catch (Exception e) {
+ // Ignore
}
}
- private Map<?,?> mapView(Object obj, Class<?> sourceCls, InternalConverter converter) {
+ private Map<?,?> mapView(Object obj, Class<?> sourceCls, InternalConverter ic) {
if (Map.class.isAssignableFrom(sourceCls) || (DTOUtil.isDTOType(sourceCls) && obj instanceof Map))
return (Map<?,?>) obj;
else if (Dictionary.class.isAssignableFrom(sourceCls))
return MapDelegate.forDictionary((Dictionary<?,?>) object, this);
else if (DTOUtil.isDTOType(sourceCls) || sourceAsDTO)
- return createMapFromDTO(obj, converter);
+ return createMapFromDTO(obj, ic);
else if (sourceAsJavaBean) {
Map<?,?> m = createMapFromBeanAccessors(obj, sourceCls);
if (m.size() > 0)
Modified: felix/trunk/converter/converter/src/test/java/org/osgi/util/converter/ConverterTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/test/java/org/osgi/util/converter/ConverterTest.java?rev=1815525&r1=1815524&r2=1815525&view=diff
==============================================================================
--- felix/trunk/converter/converter/src/test/java/org/osgi/util/converter/ConverterTest.java (original)
+++ felix/trunk/converter/converter/src/test/java/org/osgi/util/converter/ConverterTest.java Thu Nov 16 23:32:55 2017
@@ -31,8 +31,10 @@ import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
+import java.util.Collection;
import java.util.Collections;
import java.util.Date;
+import java.util.Deque;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
@@ -43,9 +45,16 @@ import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.Queue;
import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
import java.util.TimeZone;
import java.util.UUID;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentNavigableMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -832,6 +841,45 @@ public class ConverterTest {
assertEquals(new HashMap<String,String>(m), new HashMap<String,String>(m2));
}
+ @Test
+ public void testCollectionInterfaceMapping() {
+ Collection<?> coll = converter.convert("test").to(Collection.class);
+ assertEquals("test", coll.iterator().next());
+
+ List<?> list = converter.convert("test").copy().to(List.class);
+ assertEquals("test", list.iterator().next());
+
+ Set<?> set = converter.convert("test").to(Set.class);
+ assertEquals("test", set.iterator().next());
+
+ NavigableSet<?> ns = converter.convert("test").to(NavigableSet.class);
+ assertEquals("test", ns.iterator().next());
+
+ SortedSet<?> ss = converter.convert("test").to(SortedSet.class);
+ assertEquals("test", ss.iterator().next());
+
+ Queue<?> q = converter.convert("test").to(Queue.class);
+ assertEquals("test", q.iterator().next());
+
+ Deque<?> dq = converter.convert("test").to(Deque.class);
+ assertEquals("test", dq.iterator().next());
+
+ Map<?,?> m = converter.convert(Collections.singletonMap("x", "y")).copy().to(Map.class);
+ assertEquals("y", m.get("x"));
+
+ ConcurrentMap<?,?> cm = converter.convert(Collections.singletonMap("x", "y")).copy().to(ConcurrentMap.class);
+ assertEquals("y", cm.get("x"));
+
+ ConcurrentNavigableMap<?,?> cnm = converter.convert(Collections.singletonMap("x", "y")).copy().to(ConcurrentNavigableMap.class);
+ assertEquals("y", cnm.get("x"));
+
+ NavigableMap<?,?> nm = converter.convert(Collections.singletonMap("x", "y")).copy().to(NavigableMap.class);
+ assertEquals("y", nm.get("x"));
+
+ SortedMap<?,?> sm = converter.convert(Collections.singletonMap("x", "y")).copy().to(SortedMap.class);
+ assertEquals("y", sm.get("x"));
+ }
+
@SuppressWarnings("unchecked")
@Test
public void testLiveMapFromInterface() {