Author: davidb Date: Mon Jan 23 02:41:12 2017 New Revision: 1779874 URL: http://svn.apache.org/viewvc?rev=1779874&view=rev Log: FELIX-5475 Implement sourceAsDTO() and targetAsDTO()
Patch applied on behalf of David Leangen with many thanks! Added: felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/MyDTO8.java Modified: 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/ConverterTest.java 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=1779874&r1=1779873&r2=1779874&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 Jan 23 02:41:12 2017 @@ -70,6 +70,10 @@ public class ConvertingImpl implements C private List<Object> keys = new ArrayList<>(); private volatile Object root; private volatile boolean sourceAsJavaBean = false; + @SuppressWarnings( "unused" ) + private volatile boolean targetAsJavaBean = false; + private volatile boolean sourceAsDTO = false; + private volatile boolean targetAsDTO = false; ConvertingImpl(InternalConverter c, Object obj) { converter = c; @@ -84,13 +88,17 @@ public class ConvertingImpl implements C @Override public Converting sourceAsBean() { + // To avoid ambiguity, reset any instruction to sourceAsDTO + sourceAsDTO = false; sourceAsJavaBean = true; return this; } @Override public Converting sourceAsDTO() { - // TODO Implement + // To avoid ambiguity, reset any instruction to sourceAsJavaBean + sourceAsJavaBean = false; + sourceAsDTO = true; return this; } @@ -102,13 +110,17 @@ public class ConvertingImpl implements C @Override public Converting targetAsBean() { - // TODO not yet implemented + // To avoid ambiguity, reset any instruction to targetAsDTO + targetAsDTO = false; + targetAsJavaBean = true; return this; } @Override public Converting targetAsDTO() { - // TODO Implement + // To avoid ambiguity, reset any instruction to targetAsJavaBean + targetAsJavaBean = false; + targetAsDTO = true; return this; } @@ -142,6 +154,7 @@ public class ConvertingImpl implements C return this; } + @SuppressWarnings( "unchecked" ) @Override public void setConverter(Converter c) { if (c instanceof InternalConverter) @@ -190,6 +203,11 @@ public class ConvertingImpl implements C sourceClass = sourceAsClass != null ? sourceAsClass : object.getClass(); + // Temporary - to remove next commit!! + // This is just to catch any old code that may still be using {source|target}As(DTO.class) + if(DTO.class.equals(sourceClass) || DTO.class.equals(targetAsClass)) + throw new RuntimeException("To update!!"); + if (!isCopyRequiredType(targetAsClass) && targetAsClass.isAssignableFrom(sourceClass)) { return object; } @@ -202,7 +220,7 @@ public class ConvertingImpl implements C return convertToArray(); } else if (Collection.class.isAssignableFrom(targetAsClass)) { return convertToCollection(); - } else if (isDTOType(targetAsClass)) { + } else if (isDTOType(targetAsClass) || ((sourceAsDTO || targetAsDTO) && DTO.class.isAssignableFrom(targetActualClass))) { return convertToDTO(); } else if (isMapType(targetAsClass)) { return convertToMapType(); @@ -292,16 +310,19 @@ public class ConvertingImpl implements C private <T> T convertToDTO() { Map m = mapView(object, sourceClass, converter); + Class<?> cls = targetAsClass; + if (targetAsDTO) + cls = targetActualClass; try { T dto = (T) targetActualClass.newInstance(); for (Map.Entry entry : (Set<Map.Entry>) m.entrySet()) { Field f = null; try { - f = targetAsClass.getDeclaredField(mangleName(entry.getKey().toString())); + f = cls.getDeclaredField(mangleName(entry.getKey().toString())); } catch (NoSuchFieldException e) { try { - f = targetAsClass.getField(mangleName(entry.getKey().toString())); + f = cls.getField(mangleName(entry.getKey().toString())); } catch (NoSuchFieldException e1) { // There is not field with this name } @@ -309,7 +330,11 @@ public class ConvertingImpl implements C if (f != null) { Object val = entry.getValue(); - f.set(dto, converter.convert(val).to(f.getType())); + if (sourceAsDTO && DTO.class.isAssignableFrom(f.getType())) + val = converter.convert(val).sourceAsDTO().to(f.getType()); + else + val = converter.convert(val).to(f.getType()); + f.set(dto, val); } } @@ -355,7 +380,11 @@ public class ConvertingImpl implements C if (isCopyRequiredType(cls)) { cls = getConstructableType(cls); } - value = converter.convert(value).key(ka).to(cls); + if (sourceAsDTO && DTO.class.isAssignableFrom(cls)) + // sourceAsDTO or sourceAsClass??? + value = converter.convert(value).key(ka).sourceAsDTO().to(cls); + else + value = converter.convert(value).key(ka).to(cls); } } instance.put(key, value); @@ -839,11 +868,11 @@ public class ConvertingImpl implements C } private Map<?,?> mapView(Object obj, Class<?> sourceCls, InternalConverter converter) { - if (Map.class.isAssignableFrom(sourceCls)) + if (Map.class.isAssignableFrom(sourceCls) || (DTO.class.isAssignableFrom(sourceCls) && obj instanceof Map)) return (Map<?,?>) obj; else if (Dictionary.class.isAssignableFrom(sourceCls)) return null; // TODO - else if (isDTOType(sourceCls)) + else if (isDTOType(sourceCls) || sourceAsDTO) return createMapFromDTO(obj, converter); else { if (sourceAsJavaBean) { @@ -856,6 +885,8 @@ public class ConvertingImpl implements C } private static boolean isCopyRequiredType(Class<?> cls) { + if (cls.isEnum()) + return false; return Map.class.isAssignableFrom(cls) || Collection.class.isAssignableFrom(cls) || DTO.class.isAssignableFrom(cls) || 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=1779874&r1=1779873&r2=1779874&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 Jan 23 02:41:12 2017 @@ -52,6 +52,7 @@ import org.apache.felix.converter.impl.M import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.osgi.dto.DTO; import org.osgi.util.converter.ConversionException; import org.osgi.util.converter.Converter; import org.osgi.util.converter.ConverterBuilder; @@ -462,6 +463,72 @@ public class ConverterTest { assertEquals(Alpha.A, e.get("alpha")); } + @Test + public void testDTO2Map2() { + MyEmbeddedDTO embedded = new MyEmbeddedDTO(); + embedded.marco = "hohoho"; + embedded.polo = Long.MAX_VALUE; + embedded.alpha = Alpha.A; + + MyDTO dto = new MyDTO(); + dto.ping = "lalala"; + dto.pong = Long.MIN_VALUE; + dto.count = Count.ONE; + dto.embedded = embedded; + + @SuppressWarnings("rawtypes") + Map m = converter.convert(dto).sourceAsDTO().to(Map.class); + assertEquals(4, m.size()); + assertEquals("lalala", m.get("ping")); + assertEquals(Long.MIN_VALUE, m.get("pong")); + assertEquals(Count.ONE, m.get("count")); + assertNotNull(m.get("embedded")); + @SuppressWarnings("rawtypes") + Map e = (Map)m.get("embedded"); + assertEquals("hohoho", e.get("marco")); + assertEquals(Long.MAX_VALUE, e.get("polo")); + assertEquals(Alpha.A, e.get("alpha")); + } + + @Test + public void testDTO2Map3() { + MyEmbeddedDTO embedded2 = new MyEmbeddedDTO(); + embedded2.marco = "hohoho"; + embedded2.polo = Long.MAX_VALUE; + embedded2.alpha = Alpha.A; + + MyDTOWithMethods embedded = new MyDTOWithMethods(); + embedded.ping = "lalala"; + embedded.pong = Long.MIN_VALUE; + embedded.count = Count.ONE; + embedded.embedded = embedded2; + + MyDTO8 dto = new MyDTO8(); + dto.ping = "lalala"; + dto.pong = Long.MIN_VALUE; + dto.count = MyDTO8.Count.ONE; + dto.embedded = embedded; + + @SuppressWarnings("rawtypes") + Map m = converter.convert(dto).sourceAsDTO().to(Map.class); + assertEquals(4, m.size()); + assertEquals("lalala", m.get("ping")); + assertEquals(Long.MIN_VALUE, m.get("pong")); + assertEquals(MyDTO8.Count.ONE, m.get("count")); + assertNotNull(m.get("embedded")); + assertTrue(m.get( "embedded" ) instanceof MyDTOWithMethods); + MyDTOWithMethods e = (MyDTOWithMethods)m.get("embedded"); + assertEquals("lalala", e.ping); + assertEquals(Long.MIN_VALUE, e.pong); + assertEquals(Count.ONE, e.count); + assertNotNull(e.embedded); + assertTrue(e.embedded instanceof MyEmbeddedDTO); + MyEmbeddedDTO e2 = (MyEmbeddedDTO)e.embedded; + assertEquals("hohoho", e2.marco); + assertEquals(Long.MAX_VALUE, e2.polo); + assertEquals(Alpha.A, e2.alpha); + } + @Test @SuppressWarnings({ "rawtypes", "unchecked" }) public void testDTOFieldShadowing() { MySubDTO dto = new MySubDTO(); @@ -603,7 +670,7 @@ public class ConverterTest { } @Test - public void testConvertAs1() { + public void testConvertAsInterface() { MyBean mb = new MyBean(); mb.intfVal = 17; mb.beanVal = "Hello"; @@ -613,7 +680,7 @@ public class ConverterTest { } @Test - public void testConvertAs2() { + public void testConvertAsBean() { MyBean mb = new MyBean(); mb.intfVal = 17; mb.beanVal = "Hello"; @@ -623,6 +690,14 @@ public class ConverterTest { } @Test + public void testConvertAsDTO() { + MyClass3 mc3 = new MyClass3(17); + + assertEquals(17, + converter.convert(mc3).sourceAsDTO().to(Map.class).get("value")); + } + + @Test public void testDTONameMangling() { Map<String,String> m = new HashMap<>(); m.put("org.osgi.framework.uuid", "test123"); @@ -680,4 +755,17 @@ public class ConverterTest { return beanVal; } } + + static class MyClass3 { + public int value; + public String string = "String"; + + public MyClass3( int value ) { + this.value = value; + } + + public int value() { + return value; + } + } } Added: felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/MyDTO8.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/MyDTO8.java?rev=1779874&view=auto ============================================================================== --- felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/MyDTO8.java (added) +++ felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/MyDTO8.java Mon Jan 23 02:41:12 2017 @@ -0,0 +1,32 @@ +/* + * 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.apache.felix.converter.impl; + +import org.osgi.dto.DTO; + +public class MyDTO8 extends DTO { + public enum Count { ONE, TWO, THREE } + + public Count count; + + public String ping; + + public long pong; + + public MyDTOWithMethods embedded; +} +