From e833950d38330edf97f3fb65c327bd0600d084e4 Mon Sep 17 00:00:00 2001 From: Tim Ward Date: Fri, 22 Dec 2017 09:49:14 +0000 Subject: [PATCH] [converter] Avoid losing generics information in nested types Signed-off-by: Tim Ward --- .../osgi/util/converter/ConvertingImpl.java | 6 +-- .../osgi/util/converter/ConverterTest.java | 52 +++++++++++++++++++ .../util/converter/MyGenericInterface.java | 23 ++++++++ 3 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 converter/converter/src/test/java/org/osgi/util/converter/MyGenericInterface.java 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 a566cd88c79..0d4afbc6655 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 @@ -399,7 +399,7 @@ private T convertToDTO(Class< ? > sourceCls, Class< ? > targetAsCls) { val = converter.convert(val).sourceAsDTO().to( f.getType()); else - val = converter.convert(val).to(f.getType()); + val = converter.convert(val).to(f.getGenericType()); f.set(dto, val); } } @@ -662,7 +662,7 @@ public Object invoke(Object proxy, Method method, Object[] args) if (propName == null) return null; - Class< ? > targetType = method.getReturnType(); +// Class< ? > targetType = method.getReturnType(); Object val = m.get(propName); if (val == null && keysIgnoreCase) { @@ -692,7 +692,7 @@ public Object invoke(Object proxy, Method method, Object[] args) } } - return converter.convert(val).to(targetType); + return converter.convert(val).to(method.getGenericReturnType()); } }); } 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 d73f6e70b86..eaeff3f9e26 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 @@ -749,6 +749,49 @@ public void testDTOWithGenerics() { assertEquals(dto2SubAAA.charSet, new HashSet(Arrays.asList('b', 'a', 'r'))); } + @Test + public void testMapToDTOWithGenerics() { + Map dto = new HashMap<>(); + + dto.put("longList", Arrays.asList((short)999, "1000")); + + Map dtoMap = new LinkedHashMap<>(); + dto.put("dtoMap", dtoMap); + + Map subDTO1 = new HashMap<>(); + subDTO1.put("charSet", new HashSet<>(Arrays.asList("foo", (int) 'o', 'o'))); + dtoMap.put("zzz", subDTO1); + + Map subDTO2 = new HashMap<>(); + subDTO2.put("charSet", new HashSet<>(Arrays.asList('b', 'a', 'r'))); + dtoMap.put("aaa", subDTO2); + + MyDTO2 converted = converter.convert(dto).to(MyDTO2.class); + + assertEquals(Arrays.asList(999L, 1000L), converted.longList); + Map nestedMap = converted.dtoMap; + + // Check iteration order is preserved by iterating + int i=0; + for (Iterator> it = nestedMap.entrySet().iterator(); it.hasNext(); i++) { + Map.Entry entry = it.next(); + switch (i) { + case 0: + assertEquals("zzz", entry.getKey()); + MyDTO3 dto1 = entry.getValue(); + assertEquals(new HashSet(Arrays.asList('f', 'o')), dto1.charSet); + break; + case 1: + assertEquals("aaa", entry.getKey()); + MyDTO3 dto2 = entry.getValue(); + assertEquals(new HashSet(Arrays.asList('b', 'a', 'r')), dto2.charSet); + break; + default: + fail("Unexpected number of elements on map"); + } + } + } + @Test public void testMapToDTOWithSurplusMapFiels() { Map m = new HashMap<>(); @@ -1134,6 +1177,15 @@ public void testLongArrayToLongCollection() { assertEquals(la[i], it.next()); } } + + @Test + public void testMapToInterfaceWithGenerics() { + Map dto = new HashMap<>(); + dto.put("charSet", new HashSet<>(Arrays.asList("foo", (int) 'o', 'o'))); + + MyGenericInterface converted = converter.convert(dto).to(MyGenericInterface.class); + assertEquals(new HashSet(Arrays.asList('f', 'o')), converted.charSet()); + } static class MyClass2 { private final String value; diff --git a/converter/converter/src/test/java/org/osgi/util/converter/MyGenericInterface.java b/converter/converter/src/test/java/org/osgi/util/converter/MyGenericInterface.java new file mode 100644 index 00000000000..0aa4fee7e27 --- /dev/null +++ b/converter/converter/src/test/java/org/osgi/util/converter/MyGenericInterface.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.osgi.util.converter; + +import java.util.Set; + +public interface MyGenericInterface { + public Set charSet(); +}