Author: davidb Date: Tue Jul 11 12:12:27 2017 New Revision: 1801599 URL: http://svn.apache.org/viewvc?rev=1801599&view=rev Log: Felix Converter - update the implementation for the new API.
Added: felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/AbstractSpecifying.java felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/FunctioningImpl.java felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/Converters.java felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterFunctionTest.java Removed: felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/StandardConverter.java 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/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 Added: felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/AbstractSpecifying.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/AbstractSpecifying.java?rev=1801599&view=auto ============================================================================== --- felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/AbstractSpecifying.java (added) +++ felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/AbstractSpecifying.java Tue Jul 11 12:12:27 2017 @@ -0,0 +1,101 @@ +/* + * 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.util.converter.Specifying; + +public abstract class AbstractSpecifying<T extends Specifying<T>> implements Specifying<T> { + protected volatile Object defaultValue; + protected volatile boolean hasDefault = false; + protected volatile boolean forceCopy = false; + protected volatile boolean keysIgnoreCase = false; + protected volatile Class<?> sourceAsClass; + protected volatile boolean sourceAsDTO = false; + protected volatile boolean sourceAsJavaBean = false; + protected volatile Class<?> targetAsClass; + protected volatile boolean targetAsDTO = false; + protected volatile boolean targetAsJavaBean = false; + + @SuppressWarnings("unchecked") + private T castThis() { + return (T) this; + } + + @Override + public T copy() { + forceCopy = true; + return castThis(); + } + + @Override + public T defaultValue(Object defVal) { + defaultValue = defVal; + hasDefault = true; + return castThis(); + } + + @Override + public T keysIgnoreCase() { + keysIgnoreCase = true; + return castThis(); + } + + @Override + public T sourceAs(Class<?> cls) { + sourceAsClass = cls; + return castThis(); + } + + @Override + public T sourceAsBean() { + // To avoid ambiguity, reset any instruction to sourceAsDTO + sourceAsDTO = false; + sourceAsJavaBean = true; + return castThis(); + } + + @Override + public T sourceAsDTO() { + // To avoid ambiguity, reset any instruction to sourceAsJavaBean + sourceAsJavaBean = false; + sourceAsDTO = true; + return castThis(); + } + + @Override + public T targetAs(Class<?> cls) { + targetAsClass = cls; + return castThis(); + } + + @Override + public T targetAsBean() { + // To avoid ambiguity, reset any instruction to targetAsDTO + targetAsDTO = false; + targetAsJavaBean = true; + return castThis(); + } + + @Override + public T targetAsDTO() { + // To avoid ambiguity, reset any instruction to targetAsJavaBean + targetAsJavaBean = false; + targetAsDTO = true; + return null; + } + +} 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=1801599&r1=1801598&r2=1801599&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 Tue Jul 11 12:12:27 2017 @@ -27,6 +27,7 @@ import org.osgi.util.converter.Converter import org.osgi.util.converter.ConverterBuilder; import org.osgi.util.converter.ConverterFunction; import org.osgi.util.converter.Converting; +import org.osgi.util.converter.Functioning; import org.osgi.util.converter.TypeReference; public class AdapterImpl implements InternalConverter { @@ -51,6 +52,11 @@ public class AdapterImpl implements Inte } @Override + public Functioning function() { + return new FunctioningImpl(this); + } + + @Override public ConverterBuilder newConverterBuilder() { return new ConverterBuilderImpl(this); } @@ -155,7 +161,7 @@ public class AdapterImpl implements Inte for (ConverterFunction cf : converters) { try { Object res = cf.apply(object, type); - if (res != null) { + if (res != ConverterFunction.CANNOT_HANDLE) { return res; } } catch (Exception ex) { @@ -172,7 +178,7 @@ public class AdapterImpl implements Inte for (ConverterFunction eh : errorHandlers) { try { Object handled = eh.apply(object, type); - if (handled != null) + if (handled != ConverterFunction.CANNOT_HANDLE) return handled; } catch (RuntimeException re) { throw re; 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=1801599&r1=1801598&r2=1801599&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 Tue Jul 11 12:12:27 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.Functioning; import org.osgi.util.converter.Rule; public class ConverterImpl implements InternalConverter { @@ -37,6 +38,11 @@ public class ConverterImpl implements In return new ConvertingImpl(this, obj); } + @Override + public Functioning function() { + return new FunctioningImpl(this); + } + public void addStandardRules(ConverterBuilder cb) { cb.rule(new Rule<Calendar, String>(f -> f.getTime().toInstant().toString()) {}); cb.rule(new Rule<String, Calendar>(f -> { 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=1801599&r1=1801598&r2=1801599&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 Tue Jul 11 12:12:27 2017 @@ -47,7 +47,7 @@ import org.osgi.util.converter.Converter import org.osgi.util.converter.Converting; import org.osgi.util.converter.TypeReference; -public class ConvertingImpl implements Converting, InternalConverting { +public class ConvertingImpl extends AbstractSpecifying<Converting> implements Converting, InternalConverting { private static final Map<Class<?>, Class<?>> INTERFACE_IMPLS; static { Map<Class<?>, Class<?>> m = new HashMap<>(); @@ -64,25 +64,16 @@ public class ConvertingImpl implements C volatile InternalConverter converter; private volatile Object object; - private volatile Object defaultValue; - private volatile boolean hasDefault = false; - private volatile boolean keysIgnoreCase = false; volatile Class<?> sourceClass; - volatile Class<?> sourceAsClass; private volatile Class<?> targetClass; - private volatile Class<?> targetAsClass; volatile Type[] typeArguments; - private volatile boolean forceCopy = false; - private volatile boolean sourceAsJavaBean = false; - private volatile boolean targetAsJavaBean = false; - private volatile boolean sourceAsDTO = false; - private volatile boolean targetAsDTO = false; ConvertingImpl(InternalConverter c, Object obj) { converter = c; object = obj; } + /* @Override public Converting sourceAs(Class<?> cls) { sourceAsClass = cls; @@ -128,12 +119,6 @@ public class ConvertingImpl implements C } @Override - public Converting copy() { - forceCopy = true; - return this; - } - - @Override public Converting defaultValue(Object defVal) { defaultValue = defVal; hasDefault = true; @@ -147,6 +132,7 @@ public class ConvertingImpl implements C return this; } + */ @Override public void setConverter(Converter c) { Added: felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/FunctioningImpl.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/FunctioningImpl.java?rev=1801599&view=auto ============================================================================== --- felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/FunctioningImpl.java (added) +++ felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/FunctioningImpl.java Tue Jul 11 12:12:27 2017 @@ -0,0 +1,67 @@ +/* + * 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 org.osgi.util.converter.Functioning; +import org.osgi.util.converter.TypeReference; +import org.osgi.util.function.Function; + +public class FunctioningImpl extends AbstractSpecifying<Functioning> implements Functioning { + private InternalConverter converter; + + public FunctioningImpl(InternalConverter converterImpl) { + converter = converterImpl; + } + + @Override + public <T> Function<Object, T> to(Class<T> cls) { + Type type = cls; + return to(type); + } + + @Override + public <T> Function<Object, T> to(TypeReference<T> ref) { + return to(ref.getType()); + } + + @Override + public <T> Function<Object, T> to(Type type) { + return new Function<Object, T>() { + @Override + public T apply(Object t) { + InternalConverting ic = converter.convert(t); + return applyModifiers(ic).to(type); + } + }; + } + + InternalConverting applyModifiers(InternalConverting ic) { + if (hasDefault) ic.defaultValue(defaultValue); + if (forceCopy) ic.copy(); + if (keysIgnoreCase) ic.keysIgnoreCase(); + if (sourceAsClass != null) ic.sourceAs(sourceAsClass); + if (sourceAsDTO) ic.sourceAsDTO(); + if (sourceAsJavaBean) ic.sourceAsBean(); + if (targetAsClass != null) ic.targetAs(targetAsClass); + if (targetAsDTO) ic.targetAsBean(); + if (targetAsJavaBean) ic.targetAsBean(); + + return ic; + } +} Added: felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/Converters.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/Converters.java?rev=1801599&view=auto ============================================================================== --- felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/Converters.java (added) +++ felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/Converters.java Tue Jul 11 12:12:27 2017 @@ -0,0 +1,58 @@ +/* + * 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 org.apache.felix.converter.impl.ConverterBuilderImpl; +import org.apache.felix.converter.impl.ConverterImpl; +import org.apache.felix.converter.impl.InternalConverter; + +/** + * Factory class to obtain the standard converter or a new converter builder. + * + * @author $Id$ + * @ThreadSafe + */ +public class Converters { + private static final InternalConverter CONVERTER; + + static { + ConverterImpl impl = new ConverterImpl(); + ConverterBuilderImpl cb = impl.newConverterBuilder(); + impl.addStandardRules(cb); + CONVERTER = cb.build(); + } + + private Converters() { + // Do not instantiate this factory class + } + + /** + * Obtain the standard converter. + * @return The standard converter. + */ + public static Converter standardConverter() { + return CONVERTER; + } + + /** + * Obtain a converter builder based on the standard converter. + * @return A new converter builder. + */ + public static ConverterBuilder newConverterBuilder() { + return CONVERTER.newConverterBuilder(); + } +} 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=1801599&r1=1801598&r2=1801599&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 Tue Jul 11 12:12:27 2017 @@ -34,19 +34,21 @@ import org.junit.Test; import org.osgi.util.converter.Converter; import org.osgi.util.converter.ConverterBuilder; import org.osgi.util.converter.ConverterFunction; +import org.osgi.util.converter.Converters; import org.osgi.util.converter.Rule; 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; @Before public void setUp() { - converter = new ConverterImpl(); + converter = Converters.standardConverter(); } @After @@ -125,14 +127,19 @@ public class ConverterBuilderTest { @Override public Object apply(Object obj, Type type) throws Exception { if (!(obj instanceof List)) - return null; + return ConverterFunction.CANNOT_HANDLE; + List<?> t = (List<?>) obj; + if (t.size() == 0) + // Empty list is converted to null + return null; + if (type instanceof Class) { if (Number.class.isAssignableFrom((Class<?>) type)) return converter.convert(t.size()).to(type); } - return null; + return ConverterFunction.CANNOT_HANDLE; } }; @@ -144,6 +151,7 @@ public class ConverterBuilderTest { assertEquals(3L, (long) ca.convert(Arrays.asList("a", "b", "c")).to(Long.class)); assertEquals(3, (long) ca.convert(Arrays.asList("a", "b", "c")).to(Integer.class)); assertEquals("[a, b, c]", ca.convert(Arrays.asList("a", "b", "c")).to(String.class)); + assertNull(ca.convert(Arrays.asList()).to(String.class)); } @Test @@ -152,14 +160,14 @@ public class ConverterBuilderTest { @Override public Object apply(Object obj, Type type) throws Exception { if (!(obj instanceof List)) - return null; + return ConverterFunction.CANNOT_HANDLE; List<?> t = (List<?>) obj; if (type instanceof Class) { if (Number.class.isAssignableFrom((Class<?>) type)) return converter.convert(t.size()).to(type); } - return null; + return ConverterFunction.CANNOT_HANDLE; } }; @@ -186,7 +194,7 @@ public class ConverterBuilderTest { Arrays.sort(v, Collections.reverseOrder()); return new CopyOnWriteArrayList<>(Arrays.asList(v)); }) {}); - cb.rule((v,t) -> { snooped.put(v,t); return null;}); + cb.rule((v,t) -> { snooped.put(v,t); return ConverterFunction.CANNOT_HANDLE;}); Converter ca = cb.build(); assertEquals(new ArrayList<>(Arrays.asList("c", "b", "a")), ca.convert( Added: felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterFunctionTest.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterFunctionTest.java?rev=1801599&view=auto ============================================================================== --- felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterFunctionTest.java (added) +++ felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterFunctionTest.java Tue Jul 11 12:12:27 2017 @@ -0,0 +1,65 @@ +/* + * 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.junit.Test; +import org.osgi.util.converter.Converter; +import org.osgi.util.converter.Converters; +import org.osgi.util.converter.Rule; +import org.osgi.util.function.Function; + +import static org.junit.Assert.assertEquals; + +public class ConverterFunctionTest { + @Test + public void testConverterFunction() { + Converter c = Converters.standardConverter(); + assertEquals(12.5, c.convert("12.5").to(double.class), 0.001); + + Function<Object, Double> f = c.function().to(double.class); + assertEquals(12.5, f.apply("12.5"), 0.001); + assertEquals(50.505, f.apply("50.505"), 0.001); + } + + @Test + public void testConverterFunctionWithModifier() { + Converter c = Converters.standardConverter(); + + Function<Object, Integer> cf = c.function().defaultValue(999).to(Integer.class); + + assertEquals(Integer.valueOf(999), + cf.apply("")); + assertEquals(Integer.valueOf(999), + c.convert("").defaultValue(999).to(Integer.class)); + } + + @Test + public void testConverterFunctionWithRule() { + Converter c = Converters.standardConverter(); + Function<Object, String> cf = c.function().to(String.class); + + String[] sa = new String [] {"h", "i"}; + assertEquals("h", cf.apply(sa)); + + Converter ac = c.newConverterBuilder(). + rule(new Rule<String[],String>(v -> String.join("", v)) {}). + build(); + + Function<Object, String> af = ac.function().to(String.class); + assertEquals("hi", af.apply(sa)); + } +} 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=1801599&r1=1801598&r2=1801599&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 Tue Jul 11 12:12:27 2017 @@ -35,8 +35,8 @@ import org.junit.Test; import org.osgi.util.converter.ConversionException; import org.osgi.util.converter.Converter; import org.osgi.util.converter.ConverterBuilder; +import org.osgi.util.converter.Converters; import org.osgi.util.converter.Rule; -import org.osgi.util.converter.StandardConverter; import org.osgi.util.converter.TypeReference; import static org.junit.Assert.assertArrayEquals; @@ -54,7 +54,7 @@ public class ConverterMapTest { @Before public void setUp() { - converter = new StandardConverter(); + converter = Converters.standardConverter(); } @After @@ -110,7 +110,7 @@ public class ConverterMapTest { mb.setStartDate(d); mb.setEnabled(true); - ConverterBuilder cb = new StandardConverter().newConverterBuilder(); + ConverterBuilder cb = Converters.newConverterBuilder(); cb.rule(new Rule<Date,String>(v -> sdf.format(v)) {}); cb.rule(new Rule<String,Date>(v -> { try { 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=1801599&r1=1801598&r2=1801599&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 Tue Jul 11 12:12:27 2017 @@ -59,8 +59,8 @@ import org.osgi.util.converter.Conversio import org.osgi.util.converter.Converter; import org.osgi.util.converter.ConverterBuilder; import org.osgi.util.converter.ConverterFunction; +import org.osgi.util.converter.Converters; import org.osgi.util.converter.Rule; -import org.osgi.util.converter.StandardConverter; import org.osgi.util.converter.TypeReference; import static org.junit.Assert.assertArrayEquals; @@ -78,7 +78,7 @@ public class ConverterTest { @Before public void setUp() { - converter = new StandardConverter(); + converter = Converters.standardConverter(); } @After @@ -358,7 +358,10 @@ public class ConverterTest { if ("hello".equals(obj)) { return -1; } - return null; + if ("goodbye".equals(obj)) { + return null; + } + return ConverterFunction.CANNOT_HANDLE; } }; @@ -367,6 +370,14 @@ public class ConverterTest { assertEquals(new Integer(12), adapted.convert("12").to(Integer.class)); assertEquals(new Integer(-1), adapted.convert("hello").to(Integer.class)); + assertNull(adapted.convert("goodbye").to(Integer.class)); + + try { + adapted.convert("nothing").to(Integer.class); + fail("Should have thrown a Conversion Exception when converting 'hello' to a number"); + } catch (ConversionException ce) { + // good + } // This is with the non-adapted converter try { @@ -455,7 +466,7 @@ public class ConverterTest { Calendar cal = new GregorianCalendar(2017, 1, 13); Date d = cal.getTime(); - Converter c = new StandardConverter(); + Converter c = converter; String s = c.convert(d).toString(); assertEquals(d, c.convert(s).to(Date.class));