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<String, Object>}.
+ * <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);
+ }
+}