You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by dl...@apache.org on 2017/02/17 07:52:44 UTC

svn commit: r1783340 [1/2] - in /felix/trunk/converter/schematizer: ./ src/main/java/org/apache/felix/schematizer/ src/main/java/org/apache/felix/schematizer/impl/ src/main/java/org/apache/felix/serializer/impl/json/ src/test/java/org/apache/felix/sche...

Author: dleangen
Date: Fri Feb 17 07:52:44 2017
New Revision: 1783340

URL: http://svn.apache.org/viewvc?rev=1783340&view=rev
Log:
Updates to experimental Schematizer that have been pending for quite some time

Added:
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schematizing.java   (with props)
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/SchematizingConverter.java   (with props)
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizingConverterBuilderImpl.java   (with props)
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizingConverterImpl.java   (with props)
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/CollectionType.java   (with props)
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyDTO4.java   (with props)
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/SchemaTest.java   (with props)
Modified:
    felix/trunk/converter/schematizer/pom.xml
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Node.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schema.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schematizer.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/StandardSchematizer.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/CollectionNode.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/NodeImpl.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchemaImpl.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizerImpl.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonDeserializingImpl.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonParser.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonSerializerImpl.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonSerializingImpl.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyDTO3.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/SchematizerServiceTest.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/json/JsonDeserializationTest.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/json/RepositorySerializationTest.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/provider/ObjectFactory.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/DTOSerializer.java

Modified: felix/trunk/converter/schematizer/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/pom.xml?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/pom.xml (original)
+++ felix/trunk/converter/schematizer/pom.xml Fri Feb 17 07:52:44 2017
@@ -28,7 +28,7 @@
 
     <name>Apache Felix Schematizer Service</name>
     <artifactId>org.apache.felix.schematizer</artifactId>
-    <version>0.1-SNAPSHOT</version>
+    <version>0.1.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <scm>

Modified: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Node.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Node.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Node.java (original)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Node.java Fri Feb 17 07:52:44 2017
@@ -19,6 +19,7 @@ import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.lang.reflect.Field;
 import java.lang.reflect.Type;
 import java.util.Collection;
 import java.util.HashMap;
@@ -39,6 +40,7 @@ public interface Node {
         public String name;
         public String path;
         public String type;
+        public String collectionType;
         public boolean isCollection;
         public Map<String, Node.DTO> children = new HashMap<>();
     }
@@ -49,6 +51,7 @@ public interface Node {
      */
     String absolutePath();
     Type type();
+    Field field();
     Optional<TypeReference<?>> typeReference();
     boolean isCollection();
     Map<String, Node> children();

Modified: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schema.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schema.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schema.java (original)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schema.java Fri Feb 17 07:52:44 2017
@@ -15,6 +15,7 @@
  */
 package org.apache.felix.schematizer;
 
+import java.util.Collection;
 import java.util.Map;
 import java.util.Optional;
 
@@ -22,10 +23,13 @@ public interface Schema {
     String name();
     Node rootNode();
     Optional<Node> nodeAtPath(String absolutePath);
+    Optional<Node> parentOf(Node aNode);
     Map<String, Node.DTO> toMap();
 
     /**
      * Recursively visits all nodes in the {@code Schema} for processing.
      */
     void visit(NodeVisitor visitor);
+
+    Collection<?> valuesAt(String path, Object object);
 }

Modified: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schematizer.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schematizer.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schematizer.java (original)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schematizer.java Fri Feb 17 07:52:44 2017
@@ -35,4 +35,6 @@ public interface Schematizer {
      * Shortcut for rule(String name, String path, TypeReference<T> type) when path is "/".
      */
     <T extends DTO>Schematizer rule(String name, TypeReference<T> type);
+
+    Schematizer usingLookup(ClassLoader classLoader);    
 }

Added: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schematizing.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schematizing.java?rev=1783340&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schematizing.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schematizing.java Fri Feb 17 07:52:44 2017
@@ -0,0 +1,26 @@
+/*
+ * 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.schematizer;
+
+import org.osgi.util.converter.Converter;
+
+public interface Schematizing {
+    Converter asDTO();
+    boolean isDTOType();
+    Converter withSchema(Schema s);
+    Schema getSchema();
+}

Propchange: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schematizing.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/SchematizingConverter.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/SchematizingConverter.java?rev=1783340&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/SchematizingConverter.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/SchematizingConverter.java Fri Feb 17 07:52:44 2017
@@ -0,0 +1,64 @@
+/*
+ * 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.schematizer;
+
+import org.apache.felix.schematizer.impl.SchematizingConverterImpl;
+import org.osgi.util.converter.Converter;
+import org.osgi.util.converter.ConverterBuilder;
+import org.osgi.util.converter.Converting;
+import org.osgi.util.converter.StandardConverter;
+
+public class SchematizingConverter implements Schematizing, Converter {
+    private final SchematizingConverterImpl converter;
+
+    public SchematizingConverter() {
+        converter = new SchematizingConverterImpl(new StandardConverter());
+    }
+
+    public SchematizingConverter(Converter c) {
+        converter = new SchematizingConverterImpl(c);
+    }
+
+    @Override
+    public Converting convert(Object obj) {
+        return converter.convert(obj);
+    }
+
+    @Override
+    public ConverterBuilder newConverterBuilder() {
+        return converter.newConverterBuilder();
+    }
+
+    @Override
+    public Converter asDTO() {
+        converter.asDTO();
+        return converter;
+    }
+
+    @Override
+    public boolean isDTOType() {
+        return converter.isDTOType();
+    }
+
+    public Converter withSchema(Schema s) {
+        return converter.withSchema(s);
+    }
+
+    public Schema getSchema() {
+        return converter.getSchema();
+    }
+}

Propchange: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/SchematizingConverter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/StandardSchematizer.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/StandardSchematizer.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/StandardSchematizer.java (original)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/StandardSchematizer.java Fri Feb 17 07:52:44 2017
@@ -19,6 +19,7 @@ package org.apache.felix.schematizer;
 import java.util.Map;
 import java.util.Optional;
 
+import org.apache.felix.schematizer.impl.SchematizerImpl;
 import org.osgi.dto.DTO;
 import org.osgi.util.converter.TypeReference;
 
@@ -26,7 +27,7 @@ public class StandardSchematizer impleme
     private final Schematizer schematizer;
 
     public StandardSchematizer() {
-        schematizer = null;//new SchematizerImpl();
+        schematizer = new SchematizerImpl();
     }
 
     @Override
@@ -58,4 +59,9 @@ public class StandardSchematizer impleme
     public <T extends DTO> Schematizer rule(String name, TypeReference<T> type) {
         return schematizer.rule(name, type);
     }
+
+    @Override
+    public Schematizer usingLookup(ClassLoader classLoader) {
+        return schematizer.usingLookup(classLoader);
+    }
 }

Modified: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/CollectionNode.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/CollectionNode.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/CollectionNode.java (original)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/CollectionNode.java Fri Feb 17 07:52:44 2017
@@ -17,7 +17,10 @@ package org.apache.felix.schematizer.imp
 
 import java.lang.reflect.Type;
 import java.util.Collection;
+import java.util.Map;
+import java.util.function.Function;
 
+import org.apache.felix.schematizer.Node;
 import org.osgi.util.converter.TypeReference;
 
 public class CollectionNode
@@ -43,8 +46,25 @@ public class CollectionNode
         collectionType = aCollectionType;
     }
 
+    public CollectionNode(
+            Node.DTO dto, 
+            String contextPath, 
+            Function<String, Type> f, 
+            Map<String, NodeImpl> nodes,
+            Class<? extends Collection<?>> aCollectionType ) {
+        super(dto, contextPath, f, nodes);
+        collectionType = aCollectionType;
+    }
+
     @Override
     public Class<? extends Collection<?>> collectionType() {
         return collectionType;
     }
+
+    @Override
+    public DTO toDTO() {
+        DTO dto = super.toDTO();
+        dto.collectionType = collectionType.getName();
+        return dto;
+    }
 }

Modified: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/NodeImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/NodeImpl.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/NodeImpl.java (original)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/NodeImpl.java Fri Feb 17 07:52:44 2017
@@ -15,6 +15,7 @@
  */
 package org.apache.felix.schematizer.impl;
 
+import java.lang.reflect.Field;
 import java.lang.reflect.Type;
 import java.util.Collection;
 import java.util.HashMap;
@@ -34,6 +35,7 @@ public class NodeImpl implements Node {
 
     private NodeImpl parent;
     private HashMap<String, NodeImpl> children = new HashMap<>();
+    private Field field;
 
     public NodeImpl(
             String aName,
@@ -57,16 +59,25 @@ public class NodeImpl implements Node {
         absolutePath = anAbsolutePath;
     }
 
+    @SuppressWarnings( { "unchecked", "rawtypes" } )
     public NodeImpl(Node.DTO dto, String contextPath, Function<String, Type> f, Map<String, NodeImpl> nodes) {
         name = dto.name;
         type = f.apply(dto.type);
         isCollection = dto.isCollection;
         absolutePath = contextPath + dto.path;
-        dto.children.values().stream().forEach( c -> {
-                NodeImpl node = new NodeImpl(c, contextPath, f, nodes);
-                children.put("/" + c.name, node);
-                nodes.put(c.path, node);
-            });
+        for (Node.DTO child : dto.children.values()) {
+            NodeImpl node;
+            if (child.isCollection)
+                try {
+                    node = new CollectionNode(child, contextPath, f, nodes, (Class)getClass().getClassLoader().loadClass(child.collectionType));
+                } catch ( ClassNotFoundException e ) {
+                    node = new CollectionNode(child, contextPath, f, nodes, (Class)Collection.class);
+                }
+            else
+                node = new NodeImpl(child, contextPath, f, nodes);
+            children.put("/" + child.name, node);
+            nodes.put(child.path, node);        
+        }
     }
 
     @Override
@@ -98,6 +109,15 @@ public class NodeImpl implements Node {
         return absolutePath;
     }
 
+    @Override
+    public Field field() {
+        return field;
+    }
+
+    public void field(Field aField) {
+        field = aField;
+    }
+
     @SuppressWarnings( { "unchecked", "rawtypes" } )
     @Override
     public Map<String, Node> children() {

Modified: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchemaImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchemaImpl.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchemaImpl.java (original)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchemaImpl.java Fri Feb 17 07:52:44 2017
@@ -15,14 +15,23 @@
  */
 package org.apache.felix.schematizer.impl;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 import org.apache.felix.schematizer.Node;
 import org.apache.felix.schematizer.NodeVisitor;
 import org.apache.felix.schematizer.Schema;
+import org.osgi.util.converter.Converter;
+import org.osgi.util.converter.StandardConverter;
 
 public class SchemaImpl
         implements Schema
@@ -49,11 +58,22 @@ public class SchemaImpl
     }
 
     @Override
-    public Optional<Node> nodeAtPath( String absolutePath )
-    {
+    public Optional<Node> nodeAtPath( String absolutePath ) {
         return Optional.ofNullable(nodes.get(absolutePath));
     }
 
+    @Override
+    public Optional<Node> parentOf( Node aNode ) {
+        if (aNode == null || aNode.absolutePath() == null)
+            return Optional.empty();
+
+        NodeImpl node = nodes.get(aNode.absolutePath());
+        if (node == null)
+            return Optional.empty();
+
+        return Optional.ofNullable( node.parent() );
+    }
+
     void add(NodeImpl node) {
         nodes.put(node.absolutePath(), node);
     }
@@ -79,4 +99,93 @@ public class SchemaImpl
     public void visit(NodeVisitor visitor) {
         nodes.values().stream().forEach(n ->  visitor.apply(n));
     }
-}
+
+    @Override
+    public Collection<?> valuesAt(String path, Object object) {
+        final Converter converter = new StandardConverter();
+        @SuppressWarnings( "unchecked" )
+        final Map<String, Object> map = (Map<String, Object>)converter.convert(object).sourceAsDTO().to( Map.class );
+        if (map == null || map.isEmpty())
+            return Collections.emptyList();
+
+        if (path.startsWith("/"))
+            path = path.substring(1);
+        String[] pathParts = path.split("/");
+        if (pathParts.length <= 0)
+            return Collections.emptyList();
+
+        List<String> contexts = Arrays.asList(pathParts);
+
+        return valuesAt("", map, contexts, 0);
+    }
+
+    @SuppressWarnings( { "rawtypes", "unchecked" } )
+    private Collection<?> valuesAt(String context, Map<String, Object> objectMap, List<String> contexts, int currentIndex) {
+        List<Object> result = new ArrayList<>();
+        String currentContext = contexts.get(currentIndex);
+        if (objectMap == null)
+            return result;
+        Object o = objectMap.get(currentContext);
+        if (o instanceof List) {
+            List<Object> l = (List<Object>)o;
+            if (currentIndex == contexts.size() - 1) {
+                // We are at the end, so just add the collection
+                result.add(convertToType(pathFrom(contexts, 0), l));
+                return result;
+            }
+
+            currentContext = pathFrom(contexts, ++currentIndex);
+            for (Object o2 : l)
+            {
+                final Converter converter = new StandardConverter();
+                final Map<String, Object> m = (Map<String, Object>)converter.convert(o2).sourceAsDTO().to( Map.class );
+                result.addAll( valuesAt( currentContext, m, contexts, currentIndex ) );
+            }        
+        } else if (o instanceof Map){
+            if (currentIndex == contexts.size() - 1) {
+                // We are at the end, so just add the result
+                result.add(convertToType(pathFrom(contexts, 0), (Map)o));
+                return result;
+            }
+
+            result.addAll(valuesAt( currentContext, (Map)o, contexts, ++currentIndex));
+        } else if (currentIndex < contexts.size() - 1) {
+            final Converter converter = new StandardConverter();
+            final Map<String, Object> m = (Map<String, Object>)converter.convert(o).sourceAsDTO().to(Map.class);
+            currentContext = pathFrom(contexts, ++currentIndex);
+            result.addAll(valuesAt( currentContext, m, contexts, currentIndex ));
+        } else {
+            result.add(o);
+        }
+
+        return result;
+    }
+
+    @SuppressWarnings( "rawtypes" )
+    private Object convertToType( String path, Map map ) {
+        Optional<Node> node = nodeAtPath(path);
+        if (!node.isPresent())
+            return map;
+
+        Object result = new StandardConverter().convert(map).targetAsDTO().to(node.get().type());
+        return result;
+    }
+
+    private List<?> convertToType( String path, List<?> list ) {
+        Optional<Node> node = nodeAtPath(path);
+        if (!node.isPresent())
+            return list;
+
+        return list.stream()
+                .map( v -> new StandardConverter().convert(v).sourceAsDTO().to(node.get().type()))
+                .collect( Collectors.toList() );
+    }
+
+    private String pathFrom(List<String> contexts, int index) {
+        return IntStream.range(0, contexts.size())
+                .filter( i -> i >= index )
+                .mapToObj( i -> contexts.get(i) )
+                .reduce( "", (s1,s2) -> s1 + "/" + s2 );
+                
+    }
+}
\ No newline at end of file

Modified: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizerImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizerImpl.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizerImpl.java (original)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizerImpl.java Fri Feb 17 07:52:44 2017
@@ -16,16 +16,21 @@
  */
 package org.apache.felix.schematizer.impl;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Optional;
@@ -39,12 +44,14 @@ import org.apache.felix.schematizer.Sche
 import org.apache.felix.schematizer.Schematizer;
 import org.apache.felix.schematizer.TypeRule;
 import org.osgi.dto.DTO;
+import org.osgi.util.converter.StandardConverter;
 import org.osgi.util.converter.TypeReference;
 
 public class SchematizerImpl implements Schematizer {
 
     private final Map<String, SchemaImpl> schemas = new HashMap<>();
     private volatile Map<String, Map<String, Object>> typeRules = new HashMap<>();
+    private final List<ClassLoader> classloaders = new ArrayList<>();
 
     @Override
     public Optional<Schema> get(String name) {
@@ -61,9 +68,11 @@ public class SchematizerImpl implements
         try {
             // TODO: some validation of the Map here would be good
             SchemaImpl schema = new SchemaImpl(name);
-            Node.DTO rootDTO = map.get("/");
+            Object rootMap = map.get("/");
+            Node.DTO rootDTO = new StandardConverter().convert(rootMap).to(Node.DTO.class);
             Map<String, NodeImpl> allNodes = new HashMap<>();
-            NodeImpl root = new NodeImpl(rootDTO, "", instantiator, allNodes);
+            NodeImpl root = new NodeImpl(rootDTO, "", new Instantiator(classloaders), allNodes);
+            associateChildNodes(root);
             schema.add(root);
             schema.add(allNodes);
             return Optional.of(schema);
@@ -107,6 +116,13 @@ public class SchematizerImpl implements
         return typeRules.get(name);
     }
 
+    @Override
+    public Schematizer usingLookup( ClassLoader classloader ) {
+        if (classloader != null)
+            classloaders.add(classloader);
+        return this;
+    }
+
     /**
      * Top-level entry point for schematizing a DTO. This is the starting point to set up the
      * parsing. All other methods make recursive calls.
@@ -172,8 +188,8 @@ public class SchematizerImpl implements
             rootNode = new NodeImpl(contextPath, targetCls, false, contextPath + "/");
         schema.add(rootNode);
         Map<String, NodeImpl> m = createMapFromDTO(name, targetCls, ref, contextPath, rules, schematizer);
-        m.values().stream().forEach(n -> n.parent(rootNode));
         m.values().stream().filter(v -> v.absolutePath().equals(rootNode.absolutePath() + v.name())).forEach(v -> rootNode.add(v));
+        associateChildNodes( rootNode );
         schema.add(m);
         return schema;
     }
@@ -189,10 +205,6 @@ public class SchematizerImpl implements
         SchemaImpl schema = new SchemaImpl(name);
         NodeImpl node = new NodeImpl(contextPath, targetCls, isCollection, contextPath + "/");
         schema.add(node);
-//        Map<String, NodeImpl> m = createMapFromDTO(name, targetCls, ref, contextPath, rules, schematizer);
-//        m.values().stream().forEach(n -> n.parent(node));
-//        m.values().stream().filter(v -> v.absolutePath().equals(node.absolutePath() + v.name())).forEach(v -> node.add(v));
-//        schema.add(m);
         return schema;
     }
 
@@ -261,9 +273,7 @@ public class SchematizerImpl implements
                 Map<String, NodeImpl> allNodes = embedded.toMapInternal();
                 allNodes.remove(path + "/");
                 result.putAll(allNodes);
-                Map<String, NodeImpl> childNodes = new HashMap<>();
-                allNodes.keySet().stream()
-                    .forEach( k -> {String k2 = k.replace(path, ""); childNodes.put(k2, allNodes.get(k));} );
+                Map<String, NodeImpl> childNodes = extractChildren(path, allNodes);
                 node.add(childNodes);
             } else {
                 Type fieldType = field.getType();
@@ -275,8 +285,10 @@ public class SchematizerImpl implements
                     Class<?> collectionType;
                     if (collectionTypeAnnotation != null)
                         collectionType = collectionTypeAnnotation.value();
+                    else if (hasCollectionTypeAnnotation(field))
+                        collectionType = collectionTypeOf(field);
                     else
-                        collectionType = Object.class;
+                        collectionType = Object.class;                        
                     node = new CollectionNode(
                             field.getName(),
                             collectionType,
@@ -292,9 +304,7 @@ public class SchematizerImpl implements
                         Map<String, NodeImpl> allNodes = embedded.toMapInternal();
                         allNodes.remove(path + "/");
                         result.putAll(allNodes);
-                        Map<String, NodeImpl> childNodes = new HashMap<>();
-                        allNodes.keySet().stream()
-                            .forEach( k -> {String k2 = k.replace(path, ""); childNodes.put(k2, allNodes.get(k));} );
+                        Map<String, NodeImpl> childNodes = extractChildren(path, allNodes);
                         node.add(childNodes);
                     }
                 }
@@ -312,9 +322,7 @@ public class SchematizerImpl implements
                     Map<String, NodeImpl> allNodes = embedded.toMapInternal();
                     allNodes.remove(path + "/");
                     result.putAll(allNodes);
-                    Map<String, NodeImpl> childNodes = new HashMap<>();
-                    allNodes.keySet().stream()
-                        .forEach( k -> {String k2 = k.replace(path, ""); childNodes.put(k2, allNodes.get(k));} );
+                    Map<String, NodeImpl> childNodes = extractChildren(path, allNodes);
                     node.add(childNodes);
                 } else {
                     node = new NodeImpl(
@@ -334,6 +342,17 @@ public class SchematizerImpl implements
         }
     }
 
+    private static Map<String, NodeImpl> extractChildren( String path, Map<String, NodeImpl> allNodes ) {
+        final Map<String, NodeImpl> children = new HashMap<>();
+        for (String key : allNodes.keySet()) {
+            String newKey = key.replace(path, "");
+            if (!newKey.substring(1).contains("/"))
+                children.put( newKey, allNodes.get(key));
+        }
+
+        return children;
+    }
+
     private static SchemaImpl handleInvalid() {
         // TODO
         return null;
@@ -362,19 +381,78 @@ public class SchematizerImpl implements
         return typeRef;
     }
 
-    /**
-     * In an OSGi environment, this is too naive, and will quickly break down.
-     * Consider it more as a placeholder for now.
-     */
-    private static final Instantiator instantiator = new Instantiator();
     public static class Instantiator implements Function<String, Type> {
+        private final List<ClassLoader> classloaders = new ArrayList<>();
+
+        public Instantiator(List<ClassLoader> aClassLoadersList) {
+            classloaders.addAll( aClassLoadersList );
+        }
+
         @Override
         public Type apply(String className) {
+            for (ClassLoader cl : classloaders) {
+                try {
+                    return cl.loadClass(className);
+                } catch (ClassNotFoundException e) {
+                    // Try next
+                }
+            }
+
+            // Could not find the class. Try "this" ClassLoader
             try {
-                return Class.forName(className);
-            } catch ( ClassNotFoundException e ) {
-                return Object.class;
+                return getClass().getClassLoader().loadClass(className);
+            } catch (ClassNotFoundException e) {
+                // Too bad
             }
+
+            // Nothing to do. Return Object.class as the fallback
+            return Object.class;
+        }
+    }
+
+    static private void associateChildNodes(NodeImpl rootNode) {
+        for (NodeImpl child: rootNode.childrenInternal().values()) {
+            child.parent(rootNode);
+            String fieldName = child.name();
+            Class<?> parentClass = rawClassOf(rootNode.type());
+            try {
+                Field field = parentClass.getField(fieldName);
+                child.field(field);
+            } catch ( NoSuchFieldException e ) {
+                e.printStackTrace();
+            }            
+
+            associateChildNodes(child);
+        }
+    }
+
+    static private boolean hasCollectionTypeAnnotation(Field field) {
+        if (field == null)
+            return false;
+
+        Annotation[] annotations = field.getAnnotations();
+        if (annotations.length == 0)
+            return false;
+
+        return Arrays.stream(annotations)
+            .map(a -> a.annotationType().getName())
+            .anyMatch(a -> "CollectionType".equals(a.substring(a.lastIndexOf(".") + 1) ));
+    }
+
+    static private Class<?> collectionTypeOf(Field field) {
+        Annotation[] annotations = field.getAnnotations();
+
+        Annotation annotation = Arrays.stream(annotations)
+            .filter(a -> "CollectionType".equals(a.annotationType().getName().substring(a.annotationType().getName().lastIndexOf(".") + 1) ))
+            .findFirst()
+            .get();
+
+        try {
+            Method m = annotation.annotationType().getMethod("value");
+            Class<?> value = (Class<?>)m.invoke(annotation, (Object[])null);
+            return value;            
+        } catch ( Exception e ) {
+            return null;
         }
     }
 }

Added: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizingConverterBuilderImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizingConverterBuilderImpl.java?rev=1783340&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizingConverterBuilderImpl.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizingConverterBuilderImpl.java Fri Feb 17 07:52:44 2017
@@ -0,0 +1,62 @@
+/*
+ * 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.schematizer.impl;
+
+import java.lang.reflect.Type;
+
+import org.osgi.util.converter.Converter;
+import org.osgi.util.converter.ConverterBuilder;
+import org.osgi.util.converter.Rule;
+import org.osgi.util.converter.StandardConverter;
+import org.osgi.util.converter.TypeReference;
+import org.osgi.util.function.Function;
+
+public class SchematizingConverterBuilderImpl implements ConverterBuilder {
+
+    private final ConverterBuilder builder = new StandardConverter().newConverterBuilder();
+
+    @Override
+    public Converter build()
+    {
+        Converter converter = builder.build(); 
+        return new SchematizingConverterImpl(converter);
+    }
+
+    @Override
+    public <F, T> ConverterBuilder rule( Rule<F, T> rule )
+    {
+        return builder.rule(rule);
+    }
+
+    @Override
+    public <F, T> ConverterBuilder rule( Class<F> fromCls, Class<T> toCls, Function<F, T> toFun, Function<T, F> fromFun )
+    {
+        return builder.rule(fromCls, toCls, toFun, fromFun);
+    }
+
+    @Override
+    public <F, T> ConverterBuilder rule( TypeReference<F> fromRef, TypeReference<T> toRef, Function<F, T> toFun, Function<T, F> fromFun )
+    {
+        return builder.rule(fromRef, toRef, toFun, fromFun);
+    }
+
+    @Override
+    public <F, T> ConverterBuilder rule( Type fromType, Type toType, Function<F, T> toFun, Function<T, F> fromFun )
+    {
+        return builder.rule(fromType, toType, toFun, fromFun);
+    }
+}

Propchange: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizingConverterBuilderImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizingConverterImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizingConverterImpl.java?rev=1783340&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizingConverterImpl.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizingConverterImpl.java Fri Feb 17 07:52:44 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.schematizer.impl;
+
+import org.apache.felix.schematizer.Schema;
+import org.apache.felix.schematizer.Schematizing;
+import org.osgi.util.converter.Converter;
+import org.osgi.util.converter.ConverterBuilder;
+import org.osgi.util.converter.Converting;
+
+public class SchematizingConverterImpl implements Schematizing, Converter {
+
+    private final Converter converter;
+    private Schema schema;
+    private boolean asDTO = false;
+
+    public SchematizingConverterImpl(Converter c)
+    {
+        converter = c;
+    }
+
+    @Override
+    public Converting convert(Object obj) {
+        return converter.convert(obj);
+    }
+
+    @Override
+    public ConverterBuilder newConverterBuilder() {
+        return new SchematizingConverterBuilderImpl();
+    }
+
+    @Override
+    public Converter asDTO() {
+        asDTO = true;
+        return converter;
+    }
+
+    @Override
+    public boolean isDTOType() {
+        return asDTO;
+    }
+
+    public Converter withSchema(Schema s) {
+        schema = s;
+        return this;
+    }
+
+    public Schema getSchema() {
+        return schema;
+    }
+}

Propchange: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizingConverterImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonDeserializingImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonDeserializingImpl.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonDeserializingImpl.java (original)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonDeserializingImpl.java Fri Feb 17 07:52:44 2017
@@ -31,6 +31,7 @@ import java.util.Scanner;
 
 import org.apache.felix.schematizer.Node;
 import org.apache.felix.schematizer.Schema;
+import org.apache.felix.schematizer.Schematizing;
 import org.apache.felix.schematizer.impl.Util;
 import org.osgi.dto.DTO;
 import org.osgi.service.serializer.Deserializing;
@@ -42,6 +43,7 @@ public class JsonDeserializingImpl<T> im
     private final Object target;
     private Converter converter;
     private Schema schema;
+    private boolean asDTO = false;
 
     public JsonDeserializingImpl(Converter c, Object t) {
         converter = c;
@@ -52,13 +54,11 @@ public class JsonDeserializingImpl<T> im
     public JsonDeserializingImpl<T> with(Converter c)
     {
         converter = c;
-        return this;
-    }
-
-    public JsonDeserializingImpl<T> withContext(Object obj)
-    {
-        if(obj instanceof Schema)
-            schema = (Schema)obj;
+        if(converter instanceof Schematizing) {
+            Schematizing s = (Schematizing)converter;
+            schema = s.getSchema();
+            asDTO = s.isDTOType();
+        }
         return this;
     }
 
@@ -73,7 +73,10 @@ public class JsonDeserializingImpl<T> im
         if (schema != null)
             return deserialize(m);
 
-        return converter.convert(m).to(clazz);
+        if (asDTO)
+            return converter.convert(m).targetAsDTO().to(clazz);
+        else
+            return converter.convert(m).to(clazz);
     }
 
     @Override
@@ -144,6 +147,8 @@ public class JsonDeserializingImpl<T> im
                 try {
                     Field f = targetCls.getField(entry.getKey().toString());
                     Object val = entry.getValue();
+                    if (val == null)
+                        continue;
                     String path = contextPath + f.getName();
                     Optional<Node> opt = schema.nodeAtPath(path);
                     if (opt.isPresent()) {
@@ -169,14 +174,12 @@ public class JsonDeserializingImpl<T> im
                                     else if (DTO.class.isAssignableFrom(Util.rawClassOf(type)))
                                         c.add(convertToDTO((Class)Util.rawClassOf(type), (Map)o, schema, path + "/"));
                                     else
-                                        c.add(converter.convert(c).to(type));
+                                        c.add(converter.convert(o).to(type));
                                 }
                                 obj = c;
                             } else {
                                 Type type = node.type();
-                                if (val == null)
-                                    obj = null;
-                                else if (DTO.class.isAssignableFrom(Util.rawClassOf(type)))
+                                if (DTO.class.isAssignableFrom(Util.rawClassOf(type)))
                                     obj = convertToDTO((Class)Util.rawClassOf(type), (Map)val, schema, path + "/");
                                 else
                                     obj = converter.convert(val).to(type);
@@ -211,6 +214,8 @@ public class JsonDeserializingImpl<T> im
 
     @SuppressWarnings( "unchecked" )
     private <V extends Collection<?>>V instantiateCollection(Class<V> collectionClass) {
+        if (collectionClass == null)
+            return (V)new ArrayList<V>();
         if (Collection.class.equals(collectionClass) || List.class.isAssignableFrom(collectionClass))
             return (V)new ArrayList<V>();
         else

Modified: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonParser.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonParser.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonParser.java (original)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonParser.java Fri Feb 17 07:52:44 2017
@@ -123,7 +123,10 @@ public class JsonParser {
         case 'N':
             return null;
         default:
-            return Long.parseLong(jsonValue);
+            if (jsonValue.contains("."))
+                return Double.parseDouble(jsonValue);
+            else
+                return Long.parseLong(jsonValue);
         }
     }
 
@@ -132,6 +135,10 @@ public class JsonParser {
             throw new IllegalArgumentException("Malformatted JSON object: " + jsonObject);
 
         jsonObject = jsonObject.substring(1, jsonObject.length() - 1);
+
+        if (jsonObject.isEmpty())
+            return null;
+
         Map<String, Object> values = new HashMap<>();
         for (String element : parseKeyValueListRaw(jsonObject)) {
             Pair<String, Object> pair = parseKeyValue(element);
@@ -144,7 +151,9 @@ public class JsonParser {
     private static List<String> parseKeyValueListRaw(String jsonKeyValueList) {
         if (jsonKeyValueList.trim().isEmpty())
             return Collections.emptyList();
-        jsonKeyValueList = jsonKeyValueList + ","; // append comma to simplify parsing
+        // Append comma to simplify parsing, if there is not already a trailing comma
+        if (!jsonKeyValueList.endsWith(","))
+                jsonKeyValueList = jsonKeyValueList + ",";
         List<String> elements = new ArrayList<>();
 
         int i=0;

Modified: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonSerializerImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonSerializerImpl.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonSerializerImpl.java (original)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonSerializerImpl.java Fri Feb 17 07:52:44 2017
@@ -24,16 +24,16 @@ import java.nio.charset.StandardCharsets
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.apache.felix.schematizer.SchematizingConverter;
 import org.osgi.service.serializer.Serializer;
 import org.osgi.service.serializer.Serializing;
 import org.osgi.util.converter.Converter;
-import org.osgi.util.converter.StandardConverter;
 import org.osgi.util.converter.TypeReference;
 
 public class JsonSerializerImpl implements Serializer {
     private final Map<String, Object> configuration = new ConcurrentHashMap<>();
     private final ThreadLocal<Boolean> threadLocal = new ThreadLocal<>();
-    private final Converter converter = new StandardConverter();
+    private final SchematizingConverter converter = new SchematizingConverter();
 
     @Override
     public <T> JsonDeserializingImpl<T> deserialize(Class<T> cls) {

Modified: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonSerializingImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonSerializingImpl.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonSerializingImpl.java (original)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonSerializingImpl.java Fri Feb 17 07:52:44 2017
@@ -86,7 +86,7 @@ public class JsonSerializingImpl impleme
         } else if (obj instanceof Collection) {
             return encodeCollection((Collection) obj);
         } else if (obj instanceof DTO) {
-            return encodeMap(converter.convert(obj).to(Map.class));
+            return encodeMap(converter.convert(obj).sourceAsDTO().to(Map.class));
         } else if (obj.getClass().isArray()) {
             return encodeCollection(asCollection(obj));
         } else if (obj instanceof Number) {

Added: felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/CollectionType.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/CollectionType.java?rev=1783340&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/CollectionType.java (added)
+++ felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/CollectionType.java Fri Feb 17 07:52:44 2017
@@ -0,0 +1,28 @@
+/*
+ * 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.schematizer.impl;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface CollectionType {
+    Class<?> value() default Object.class;
+}

Propchange: felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/CollectionType.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyDTO3.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyDTO3.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyDTO3.java (original)
+++ felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyDTO3.java Fri Feb 17 07:52:44 2017
@@ -1,51 +1,4 @@
 /*
-    @Test
-    public void testSchematizeDTO() {
-        Optional<Schema> opt = schematizer
-                .rule("MyDTO", new TypeReference<MyDTO>(){})
-                .rule("MyDTO", "/embedded", new TypeReference<MyEmbeddedDTO>(){})
-                .get("MyDTO");
-
-        assertTrue(opt.isPresent());
-        Schema s = opt.get();
-        assertNotNull(s);
-        Node root = s.rootNode();
-        assertNodeEquals("", "/", false, MyDTO.class, root);
-        assertEquals(4, root.children().size());
-        Node pingNode = root.children().get("/ping");
-        assertNodeEquals("ping", "/ping", false, String.class, pingNode);
-        Node pongNode = root.children().get("/pong");
-        assertNodeEquals("pong", "/pong", false, Long.class, pongNode);
-        Node countNode = root.children().get("/count");
-        assertNodeEquals("count", "/count", false, MyDTO.Count.class, countNode);
-        Node embeddedNode = root.children().get("/embedded");
-        assertEquals(3, embeddedNode.children().size());
-        assertNodeEquals("embedded", "/embedded", false, MyEmbeddedDTO.class, embeddedNode);
-        Node marcoNode = embeddedNode.children().get("/marco");
-        assertNodeEquals("marco", "/embedded/marco", false, String.class, marcoNode);
-        Node poloNode = embeddedNode.children().get("/polo");
-        assertNodeEquals("polo", "/embedded/polo", false, Long.class, poloNode);
-        Node alphaNode = embeddedNode.children().get("/alpha");
-        assertNodeEquals("alpha", "/embedded/alpha", false, MyEmbeddedDTO.Alpha.class, alphaNode);
-
-        Node sRoot = s.nodeAtPath("/").get();
-        assertNodeEquals("", "/", false, MyDTO.class, sRoot);
-        Node sPingNode = s.nodeAtPath("/ping").get();
-        assertNodeEquals("ping", "/ping", false, String.class, sPingNode);
-        Node sPongNode = s.nodeAtPath("/pong").get();
-        assertNodeEquals("pong", "/pong", false, Long.class, sPongNode);
-        Node sCountNode = s.nodeAtPath("/count").get();
-        assertNodeEquals("count", "/count", false, MyDTO.Count.class, sCountNode);
-        Node sEmbeddedNode = s.nodeAtPath("/embedded").get();
-        assertNodeEquals("embedded", "/embedded", false, MyEmbeddedDTO.class, sEmbeddedNode);
-        Node sMarcoNode = s.nodeAtPath("/embedded/marco").get();
-        assertNodeEquals("marco", "/embedded/marco", false, String.class, sMarcoNode);
-        Node sPoloNode = s.nodeAtPath("/embedded/polo").get();
-        assertNodeEquals("polo", "/embedded/polo", false, Long.class, sPoloNode);
-        Node sAlphaNode = s.nodeAtPath("/embedded/alpha").get();
-        assertNodeEquals("alpha", "/embedded/alpha", false, MyEmbeddedDTO.Alpha.class, sAlphaNode);
-    }
-
  * 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.

Added: felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyDTO4.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyDTO4.java?rev=1783340&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyDTO4.java (added)
+++ felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyDTO4.java Fri Feb 17 07:52:44 2017
@@ -0,0 +1,35 @@
+/*
+ * 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.schematizer.impl;
+
+import java.util.List;
+
+import org.osgi.dto.DTO;
+
+public class MyDTO4 extends DTO {
+    public enum Count { ONE, TWO, THREE }
+
+    public Count count;
+
+    public String ping;
+
+    public long pong;
+
+    @org.apache.felix.schematizer.impl.CollectionType(MyEmbeddedDTO.class)
+    public List<MyEmbeddedDTO> embedded;
+}
+

Propchange: felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyDTO4.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/SchemaTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/SchemaTest.java?rev=1783340&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/SchemaTest.java (added)
+++ felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/SchemaTest.java Fri Feb 17 07:52:44 2017
@@ -0,0 +1,174 @@
+/*
+ * 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.schematizer.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.felix.schematizer.Schema;
+import org.apache.felix.schematizer.impl.MyEmbeddedDTO.Alpha;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.util.converter.TypeReference;
+
+import junit.framework.AssertionFailedError;
+
+import static org.junit.Assert.*;
+
+public class SchemaTest {
+    private SchematizerImpl schematizer;
+
+    @Before
+    public void setUp() {
+        schematizer = new SchematizerImpl();
+    }
+
+    @After
+    public void tearDown() {
+        schematizer = null;
+    }
+
+    @Test
+    public void testValues() {
+        Optional<Schema> opt = schematizer
+                .rule("MyDTO", new TypeReference<MyDTO3<MyEmbeddedDTO2<String>>>(){})
+                .rule("MyDTO", "/embedded", new TypeReference<MyEmbeddedDTO2<String>>(){})
+                .rule("MyDTO", "/embedded/value", String.class)
+                .get("MyDTO");
+
+        assertTrue(opt.isPresent());
+        Schema s = opt.get();
+        assertNotNull(s);
+
+        MyEmbeddedDTO2<String> embedded1 = new MyEmbeddedDTO2<>();
+        embedded1.value = "value1";
+        MyEmbeddedDTO2<String> embedded2 = new MyEmbeddedDTO2<>();
+        embedded2.value = "value2";
+        MyEmbeddedDTO2<String> embedded3 = new MyEmbeddedDTO2<>();
+        embedded3.value = "value3";
+
+        MyDTO3<MyEmbeddedDTO2<String>> dto = new MyDTO3<>();
+        dto.ping = "lalala";
+        dto.pong = Long.MIN_VALUE;
+        dto.count = MyDTO3.Count.ONE;
+        dto.embedded = new ArrayList<>();
+        dto.embedded.add(embedded1);
+        dto.embedded.add(embedded2);
+        dto.embedded.add(embedded3);
+
+        assertEquals("lalala", s.valuesAt("/ping", dto).iterator().next());
+        assertEquals(Long.MIN_VALUE, s.valuesAt("/pong", dto).iterator().next());
+        assertEquals(MyDTO3.Count.ONE, s.valuesAt("/count", dto).iterator().next());
+        assertNotNull(s.valuesAt("/embedded", dto));
+        Object embeddedList = s.valuesAt("/embedded", dto).iterator().next();
+        assertNotNull(embeddedList);
+        assertTrue(embeddedList instanceof List);
+        assertFalse(((List<?>)embeddedList).isEmpty());
+        Object embeddedObject = ((List<?>)embeddedList).get(0);
+        assertTrue(embeddedObject instanceof MyEmbeddedDTO2);
+        assertListEquals(Arrays.asList(new String[]{"value1", "value2", "value3"}), s.valuesAt("/embedded/value", dto));
+    }
+
+    @Test
+    public void testEmbeddedValues() {
+        Optional<Schema> opt = schematizer
+                .rule("MyDTO", new TypeReference<MyDTO>(){})
+                .rule("MyDTO", "/embedded", new TypeReference<MyEmbeddedDTO>(){})
+                .get("MyDTO");
+
+        assertTrue(opt.isPresent());
+        Schema s = opt.get();
+        assertNotNull(s);
+
+        MyEmbeddedDTO embedded = new MyEmbeddedDTO();
+        embedded.alpha = Alpha.A;
+        embedded.marco = "mmmm";
+        embedded.polo = 66;
+
+        MyDTO dto = new MyDTO();
+        dto.ping = "lalala";
+        dto.pong = Long.MIN_VALUE;
+        dto.count = MyDTO.Count.ONE;
+        dto.embedded = embedded;
+
+        assertEquals("lalala", s.valuesAt("/ping", dto).iterator().next());
+        assertEquals(Long.MIN_VALUE, s.valuesAt("/pong", dto).iterator().next());
+        assertEquals(MyDTO.Count.ONE, s.valuesAt("/count", dto).iterator().next());
+        assertNotNull(s.valuesAt("/embedded", dto));
+        Object embeddedObject = s.valuesAt("/embedded", dto).iterator().next();
+        assertTrue(embeddedObject instanceof MyEmbeddedDTO);
+        assertEquals(Alpha.A, s.valuesAt("/embedded/alpha", dto).iterator().next());
+        assertEquals("mmmm", s.valuesAt("/embedded/marco", dto).iterator().next());
+        assertEquals(66L, s.valuesAt("/embedded/polo", dto).iterator().next());
+    }
+
+    @Test
+    public void testNullValues() {
+        Optional<Schema> opt = schematizer
+                .rule("MyDTO", new TypeReference<MyDTO3<MyEmbeddedDTO2<String>>>(){})
+                .rule("MyDTO", "/embedded", new TypeReference<MyEmbeddedDTO2<String>>(){})
+                .rule("MyDTO", "/embedded/value", String.class)
+                .get("MyDTO");
+
+        assertTrue(opt.isPresent());
+        Schema s = opt.get();
+        assertNotNull(s);
+
+        MyEmbeddedDTO2<String> embedded1 = new MyEmbeddedDTO2<>();
+        MyEmbeddedDTO2<String> embedded2 = new MyEmbeddedDTO2<>();
+        MyEmbeddedDTO2<String> embedded3 = new MyEmbeddedDTO2<>();
+
+        MyDTO3<MyEmbeddedDTO2<String>> dto = new MyDTO3<>();
+        dto.ping = "lalala";
+        dto.pong = Long.MIN_VALUE;
+        dto.count = MyDTO3.Count.ONE;
+        dto.embedded = new ArrayList<>();
+        dto.embedded.add(embedded1);
+        dto.embedded.add(embedded2);
+        dto.embedded.add(embedded3);
+
+        assertEquals("lalala", s.valuesAt("/ping", dto).iterator().next());
+        assertEquals(Long.MIN_VALUE, s.valuesAt("/pong", dto).iterator().next());
+        assertEquals(MyDTO3.Count.ONE, s.valuesAt("/count", dto).iterator().next());
+        assertNotNull(s.valuesAt("/embedded", dto));
+        assertListEquals(Arrays.asList(new String[]{null, null, null}), s.valuesAt("/embedded/value", dto));
+    }
+
+    @SuppressWarnings( { "rawtypes", "unchecked" } )
+    private boolean assertListEquals(List<?> expected, Collection<?> actual) {
+        if (expected == null || actual == null)
+            throw new AssertionFailedError("The collection is null");
+
+        if (expected.size() != actual.size())
+            throw new AssertionFailedError("Expected list size of " + expected.size() + ", but was: " + actual.size());
+
+        List actualList = new ArrayList<>();
+        if (actual instanceof List)
+            actualList = (List)actual;
+        else
+            actualList.addAll(actual);
+
+        for (int i = 0; i < actual.size(); i++)
+            assertEquals(expected.get(i), actualList.get(i));
+
+        return true;
+    }
+}

Propchange: felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/SchemaTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/SchematizerServiceTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/SchematizerServiceTest.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/SchematizerServiceTest.java (original)
+++ felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/SchematizerServiceTest.java Fri Feb 17 07:52:44 2017
@@ -59,40 +59,40 @@ public class SchematizerServiceTest {
         Schema s = opt.get();
         assertNotNull(s);
         Node root = s.rootNode();
-        assertNodeEquals("", "/", false, MyDTO.class, root);
+        assertNodeEquals("", "/", false, MyDTO.class, false, root);
         assertEquals(4, root.children().size());
         Node pingNode = root.children().get("/ping");
-        assertNodeEquals("ping", "/ping", false, String.class, pingNode);
+        assertNodeEquals("ping", "/ping", false, String.class, true, pingNode);
         Node pongNode = root.children().get("/pong");
-        assertNodeEquals("pong", "/pong", false, Long.class, pongNode);
+        assertNodeEquals("pong", "/pong", false, Long.class, true, pongNode);
         Node countNode = root.children().get("/count");
-        assertNodeEquals("count", "/count", false, MyDTO.Count.class, countNode);
+        assertNodeEquals("count", "/count", false, MyDTO.Count.class, true, countNode);
         Node embeddedNode = root.children().get("/embedded");
         assertEquals(3, embeddedNode.children().size());
-        assertNodeEquals("embedded", "/embedded", false, MyEmbeddedDTO.class, embeddedNode);
+        assertNodeEquals("embedded", "/embedded", false, MyEmbeddedDTO.class, true, embeddedNode);
         Node marcoNode = embeddedNode.children().get("/marco");
-        assertNodeEquals("marco", "/embedded/marco", false, String.class, marcoNode);
+        assertNodeEquals("marco", "/embedded/marco", false, String.class, true, marcoNode);
         Node poloNode = embeddedNode.children().get("/polo");
-        assertNodeEquals("polo", "/embedded/polo", false, Long.class, poloNode);
+        assertNodeEquals("polo", "/embedded/polo", false, Long.class, true, poloNode);
         Node alphaNode = embeddedNode.children().get("/alpha");
-        assertNodeEquals("alpha", "/embedded/alpha", false, MyEmbeddedDTO.Alpha.class, alphaNode);
+        assertNodeEquals("alpha", "/embedded/alpha", false, MyEmbeddedDTO.Alpha.class, true, alphaNode);
 
         Node sRoot = s.nodeAtPath("/").get();
-        assertNodeEquals("", "/", false, MyDTO.class, sRoot);
+        assertNodeEquals("", "/", false, MyDTO.class, false, sRoot);
         Node sPingNode = s.nodeAtPath("/ping").get();
-        assertNodeEquals("ping", "/ping", false, String.class, sPingNode);
+        assertNodeEquals("ping", "/ping", false, String.class, true, sPingNode);
         Node sPongNode = s.nodeAtPath("/pong").get();
-        assertNodeEquals("pong", "/pong", false, Long.class, sPongNode);
+        assertNodeEquals("pong", "/pong", false, Long.class, true, sPongNode);
         Node sCountNode = s.nodeAtPath("/count").get();
-        assertNodeEquals("count", "/count", false, MyDTO.Count.class, sCountNode);
+        assertNodeEquals("count", "/count", false, MyDTO.Count.class, true, sCountNode);
         Node sEmbeddedNode = s.nodeAtPath("/embedded").get();
-        assertNodeEquals("embedded", "/embedded", false, MyEmbeddedDTO.class, sEmbeddedNode);
+        assertNodeEquals("embedded", "/embedded", false, MyEmbeddedDTO.class, true, sEmbeddedNode);
         Node sMarcoNode = s.nodeAtPath("/embedded/marco").get();
-        assertNodeEquals("marco", "/embedded/marco", false, String.class, sMarcoNode);
+        assertNodeEquals("marco", "/embedded/marco", false, String.class, true, sMarcoNode);
         Node sPoloNode = s.nodeAtPath("/embedded/polo").get();
-        assertNodeEquals("polo", "/embedded/polo", false, Long.class, sPoloNode);
+        assertNodeEquals("polo", "/embedded/polo", false, Long.class, true, sPoloNode);
         Node sAlphaNode = s.nodeAtPath("/embedded/alpha").get();
-        assertNodeEquals("alpha", "/embedded/alpha", false, MyEmbeddedDTO.Alpha.class, sAlphaNode);
+        assertNodeEquals("alpha", "/embedded/alpha", false, MyEmbeddedDTO.Alpha.class, true, sAlphaNode);
     }
 
     @Test
@@ -107,32 +107,78 @@ public class SchematizerServiceTest {
         Schema s = opt.get();
         assertNotNull(s);
         Node root = s.rootNode();
-        assertNodeEquals("", "/", false, new TypeReference<MyDTO3<MyEmbeddedDTO2<String>>>(){}.getType(), root);
+        assertNodeEquals("", "/", false, new TypeReference<MyDTO3<MyEmbeddedDTO2<String>>>(){}.getType(), false, root);
         assertEquals(4, root.children().size());
         Node pingNode = root.children().get("/ping");
-        assertNodeEquals("ping", "/ping", false, String.class, pingNode);
+        assertNodeEquals("ping", "/ping", false, String.class, true, pingNode);
         Node pongNode = root.children().get("/pong");
-        assertNodeEquals("pong", "/pong", false, Long.class, pongNode);
+        assertNodeEquals("pong", "/pong", false, Long.class, true, pongNode);
         Node countNode = root.children().get("/count");
-        assertNodeEquals("count", "/count", false, MyDTO3.Count.class, countNode);
+        assertNodeEquals("count", "/count", false, MyDTO3.Count.class, true, countNode);
         Node embeddedNode = root.children().get("/embedded");
         assertEquals(1, embeddedNode.children().size());
-        assertNodeEquals("embedded", "/embedded", true, new TypeReference<MyEmbeddedDTO2<String>>(){}.getType(), embeddedNode);
+        assertNodeEquals("embedded", "/embedded", true, new TypeReference<MyEmbeddedDTO2<String>>(){}.getType(), true, embeddedNode);
         Node valueNode = embeddedNode.children().get("/value");
-        assertNodeEquals("value", "/embedded/value", false, String.class, valueNode);
+        assertNodeEquals("value", "/embedded/value", false, String.class, true, valueNode);
 
         Node sRoot = s.nodeAtPath("/").get();
-        assertNodeEquals("", "/", false, new TypeReference<MyDTO3<MyEmbeddedDTO2<String>>>(){}.getType(), sRoot);
+        assertNodeEquals("", "/", false, new TypeReference<MyDTO3<MyEmbeddedDTO2<String>>>(){}.getType(), false, sRoot);
         Node sPingNode = s.nodeAtPath("/ping").get();
-        assertNodeEquals("ping", "/ping", false, String.class, sPingNode);
+        assertNodeEquals("ping", "/ping", false, String.class, true, sPingNode);
         Node sPongNode = s.nodeAtPath("/pong").get();
-        assertNodeEquals("pong", "/pong", false, Long.class, sPongNode);
+        assertNodeEquals("pong", "/pong", false, Long.class, true, sPongNode);
         Node sCountNode = s.nodeAtPath("/count").get();
-        assertNodeEquals("count", "/count", false, MyDTO3.Count.class, sCountNode);
+        assertNodeEquals("count", "/count", false, MyDTO3.Count.class, true, sCountNode);
         Node sEmbeddedNode = s.nodeAtPath("/embedded").get();
-        assertNodeEquals("embedded", "/embedded", true, new TypeReference<MyEmbeddedDTO2<String>>(){}.getType(), sEmbeddedNode);
+        assertNodeEquals("embedded", "/embedded", true, new TypeReference<MyEmbeddedDTO2<String>>(){}.getType(), true, sEmbeddedNode);
         Node sValueNode = s.nodeAtPath("/embedded/value").get();
-        assertNodeEquals("value", "/embedded/value", false, String.class, sValueNode);
+        assertNodeEquals("value", "/embedded/value", false, String.class, true, sValueNode);
+    }
+
+    @Test
+    public void testSchematizeDTOWithAnnotatedColletion() {
+        Optional<Schema> opt = schematizer
+                .rule("MyDTO4", new TypeReference<MyDTO4>(){})
+                .get("MyDTO4");
+
+        assertTrue(opt.isPresent());
+        Schema s = opt.get();
+        assertNotNull(s);
+        Node root = s.rootNode();
+        assertNodeEquals("", "/", false, MyDTO4.class, false, root);
+        assertEquals(4, root.children().size());
+        Node pingNode = root.children().get("/ping");
+        assertNodeEquals("ping", "/ping", false, String.class, true, pingNode);
+        Node pongNode = root.children().get("/pong");
+        assertNodeEquals("pong", "/pong", false, Long.class, true, pongNode);
+        Node countNode = root.children().get("/count");
+        assertNodeEquals("count", "/count", false, MyDTO4.Count.class, true, countNode);
+        Node embeddedNode = root.children().get("/embedded");
+        assertEquals(3, embeddedNode.children().size());
+        assertNodeEquals("embedded", "/embedded", true, MyEmbeddedDTO.class, true, embeddedNode);
+        Node marcoNode = embeddedNode.children().get("/marco");
+        assertNodeEquals("marco", "/embedded/marco", false, String.class, true, marcoNode);
+        Node poloNode = embeddedNode.children().get("/polo");
+        assertNodeEquals("polo", "/embedded/polo", false, Long.class, true, poloNode);
+        Node alphaNode = embeddedNode.children().get("/alpha");
+        assertNodeEquals("alpha", "/embedded/alpha", false, MyEmbeddedDTO.Alpha.class, true, alphaNode);
+
+        Node sRoot = s.nodeAtPath("/").get();
+        assertNodeEquals("", "/", false, MyDTO4.class, false, sRoot);
+        Node sPingNode = s.nodeAtPath("/ping").get();
+        assertNodeEquals("ping", "/ping", false, String.class, true, sPingNode);
+        Node sPongNode = s.nodeAtPath("/pong").get();
+        assertNodeEquals("pong", "/pong", false, Long.class, true, sPongNode);
+        Node sCountNode = s.nodeAtPath("/count").get();
+        assertNodeEquals("count", "/count", false, MyDTO4.Count.class, true, sCountNode);
+        Node sEmbeddedNode = s.nodeAtPath("/embedded").get();
+        assertNodeEquals("embedded", "/embedded", true, MyEmbeddedDTO.class, true, sEmbeddedNode);
+        Node sMarcoNode = s.nodeAtPath("/embedded/marco").get();
+        assertNodeEquals("marco", "/embedded/marco", false, String.class, true, sMarcoNode);
+        Node sPoloNode = s.nodeAtPath("/embedded/polo").get();
+        assertNodeEquals("polo", "/embedded/polo", false, Long.class, true, sPoloNode);
+        Node sAlphaNode = s.nodeAtPath("/embedded/alpha").get();
+        assertNodeEquals("alpha", "/embedded/alpha", false, MyEmbeddedDTO.Alpha.class, true, sAlphaNode);
     }
 
     @Test
@@ -193,39 +239,39 @@ public class SchematizerServiceTest {
         assertNotNull(s);
         Node root = s.rootNode();
         assertEquals(4, root.children().size());
-        assertNodeEquals("", "/", false, MyDTO.class, root);
+        assertNodeEquals("", "/", false, MyDTO.class, false, root);
         Node pingNode = root.children().get("/ping");
-        assertNodeEquals("ping", "/ping", false, String.class, pingNode);
+        assertNodeEquals("ping", "/ping", false, String.class, true, pingNode);
         Node pongNode = root.children().get("/pong");
-        assertNodeEquals("pong", "/pong", false, Long.class, pongNode);
+        assertNodeEquals("pong", "/pong", false, Long.class, true, pongNode);
         Node countNode = root.children().get("/count");
-        assertNodeEquals("count", "/count", false, MyDTO.Count.class, countNode);
+        assertNodeEquals("count", "/count", false, MyDTO.Count.class, true, countNode);
         Node embeddedNode = root.children().get("/embedded");
         assertEquals(3, embeddedNode.children().size());
-        assertNodeEquals("embedded", "/embedded", false, MyEmbeddedDTO.class, embeddedNode);
+        assertNodeEquals("embedded", "/embedded", false, MyEmbeddedDTO.class, true, embeddedNode);
         Node marcoNode = embeddedNode.children().get("/marco");
-        assertNodeEquals("marco", "/embedded/marco", false, String.class, marcoNode);
+        assertNodeEquals("marco", "/embedded/marco", false, String.class, true, marcoNode);
         Node poloNode = embeddedNode.children().get("/polo");
-        assertNodeEquals("polo", "/embedded/polo", false, Long.class, poloNode);
+        assertNodeEquals("polo", "/embedded/polo", false, Long.class, true, poloNode);
         Node alphaNode = embeddedNode.children().get("/alpha");
-        assertNodeEquals("alpha", "/embedded/alpha", false, MyEmbeddedDTO.Alpha.class, alphaNode);
+        assertNodeEquals("alpha", "/embedded/alpha", false, MyEmbeddedDTO.Alpha.class, true, alphaNode);
 
         Node sRoot = s.nodeAtPath("/").get();
-        assertNodeEquals("", "/", false, MyDTO.class, sRoot);
+        assertNodeEquals("", "/", false, MyDTO.class, false, sRoot);
         Node sPingNode = s.nodeAtPath("/ping").get();
-        assertNodeEquals("ping", "/ping", false, String.class, sPingNode);
+        assertNodeEquals("ping", "/ping", false, String.class, true, sPingNode);
         Node sPongNode = s.nodeAtPath("/pong").get();
-        assertNodeEquals("pong", "/pong", false, Long.class, sPongNode);
+        assertNodeEquals("pong", "/pong", false, Long.class, true, sPongNode);
         Node sCountNode = s.nodeAtPath("/count").get();
-        assertNodeEquals("count", "/count", false, MyDTO.Count.class, sCountNode);
+        assertNodeEquals("count", "/count", false, MyDTO.Count.class, true, sCountNode);
         Node sEmbeddedNode = s.nodeAtPath("/embedded").get();
-        assertNodeEquals("embedded", "/embedded", false, MyEmbeddedDTO.class, sEmbeddedNode);
+        assertNodeEquals("embedded", "/embedded", false, MyEmbeddedDTO.class, true, sEmbeddedNode);
         Node sMarcoNode = s.nodeAtPath("/embedded/marco").get();
-        assertNodeEquals("marco", "/embedded/marco", false, String.class, sMarcoNode);
+        assertNodeEquals("marco", "/embedded/marco", false, String.class, true, sMarcoNode);
         Node sPoloNode = s.nodeAtPath("/embedded/polo").get();
-        assertNodeEquals("polo", "/embedded/polo", false, Long.class, sPoloNode);
+        assertNodeEquals("polo", "/embedded/polo", false, Long.class, true, sPoloNode);
         Node sAlphaNode = s.nodeAtPath("/embedded/alpha").get();
-        assertNodeEquals("alpha", "/embedded/alpha", false, MyEmbeddedDTO.Alpha.class, sAlphaNode);
+        assertNodeEquals("alpha", "/embedded/alpha", false, MyEmbeddedDTO.Alpha.class, true, sAlphaNode);
     }
 
     @Test
@@ -243,12 +289,55 @@ public class SchematizerServiceTest {
         assertEquals("::::count::embedded::alpha::marco::polo::ping::pong", sb.toString());
     }
 
-    private void assertNodeEquals(String name, String path, boolean isCollection, Object type, Node node) {
+    @Test
+    public void testGetParentNode() {
+        Optional<Schema> opt = schematizer
+                .rule("MyDTO", new TypeReference<MyDTO>(){})
+                .rule("MyDTO", "/embedded", new TypeReference<MyEmbeddedDTO>(){})
+                .get("MyDTO");
+
+        assertTrue(opt.isPresent());
+        Schema s = opt.get();
+        assertNotNull(s);
+        Optional<Node> embeddedNode = s.nodeAtPath("/embedded/marco");
+        assertTrue(embeddedNode.isPresent());
+        Optional<Node> parentNode = s.parentOf(embeddedNode.get());
+        assertTrue(parentNode.isPresent());
+        Optional<Node> grandparentNode = s.parentOf(parentNode.get());
+        assertTrue(grandparentNode.isPresent());
+        assertEquals("/", grandparentNode.get().absolutePath());
+    }
+
+    @Test
+    public void testGetParentNode2() {
+        Optional<Schema> opt = schematizer
+                .rule("MyDTO", new TypeReference<MyDTO3<MyEmbeddedDTO2<String>>>(){})
+                .rule("MyDTO", "/embedded", new TypeReference<MyEmbeddedDTO2<String>>(){})
+                .rule("MyDTO", "/embedded/value", String.class)
+                .get("MyDTO");
+
+        assertTrue(opt.isPresent());
+        Schema s = opt.get();
+        assertNotNull(s);
+        Optional<Node> embeddedNode = s.nodeAtPath("/embedded/value");
+        assertTrue(embeddedNode.isPresent());
+        Optional<Node> parentNode = s.parentOf(embeddedNode.get());
+        assertTrue(parentNode.isPresent());
+        Optional<Node> grandparentNode = s.parentOf(parentNode.get());
+        assertTrue(grandparentNode.isPresent());
+        assertEquals("/", grandparentNode.get().absolutePath());
+    }
+
+    private void assertNodeEquals(String name, String path, boolean isCollection, Object type, boolean fieldNotNull, Node node) {
         assertNotNull(node);
         assertEquals(name, node.name());
         assertEquals(path, node.absolutePath());
         assertEquals(isCollection, node.isCollection());
         assertEquals(type, node.type());
+        if (fieldNotNull)
+            assertNotNull(node.field());
+        else
+            assertTrue(node.field() == null);
     }
 
     private void assertNodeDTOEquals(String name, String path, boolean isCollection, Class<?> type, Node.DTO node) {

Modified: felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/json/JsonDeserializationTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/json/JsonDeserializationTest.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/json/JsonDeserializationTest.java (original)
+++ felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/json/JsonDeserializationTest.java Fri Feb 17 07:52:44 2017
@@ -20,25 +20,24 @@ import java.util.ArrayList;
 import java.util.Optional;
 
 import org.apache.felix.schematizer.Schema;
+import org.apache.felix.schematizer.SchematizingConverter;
 import org.apache.felix.schematizer.impl.SchematizerImpl;
 import org.apache.felix.serializer.impl.json.MyDTO.Count;
 import org.apache.felix.serializer.impl.json.MyEmbeddedDTO.Alpha;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.osgi.util.converter.Converter;
-import org.osgi.util.converter.StandardConverter;
 import org.osgi.util.converter.TypeReference;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 public class JsonDeserializationTest {
-    private Converter converter;
+    private SchematizingConverter converter;
 
     @Before
     public void setUp() {
-        converter = new StandardConverter();
+        converter = new SchematizingConverter();
     }
 
     @After
@@ -59,8 +58,6 @@ public class JsonDeserializationTest {
         dto.count = Count.TWO;
         dto.embedded = embedded;
 
-        String serialized = new JsonSerializerImpl().serialize(dto).toString();
-
         // TODO
         Optional<Schema> opt = new SchematizerImpl()
             .rule("MyDTO", new TypeReference<MyDTO>(){})
@@ -71,10 +68,10 @@ public class JsonDeserializationTest {
 
         Schema s = opt.get();
 
+        String serialized = new JsonSerializerImpl().serialize(dto).with(converter.withSchema(s)).toString();
         MyDTO result = new JsonSerializerImpl()
                 .deserialize(MyDTO.class)
-                .with(converter)
-                .withContext(s)
+                .with(converter.withSchema(s))
                 .from(serialized);
 
         assertEquals(dto.ping, result.ping);
@@ -110,8 +107,7 @@ public class JsonDeserializationTest {
         MyDTO2<MyEmbeddedDTO2<String>> result =
                 new JsonSerializerImpl()
                 .deserialize(new TypeReference<MyDTO2<MyEmbeddedDTO2<String>>>(){})
-                .with(converter)
-                .withContext(s)
+                .with(converter.withSchema(s))
                 .from(serialized);
 
         assertEquals(dto.ping, result.ping);

Modified: felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/json/RepositorySerializationTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/json/RepositorySerializationTest.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/json/RepositorySerializationTest.java (original)
+++ felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/json/RepositorySerializationTest.java Fri Feb 17 07:52:44 2017
@@ -43,7 +43,6 @@ import org.apache.felix.serializer.test.
 import org.apache.felix.serializer.test.prevayler.Repository;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
@@ -74,7 +73,6 @@ public class RepositorySerializationTest
 	}
 
     @Test
-    @Ignore("davidb: I've ignore'd this test as it fails. Need to revisit once the converter has stabilized")
 	public void shouldPutAndRemoveSimpleEntitiesFromStore() {
 		simpleManager.clear();
 		final SimpleTopEntity e1 = factory.newSimpleTop( "ID01", "Value01", null );
@@ -115,9 +113,6 @@ public class RepositorySerializationTest
 	}
 
     @Test
-    @Ignore("davidb: I've @Ignore-d this test as the DTO used breaks the DTO "
-            + "contract which says that DTOs cannot contain any methods. As these "
-            + "entities contain some methods they are not recognized as DTOs")
     public void shouldPutAndRemoveComplexEntityFromStore() {
         complexManager.clear();
         assertTrue( complexManager.list().isEmpty() );
@@ -158,9 +153,6 @@ public class RepositorySerializationTest
     }
 
     @Test
-    @Ignore("davidb: I've @Ignore-d this test as the DTO used breaks the DTO "
-            + "contract which says that DTOs cannot contain any methods. As these "
-            + "entities contain some methods they are not recognized as DTOs")
     public void shouldPutAllToStore() {
         complexManager.clear();
         assertTrue( complexManager.list().isEmpty() );
@@ -211,7 +203,6 @@ public class RepositorySerializationTest
     }
 
     @Test
-    @Ignore("davidb: I've ignore'd this test as it fails. Need to revisit once the converter has stabilized")
 	public void shouldIterateThroughKeysAndValues() {
 	    simpleManager.clear();
 

Modified: felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/provider/ObjectFactory.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/provider/ObjectFactory.java?rev=1783340&r1=1783339&r2=1783340&view=diff
==============================================================================
--- felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/provider/ObjectFactory.java (original)
+++ felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/provider/ObjectFactory.java Fri Feb 17 07:52:44 2017
@@ -30,7 +30,7 @@ public class ObjectFactory
         final ComplexTopEntity top = new ComplexTopEntity();
         top.id = anId;
         top.value = aValue;
-        top.embeddedValue = cnv.convert( aMiddle ).to( ComplexMiddleEntity.class );
+        top.embeddedValue = cnv.convert( aMiddle ).sourceAsDTO().to( ComplexMiddleEntity.class );
         return top;
     }