You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cz...@apache.org on 2017/11/14 16:17:28 UTC

svn commit: r1815229 - in /felix/trunk/osgi-r7/configurator: ./ src/main/java/org/apache/felix/configurator/impl/json/ src/test/java/org/apache/felix/configurator/impl/json/ src/test/resources/json/

Author: cziegeler
Date: Tue Nov 14 16:17:28 2017
New Revision: 1815229

URL: http://svn.apache.org/viewvc?rev=1815229&view=rev
Log:
Update to latest converter and add handling of special cases incl test case

Added:
    felix/trunk/osgi-r7/configurator/src/test/resources/json/complex-types.json   (with props)
Modified:
    felix/trunk/osgi-r7/configurator/pom.xml
    felix/trunk/osgi-r7/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSONUtil.java
    felix/trunk/osgi-r7/configurator/src/main/java/org/apache/felix/configurator/impl/json/TypeConverter.java
    felix/trunk/osgi-r7/configurator/src/test/java/org/apache/felix/configurator/impl/json/TypeConverterTest.java

Modified: felix/trunk/osgi-r7/configurator/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/configurator/pom.xml?rev=1815229&r1=1815228&r2=1815229&view=diff
==============================================================================
--- felix/trunk/osgi-r7/configurator/pom.xml (original)
+++ felix/trunk/osgi-r7/configurator/pom.xml Tue Nov 14 16:17:28 2017
@@ -101,7 +101,7 @@
         <dependency>
             <groupId>org.apache.felix</groupId>
 		    <artifactId>org.apache.felix.converter</artifactId>
-		    <version>0.1.0-SNAPSHOT</version>
+		    <version>0.2.0-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
         <dependency>

Modified: felix/trunk/osgi-r7/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSONUtil.java
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSONUtil.java?rev=1815229&r1=1815228&r2=1815229&view=diff
==============================================================================
--- felix/trunk/osgi-r7/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSONUtil.java (original)
+++ felix/trunk/osgi-r7/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSONUtil.java Tue Nov 14 16:17:28 2017
@@ -239,17 +239,8 @@ public class JSONUtil {
                         }
                     } else {
                         try {
-                            Object convertedVal = converter.convert(pid, value, typeInfo);
-                            if ( convertedVal == null ) {
-                                JsonStructure json = build(value);
-                                if ( json == null ) {
-                                    convertedVal = value.toString();
-                                } else {
-                                    final StringWriter writer = new StringWriter();
-                                    Json.createWriter(writer).write(json);
-                                    convertedVal = writer.toString();
-                                }
-                            }
+
+                            final Object convertedVal = getTypedValue(converter, pid, value, typeInfo);
                             properties.put(key, convertedVal);
                         } catch ( final IOException io ) {
                             report.errors.add("Invalid value/type for configuration in '" + identifier + "' : " + pid + " - " + mapKey + " : " + io.getMessage());
@@ -269,7 +260,7 @@ public class JSONUtil {
         return configurations;
     }
 
-    private static JsonStructure build(final Object value) {
+    public static JsonStructure build(final Object value) {
         if ( value instanceof List ) {
             @SuppressWarnings("unchecked")
             final List<Object> list = (List<Object>)value;
@@ -398,6 +389,36 @@ public class JSONUtil {
         return null;
     }
 
+    public static Object getTypedValue(final TypeConverter converter,
+            final String pid,
+            final Object value,
+            final String typeInfo) throws IOException {
+        Object convertedVal = converter.convert(pid, value, typeInfo);
+        if ( convertedVal == null ) {
+            if ( typeInfo != null ) {
+                throw new IOException("Unable to convert to type " + typeInfo);
+            }
+            JsonStructure json = build(value);
+            if ( json == null ) {
+                convertedVal = value.toString();
+            } else {
+                // JSON Structure, this will result in a String or in an array of Strings
+                if ( json.getValueType() == ValueType.ARRAY ) {
+                    final JsonArray arr = (JsonArray)json;
+                    final String[] val = new String[arr.size()];
+                    for(int i=0;i<val.length;i++) {
+                        val[i] = TypeConverter.getConverter().convert(arr.get(i)).to(String.class);
+                    }
+                    convertedVal = val;
+
+                } else {
+                    convertedVal = TypeConverter.getConverter().convert(value).to(String.class);
+                }
+            }
+        }
+        return convertedVal;
+    }
+
     /**
      * Verify the JSON according to the rules
      * @param name The JSON name

Modified: felix/trunk/osgi-r7/configurator/src/main/java/org/apache/felix/configurator/impl/json/TypeConverter.java
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/configurator/src/main/java/org/apache/felix/configurator/impl/json/TypeConverter.java?rev=1815229&r1=1815228&r2=1815229&view=diff
==============================================================================
--- felix/trunk/osgi-r7/configurator/src/main/java/org/apache/felix/configurator/impl/json/TypeConverter.java (original)
+++ felix/trunk/osgi-r7/configurator/src/main/java/org/apache/felix/configurator/impl/json/TypeConverter.java Tue Nov 14 16:17:28 2017
@@ -20,17 +20,90 @@ package org.apache.felix.configurator.im
 
 import java.io.File;
 import java.io.IOException;
+import java.io.StringWriter;
+import java.lang.reflect.Type;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+
+import javax.json.Json;
+import javax.json.JsonStructure;
 
 import org.osgi.util.converter.Converter;
+import org.osgi.util.converter.ConverterFunction;
 import org.osgi.util.converter.Converters;
+import org.osgi.util.converter.TargetRule;
 import org.osgi.util.converter.TypeReference;
 
 public class TypeConverter {
 
     public static Converter getConverter() {
-        return Converters.standardConverter();
+        return Converters.standardConverter().newConverterBuilder().rule(new TargetRule() {
+
+            @Override
+            public Type getTargetType() {
+                return String.class;
+            }
+
+            @Override
+            public ConverterFunction getFunction() {
+                return new ConverterFunction() {
+
+                    @Override
+                    public Object apply(final Object obj, final Type targetType) throws Exception {
+                        if ( obj instanceof Map || obj instanceof List ) {
+                            final JsonStructure json = JSONUtil.build(obj);
+                            final StringWriter w = new StringWriter();
+                            Json.createWriter(w).write(json);
+                            return w.toString();
+                        }
+                        return CANNOT_HANDLE;
+                    }
+                };
+            }
+        }).build();
+    }
+
+    private static final Map<String, Class<?>> TYPE_MAP = new HashMap<>();
+    static {
+        // scalar types and primitive types
+        TYPE_MAP.put("String", String.class);
+        TYPE_MAP.put("Integer", Integer.class);
+        TYPE_MAP.put("int", Integer.class);
+        TYPE_MAP.put("Long", Long.class);
+        TYPE_MAP.put("long", Long.class);
+        TYPE_MAP.put("Float", Float.class);
+        TYPE_MAP.put("float", Float.class);
+        TYPE_MAP.put("Double", Double.class);
+        TYPE_MAP.put("double", Double.class);
+        TYPE_MAP.put("Byte", Byte.class);
+        TYPE_MAP.put("byte", Byte.class);
+        TYPE_MAP.put("Short", Short.class);
+        TYPE_MAP.put("short", Short.class);
+        TYPE_MAP.put("Character", Character.class);
+        TYPE_MAP.put("char", Character.class);
+        TYPE_MAP.put("Boolean", Boolean.class);
+        TYPE_MAP.put("boolean", Boolean.class);
+         // array of scalar types and primitive types
+        TYPE_MAP.put("String[]", String[].class);
+        TYPE_MAP.put("Integer[]", Integer[].class);
+        TYPE_MAP.put("int[]", int[].class);
+        TYPE_MAP.put("Long[]", Long[].class);
+        TYPE_MAP.put("long[]", long[].class);
+        TYPE_MAP.put("Float[]", Float[].class);
+        TYPE_MAP.put("float[]", float[].class);
+        TYPE_MAP.put("Double[]", Double[].class);
+        TYPE_MAP.put("double[]", double[].class);
+        TYPE_MAP.put("Byte[]", Byte[].class);
+        TYPE_MAP.put("byte[]", byte[].class);
+        TYPE_MAP.put("Short[]", Short[].class);
+        TYPE_MAP.put("short[]", short[].class);
+        TYPE_MAP.put("Boolean[]", Boolean[].class);
+        TYPE_MAP.put("boolean[]", boolean[].class);
+        TYPE_MAP.put("Character[]", Character[].class);
+        TYPE_MAP.put("char[]", char[].class);
     }
 
     private final List<File> allFiles = new ArrayList<>();
@@ -79,15 +152,19 @@ public class TypeConverter {
                     return new String[0];
                 }
                 final Object firstObject = list.get(0);
-                if ( firstObject instanceof String ) {
-                    return getConverter().convert(list).defaultValue(null).to(String[].class);
-                } else if ( firstObject instanceof Boolean ) {
-                    return getConverter().convert(list).defaultValue(null).to(Boolean[].class);
-                } else if ( firstObject instanceof Long || firstObject instanceof Integer ) {
-                    return getConverter().convert(list).defaultValue(null).to(Long[].class);
+                Object convertedValue = null;
+                if ( firstObject instanceof Boolean ) {
+                    convertedValue = getConverter().convert(list).defaultValue(null).to(Boolean[].class);
+                } else if ( firstObject instanceof Long || firstObject instanceof Integer || firstObject instanceof Byte || firstObject instanceof Short ) {
+                    convertedValue =  getConverter().convert(list).defaultValue(null).to(Long[].class);
                 } else if ( firstObject instanceof Double || firstObject instanceof Float ) {
-                    return getConverter().convert(list).defaultValue(null).to(Double[].class);
+                    convertedValue =  getConverter().convert(list).defaultValue(null).to(Double[].class);
+                }
+                if ( convertedValue == null ) {
+                    // convert to String (TODO)
+                    convertedValue = getConverter().convert(list).defaultValue(null).to(String[].class);
                 }
+                return convertedValue;
             }
             return null;
         }
@@ -148,87 +225,9 @@ public class TypeConverter {
             return filePaths;
         }
 
-        // scalar types and primitive types
-        if ( "String".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(String.class);
-
-        } else if ( "Integer".equals(typeInfo) || "int".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(Integer.class);
-
-        } else if ( "Long".equals(typeInfo) || "long".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(Long.class);
-
-        } else if ( "Float".equals(typeInfo) || "float".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(Float.class);
-
-        } else if ( "Double".equals(typeInfo) || "double".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(Double.class);
-
-        } else if ( "Byte".equals(typeInfo) || "byte".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(Byte.class);
-
-        } else if ( "Short".equals(typeInfo) || "short".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(Short.class);
-
-        } else if ( "Character".equals(typeInfo) || "char".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(Character.class);
-
-        } else if ( "Boolean".equals(typeInfo) || "boolean".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(Boolean.class);
-
-        }
-
-        // array of scalar types and primitive types
-        if ( "String[]".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(String[].class);
-
-        } else if ( "Integer[]".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(Integer[].class);
-
-        } else if ( "int[]".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(int[].class);
-
-        } else if ( "Long[]".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(Long[].class);
-
-        } else if ( "long[]".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(long[].class);
-
-        } else if ( "Float[]".equals(typeInfo)  ) {
-            return getConverter().convert(value).defaultValue(null).to(Float[].class);
-
-        } else if ( "float[]".equals(typeInfo)  ) {
-            return getConverter().convert(value).defaultValue(null).to(float[].class);
-
-        } else if ( "Double[]".equals(typeInfo)  ) {
-            return getConverter().convert(value).defaultValue(null).to(Double[].class);
-
-        } else if ( "double[]".equals(typeInfo)  ) {
-            return getConverter().convert(value).defaultValue(null).to(double[].class);
-
-        } else if ( "Byte[]".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(Byte[].class);
-
-        } else if ( "byte[]".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(byte[].class);
-
-        } else if ( "Short[]".equals(typeInfo)  ) {
-            return getConverter().convert(value).defaultValue(null).to(Short[].class);
-
-        } else if ( "short[]".equals(typeInfo)  ) {
-            return getConverter().convert(value).defaultValue(null).to(short[].class);
-
-        } else if ( "Character[]".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(Character[].class);
-
-        } else if ( "char[]".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(char[].class);
-
-        } else if ( "Boolean[]".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(Boolean[].class);
-
-        } else if ( "boolean[]".equals(typeInfo) ) {
-            return getConverter().convert(value).defaultValue(null).to(boolean[].class);
+        final Class<?> typeClass = TYPE_MAP.get(typeInfo);
+        if ( typeClass != null ) {
+            return getConverter().convert(value).defaultValue(null).to(typeClass);
         }
 
         // Collections of scalar types
@@ -258,6 +257,30 @@ public class TypeConverter {
 
         } else if ( "Collection<Boolean>".equals(typeInfo) ) {
             return getConverter().convert(value).defaultValue(null).to(new TypeReference<List<Boolean>>() {});
+        } else if ( "Collection".equals(typeInfo) ) {
+            if ( value instanceof List ) {
+                @SuppressWarnings("unchecked")
+                final List<Object> list = (List<Object>)value;
+                if ( list.isEmpty() ) {
+                    return new String[0];
+                }
+                final Object firstObject = list.get(0);
+                Object convertedValue = null;
+                if ( firstObject instanceof Boolean ) {
+                    convertedValue = getConverter().convert(list).defaultValue(null).to(new TypeReference<List<Boolean>>() {});
+                } else if ( firstObject instanceof Long || firstObject instanceof Integer || firstObject instanceof Byte || firstObject instanceof Short) {
+                    convertedValue = getConverter().convert(list).defaultValue(null).to(new TypeReference<List<Long>>() {});
+                } else if ( firstObject instanceof Double || firstObject instanceof Float ) {
+                    convertedValue = getConverter().convert(list).defaultValue(null).to(new TypeReference<List<Double>>() {});
+                }
+                if ( convertedValue == null ) {
+
+                    // convert to String (TODO)
+                    convertedValue = getConverter().convert(list).defaultValue(null).to(new TypeReference<List<String>>() {});
+                }
+                return convertedValue;
+            }
+            return getConverter().convert(value).defaultValue(null).to(Collection.class);
         }
 
         // unknown type - ignore configuration

Modified: felix/trunk/osgi-r7/configurator/src/test/java/org/apache/felix/configurator/impl/json/TypeConverterTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/configurator/src/test/java/org/apache/felix/configurator/impl/json/TypeConverterTest.java?rev=1815229&r1=1815228&r2=1815229&view=diff
==============================================================================
--- felix/trunk/osgi-r7/configurator/src/test/java/org/apache/felix/configurator/impl/json/TypeConverterTest.java (original)
+++ felix/trunk/osgi-r7/configurator/src/test/java/org/apache/felix/configurator/impl/json/TypeConverterTest.java Tue Nov 14 16:17:28 2017
@@ -19,6 +19,7 @@
 package org.apache.felix.configurator.impl.json;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -26,11 +27,10 @@ import static org.junit.Assert.assertTru
 import java.io.IOException;
 import java.lang.reflect.Array;
 import java.util.Collection;
+import java.util.Iterator;
 
 import javax.json.JsonObject;
 
-import org.apache.felix.configurator.impl.json.JSONUtil;
-import org.apache.felix.configurator.impl.json.TypeConverter;
 import org.junit.Test;
 
 public class TypeConverterTest {
@@ -250,4 +250,75 @@ public class TypeConverterTest {
         assertTrue(converter.convert(null, JSONUtil.getValue(properties, "boolean.array"), "Collection<Boolean>") instanceof Collection<?>);
         assertTrue(((Collection<Boolean>)converter.convert(null, JSONUtil.getValue(properties, "boolean.array"), "Collection<Boolean>")).iterator().next() instanceof Boolean);
     }
+
+    private Object getConverted(final String propName, final String typeInfo) throws Exception {
+        final TypeConverter converter = new TypeConverter(null);
+        final JsonObject config = JSONUtil.parseJSON("a",
+                JSONUtilTest.readJSON("json/complex-types.json"),
+                new JSONUtil.Report());
+        final JsonObject properties = (JsonObject)config.get("config");
+
+        final Object value = JSONUtil.getValue(properties, propName);
+        assertNotNull(value);
+        final Object converted = JSONUtil.getTypedValue(converter, null, value, typeInfo);
+        assertNotNull(converted);
+
+        return converted;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test public void testUntypedLongCollection() throws Exception {
+        final Object converted = getConverted("untyped", "Collection");
+        assertTrue(converted instanceof Collection<?>);
+        final Iterator<Object> iter = ((Collection<Object>)converted).iterator();
+        assertEquals(1L, iter.next());
+        assertEquals(2L, iter.next());
+        assertEquals(3L, iter.next());
+        assertFalse(iter.hasNext());
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test public void testUntypedMixedCollection() throws Exception {
+        // an untyped collection is tried to be converted to the type
+        // of the first item in the list. If that fails, String is used.
+        final Object converted = getConverted("untyped_mixed", "Collection");
+        assertTrue(converted instanceof Collection<?>);
+        final Iterator<Object> iter = ((Collection<Object>)converted).iterator();
+        assertEquals("1", iter.next());
+        assertEquals("two", iter.next());
+        assertEquals("3", iter.next());
+        assertFalse(iter.hasNext());
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test public void testEmptyTypedCollection() throws Exception {
+        final Object converted = getConverted("empty", "Collection<Integer>");
+        assertTrue(converted instanceof Collection<?>);
+        final Iterator<Object> iter = ((Collection<Object>)converted).iterator();
+        assertFalse(iter.hasNext());
+    }
+
+    @Test public void testObjectArray() throws Exception {
+        final Object converted = getConverted("objects_array", null);
+        assertTrue(converted.getClass().isArray());
+        final String[] vals = (String[])converted;
+        assertEquals(2, vals.length);
+        assertTrue(vals[0] instanceof String);
+        assertTrue(vals[1] instanceof String);
+        assertEquals("{\"foo\":1}", vals[0]);
+        assertEquals("{\"foo\":2}", vals[1]);
+    }
+
+    @Test public void testMixedObjectArray() throws Exception {
+        final Object converted = getConverted("objects_array_mixed", null);
+        assertTrue(converted.getClass().isArray());
+        final String[] vals = (String[])converted;
+        assertEquals(3, vals.length);
+        assertTrue(vals[0] instanceof String);
+        assertTrue(vals[1] instanceof String);
+        assertTrue(vals[2] instanceof String);
+        assertEquals("2", vals[0]);
+        assertEquals("{\"foo\":1}", vals[1]);
+        assertEquals("{\"foo\":2}", vals[2]);
+    }
 }

Added: felix/trunk/osgi-r7/configurator/src/test/resources/json/complex-types.json
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/configurator/src/test/resources/json/complex-types.json?rev=1815229&view=auto
==============================================================================
--- felix/trunk/osgi-r7/configurator/src/test/resources/json/complex-types.json (added)
+++ felix/trunk/osgi-r7/configurator/src/test/resources/json/complex-types.json Tue Nov 14 16:17:28 2017
@@ -0,0 +1,16 @@
+{
+  "config" : {
+    "untyped" : [1,2,3],
+    "untyped_mixed" : [1,"two",3],
+    "empty" : [],
+    "objects_array" : [
+       {"foo":1},
+       {"foo":2}      
+    ],
+    "objects_array_mixed" : [
+       2,
+       {"foo":1},       
+       {"foo":2}      
+    ]
+  }
+}

Propchange: felix/trunk/osgi-r7/configurator/src/test/resources/json/complex-types.json
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/osgi-r7/configurator/src/test/resources/json/complex-types.json
------------------------------------------------------------------------------
    svn:keywords = Id