You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by da...@apache.org on 2016/09/26 12:46:49 UTC

svn commit: r1762334 [1/3] - in /felix/trunk/converter: ./ schematizer/ schematizer/src/ schematizer/src/main/ schematizer/src/main/java/ schematizer/src/main/java/org/ schematizer/src/main/java/org/apache/ schematizer/src/main/java/org/apache/felix/ s...

Author: davidb
Date: Mon Sep 26 12:46:48 2016
New Revision: 1762334

URL: http://svn.apache.org/viewvc?rev=1762334&view=rev
Log:
FELIX-5332 Schematizer

This contribution was committed on behalf of David Leangen with many thanks!

Added:
    felix/trunk/converter/schematizer/
    felix/trunk/converter/schematizer/pom.xml
    felix/trunk/converter/schematizer/src/
    felix/trunk/converter/schematizer/src/main/
    felix/trunk/converter/schematizer/src/main/java/
    felix/trunk/converter/schematizer/src/main/java/org/
    felix/trunk/converter/schematizer/src/main/java/org/apache/
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Node.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/NodeVisitor.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/TypeRule.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/Activator.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/schematizer/impl/Util.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/package-info.java
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/
    felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/
    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/
    felix/trunk/converter/schematizer/src/test/java/
    felix/trunk/converter/schematizer/src/test/java/org/
    felix/trunk/converter/schematizer/src/test/java/org/apache/
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyBean.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyDTO.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyDTO2.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/MyEmbeddedDTO.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MyEmbeddedDTO2.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/schematizer/impl/MySubDTO.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/
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/json/
    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/MyDTO.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/json/MyDTO2.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/json/MyEmbeddedDTO.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/impl/json/MyEmbeddedDTO2.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/
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/Bottom.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/ComplexManager.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/ComplexMiddle.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/ComplexTop.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/Middle.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/SimpleManager.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/SimpleMiddle.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/SimpleTop.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/provider/
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/provider/AbstractMiddleEntity.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/provider/BottomEntity.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/provider/ComplexManagerService.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/provider/ComplexMiddleEntity.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/provider/ComplexTopEntity.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/objects/provider/SimpleManagerService.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/provider/SimpleMiddleEntity.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/objects/provider/SimpleTopEntity.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/AggregateTypeReference.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/ClearCommand.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/Command.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/CommandDTO.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/DTOSerializer.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/MockPrevaylerBackedRepository.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/MockPrevaylerSerializer.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/ParameterizedAggregateType.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/PutAllCommand.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/PutCommand.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/RemoveCommand.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/Repository.java
    felix/trunk/converter/schematizer/src/test/java/org/apache/felix/serializer/test/prevayler/SerializerAdapter.java
Modified:
    felix/trunk/converter/pom.xml

Modified: felix/trunk/converter/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/converter/pom.xml?rev=1762334&r1=1762333&r2=1762334&view=diff
==============================================================================
--- felix/trunk/converter/pom.xml (original)
+++ felix/trunk/converter/pom.xml Mon Sep 26 12:46:48 2016
@@ -40,5 +40,6 @@
     <modules>
         <module>converter</module>
         <module>serializer</module>
+        <module>schematizer</module>
     </modules>
 </project>

Added: felix/trunk/converter/schematizer/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/pom.xml?rev=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/pom.xml (added)
+++ felix/trunk/converter/schematizer/pom.xml Mon Sep 26 12:46:48 2016
@@ -0,0 +1,139 @@
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>felix-parent</artifactId>
+        <version>4</version>
+        <relativePath>../pom/pom.xml</relativePath>
+    </parent>
+
+    <name>Apache Felix Schematizer Service</name>
+    <artifactId>org.apache.felix.schematizer</artifactId>
+    <version>0.1-SNAPSHOT</version>
+    <packaging>jar</packaging>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/felix/trunk/converter/schematizer</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/felix/trunk/converter/schematizer</developerConnection>
+        <url>http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/</url>
+    </scm>
+
+    <properties>
+        <felix.java.version>8</felix.java.version>
+        <felix.java.signature.artifactId>java18</felix.java.signature.artifactId>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>3.2.0</version>
+                <executions>
+                    <execution>
+                        <id>bundle</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>bundle</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>baseline</id>
+                        <goals>
+                            <goal>baseline</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Activator>org.apache.felix.schematizer.impl.Activator</Bundle-Activator>
+                        <Private-Package>org.apache.felix.schematizer.*, org.apache.felix.serializer.*</Private-Package>
+                        <Export-Package>org.apache.felix.schematizer</Export-Package>
+                        <Import-Package>org.apache.felix.converter, org.apache.felix.serializer, *</Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>verify</phase>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <includes>
+                        <include>src/**</include>
+                    </includes>
+                    <excludes>
+                        <exclude>src/main/resources/META-INF/services/org.apache.felix.schematizer.Schematizer</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+            
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.converter</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.serializer</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.annotation</artifactId>
+            <version>6.0.1</version>
+            <scope>provided</scope>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.core</artifactId>
+            <version>6.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.json</artifactId>
+            <version>2.0.16</version>
+            <scope>test</scope>            
+        </dependency>
+    </dependencies>
+</project>

Added: 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=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Node.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Node.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) OSGi Alliance (2016). All Rights Reserved.
+ *
+ * Licensed 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 java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import org.osgi.service.converter.TypeReference;
+
+public interface Node {
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public static @interface CollectionType {
+        Class<?> value() default Object.class;
+    }
+
+    public static class DTO extends org.osgi.dto.DTO {
+        public String name;
+        public String path;
+        public String type;
+        public boolean isCollection;
+        public Map<String, Node.DTO> children = new HashMap<>();
+    }
+
+    String name();
+    /**
+     * Return the absolute path of this Node relative to the root Node.
+     */
+    String absolutePath();
+    Type type();
+    Optional<TypeReference<?>> typeReference();
+    boolean isCollection();
+    Map<String, Node> children();
+    Class<? extends Collection<?>> collectionType();
+}

Added: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/NodeVisitor.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/NodeVisitor.java?rev=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/NodeVisitor.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/NodeVisitor.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) OSGi Alliance (2016). All Rights Reserved.
+ *
+ * Licensed 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;
+
+@FunctionalInterface
+public interface NodeVisitor{
+    void apply(Node node);
+}

Added: 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=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schema.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schema.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) OSGi Alliance (2016). All Rights Reserved.
+ *
+ * Licensed 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 java.util.Map;
+import java.util.Optional;
+
+public interface Schema {
+    String name();
+    Node rootNode();
+    Optional<Node> nodeAtPath(String absolutePath);
+    Map<String, Node.DTO> toMap();
+
+    /**
+     * Recursively visits all nodes in the {@code Schema} for processing.
+     */
+    void visit(NodeVisitor visitor);
+}

Added: 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=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schematizer.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/Schematizer.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) OSGi Alliance (2016). All Rights Reserved.
+ *
+ * Licensed 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 java.util.Map;
+import java.util.Optional;
+
+import org.osgi.annotation.versioning.ProviderType;
+import org.osgi.dto.DTO;
+import org.osgi.service.converter.TypeReference;
+
+@ProviderType
+public interface Schematizer {
+    Optional<Schema> get(String name);
+    Optional<Schema> from(String name, Map<String, Node.DTO> map);
+
+    <T extends DTO>Schematizer rule(String name, TypeRule<T> rule);
+    <T extends DTO>Schematizer rule(String name, String path, TypeReference<T> type);
+    <T>Schematizer rule(String name, String path, Class<T> cls);
+
+    /**
+     * Shortcut for rule(String name, String path, TypeReference<T> type) when path is "/".
+     */
+    <T extends DTO>Schematizer rule(String name, TypeReference<T> type);
+}

Added: 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=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/StandardSchematizer.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/StandardSchematizer.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,61 @@
+/*
+ * 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 java.util.Map;
+import java.util.Optional;
+
+import org.osgi.dto.DTO;
+import org.osgi.service.converter.TypeReference;
+
+public class StandardSchematizer implements Schematizer {
+    private final Schematizer schematizer;
+
+    public StandardSchematizer() {
+        schematizer = null;//new SchematizerImpl();
+    }
+
+    @Override
+    public Optional<Schema> get(String name) {
+        return schematizer.get(name);
+    }
+
+    @Override
+    public Optional<Schema> from(String name, Map<String, Node.DTO> map) {
+        return schematizer.from(name, map);
+    }
+
+    @Override
+    public <T extends DTO> Schematizer rule(String name, TypeRule<T> rule) {
+        return schematizer.rule(name, rule);
+    }
+
+    @Override
+    public <T extends DTO> Schematizer rule( String name, String path, TypeReference<T> type ) {
+        return schematizer.rule(name, path, type);
+    }
+
+    @Override
+    public <T> Schematizer rule(String name, String path, Class<T> cls) {
+        return schematizer.rule(name, path, cls);
+    }
+
+    @Override
+    public <T extends DTO> Schematizer rule(String name, TypeReference<T> type) {
+        return schematizer.rule(name, type);
+    }
+}

Added: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/TypeRule.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/TypeRule.java?rev=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/TypeRule.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/TypeRule.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) OSGi Alliance (2016). All Rights Reserved.
+ *
+ * Licensed 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.service.converter.TypeReference;
+
+public class TypeRule<T> {
+	private final String           			path;
+	private final TypeReference<T>			type;
+
+	public TypeRule(String aPath, TypeReference<T> aTypeRef) {
+		path = aPath;
+		type = aTypeRef;
+	}
+
+	public String getPath() {
+		return path;
+	}
+
+	public TypeReference<T> getType() {
+		return type;
+	}
+}

Added: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/Activator.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/Activator.java?rev=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/Activator.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/Activator.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,44 @@
+/*
+ * 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.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.schematizer.Schematizer;
+import org.apache.felix.serializer.impl.json.JsonSerializerImpl;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.serializer.Serializer;
+
+public class Activator implements BundleActivator {
+    @Override
+    public void start(BundleContext context) throws Exception {
+        Dictionary<String, Object> jsonProps = new Hashtable<>();
+        jsonProps.put("osgi.codec.mimetype", new String[] {
+                "application/json", "application/x-javascript", "text/javascript",
+                "text/x-javascript", "text/x-json" });
+        jsonProps.put("provider", "felix");
+        context.registerService(Serializer.class, new JsonSerializerImpl(), jsonProps);
+
+        context.registerService(Schematizer.class, new SchematizerImpl(), null);
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+    }
+}

Added: 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=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/CollectionNode.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/CollectionNode.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) OSGi Alliance (2016). All Rights Reserved.
+ *
+ * Licensed 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 java.util.Collection;
+
+import org.osgi.service.converter.TypeReference;
+
+public class CollectionNode
+        extends NodeImpl
+{
+    private final Class<? extends Collection<?>> collectionType;
+
+    public CollectionNode(
+            String aName,
+            Type aType,
+            String anAbsolutePath,
+            Class<? extends Collection<?>> aCollectionType ) {
+        super( aName, aType, true, anAbsolutePath );
+        collectionType = aCollectionType;
+    }
+
+    public CollectionNode(
+            String aName,
+            TypeReference<?> aTypeRef,
+            String anAbsolutePath,
+            Class<? extends Collection<?>> aCollectionType ) {
+        super( aName, aTypeRef, true, anAbsolutePath );
+        collectionType = aCollectionType;
+    }
+
+    @Override
+    public Class<? extends Collection<?>> collectionType() {
+        return collectionType;
+    }
+}

Added: 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=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/NodeImpl.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/NodeImpl.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) OSGi Alliance (2016). All Rights Reserved.
+ *
+ * Licensed 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 java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+
+import org.apache.felix.schematizer.Node;
+import org.osgi.service.converter.TypeReference;
+
+public class NodeImpl implements Node {
+
+    private final String name;
+    private final Object type;
+    private final boolean isCollection;
+    private final String absolutePath;
+
+    private NodeImpl parent;
+    private HashMap<String, NodeImpl> children = new HashMap<>();
+
+    public NodeImpl(
+            String aName,
+            Type aType,
+            boolean isACollection,
+            String anAbsolutePath ) {
+        name = aName;
+        type = aType;
+        isCollection = isACollection;
+        absolutePath = anAbsolutePath;
+    }
+
+    public NodeImpl(
+            String aName,
+            TypeReference<?> aTypeRef,
+            boolean isACollection,
+            String anAbsolutePath ) {
+        name = aName;
+        type = aTypeRef;
+        isCollection = isACollection;
+        absolutePath = anAbsolutePath;
+    }
+
+    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);
+            });
+    }
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public Type type() {
+        if (type instanceof TypeReference)
+            return ((TypeReference<?>)type).getType();
+        return (Type)type;
+    }
+
+    @Override
+    public Optional<TypeReference<?>> typeReference() {
+        if (type instanceof TypeReference)
+            return Optional.of((TypeReference<?>)type);
+        return Optional.empty();
+    }
+
+    @Override
+    public boolean isCollection() {
+        return isCollection;
+    }
+
+    @Override
+    public String absolutePath() {
+        return absolutePath;
+    }
+
+    @SuppressWarnings( { "unchecked", "rawtypes" } )
+    @Override
+    public Map<String, Node> children() {
+        return (Map)childrenInternal();
+    }
+
+    @Override
+    public Class<? extends Collection<?>> collectionType() {
+        return null;
+    }
+
+    @SuppressWarnings( { "unchecked", "rawtypes" } )
+    Map<String, NodeImpl> childrenInternal() {
+        return (Map)children.clone();
+    }
+
+    NodeImpl parent() {
+        return parent;
+    }
+
+    void parent(NodeImpl aParent) {
+        parent = aParent;
+    }
+
+    void add(NodeImpl child) {
+        children.put(child.absolutePath, child);
+    }
+
+    void add(Map<String, NodeImpl> moreChildren) {
+        children.putAll(moreChildren);
+    }
+
+    public Node.DTO toDTO() {
+        Node.DTO dto = new Node.DTO();
+        dto.name = name();
+        dto.path = absolutePath();
+        dto.type = type().getTypeName();
+        dto.isCollection = isCollection();
+        childrenInternal().values().stream().forEach(v -> dto.children.put(v.name, v.toDTO()));
+        return dto;
+    }
+
+    @Override
+    public String toString() {
+        return absolutePath;
+    }
+}

Added: 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=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchemaImpl.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchemaImpl.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) OSGi Alliance (2016). All Rights Reserved.
+ *
+ * Licensed 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.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.felix.schematizer.Node;
+import org.apache.felix.schematizer.NodeVisitor;
+import org.apache.felix.schematizer.Schema;
+
+public class SchemaImpl
+        implements Schema
+{
+    private final String name;
+    private final HashMap<String, NodeImpl> nodes = new LinkedHashMap<>();
+
+    public SchemaImpl(String aName) {
+        name = aName;
+    }
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public Node rootNode() {
+        return rootNodeInternal();
+    }
+
+    public NodeImpl rootNodeInternal() {
+        return nodes.get("/");        
+    }
+
+    @Override
+    public Optional<Node> nodeAtPath( String absolutePath )
+    {
+        return Optional.ofNullable(nodes.get(absolutePath));
+    }
+
+    void add(NodeImpl node) {
+        nodes.put(node.absolutePath(), node);
+    }
+
+    void add(Map<String, NodeImpl> moreNodes) {
+        nodes.putAll(moreNodes);
+    }
+
+    @Override
+    public Map<String, Node.DTO> toMap() {
+        NodeImpl root = nodes.get("/");
+        Map<String, Node.DTO> m = new HashMap<>();
+        m.put("/",root.toDTO());
+        return m;
+    }
+
+    @SuppressWarnings( { "unchecked", "rawtypes" } )
+    Map<String, NodeImpl> toMapInternal() {
+        return (Map)nodes.clone();
+    }
+
+    @Override
+    public void visit(NodeVisitor visitor) {
+        nodes.values().stream().forEach(n ->  visitor.apply(n));
+    }
+}

Added: 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=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizerImpl.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/SchematizerImpl.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,380 @@
+/*
+ * 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.Field;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+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.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.Map.Entry;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.apache.felix.schematizer.Node;
+import org.apache.felix.schematizer.Node.CollectionType;
+import org.apache.felix.schematizer.Schema;
+import org.apache.felix.schematizer.Schematizer;
+import org.apache.felix.schematizer.TypeRule;
+import org.osgi.dto.DTO;
+import org.osgi.service.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<>();
+
+    @Override
+    public Optional<Schema> get(String name) {
+        if (!schemas.containsKey(name)) {
+            SchemaImpl schema = schematize(name, "");
+            schemas.put(name, schema);
+        }
+
+        return Optional.ofNullable(schemas.get(name));
+    }
+
+    @Override
+    public Optional<Schema> from(String name, Map<String, Node.DTO> map) {
+        try {
+            // TODO: some validation of the Map here would be good
+            SchemaImpl schema = new SchemaImpl(name);
+            Node.DTO rootDTO = map.get("/");
+            Map<String, NodeImpl> allNodes = new HashMap<>();
+            NodeImpl root = new NodeImpl(rootDTO, "", instantiator, allNodes);
+            schema.add(root);
+            schema.add(allNodes);
+            return Optional.of(schema);
+        } catch (Throwable t) {
+            return Optional.empty();
+        }
+    }
+
+    @Override
+    public <T extends DTO> Schematizer rule(String name, TypeRule<T> rule) {
+        Map<String, Object> rules = rulesFor(name);
+        rules.put(rule.getPath(), rule.getType());
+        return this;
+    }
+
+    @Override
+    public <T extends DTO> Schematizer rule(String name, String path, TypeReference<T> type) {
+        Map<String, Object> rules = rulesFor(name);
+        rules.put(path, type);
+        return this;
+    }
+
+    @Override
+    public <T extends DTO> Schematizer rule(String name, TypeReference<T> type) {
+        Map<String, Object> rules = rulesFor(name);
+        rules.put("/", type);
+        return this;
+    }
+
+    @Override
+    public <T> Schematizer rule(String name, String path, Class<T> cls) {
+        Map<String, Object> rules = rulesFor(name);
+        rules.put(path, cls);
+        return this;
+    }
+
+    private Map<String, Object> rulesFor(String name) {
+        if (!typeRules.containsKey(name))
+            typeRules.put(name, new HashMap<>());
+
+        return typeRules.get(name);
+    }
+
+    /**
+     * Top-level entry point for schematizing a DTO. This is the starting point to set up the
+     * parsing. All other methods make recursive calls.
+     */
+    private SchemaImpl schematize(String name, String contextPath) {
+        Map<String, Object> rules = typeRules.get(name);
+        rules = ( rules != null ) ? rules : Collections.emptyMap();
+        return SchematizerImpl.internalSchematize(name, contextPath, rules, false, this);
+    }
+
+    @SuppressWarnings( { "unchecked", "rawtypes" } )
+    /**
+     * Schematize any node, without knowing in advance its type.
+     */
+    private static SchemaImpl internalSchematize(
+            String name, 
+            String contextPath, 
+            Map<String, Object> rules,
+            boolean isCollection,
+            SchematizerImpl schematizer)  {
+        Class<?> cls = null;
+        TypeReference<? extends DTO> ref = null;
+        if (contextPath.isEmpty() && rules.containsKey("/")) {
+            ref = (TypeReference)typeReferenceOf(rules.get("/"));
+            if (ref == null )
+                cls = rawClassOf(rules.get("/"));
+        }
+
+        if (rules.containsKey(contextPath)) {
+            ref = (TypeReference)(typeReferenceOf(rules.get(contextPath)));
+            if (ref == null )
+                cls = rawClassOf(rules.get(contextPath));
+        }
+
+        if (ref != null )
+            cls = rawClassOf(ref);
+
+        if (cls == null)
+            return handleInvalid();
+
+        if (DTO.class.isAssignableFrom(cls)) {
+            Class<? extends DTO> targetCls = (Class<DTO>)cls;
+            return schematizeDTO(name, targetCls, ref, contextPath, rules, isCollection, schematizer);            
+        }
+
+        return schematizeObject( name, cls, contextPath, rules, isCollection, schematizer);
+    }
+
+    private static SchemaImpl schematizeDTO(
+            String name, 
+            Class<? extends DTO> targetCls, 
+            TypeReference<? extends DTO> ref, 
+            String contextPath,
+            Map<String, Object> rules,
+            boolean isCollection,
+            SchematizerImpl schematizer) {
+
+        SchemaImpl schema = new SchemaImpl(name);
+        NodeImpl rootNode;
+        if (ref != null)
+            rootNode = new NodeImpl(contextPath, ref, false, contextPath + "/");
+        else
+            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));
+        schema.add(m);
+        return schema;
+    }
+
+    private static SchemaImpl schematizeObject(
+            String name, 
+            Class<?> targetCls,
+            String contextPath,
+            Map<String, Object> rules,
+            boolean isCollection,
+            SchematizerImpl schematizer) {
+
+        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;
+    }
+
+    private static final Comparator<Entry<String, NodeImpl>> byPath = (e1, e2) -> e1.getValue().absolutePath().compareTo(e2.getValue().absolutePath());
+    private static Map<String, NodeImpl> createMapFromDTO(
+            String name,
+            Class<?> targetCls, 
+            TypeReference<? extends DTO> ref, 
+            String contextPath, 
+            Map<String, Object> typeRules,
+            SchematizerImpl schematizer) {
+        Set<String> handledFields = new HashSet<>();
+
+        Map<String, NodeImpl> result = new HashMap<>();
+        for (Field f : targetCls.getDeclaredFields()) {
+            handleField(name, f, handledFields, result, targetCls, ref, contextPath, typeRules, schematizer);
+        }
+        for (Field f : targetCls.getFields()) {
+            handleField(name, f, handledFields, result, targetCls, ref, contextPath, typeRules, schematizer);
+        }
+
+        return result.entrySet().stream().sorted(byPath).collect(Collectors.toMap(Entry::getKey, Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
+    }
+
+    @SuppressWarnings( { "rawtypes", "unchecked" } )
+    private static void handleField(
+            String name,
+            Field field, 
+            Set<String> handledFields, 
+            Map<String, NodeImpl> result, 
+            Class<?> targetCls, 
+            TypeReference<?> ref, 
+            String contextPath,
+            Map<String, Object> rules,
+            SchematizerImpl schematizer) {
+        if (Modifier.isStatic(field.getModifiers()))
+            return;
+
+        String fieldName = field.getName();
+        if (handledFields.contains(fieldName))
+            return; // Field with this name was already handled
+
+        try {
+            String path = contextPath + "/" + fieldName;
+            NodeImpl node;
+            if (rules.containsKey(path)) {
+                // The actual field. Since the type for this node is provided as a rule, we 
+                // only need it to test whether or not it is a collection.
+                Class<?> actualFieldType = field.getType();
+                boolean isCollection = Collection.class.isAssignableFrom(actualFieldType);
+                Class<?> rawClass = rawClassOf(rules.get(path));
+                // This is the type we will persist in the Schema (as provided by the rules), NOT the "actual" field type.
+                SchemaImpl embedded = SchematizerImpl.internalSchematize(name, path, rules, isCollection, schematizer);
+                Class<?> fieldClass = Util.primitiveToBoxed(rawClass);
+                TypeReference fieldRef = typeReferenceOf(rules.get(path));
+                if (isCollection)
+                    node = new CollectionNode(
+                            field.getName(), 
+                            fieldRef, 
+                            path,
+                            (Class)actualFieldType);
+                else if (fieldRef != null )
+                    node = new NodeImpl(fieldName, fieldRef, false, path);
+                else
+                    node = new NodeImpl(fieldName, fieldClass, false, path);
+                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));} );
+                node.add(childNodes);
+            } else {
+                Type fieldType = field.getType();
+                Class<?> rawClass = rawClassOf(fieldType);
+                Class<?> fieldClass = Util.primitiveToBoxed(rawClass);
+
+                if (Collection.class.isAssignableFrom(fieldClass)) {
+                    CollectionType collectionTypeAnnotation = field.getAnnotation( CollectionType.class );
+                    Class<?> collectionType;
+                    if (collectionTypeAnnotation != null)
+                        collectionType = collectionTypeAnnotation.value();
+                    else
+                        collectionType = Object.class;
+                    node = new CollectionNode(
+                            field.getName(), 
+                            collectionType, 
+                            path,
+                            (Class)fieldClass);
+
+                    if (DTO.class.isAssignableFrom(collectionType)) {
+                        SchematizerImpl newSchematizer = new SchematizerImpl();
+                        newSchematizer.typeRules.put(path, rules);
+                        if (!rules.containsKey(path))
+                            newSchematizer.rule(path, path, collectionType);
+                        SchemaImpl embedded = newSchematizer.schematize(path, path);
+                        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));} );
+                        node.add(childNodes);
+                    }
+                }
+                else if (DTO.class.isAssignableFrom(fieldClass)) {
+                    SchematizerImpl newSchematizer = new SchematizerImpl();
+                    newSchematizer.typeRules.put(path, rules);
+                    if (!rules.containsKey(path))
+                        newSchematizer.rule(path, path, fieldClass);
+                    SchemaImpl embedded = newSchematizer.schematize(path, path);
+                    node = new NodeImpl(
+                            field.getName(), 
+                            fieldClass,
+                            false,
+                            path);
+                    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));} );
+                    node.add(childNodes);
+                } else {
+                    node = new NodeImpl(
+                            field.getName(), 
+                            fieldClass, 
+                            false, 
+                            path);
+                }
+            }
+
+            result.put(node.absolutePath(), node);
+            handledFields.add(fieldName);
+        } catch (Exception e) {
+            // Ignore this field
+            // TODO print warning??
+            return;
+        }
+    }
+
+    private static SchemaImpl handleInvalid() {
+        // TODO
+        return null;
+    }
+
+    private static Class<?> rawClassOf(Object type) {
+        Class<?> rawClass = null;
+        if (type instanceof Class) {
+            rawClass = (Class<?>)type;
+        } else if (type instanceof ParameterizedType) {
+            ParameterizedType paramType = (ParameterizedType) type;
+            Type rawType = paramType.getRawType();
+            if (rawType instanceof Class)
+                rawClass = (Class<?>)rawType;
+        } else if (type instanceof TypeReference) {
+            return rawClassOf(((TypeReference<?>)type).getType());
+        }
+
+        return rawClass;
+    }
+
+    private static TypeReference<?> typeReferenceOf(Object type) {
+        TypeReference<?> typeRef = null;
+        if (type instanceof TypeReference)
+            typeRef = (TypeReference<?>)type;
+        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> {
+        @Override
+        public Type apply(String className) {
+            try {
+                return Class.forName(className);
+            } catch ( ClassNotFoundException e ) {
+                return Object.class;
+            }
+        }
+    }
+}

Added: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/Util.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/Util.java?rev=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/Util.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/impl/Util.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,108 @@
+/*
+ * 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.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.service.converter.TypeReference;
+
+public class Util {
+    private static final Map<Class<?>, Class<?>> boxedClasses;
+    static {
+        Map<Class<?>, Class<?>> m = new HashMap<>();
+        m.put(int.class, Integer.class);
+        m.put(long.class, Long.class);
+        m.put(double.class, Double.class);
+        m.put(float.class, Float.class);
+        m.put(boolean.class, Boolean.class);
+        m.put(char.class, Character.class);
+        m.put(byte.class, Byte.class);
+        m.put(void.class, Void.class);
+        m.put(short.class, Short.class);
+        boxedClasses = Collections.unmodifiableMap(m);
+    }
+
+    public static Type primitiveToBoxed(Type type) {
+        if (type instanceof Class)
+            return primitiveToBoxed((Class<?>) type);
+        else
+            return null;
+    }
+
+    public static Class<?> primitiveToBoxed(Class<?> cls) {
+        Class<?> boxed = boxedClasses.get(cls);
+        if (boxed != null)
+            return boxed;
+        else
+            return cls;
+    }
+
+    public static byte [] readStream(InputStream is) throws IOException {
+        try {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            byte[] bytes = new byte[8192];
+
+            int length = 0;
+            int offset = 0;
+
+            while ((length = is.read(bytes, offset, bytes.length - offset)) != -1) {
+                offset += length;
+
+                if (offset == bytes.length) {
+                    baos.write(bytes, 0, bytes.length);
+                    offset = 0;
+                }
+            }
+            if (offset != 0) {
+                baos.write(bytes, 0, offset);
+            }
+            return baos.toByteArray();
+        } finally {
+            is.close();
+        }
+    }
+
+    public static Class<?> rawClassOf(Object type) {
+        Class<?> rawClass = null;
+        if (type instanceof Class) {
+            rawClass = (Class<?>)type;
+        } else if (type instanceof ParameterizedType) {
+            ParameterizedType paramType = (ParameterizedType) type;
+            Type rawType = paramType.getRawType();
+            if (rawType instanceof Class)
+                rawClass = (Class<?>)rawType;
+        } else if (type instanceof TypeReference) {
+            return rawClassOf(((TypeReference<?>)type).getType());
+        }
+
+        return rawClass;
+    }
+
+    public static TypeReference<?> typeReferenceOf(Object type) {
+        TypeReference<?> typeRef = null;
+        if (type instanceof TypeReference)
+            typeRef = (TypeReference<?>)type;
+        return typeRef;
+    }
+}

Added: felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/package-info.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/package-info.java?rev=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/package-info.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/schematizer/package-info.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) OSGi Alliance (2016). All Rights Reserved.
+ * 
+ * Licensed 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.
+ */
+
+/**
+ * Schematizer Package Version 1.0.
+ * <p>
+ * Bundles wishing to use this package must list the package in the
+ * Import-Package header of the bundle's manifest. This package has two types of
+ * users: the consumers that use the API in this package and the providers that
+ * implement the API in this package.
+ * <p>
+ * Example import for consumers using the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.service.converter; version="[1.0,2.0)"}
+ * <p>
+ * Example import for providers implementing the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.service.converter; version="[1.0,1.1)"}
+ * 
+ * @author $Id$
+ */
+@Version("1.0")
+package org.apache.felix.schematizer;
+
+import org.osgi.annotation.versioning.Version;

Added: 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=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonDeserializingImpl.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonDeserializingImpl.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,268 @@
+/*
+ * 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.serializer.impl.json;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Scanner;
+
+import org.apache.felix.schematizer.Node;
+import org.apache.felix.schematizer.Schema;
+import org.apache.felix.schematizer.impl.Util;
+import org.osgi.dto.DTO;
+import org.osgi.service.converter.ConversionException;
+import org.osgi.service.converter.Converter;
+import org.osgi.service.converter.TypeReference;
+import org.osgi.service.serializer.Deserializing;
+
+public class JsonDeserializingImpl<T> implements Deserializing<T> {
+    private final Object target;
+    private Converter converter;
+    private Schema schema;
+
+    public JsonDeserializingImpl(Converter c, Object t) {
+        converter = c;
+        target = t;
+    }
+
+    @Override
+    public Deserializing<T> with(Converter c)
+    {
+        converter = c;
+        return this;
+    }
+
+    @Override
+    public Deserializing<T> withContext(Object obj)
+    {
+        if(obj instanceof Schema)
+            schema = (Schema)obj;
+        return this;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public T from(CharSequence in) {
+        JsonParser jp = new JsonParser(in);
+        Map<?,?> m = jp.getParsed();
+        Class<T> clazz = (Class<T>)Util.rawClassOf(target);
+        if (m.getClass().isAssignableFrom(clazz))
+            return (T) m;
+        if (schema != null)
+            return deserialize(m);
+
+        return converter.convert(m).to(clazz);
+    }
+
+    @Override
+    public T from(InputStream in) {
+        return from(in, StandardCharsets.UTF_8);
+    }
+
+    @Override
+    public T from(InputStream in, Charset charset) {
+        try {
+            byte[] bytes = Util.readStream(in);
+            String s = new String(bytes, charset);
+            return from(s);
+        } catch (IOException e) {
+            throw new ConversionException("Error reading inputstream", e);
+        }
+    }
+
+    @Override
+    public T from(Readable in) {
+        try (Scanner s = new Scanner(in)) {
+            s.useDelimiter("\\Z");
+            return from(s.next());
+        }
+    }
+
+    private T deserialize(Map<?,?> map) {
+        return deserialize(map, schema, "");
+    }
+
+    @SuppressWarnings( { "unchecked", "rawtypes" } )
+    private T deserialize(Map<?,?> map, Schema s, String contextPath) {
+        if (s == null)
+            return handleNull();
+
+        Class<?> cls = null;
+        if (contextPath.isEmpty()) {
+            Optional<Node> opt = s.nodeAtPath("/");
+            if (opt.isPresent())
+                cls = Util.rawClassOf(opt.get().type());
+        }
+
+        if (cls == null) {
+            Optional<Node> opt = s.nodeAtPath(contextPath);
+            if (opt.isPresent())
+                cls = Util.rawClassOf(opt.get().type());
+        }
+
+        if (cls == null)
+            return (T)handleInvalid();
+
+        if (!DTO.class.isAssignableFrom(cls))
+            return (T)handleInvalid();
+
+        Class<? extends DTO> targetCls = (Class)cls;
+
+        if (!contextPath.endsWith("/"))
+            contextPath = contextPath + "/";
+        return (T)convertToDTO(targetCls, map, s, contextPath);
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private <U extends DTO>U convertToDTO(Class<U> targetCls, Map<?,?> m, Schema schema, String contextPath) {
+        try {
+            U dto = targetCls.newInstance();
+
+            for (Map.Entry entry : m.entrySet()) {
+                try {
+                    Field f = targetCls.getField(entry.getKey().toString());
+                    Object val = entry.getValue();
+                    String path = contextPath + f.getName();
+                    Optional<Node> opt = schema.nodeAtPath(path);
+                    if (opt.isPresent()) {
+                        Node node = opt.get();
+                        Object obj;
+                        if (node.typeReference().isPresent()) {
+                            TypeReference<?> tr = Util.typeReferenceOf(node.typeReference().get());
+                            if (node.isCollection())
+                                if (!Collection.class.isAssignableFrom(val.getClass()))
+                                    // TODO: PANIC! Something is wrong... what should we do??
+                                    obj = null;
+                                else
+                                    obj = convertToCollection( (Class)Util.rawClassOf(tr), (Class)node.collectionType(), (Collection)val, schema, path);
+                            else
+                                obj = convertToDTO((Class)Util.rawClassOf(tr), (Map)val, schema, path + "/");
+                        } else {
+                            if (node.isCollection()) {
+                                Collection c = instantiateCollection(node.collectionType());
+                                Type type = node.type();
+                                for (Object o : (Collection)val) {
+                                    if (o == null)
+                                        c.add(null);
+                                    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));                                
+                                }
+                                obj = c;
+                            } else {
+                                Type type = node.type();
+                                if (val == null)
+                                    obj = null;
+                                else if (DTO.class.isAssignableFrom(Util.rawClassOf(type)))
+                                    obj = convertToDTO((Class)Util.rawClassOf(type), (Map)val, schema, path + "/");
+                                else
+                                    obj = converter.convert(val).to(type);                                
+                            }
+                        }
+
+                        f.set(dto, obj);                        
+                    }
+                } catch (NoSuchFieldException e) {
+                }
+            }
+
+            return dto;
+        } catch (Exception e) {
+            throw new ConversionException("Cannot create DTO " + targetCls, e);
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private <U, V extends Collection<U>>V convertToCollection(Class<U> targetCls, Class<V> collectionClass, Collection sourceCollection, Schema schema, String path) {
+        try {
+            V targetCollection = instantiateCollection(collectionClass);
+            sourceCollection.stream()
+                .map(obj -> convertCollectionItemToObject(obj, targetCls, schema, path))
+                .forEach(u -> targetCollection.add((U)u));
+
+            return targetCollection;
+        } catch (Exception e) {
+            throw new ConversionException("Cannot create DTO " + targetCls, e);
+        }
+    }
+
+    @SuppressWarnings( "unchecked" )
+    private <V extends Collection<?>>V instantiateCollection(Class<V> collectionClass) {
+        if (Collection.class.equals(collectionClass) || List.class.isAssignableFrom(collectionClass))
+            return (V)new ArrayList<V>();
+        else
+            // TODO: incomplete
+            return null;
+    }
+
+    private <U>U convertCollectionItemToObject(Object obj, Class<U> targetCls, Schema schema, String path) {
+        try
+        {
+            if (DTO.class.isAssignableFrom(targetCls ))
+                return convertCollectionItemToDTO(obj, targetCls, schema, path);
+            
+            U newItem = targetCls.newInstance();
+            return newItem;
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    @SuppressWarnings( "unchecked" )
+    private <U>U convertCollectionItemToDTO(Object obj, Class<U> targetCls, Schema schema, String path) {
+        Optional<Node> opt = schema.nodeAtPath(path);
+        if (opt.isPresent()) {
+            Node node = opt.get();
+            if (node.typeReference().isPresent()) {
+                TypeReference<U> tr = (TypeReference<U>)Util.typeReferenceOf(node.typeReference().get());
+                return converter.convert(obj).to(tr);
+            } else {
+                Type type = node.type();
+                type.toString();
+                // TODO
+//                if (DTO.class.isAssignableFrom(Util.rawClassOf(type)))
+//                    obj = convertToDTO((Class)Util.rawClassOf(type), (Map)val, schema, path + "/" );
+//                else
+//                    obj = converter.convert(val).to(type);
+                return null;
+            }
+        }
+
+        return null;
+    }
+
+    private T handleNull() {
+        return null;
+    }
+
+    private T handleInvalid() {
+        return null;
+    }
+}

Added: 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=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonParser.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonParser.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,253 @@
+/*
+ * 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.serializer.impl.json;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.felix.converter.impl.Util;
+
+/**
+ * A very small JSON parser.
+ *
+ * The JSON input is parsed into an object structure in the following way:
+ * <ul>
+ * <li>Object names are represented as a {@link String}.
+ * <li>String values are represented as a {@link String}.
+ * <li>Numeric values are represented as a {@link Long} (TODO support floats).
+ * <li>Boolean values are represented as a {@link Boolean}.
+ * <li>Nested JSON objects are parsed into a {@link java.util.Map Map&lt;String, Object&gt;}.
+ * <li>JSON lists are parsed into a {@link java.util.List} which may contain any of the above values.
+ * </ul>
+ */
+public class JsonParser {
+    private static final Pattern KEY_VALUE_PATTERN = Pattern.compile("^\\s*[\"](.+?)[\"]\\s*[:]\\s*(.+)$");
+
+    private enum Scope { QUOTE, CURLY, BRACKET;
+        static Scope getScope(char c) {
+            switch (c) {
+            case '"':
+                return QUOTE;
+            case '[':
+            case ']':
+                return BRACKET;
+            case '{':
+            case '}':
+                return CURLY;
+            default:
+                return null;
+            }
+        }
+    }
+
+    static class Pair<K, V> {
+        final K key;
+        final V value;
+
+        Pair(K k, V v) {
+            key = k;
+            value = v;
+        }
+    }
+
+    private final Map<String, Object> parsed;
+
+    public JsonParser(CharSequence json) {
+        String str = json.toString();
+        str = str.trim().replace('\n', ' ');
+        parsed = parseObject(str);
+    }
+
+    public JsonParser(InputStream is) throws IOException {
+        this(readStreamAsString(is));
+    }
+
+    public Map<String, Object> getParsed() {
+        return parsed;
+    }
+
+    private static Pair<String, Object> parseKeyValue(String jsonKeyValue) {
+        Matcher matcher = KEY_VALUE_PATTERN.matcher(jsonKeyValue);
+        if (!matcher.matches() || matcher.groupCount() < 2) {
+            throw new IllegalArgumentException("Malformatted JSON key-value pair: " + jsonKeyValue);
+        }
+
+        return new Pair<>(matcher.group(1), parseValue(matcher.group(2)));
+    }
+
+    private static Object parseValue(String jsonValue) {
+        jsonValue = jsonValue.trim();
+
+        switch (jsonValue.charAt(0)) {
+        case '\"':
+            if (!jsonValue.endsWith("\""))
+                throw new IllegalArgumentException("Malformatted JSON string: " + jsonValue);
+
+            return jsonValue.substring(1, jsonValue.length() - 1);
+        case '[':
+            List<Object> entries = new ArrayList<>();
+            for (String v : parseListValuesRaw(jsonValue)) {
+                entries.add(parseValue(v));
+            }
+            return entries;
+        case '{':
+            return parseObject(jsonValue);
+        case 't':
+        case 'T':
+        case 'f':
+        case 'F':
+            return Boolean.parseBoolean(jsonValue);
+        case 'n':
+        case 'N':
+            return null;
+        default:
+            return Long.parseLong(jsonValue);
+        }
+    }
+
+    private static Map<String, Object> parseObject(String jsonObject) {
+        if (!(jsonObject.startsWith("{") && jsonObject.endsWith("}")))
+            throw new IllegalArgumentException("Malformatted JSON object: " + jsonObject);
+
+        jsonObject = jsonObject.substring(1, jsonObject.length() - 1);
+        Map<String, Object> values = new HashMap<>();
+        for (String element : parseKeyValueListRaw(jsonObject)) {
+            Pair<String, Object> pair = parseKeyValue(element);
+            values.put(pair.key, pair.value);
+        }
+
+        return values;
+    }
+
+    private static List<String> parseKeyValueListRaw(String jsonKeyValueList) {
+        jsonKeyValueList = jsonKeyValueList + ","; // append comma to simplify parsing
+        List<String> elements = new ArrayList<>();
+
+        int i=0;
+        int start=0;
+        Stack<Scope> scopeStack = new Stack<>();
+        while (i < jsonKeyValueList.length()) {
+            char curChar = jsonKeyValueList.charAt(i);
+            switch (curChar) {
+            case '"':
+                if (i > 0 && jsonKeyValueList.charAt(i-1) == '\\') {
+                    // it's escaped, ignore for now
+                } else {
+                    if (!scopeStack.empty() && scopeStack.peek() == Scope.QUOTE) {
+                        scopeStack.pop();
+                    } else {
+                        scopeStack.push(Scope.QUOTE);
+                    }
+                }
+                break;
+            case '[':
+            case '{':
+                if ((scopeStack.empty() ? null : scopeStack.peek()) == Scope.QUOTE) {
+                    // inside quotes, ignore
+                } else {
+                    scopeStack.push(Scope.getScope(curChar));
+                }
+                break;
+            case ']':
+            case '}':
+                Scope curScope = scopeStack.empty() ? null : scopeStack.peek();
+                if (curScope == Scope.QUOTE) {
+                    // inside quotes, ignore
+                } else {
+                    Scope newScope = Scope.getScope(curChar);
+                    if (curScope == newScope) {
+                        scopeStack.pop();
+                    } else {
+                        throw new IllegalArgumentException("Unbalanced closing " +
+                            curChar + " in: " + jsonKeyValueList);
+                    }
+                }
+                break;
+            case ',':
+                if (scopeStack.empty()) {
+                    elements.add(jsonKeyValueList.substring(start, i));
+                    start = i+1;
+                }
+                break;
+            }
+
+            i++;
+        }
+        return elements;
+    }
+
+    private static List<String> parseListValuesRaw(String jsonList) {
+        if (!(jsonList.startsWith("[") && jsonList.endsWith("]")))
+            throw new IllegalArgumentException("Malformatted JSON list: " + jsonList);
+
+        jsonList = jsonList.substring(1, jsonList.length() - 1);
+        return parseKeyValueListRaw(jsonList);
+    }
+
+    private static String readStreamAsString(InputStream is) throws IOException {
+        byte [] bytes = Util.readStream(is);
+        if (bytes.length < 5)
+            // need at least 5 bytes to establish the encoding
+            throw new IllegalArgumentException("Malformatted JSON");
+
+        int offset = 0;
+        if ((bytes[0] == -1 && bytes[1] == -2)
+            || (bytes[0] == -2 && bytes[1] == -1)) {
+            // Skip UTF16/UTF32 Byte Order Mark (BOM)
+            offset = 2;
+        }
+
+        /* Infer the encoding as described in section 3 of http://www.ietf.org/rfc/rfc4627.txt
+         * which reads:
+         *   Encoding
+         *
+         *   JSON text SHALL be encoded in Unicode.  The default encoding is
+         *   UTF-8.
+         *
+         *   Since the first two characters of a JSON text will always be ASCII
+         *   characters [RFC0020], it is possible to determine whether an octet
+         *   stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
+         *   at the pattern of nulls in the first four octets.
+         *
+         *         00 00 00 xx  UTF-32BE
+         *         00 xx 00 xx  UTF-16BE
+         *         xx 00 00 00  UTF-32LE
+         *         xx 00 xx 00  UTF-16LE
+         *         xx xx xx xx  UTF-8
+         */
+        String encoding;
+        if (bytes[offset + 2] == 0) {
+            if (bytes[offset + 1] != 0) {
+                encoding = "UTF-16";
+            } else {
+                encoding = "UTF-32";
+            }
+        } else if (bytes[offset + 1] == 0) {
+            encoding = "UTF-16";
+        } else {
+            encoding = "UTF-8";
+        }
+        return new String(bytes, encoding);
+    }
+}
\ No newline at end of file

Added: 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=1762334&view=auto
==============================================================================
--- felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonSerializerImpl.java (added)
+++ felix/trunk/converter/schematizer/src/main/java/org/apache/felix/serializer/impl/json/JsonSerializerImpl.java Mon Sep 26 12:46:48 2016
@@ -0,0 +1,131 @@
+/*
+ * 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.serializer.impl.json;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.osgi.service.converter.Converter;
+import org.osgi.service.converter.StandardConverter;
+import org.osgi.service.converter.TypeReference;
+import org.osgi.service.serializer.Deserializing;
+import org.osgi.service.serializer.Serializer;
+import org.osgi.service.serializer.Serializing;
+
+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();
+
+    @Override
+    public <T> Deserializing<T> deserialize(Class<T> cls) {
+        return new JsonDeserializingImpl<T>(converter, cls);
+    }
+
+    @Override
+    public Serializing serialize(Object obj) {
+        Serializing encoding = new JsonSerializingImpl(converter, configuration, obj);
+
+        if (pretty()) {
+            Boolean top = threadLocal.get();
+            if (top == null) {
+                threadLocal.set(Boolean.TRUE);
+
+                // TODO implement this properly, the following it just a dev temp thing
+                encoding = new EncodingWrapper("{}{}{}{}{}", encoding, "{}{}{}{}{}");
+            }
+        }
+        return encoding;
+    }
+
+    private boolean pretty() {
+        return Boolean.TRUE.equals(Boolean.parseBoolean((String) configuration.get("pretty")));
+    }
+
+    private class EncodingWrapper implements Serializing {
+        private final Serializing delegate;
+        private String prefix;
+        private String postfix;
+
+        EncodingWrapper(String pre, Serializing encoding, String post) {
+            prefix = pre;
+            delegate = encoding;
+            postfix = post;
+        }
+
+        @Override
+        public void to(OutputStream os) {
+            try {
+                os.write(toString().getBytes(StandardCharsets.UTF_8));
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        @Override
+        public String toString() {
+            try {
+                return prefix + delegate.toString() + postfix;
+            } finally {
+                threadLocal.set(null);
+            }
+        }
+
+        @Override
+        public Serializing ignoreNull() {
+            return this;
+        }
+
+        @Override
+        public Serializing pretty() {
+            return this;
+        }
+
+        @Override
+        public void to(OutputStream out, Charset charset) {
+            // TODO Auto-generated method stub
+
+        }
+
+        @Override
+        public Appendable to(Appendable out) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public Serializing with(Converter converter) {
+            delegate.with(converter);
+            return this;
+        }
+    }
+
+    @Override
+    public <T> Deserializing<T> deserialize(TypeReference<T> ref) {
+        return new JsonDeserializingImpl<>(converter, ref);
+    }
+
+    @Override
+    public Deserializing<?> deserialize(Type type) {
+        return new JsonDeserializingImpl<>(converter, type);
+    }
+}