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 2016/10/28 11:00:19 UTC
svn commit: r1767000 - in /felix/trunk/converter/converter/src:
main/java/org/apache/felix/converter/impl/ main/java/org/osgi/util/converter/
test/java/org/apache/felix/converter/impl/
Author: davidb
Date: Fri Oct 28 11:00:19 2016
New Revision: 1767000
URL: http://svn.apache.org/viewvc?rev=1767000&view=rev
Log:
Felix Converter - additional information for converter rules
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/ConvertingImpl.java
felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/InternalConverting.java
felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/ConvertFunction.java
felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/Converting.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/ConverterTest.java
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=1767000&r1=1766999&r2=1767000&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 Fri Oct 28 11:00:19 2016
@@ -82,6 +82,7 @@ public class AdapterImpl implements Inte
private volatile Object defaultValue;
private volatile Class<?> treatAsClass;
private volatile boolean hasDefault;
+ private volatile Object key;
ConvertingWrapper(Object obj, InternalConverting c) {
object = obj;
@@ -89,9 +90,9 @@ public class AdapterImpl implements Inte
}
@Override
- public Converting as(Class<?> cls) {
+ public Converting sourceType(Class<?> cls) {
treatAsClass = cls;
- del.as(cls);
+ del.sourceType(cls);
return this;
}
@@ -110,6 +111,12 @@ public class AdapterImpl implements Inte
}
@Override
+ public InternalConverting key(Object k) {
+ key = k;
+ return this;
+ }
+
+ @Override
public void setConverter(Converter c) {
del.setConverter(c);
}
@@ -154,7 +161,7 @@ public class AdapterImpl implements Inte
continue;
try {
- Object res = func.convert(object, type);
+ Object res = func.convert(object, key, type);
if (res != null) {
return res;
}
@@ -176,8 +183,8 @@ public class AdapterImpl implements Inte
}
@Override
- public Converting target(Class<?> cls) {
- del.target(cls);
+ public Converting targetType(Class<?> cls) {
+ del.targetType(cls);
return this;
}
}
@@ -232,7 +239,7 @@ public class AdapterImpl implements Inte
}
@Override
- public T convert(F obj, Type targetType) throws Exception {
+ public T convert(F obj, Object key, Type targetType) throws Exception {
return function.apply(obj);
}
}
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=1767000&r1=1766999&r2=1767000&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 Fri Oct 28 11:00:19 2016
@@ -32,6 +32,7 @@ import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -57,7 +58,7 @@ public class ConvertingImpl implements C
interfaceImplementations = Collections.unmodifiableMap(m);
}
- private volatile Converter converter;
+ private volatile InternalConverter converter;
private volatile Object object;
private volatile Class<?> treatAsClass;
private volatile Object defaultValue;
@@ -67,13 +68,13 @@ public class ConvertingImpl implements C
private volatile Class<?> targetViewClass;
private volatile Type[] typeArguments;
- ConvertingImpl(Converter c, Object obj) {
+ ConvertingImpl(InternalConverter c, Object obj) {
converter = c;
object = obj;
}
@Override
- public Converting as(Class<?> type) {
+ public Converting sourceType(Class<?> type) {
treatAsClass = type;
return this;
}
@@ -93,8 +94,18 @@ public class ConvertingImpl implements C
}
@Override
+ public InternalConverting key(Object k) {
+ // This is only for adapters, so we don't need to do anything here
+ return this;
+ }
+
+ @Override
public void setConverter(Converter c) {
- converter = c;
+ if (c instanceof InternalConverter)
+ converter = (InternalConverter) c;
+ else
+ throw new IllegalStateException("Incorrect converter used. Should implement " +
+ InternalConverter.class + " but was " + c);
}
@SuppressWarnings("unchecked")
@@ -165,19 +176,14 @@ public class ConvertingImpl implements C
return res2;
} else {
if (defaultValue != null)
- return converter.convert(defaultValue).as(treatAsClass).target(targetViewClass).to(targetActualClass);
+ return converter.convert(defaultValue).sourceType(treatAsClass).targetType(targetViewClass).to(targetActualClass);
else
return null;
}
}
@Override
- public String toString() {
- return to(String.class);
- }
-
- @Override
- public Converting target(Class<?> cls) {
+ public Converting targetType(Class<?> cls) {
targetViewClass = cls;
return this;
}
@@ -297,17 +303,17 @@ public class ConvertingImpl implements C
for (Map.Entry entry : (Set<Entry>) m.entrySet()) {
Object key = entry.getKey();
if (targetKeyType != null)
- key = converter.convert(key).to(targetKeyType);
+ key = converter.convert(key).key(key).to(targetKeyType);
Object value = entry.getValue();
if (value != null) {
if (targetValueType != null) {
- value = converter.convert(value).to(targetValueType);
+ value = converter.convert(value).key(key).to(targetValueType);
} else {
Class<?> cls = value.getClass();
if (isCopyRequiredType(cls)) {
cls = getConstructableType(cls);
}
- value = converter.convert(value).to(cls);
+ value = converter.convert(value).key(key).to(cls);
}
}
instance.put(key, value);
@@ -316,11 +322,27 @@ public class ConvertingImpl implements C
return instance;
}
+ @SuppressWarnings({ "unchecked", "rawtypes" })
private Object convertToMapType() {
if (Map.class.isAssignableFrom(targetViewClass))
return convertToMap();
else if (Dictionary.class.isAssignableFrom(targetViewClass))
- return null; // TODO new Hashtable(convertToMap(sourceCls, Map.class, typeArguments));
+ return new Hashtable((Map) converter.convert(object).to(new ParameterizedType() {
+ @Override
+ public Type getRawType() {
+ return HashMap.class;
+ }
+
+ @Override
+ public Type getOwnerType() {
+ return null;
+ }
+
+ @Override
+ public Type[] getActualTypeArguments() {
+ return typeArguments;
+ }
+ }));
else if (targetViewClass.isInterface())
return createProxy(sourceClass, targetViewClass);
return createJavaBean(sourceClass, targetViewClass);
Modified: felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/InternalConverting.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/InternalConverting.java?rev=1767000&r1=1766999&r2=1767000&view=diff
==============================================================================
--- felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/InternalConverting.java (original)
+++ felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/InternalConverting.java Fri Oct 28 11:00:19 2016
@@ -20,5 +20,7 @@ import org.osgi.util.converter.Converter
import org.osgi.util.converter.Converting;
public interface InternalConverting extends Converting {
- public void setConverter(Converter c);
+ void setConverter(Converter c);
+
+ InternalConverting key(Object key);
}
Modified: felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/ConvertFunction.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/ConvertFunction.java?rev=1767000&r1=1766999&r2=1767000&view=diff
==============================================================================
--- felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/ConvertFunction.java (original)
+++ felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/ConvertFunction.java Fri Oct 28 11:00:19 2016
@@ -36,6 +36,8 @@ public interface ConvertFunction<F, T> {
* @param obj The object to be converted. This object will never be
* {@code null} as the convert function will not be invoked for
* null values.
+ * @param key If the object was part of a map-like structure, the associated
+ * key is provided. Otherwise {@code null}.
* @param targetType The target type.
* @return The conversion result or {@code null} to indicate that the
* convert function cannot handle this conversion. In this case the
@@ -43,5 +45,5 @@ public interface ConvertFunction<F, T> {
* convert.
* @throws Exception
*/
- T convert(F obj, Type targetType) throws Exception;
+ T convert(F obj, Object key, Type targetType) throws Exception;
}
Modified: felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/Converting.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/Converting.java?rev=1767000&r1=1766999&r2=1767000&view=diff
==============================================================================
--- felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/Converting.java (original)
+++ felix/trunk/converter/converter/src/main/java/org/osgi/util/converter/Converting.java Fri Oct 28 11:00:19 2016
@@ -29,88 +29,82 @@ import org.osgi.annotation.versioning.Pr
*/
@ProviderType
public interface Converting {
- /**
- * Convert the source object based on rules for the class being passed in.
- * This method can be used to disambiguate objects that would match multiple
- * conversion rules.
- *
- * @param type The type or class to be used as the source type for the
- * conversion
- * @return The current {@code Converting} object so that additional calls
- * can be chained.
- */
- Converting as(Class< ? > type);
-
- /**
- * Always return a fully populated copy of the object, however if the object
- * is an immutable built-in scalar such as String or Long, then a copy is not
- * needed. By default a wrapped object is returned by the converter if possible.
+ /**
+ * Convert the source object based on rules for the class being passed in.
+ * This method can be used to disambiguate objects that would match multiple
+ * conversion rules.
+ *
+ * @param type The type or class to be used as the source type for the
+ * conversion
* @return The current {@code Converting} object so that additional calls
* can be chained.
- */
- Converting copy();
+ */
+ Converting sourceType(Class< ? > type);
- /**
- * The default value to use when the object cannot be converted or in case
- * of conversion from a {@code null} value.
- *
- * @param defVal The default value.
- * @return The current {@code Converting} object so that additional calls
- * can be chained.
- */
- Converting defaultValue(Object defVal);
-
- /**
- * Specify the target type to view the conversion target as. Can be used to force
- * the converter to treat the target, specified in the {@link #to(Class)} method
- * to be viewed as the type specified here.
- * If specified, the class specified by the {@link #to(Class)} method will need to be
- * assignable to this type.
- *
- * @param cls The class to view the target type as.
+ /**
+ * Always return a fully populated copy of the object, however if the object
+ * is an immutable built-in scalar such as String or Long, then a copy is
+ * not needed. By default a wrapped object is returned by the converter if
+ * possible.
+ *
* @return The current {@code Converting} object so that additional calls
* can be chained.
- */
- Converting target(Class<?> cls);
+ */
+ Converting copy();
- /**
- * Specify the target object type for the conversion as a class object.
- *
- * @param cls The class to convert to.
- * @return The converted object.
- */
- <T> T to(Class<T> cls);
-
- /**
- * Specify the target object type as a {@link TypeReference}. If the target
- * class carries generics information a TypeReference should be used as this
- * preserves the generic information whereas a Class object has this
- * information erased. Example use:
- *
- * <pre>
- * List<String> result = converter.convert(Arrays.asList(1, 2, 3))
- * .to(new TypeReference<List<String>>() {});
- * </pre>
- *
- * @param ref A type reference to the object being converted to.
- * @return The converted object.
- */
- <T> T to(TypeReference<T> ref);
-
- /**
- * Specify the target object type as a Java Reflection Type object.
- *
- * @param type A Type object to represent the target type to be converted
- * to.
- * @return The converted object.
- */
- Object to(Type type);
-
- /**
- * Same as {@code to(String.class)}.
- *
- * @return The converted object.
- */
- @Override
- String toString();
+ /**
+ * The default value to use when the object cannot be converted or in case
+ * of conversion from a {@code null} value.
+ *
+ * @param defVal The default value.
+ * @return The current {@code Converting} object so that additional calls
+ * can be chained.
+ */
+ Converting defaultValue(Object defVal);
+
+ /**
+ * Specify the target type to view the conversion target as. Can be used to
+ * force the converter to treat the target, specified in the
+ * {@link #to(Class)} method to be viewed as the type specified here. If
+ * specified, the class specified by the {@link #to(Class)} method will need
+ * to be assignable to this type.
+ *
+ * @param cls The class to view the target type as.
+ * @return The current {@code Converting} object so that additional calls
+ * can be chained.
+ */
+ Converting targetType(Class< ? > cls);
+
+ /**
+ * Specify the target object type for the conversion as a class object.
+ *
+ * @param cls The class to convert to.
+ * @return The converted object.
+ */
+ <T> T to(Class<T> cls);
+
+ /**
+ * Specify the target object type as a {@link TypeReference}. If the target
+ * class carries generics information a TypeReference should be used as this
+ * preserves the generic information whereas a Class object has this
+ * information erased. Example use:
+ *
+ * <pre>
+ * List<String> result = converter.convert(Arrays.asList(1, 2, 3))
+ * .to(new TypeReference<List<String>>() {});
+ * </pre>
+ *
+ * @param ref A type reference to the object being converted to.
+ * @return The converted object.
+ */
+ <T> T to(TypeReference<T> ref);
+
+ /**
+ * Specify the target object type as a Java Reflection Type object.
+ *
+ * @param type A Type object to represent the target type to be converted
+ * to.
+ * @return The converted object.
+ */
+ Object to(Type type);
}
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=1767000&r1=1766999&r2=1767000&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 Fri Oct 28 11:00:19 2016
@@ -19,6 +19,7 @@ package org.apache.felix.converter.impl;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
@@ -34,6 +35,7 @@ import org.osgi.util.converter.ConvertFu
import org.osgi.util.converter.Converter;
import org.osgi.util.converter.ConverterBuilder;
import org.osgi.util.converter.Rule;
+import org.osgi.util.converter.TypeReference;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -83,7 +85,7 @@ public class ConverterBuilderTest {
cb.rule(char[].class, String.class, ConverterBuilderTest::convertToString, null);
cb.rule(new Rule<String, Number>(String.class, Number.class, new ConvertFunction<String, Number>() {
@Override
- public Number convert(String obj, Type targetType) throws Exception {
+ public Number convert(String obj, Object key, Type targetType) throws Exception {
if (Integer.class.equals(targetType))
return Integer.valueOf(-1);
else if (Long.class.equals(targetType))
@@ -108,7 +110,7 @@ public class ConverterBuilderTest {
Converter ca = converter.newConverterBuilder().rule(
new Rule<Integer, Long>(Integer.class, Long.class, new ConvertFunction<Integer,Long>() {
@Override
- public Long convert(Integer obj, Type targetType) throws Exception {
+ public Long convert(Integer obj, Object key, Type targetType) throws Exception {
if (obj.intValue() != 1)
return new Long(-obj.intValue());
return null;
@@ -125,7 +127,7 @@ public class ConverterBuilderTest {
public void testWildcardAdapter() {
ConvertFunction<List, Object> foo = new ConvertFunction<List, Object>() {
@Override
- public Object convert(List t, Type type) throws Exception {
+ public Object convert(List t, Object key, Type type) throws Exception {
if (type instanceof Class) {
if (Number.class.isAssignableFrom((Class<?>) type))
return converter.convert(t.size()).to(type);
@@ -136,7 +138,7 @@ public class ConverterBuilderTest {
Rule<List, Object> r = new Rule<>(List.class, Object.class, foo);
Rule<Object, Object> allCatch = new Rule<>(Object.class, Object.class,
- (v,t) -> v.toString());
+ (v,k,t) -> v.toString());
ConverterBuilder cb = converter.newConverterBuilder();
cb.rule(r);
@@ -152,13 +154,13 @@ public class ConverterBuilderTest {
public void testWildcardAdapter2() {
Map<Object, Object> snooped = new HashMap<>();
Rule<Object, ArrayList> r = new Rule<>(Object.class, ArrayList.class,
- (v,t) -> null,
- (v,t) -> "arraylist");
+ (v,k,t) -> null,
+ (v,k,t) -> "arraylist");
Rule<Object, List> r2 = new Rule<>(Object.class, List.class,
- (v,t) -> null,
- (v,t) -> "list");
+ (v,k,t) -> null,
+ (v,k,t) -> "list");
Rule<Object, Object> allCatch = new Rule<>(Object.class, Object.class,
- (v,t) -> {snooped.put(v,t); return null;}, null);
+ (v,k,t) -> {snooped.put(v,t); return null;}, null);
ConverterBuilder cb = converter.newConverterBuilder();
cb.rule(r);
@@ -182,9 +184,9 @@ public class ConverterBuilderTest {
public void testConvertAs() {
ConverterBuilder cb = converter.newConverterBuilder();
cb.rule(new Rule<>(MyIntf.class, MyCustomDTO.class,
- (i, t) -> { MyCustomDTO dto = new MyCustomDTO(); dto.field = "" + i.value(); return dto; }));
+ (i, k, t) -> { MyCustomDTO dto = new MyCustomDTO(); dto.field = "" + i.value(); return dto; }));
cb.rule(new Rule<>(MyBean.class, MyCustomDTO.class,
- (b, t) -> { MyCustomDTO dto = new MyCustomDTO(); dto.field = b.getValue(); return dto; }));
+ (b, k, t) -> { MyCustomDTO dto = new MyCustomDTO(); dto.field = b.getValue(); return dto; }));
Converter cc = cb.build();
MyBean mb = new MyBean();
@@ -192,9 +194,51 @@ public class ConverterBuilderTest {
mb.beanVal = "Hello";
assertNull(converter.convert(mb).to(MyCustomDTO.class).field);
- assertNull(converter.convert(mb).as(MyIntf.class).to(MyCustomDTO.class).field);
+ assertNull(converter.convert(mb).sourceType(MyIntf.class).to(MyCustomDTO.class).field);
assertEquals("Hello", cc.convert(mb).to(MyCustomDTO.class).field);
- assertEquals("17", cc.convert(mb).as(MyIntf.class).to(MyCustomDTO.class).field);
+ assertEquals("17", cc.convert(mb).sourceType(MyIntf.class).to(MyCustomDTO.class).field);
+ }
+
+ @Test
+ public void testConvertWithKeys() {
+ ConverterBuilder cb = converter.newConverterBuilder();
+ ConvertFunction<Number, String> ntc = new ConvertFunction<Number, String>() {
+ @Override
+ public String convert(Number obj, Object key, Type targetType) throws Exception {
+ if ("cost".equals(key))
+ return "$" + obj + ".00";
+ else
+ return "" + obj;
+ }
+ };
+ ConvertFunction<String, Number> ctn = new ConvertFunction<String, Number>() {
+ @Override
+ public Number convert(String obj, Object key, Type targetType) throws Exception {
+ if ("cost".equals(key)) {
+ int dotIdx = obj.indexOf('.');
+ obj = obj.substring(1, dotIdx); // eat off dollar sign and decimals
+ }
+ return Integer.parseInt(obj);
+ }
+ };
+ cb.rule(new Rule<Number, String>(Number.class, String.class, ntc, ctn));
+ Converter c = cb.build();
+
+ Map<String, Integer> m = new HashMap<>();
+ m.put("amount", 7);
+ m.put("cost", 100);
+
+ // Convert to Dictionary<String,String>
+ Dictionary<String,String> d = c.convert(m).to(new TypeReference<Dictionary<String, String>>(){});
+ assertEquals(2, d.size());
+ assertEquals("7", d.get("amount"));
+ assertEquals("$100.00", d.get("cost"));
+
+ // Convert back to HashMap<String,Integer>
+ HashMap<String, Integer> hm = c.convert(d).to(new TypeReference<HashMap<String, Integer>>() {});
+ assertEquals(2, hm.size());
+ assertEquals(7, (int) hm.get("amount"));
+ assertEquals(100, (int) hm.get("cost"));
}
static interface MyIntf {
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=1767000&r1=1766999&r2=1767000&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 Fri Oct 28 11:00:19 2016
@@ -487,7 +487,7 @@ public class ConverterTest {
@Test
public void testMap2DTOView() {
Map<String, Object> src = Collections.singletonMap("pong", 42);
- MyDTOWithMethods dto = converter.convert(src).target(MyDTO.class).to(MyDTOWithMethods.class);
+ MyDTOWithMethods dto = converter.convert(src).targetType(MyDTO.class).to(MyDTOWithMethods.class);
assertEquals(42, dto.pong);
}
@@ -587,7 +587,7 @@ public class ConverterTest {
mb.beanVal = "Hello";
assertEquals(17,
- converter.convert(mb).as(MyIntf.class).to(Map.class).get("value"));
+ converter.convert(mb).sourceType(MyIntf.class).to(Map.class).get("value"));
}
@Test
@@ -597,7 +597,7 @@ public class ConverterTest {
mb.beanVal = "Hello";
assertEquals(Collections.singletonMap("value", "Hello"),
- converter.convert(mb).as(MyBean.class).to(Map.class));
+ converter.convert(mb).sourceType(MyBean.class).to(Map.class));
}
static class MyClass2 {