Author: davidb Date: Wed Jun 29 17:36:33 2016 New Revision: 1750685 URL: http://svn.apache.org/viewvc?rev=1750685&view=rev Log: Felix Converter Service - added some support for exceptions and defaults.
Added: felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/Util.java Modified: felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConverterService.java felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterServiceTest.java Modified: felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java?rev=1750685&r1=1750684&r2=1750685&view=diff ============================================================================== --- felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java (original) +++ felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java Wed Jun 29 17:36:33 2016 @@ -23,6 +23,7 @@ import java.util.concurrent.ConcurrentHa import java.util.function.Function; import org.osgi.service.converter.Adapter; +import org.osgi.service.converter.ConversionException; import org.osgi.service.converter.Converter; import org.osgi.service.converter.Converting; import org.osgi.service.converter.Rule; @@ -81,6 +82,8 @@ public class AdapterImpl implements Adap private class ConvertingWrapper implements Converting { private final Converting del; private final Object object; + private volatile Object defaultValue; + private volatile boolean hasDefault; ConvertingWrapper(Object obj, Converting c) { object = obj; @@ -90,6 +93,8 @@ public class AdapterImpl implements Adap @Override public Converting defaultValue(Object defVal) { del.defaultValue(defVal); + defaultValue = defVal; + hasDefault = true; return this; } @@ -109,9 +114,18 @@ public class AdapterImpl implements Adap @Override public Object to(Type type) { if (object != null) { - Function<Object, Object> f = classRules.get(new TypePair(object.getClass(), type)); - if (f != null) - return f.apply(object); + Function<Object, Object> f = classRules.get( + new TypePair(object.getClass(), Util.primitiveToBoxed(type))); + if (f != null) { + try { + return f.apply(object); + } catch (Exception ex) { + if (hasDefault) + return defaultValue; + else + throw new ConversionException("Cannot convert " + object + " to " + type, ex); + } + } } return del.to(type); Modified: felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConverterService.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConverterService.java?rev=1750685&r1=1750684&r2=1750685&view=diff ============================================================================== --- felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConverterService.java (original) +++ felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConverterService.java Wed Jun 29 17:36:33 2016 @@ -42,6 +42,7 @@ public class ConverterService implements a.rule(OffsetDateTime.class, String.class, OffsetDateTime::toString, OffsetDateTime::parse); a.rule(OffsetTime.class, String.class, OffsetTime::toString, OffsetTime::parse); a.rule(ZonedDateTime.class, String.class, ZonedDateTime::toString, ZonedDateTime::parse); + a.rule(Integer.class, String.class, v -> v.toString(), Integer::parseInt); adapter = a; } Modified: felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java?rev=1750685&r1=1750684&r2=1750685&view=diff ============================================================================== --- felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java (original) +++ felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java Wed Jun 29 17:36:33 2016 @@ -45,20 +45,6 @@ import org.osgi.service.converter.Conver import org.osgi.service.converter.TypeReference; public class ConvertingImpl implements Converting { - private static final Map<Class<?>, Class<?>> boxedClasses; - static { - Map<Class<?>, Class<?>> m = new HashMap<>(); - m.put(int.class, Integer.class); - m.put(long.class, Long.class); - m.put(double.class, Double.class); - m.put(float.class, Float.class); - m.put(boolean.class, Boolean.class); - m.put(char.class, Character.class); - m.put(byte.class, Byte.class); - m.put(void.class, Void.class); - m.put(short.class, Short.class); - boxedClasses = Collections.unmodifiableMap(m); - } private static final Map<Class<?>, Class<?>> interfaceImplementations; static { Map<Class<?>, Class<?>> m = new HashMap<>(); @@ -72,6 +58,7 @@ public class ConvertingImpl implements C private volatile Converter converter; private volatile Object object; private volatile Object defaultValue; + private volatile boolean hasDefault; ConvertingImpl(Converter c, Object obj) { converter = c; @@ -81,10 +68,12 @@ public class ConvertingImpl implements C @Override public Converting defaultValue(Object defVal) { if (object == null) - object = defVal; + object = defVal; // TODO do we need this??? else defaultValue = defVal; + hasDefault = true; + return this; } @@ -121,7 +110,7 @@ public class ConvertingImpl implements C if (object == null) return handleNull(cls); - Class<?> targetCls = primitiveToBoxed(cls); + Class<?> targetCls = Util.primitiveToBoxed(cls); if (!Map.class.isAssignableFrom(targetCls) && !Collection.class.isAssignableFrom(targetCls) && @@ -309,8 +298,8 @@ public class ConvertingImpl implements C } private Object handleNull(Class<?> cls) { - Class<?> boxed = boxedClasses.get(cls); - if (boxed == null) { + Class<?> boxed = Util.primitiveToBoxed(cls); + if (boxed.equals(cls)) { // This is not a primitive, just return null return null; } @@ -331,14 +320,6 @@ public class ConvertingImpl implements C return Dictionary.class.isAssignableFrom(targetCls); } - private Class<?> primitiveToBoxed(Class<?> cls) { - Class<?> boxed = boxedClasses.get(cls); - if (boxed != null) - return boxed; - else - return cls; - } - private Object trySpecialCases(Class<?> targetCls) { // TODO some of these can probably be implemented as an adapter @@ -441,7 +422,7 @@ public class ConvertingImpl implements C return obj; int len = Array.getLength(obj); - Object arr = Array.newInstance(Object.class, len); + Object arr = Array.newInstance(Util.primitiveToBoxed(objClass.getComponentType()), len); for (int i=0; i<len; i++) { Object val = Array.get(obj, i); Array.set(arr, i, val); Added: felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/Util.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/Util.java?rev=1750685&view=auto ============================================================================== --- felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/Util.java (added) +++ felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/Util.java Wed Jun 29 17:36:33 2016 @@ -0,0 +1,54 @@ +/* + * 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 java.lang.reflect.Type; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class Util { + private static final Map<Class<?>, Class<?>> boxedClasses; + static { + Map<Class<?>, Class<?>> m = new HashMap<>(); + m.put(int.class, Integer.class); + m.put(long.class, Long.class); + m.put(double.class, Double.class); + m.put(float.class, Float.class); + m.put(boolean.class, Boolean.class); + m.put(char.class, Character.class); + m.put(byte.class, Byte.class); + m.put(void.class, Void.class); + m.put(short.class, Short.class); + boxedClasses = Collections.unmodifiableMap(m); + } + + static Type primitiveToBoxed(Type type) { + if (type instanceof Class) + return primitiveToBoxed((Class<?>) type); + else + return null; + } + + static Class<?> primitiveToBoxed(Class<?> cls) { + Class<?> boxed = boxedClasses.get(cls); + if (boxed != null) + return boxed; + else + return cls; + } +} Modified: felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterServiceTest.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterServiceTest.java?rev=1750685&r1=1750684&r2=1750685&view=diff ============================================================================== --- felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterServiceTest.java (original) +++ felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterServiceTest.java Wed Jun 29 17:36:33 2016 @@ -42,6 +42,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.osgi.service.converter.Adapter; +import org.osgi.service.converter.ConversionException; import org.osgi.service.converter.TypeReference; import static org.junit.Assert.assertArrayEquals; @@ -51,6 +52,7 @@ import static org.junit.Assert.assertNot import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public class ConverterServiceTest { private ConverterService converter; @@ -269,6 +271,18 @@ public class ConverterServiceTest { } @Test + public void testExceptionDefaultValue() { + assertEquals(42, (int) converter.convert("haha").defaultValue(42).to(int.class)); + assertNull(converter.convert("haha").defaultValue(null).to(int.class)); + try { + converter.convert("haha").to(int.class); + fail("Should have thrown an exception"); + } catch (ConversionException ex) { + // good + } + } + + @Test public void testStandardStringArrayConversion() { String[] sa = {"A", "B"}; assertEquals("A", converter.convert(sa).toString());