You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by si...@apache.org on 2018/09/20 12:49:50 UTC

[sling-org-apache-sling-feature-io] 01/01: SLING-7941 - Use streaming APIs to marshall the Feature to JSON

This is an automated email from the ASF dual-hosted git repository.

simonetripodi pushed a commit to branch streaming-json
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-io.git

commit a230049634d7bb9cb21174235f0c77944cefdc95
Author: Simo Tripodi <st...@adobe.com>
AuthorDate: Thu Sep 20 14:49:34 2018 +0200

    SLING-7941 - Use streaming APIs to marshall the Feature to JSON
    
    initial check-in
---
 .../feature/io/json/ConfigurationJSONWriter.java   |  22 +-
 .../sling/feature/io/json/FeatureJSONWriter.java   | 249 +++++++++++----------
 .../sling/feature/io/json/JSONWriterBase.java      | 129 ++++++-----
 3 files changed, 206 insertions(+), 194 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/io/json/ConfigurationJSONWriter.java b/src/main/java/org/apache/sling/feature/io/json/ConfigurationJSONWriter.java
index 64e937d..3732a5e 100644
--- a/src/main/java/org/apache/sling/feature/io/json/ConfigurationJSONWriter.java
+++ b/src/main/java/org/apache/sling/feature/io/json/ConfigurationJSONWriter.java
@@ -16,18 +16,13 @@
  */
 package org.apache.sling.feature.io.json;
 
-import org.apache.sling.feature.Configurations;
-
 import java.io.IOException;
 import java.io.Writer;
-import java.util.Collections;
 
-import javax.json.Json;
-import javax.json.JsonObjectBuilder;
-import javax.json.JsonWriter;
-import javax.json.JsonWriterFactory;
 import javax.json.stream.JsonGenerator;
 
+import org.apache.sling.feature.Configurations;
+
 
 /**
  * JSON writer for configurations
@@ -49,16 +44,13 @@ public class ConfigurationJSONWriter extends JSONWriterBase {
 
     private void writeConfigurations(final Writer writer, final Configurations configs)
     throws IOException {
-        JsonObjectBuilder ob = Json.createObjectBuilder();
+        JsonGenerator generator = newGenerator(writer);
 
         // TODO is this correct?
-        ob.add(JSONConstants.FEATURE_CONFIGURATIONS,
-                writeConfigurationsMap(configs));
+        generator.writeStartObject(JSONConstants.FEATURE_CONFIGURATIONS);
+        writeConfigurations(generator, configs);
+        generator.writeEnd();
 
-        JsonWriterFactory writerFactory = Json.createWriterFactory(
-                Collections.singletonMap(JsonGenerator.PRETTY_PRINTING, true));
-        JsonWriter jw = writerFactory.createWriter(writer);
-        jw.writeObject(ob.build());
-        jw.close();
+        generator.close();
     }
 }
diff --git a/src/main/java/org/apache/sling/feature/io/json/FeatureJSONWriter.java b/src/main/java/org/apache/sling/feature/io/json/FeatureJSONWriter.java
index 6d1776b..d008a7c 100644
--- a/src/main/java/org/apache/sling/feature/io/json/FeatureJSONWriter.java
+++ b/src/main/java/org/apache/sling/feature/io/json/FeatureJSONWriter.java
@@ -18,15 +18,10 @@ package org.apache.sling.feature.io.json;
 
 import java.io.IOException;
 import java.io.Writer;
-import java.util.Collections;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
-import javax.json.Json;
-import javax.json.JsonArrayBuilder;
-import javax.json.JsonObjectBuilder;
-import javax.json.JsonWriter;
-import javax.json.JsonWriterFactory;
 import javax.json.stream.JsonGenerator;
 
 import org.apache.sling.feature.ArtifactId;
@@ -56,131 +51,151 @@ public class FeatureJSONWriter extends JSONWriterBase {
         w.writeFeature(writer, feature);
     }
 
-    private void writeProperty(final JsonObjectBuilder ob, final String key, final String value) {
+    private void writeProperty(final JsonGenerator generator, final String key, final String value) {
         if ( value != null ) {
-            ob.add(key, value);
+            generator.write(key, value);
         }
     }
 
-    private void writeFeature(final Writer writer, final Feature feature)
-    throws IOException {
-        JsonObjectBuilder ob = Json.createObjectBuilder();
-        ob.add(JSONConstants.FEATURE_ID, feature.getId().toMvnId());
-
-        // title, description, vendor, license
-        writeProperty(ob, JSONConstants.FEATURE_TITLE, feature.getTitle());
-        writeProperty(ob, JSONConstants.FEATURE_DESCRIPTION, feature.getDescription());
-        writeProperty(ob, JSONConstants.FEATURE_VENDOR, feature.getVendor());
-        writeProperty(ob, JSONConstants.FEATURE_LICENSE, feature.getLicense());
+    private <T> void writeList(final JsonGenerator generator, final String name, final Collection<T> values) {
+        if (!values.isEmpty()) {
+            generator.writeStartArray(name);
+            for (T value : values) {
+                generator.write(value.toString());
+            }
+            generator.writeEnd();
+        }
+    }
 
-        // variables
-        writeVariables(ob, feature.getVariables());
+    private void writeIncludes(final JsonGenerator generator, final List<Include> includes) {
+        if (includes.isEmpty()) {
+            return;
+        }
 
-        // includes
-        if ( !feature.getIncludes().isEmpty() ) {
-            JsonArrayBuilder incArray = Json.createArrayBuilder();
-            for(final Include inc : feature.getIncludes()) {
-                if ( inc.getArtifactExtensionRemovals().isEmpty()
-                     && inc.getBundleRemovals().isEmpty()
-                     && inc.getConfigurationRemovals().isEmpty()
-                     && inc.getFrameworkPropertiesRemovals().isEmpty() ) {
-                    incArray.add(inc.getId().toMvnId());
-                } else {
-                    JsonObjectBuilder includeObj = Json.createObjectBuilder();
-                    includeObj.add(JSONConstants.ARTIFACT_ID, inc.getId().toMvnId());
-
-                    JsonObjectBuilder removalsObj = Json.createObjectBuilder();
-                    if ( !inc.getArtifactExtensionRemovals().isEmpty()
-                         || inc.getExtensionRemovals().isEmpty() ) {
-                        JsonArrayBuilder extRemovals = Json.createArrayBuilder();
-                        for(final String id : inc.getExtensionRemovals()) {
-                            extRemovals.add(id);
-                        }
-                        for(final Map.Entry<String, List<ArtifactId>> entry : inc.getArtifactExtensionRemovals().entrySet()) {
-                            JsonArrayBuilder ab = Json.createArrayBuilder();
-                            for(final ArtifactId id : entry.getValue()) {
-                                ab.add(id.toMvnId());
-                            }
-                            extRemovals.add(Json.createObjectBuilder().add(entry.getKey(),
-                                    ab.build()).build());
-                        }
-                        removalsObj.add(JSONConstants.INCLUDE_EXTENSION_REMOVALS, extRemovals.build());
+        generator.writeStartArray(JSONConstants.FEATURE_INCLUDES);
+
+        for(final Include inc : includes) {
+            if ( inc.getArtifactExtensionRemovals().isEmpty()
+                 && inc.getBundleRemovals().isEmpty()
+                 && inc.getConfigurationRemovals().isEmpty()
+                 && inc.getFrameworkPropertiesRemovals().isEmpty() ) {
+                generator.write(inc.getId().toMvnId());
+            } else {
+                generator.writeStartObject();
+                //JsonObjectBuilder includeObj = Json.createObjectBuilder();
+                writeProperty(generator, JSONConstants.ARTIFACT_ID, inc.getId().toMvnId());
+
+                generator.writeStartObject(JSONConstants.INCLUDE_REMOVALS);
+
+                //JsonObjectBuilder removalsObj = Json.createObjectBuilder();
+                if ( !inc.getArtifactExtensionRemovals().isEmpty()
+                     || inc.getExtensionRemovals().isEmpty() ) {
+                    //JsonArrayBuilder extRemovals = Json.createArrayBuilder();
+                    generator.writeStartArray(JSONConstants.INCLUDE_EXTENSION_REMOVALS);
+
+                    for(final String id : inc.getExtensionRemovals()) {
+                        generator.write(id);
                     }
-                    if ( !inc.getConfigurationRemovals().isEmpty() ) {
-                        JsonArrayBuilder cfgRemovals = Json.createArrayBuilder();
-                        for(final String val : inc.getConfigurationRemovals()) {
-                            cfgRemovals.add(val);
-                        }
-                        removalsObj.add(JSONConstants.FEATURE_CONFIGURATIONS, cfgRemovals.build());
-                    }
-                    if ( !inc.getBundleRemovals().isEmpty() ) {
-                        JsonArrayBuilder bundleRemovals = Json.createArrayBuilder();
-                        for(final ArtifactId val : inc.getBundleRemovals()) {
-                            bundleRemovals.add(val.toMvnId());
-                        }
-                        removalsObj.add(JSONConstants.FEATURE_BUNDLES, bundleRemovals.build());
-                    }
-                    if ( !inc.getFrameworkPropertiesRemovals().isEmpty() ) {
-                        JsonArrayBuilder propRemovals = Json.createArrayBuilder();
-                        for(final String val : inc.getFrameworkPropertiesRemovals()) {
-                            propRemovals.add(val);
-                        }
-                        removalsObj.add(JSONConstants.FEATURE_FRAMEWORK_PROPERTIES, propRemovals.build());
+                    for(final Map.Entry<String, List<ArtifactId>> entry : inc.getArtifactExtensionRemovals().entrySet()) {
+                        generator.writeStartObject();
+
+                        writeList(generator, entry.getKey(), entry.getValue());
+
+                        generator.writeEnd(); 
                     }
-                    includeObj.add(JSONConstants.INCLUDE_REMOVALS, removalsObj.build());
 
-                    incArray.add(includeObj.build());
+                    generator.writeEnd();
                 }
+                writeList(generator, JSONConstants.FEATURE_CONFIGURATIONS, inc.getConfigurationRemovals());
+                writeList(generator, JSONConstants.FEATURE_BUNDLES, inc.getBundleRemovals());
+                writeList(generator, JSONConstants.FEATURE_FRAMEWORK_PROPERTIES, inc.getFrameworkPropertiesRemovals());
+
+                generator.writeEnd();
             }
-            ob.add(JSONConstants.FEATURE_INCLUDES, incArray.build());
         }
 
-        // requirements
-        if ( !feature.getRequirements().isEmpty() ) {
-            JsonArrayBuilder requirements = Json.createArrayBuilder();
-
-            for(final Requirement req : feature.getRequirements()) {
-                JsonObjectBuilder requirementObj = Json.createObjectBuilder();
-                requirementObj.add(JSONConstants.REQCAP_NAMESPACE, req.getNamespace());
-                if ( !req.getAttributes().isEmpty() ) {
-                    JsonObjectBuilder attrObj = Json.createObjectBuilder();
-                    req.getAttributes().forEach((key, value) -> ManifestUtils.marshalAttribute(key, value, attrObj::add));
-                    requirementObj.add(JSONConstants.REQCAP_ATTRIBUTES, attrObj.build());
-                }
-                if ( !req.getDirectives().isEmpty() ) {
-                    JsonObjectBuilder reqObj = Json.createObjectBuilder();
-                    req.getDirectives().forEach((key, value) -> ManifestUtils.marshalDirective(key, value, reqObj::add));
-                    requirementObj.add(JSONConstants.REQCAP_DIRECTIVES, reqObj.build());
-                }
-                requirements.add(requirementObj.build());
+        generator.writeEnd();
+    }
+
+    private void writeRequirements(final JsonGenerator generator, final List<Requirement> requirements) {
+        if (requirements.isEmpty()) {
+            return;
+        }
+
+        generator.writeStartArray(JSONConstants.FEATURE_REQUIREMENTS);
+
+        for(final Requirement req : requirements) {
+            generator.writeStartObject();
+            writeProperty(generator, JSONConstants.REQCAP_NAMESPACE, req.getNamespace());
+            if ( !req.getAttributes().isEmpty() ) {
+                generator.writeStartObject(JSONConstants.REQCAP_ATTRIBUTES);
+                req.getAttributes().forEach((key, value) -> ManifestUtils.marshalAttribute(key, value, generator::write));
+                generator.writeEnd();
+            }
+            if ( !req.getDirectives().isEmpty() ) {
+                generator.writeStartObject(JSONConstants.REQCAP_DIRECTIVES);
+                req.getDirectives().forEach((key, value) -> ManifestUtils.marshalDirective(key, value, generator::write));
+                generator.writeEnd();
             }
-            ob.add(JSONConstants.FEATURE_REQUIREMENTS, requirements.build());
+            generator.writeEnd();
         }
 
-        // capabilities
-        if ( !feature.getCapabilities().isEmpty() ) {
-            JsonArrayBuilder capabilities = Json.createArrayBuilder();
-
-            for(final Capability cap : feature.getCapabilities()) {
-                JsonObjectBuilder capabilityObj = Json.createObjectBuilder();
-                capabilityObj.add(JSONConstants.REQCAP_NAMESPACE, cap.getNamespace());
-                if ( !cap.getAttributes().isEmpty() ) {
-                    JsonObjectBuilder attrObj = Json.createObjectBuilder();
-                    cap.getAttributes().forEach((key, value) -> ManifestUtils.marshalAttribute(key, value, attrObj::add));
-                    capabilityObj.add(JSONConstants.REQCAP_ATTRIBUTES, attrObj.build());
-                }
-                if ( !cap.getDirectives().isEmpty() ) {
-                    JsonObjectBuilder reqObj = Json.createObjectBuilder();
-                    cap.getDirectives().forEach((key, value) -> ManifestUtils.marshalDirective(key, value, reqObj::add));
-                    capabilityObj.add(JSONConstants.REQCAP_DIRECTIVES, reqObj.build());
-                }
-                capabilities.add(capabilityObj.build());
+        generator.writeEnd();
+    }
+
+    private void writeCapabilities(final JsonGenerator generator, final List<Capability> capabilities) {
+        if (capabilities.isEmpty()) {
+            return;
+        }
+
+        generator.writeStartArray(JSONConstants.FEATURE_CAPABILITIES);
+
+        for(final Capability cap : capabilities) {
+            generator.writeStartObject();
+            writeProperty(generator, JSONConstants.REQCAP_NAMESPACE, cap.getNamespace());
+            if ( !cap.getAttributes().isEmpty() ) {
+                generator.writeStartObject(JSONConstants.REQCAP_ATTRIBUTES);
+                cap.getAttributes().forEach((key, value) -> ManifestUtils.marshalAttribute(key, value, generator::write));
+                generator.writeEnd();
+            }
+            if ( !cap.getDirectives().isEmpty() ) {
+                generator.writeStartObject(JSONConstants.REQCAP_DIRECTIVES);
+                cap.getDirectives().forEach((key, value) -> ManifestUtils.marshalDirective(key, value, generator::write));
+                generator.writeEnd();
             }
-            ob.add(JSONConstants.FEATURE_CAPABILITIES, capabilities.build());
+            generator.writeEnd();
         }
 
+        generator.writeEnd();
+    }
+
+    private void writeFeature(final Writer writer, final Feature feature)
+    throws IOException {
+        JsonGenerator generator = newGenerator(writer);
+        generator.writeStartObject();
+
+        writeProperty(generator, JSONConstants.FEATURE_ID, feature.getId().toMvnId());
+
+        // title, description, vendor, license
+        writeProperty(generator, JSONConstants.FEATURE_TITLE, feature.getTitle());
+        writeProperty(generator, JSONConstants.FEATURE_DESCRIPTION, feature.getDescription());
+        writeProperty(generator, JSONConstants.FEATURE_VENDOR, feature.getVendor());
+        writeProperty(generator, JSONConstants.FEATURE_LICENSE, feature.getLicense());
+
+        // variables
+        writeVariables(generator, feature.getVariables());
+
+        // includes
+        writeIncludes(generator, feature.getIncludes());
+
+        // requirements
+        writeRequirements(generator, feature.getRequirements());
+
+        // capabilities
+        writeCapabilities(generator, feature.getCapabilities());
+
         // bundles
-        writeBundles(ob, feature.getBundles(), feature.getConfigurations());
+        writeBundles(generator, feature.getBundles(), feature.getConfigurations());
 
         // configurations
         final Configurations cfgs = new Configurations();
@@ -190,18 +205,14 @@ public class FeatureJSONWriter extends JSONWriterBase {
                 cfgs.add(cfg);
             }
         }
-        writeConfigurations(ob, cfgs);
+        writeConfigurations(generator, cfgs);
 
         // framework properties
-        writeFrameworkProperties(ob, feature.getFrameworkProperties());
+        writeFrameworkProperties(generator, feature.getFrameworkProperties());
 
         // extensions
-        writeExtensions(ob, feature.getExtensions(), feature.getConfigurations());
+        writeExtensions(generator, feature.getExtensions(), feature.getConfigurations());
 
-        JsonWriterFactory writerFactory = Json.createWriterFactory(
-                Collections.singletonMap(JsonGenerator.PRETTY_PRINTING, true));
-        JsonWriter jw = writerFactory.createWriter(writer);
-        jw.writeObject(ob.build());
-        jw.close();
+        generator.writeEnd().close();
     }
 }
diff --git a/src/main/java/org/apache/sling/feature/io/json/JSONWriterBase.java b/src/main/java/org/apache/sling/feature/io/json/JSONWriterBase.java
index 9c77301..ecfebb8 100644
--- a/src/main/java/org/apache/sling/feature/io/json/JSONWriterBase.java
+++ b/src/main/java/org/apache/sling/feature/io/json/JSONWriterBase.java
@@ -17,16 +17,17 @@
 package org.apache.sling.feature.io.json;
 
 import java.io.StringReader;
+import java.io.Writer;
 import java.lang.reflect.Array;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.List;
 import java.util.Map;
 
 import javax.json.Json;
-import javax.json.JsonArrayBuilder;
-import javax.json.JsonObject;
-import javax.json.JsonObjectBuilder;
 import javax.json.JsonStructure;
+import javax.json.stream.JsonGenerator;
+import javax.json.stream.JsonGeneratorFactory;
 
 import org.apache.sling.feature.Artifact;
 import org.apache.sling.feature.Bundles;
@@ -41,12 +42,19 @@ import org.apache.sling.feature.KeyValueMap;
  */
 abstract class JSONWriterBase {
 
-    protected void writeBundles(final JsonObjectBuilder ob,
+    private final JsonGeneratorFactory generatorFactory = Json.createGeneratorFactory(Collections.singletonMap(JsonGenerator.PRETTY_PRINTING, true));
+
+    protected final JsonGenerator newGenerator(final Writer writer) {
+        return generatorFactory.createGenerator(writer);
+    }
+
+    protected void writeBundles(final JsonGenerator generator,
             final Bundles bundles,
             final Configurations allConfigs) {
         // bundles
         if ( !bundles.isEmpty() ) {
-            JsonArrayBuilder bundleArray = Json.createArrayBuilder();
+            generator.writeStartArray(JSONConstants.FEATURE_BUNDLES);
+            //JsonArrayBuilder bundleArray = Json.createArrayBuilder();
 
             for(final Artifact artifact : bundles) {
                 final Configurations cfgs = new Configurations();
@@ -58,21 +66,21 @@ abstract class JSONWriterBase {
                 }
                 KeyValueMap md = artifact.getMetadata();
                 if ( md.isEmpty() && cfgs.isEmpty() ) {
-                    bundleArray.add(artifact.getId().toMvnId());
+                    generator.write(artifact.getId().toMvnId());
                 } else {
-                    JsonObjectBuilder bundleObj = Json.createObjectBuilder();
-                    bundleObj.add(JSONConstants.ARTIFACT_ID, artifact.getId().toMvnId());
+                    generator.writeStartObject();
+                    generator.write(JSONConstants.ARTIFACT_ID, artifact.getId().toMvnId());
 
                     for(final Map.Entry<String, String> me : md) {
-                        bundleObj.add(me.getKey(), me.getValue());
+                        generator.write(me.getKey(), me.getValue());
                     }
 
-                    writeConfigurations(bundleObj, cfgs);
-
-                    bundleArray.add(bundleObj.build());
+                    generator.writeEnd();
                 }
             }
-            ob.add(JSONConstants.FEATURE_BUNDLES, bundleArray.build());
+            //ob.add(JSONConstants.FEATURE_BUNDLES, bundleArray.build());
+
+            generator.writeEnd();
         }
     }
 
@@ -81,20 +89,13 @@ abstract class JSONWriterBase {
      * @param ob The json generator
      * @param cfgs The list of configurations
      */
-    protected void writeConfigurations(final JsonObjectBuilder ob, final Configurations cfgs) {
-        if ( !cfgs.isEmpty() ) {
-            ob.add(JSONConstants.FEATURE_CONFIGURATIONS,
-                    writeConfigurationsMap(cfgs));
+    protected void writeConfigurations(final JsonGenerator generator, final Configurations cfgs) {
+        if ( cfgs.isEmpty() ) {
+            return;
         }
-    }
 
-    /**
-     * Write the list of configurations into a "configurations" element
-     * @param cfgs The list of configurations.
-     * @return The JSON element containing the configurations.
-     */
-    protected JsonObject writeConfigurationsMap(final Configurations cfgs) {
-        JsonObjectBuilder configObj = Json.createObjectBuilder();
+        generator.writeStartObject(JSONConstants.FEATURE_CONFIGURATIONS);
+
         for(final Configuration cfg : cfgs) {
             final String key;
             if ( cfg.isFactoryConfiguration() ) {
@@ -102,7 +103,8 @@ abstract class JSONWriterBase {
             } else {
                 key = cfg.getPid();
             }
-            JsonObjectBuilder cfgValObj = Json.createObjectBuilder();
+
+            generator.writeStartObject(key);
 
             final Enumeration<String> e = cfg.getProperties().keys();
             while ( e.hasMoreElements() ) {
@@ -136,71 +138,77 @@ abstract class JSONWriterBase {
                 }
 
                 if ( val.getClass().isArray() ) {
-                    JsonArrayBuilder ab = Json.createArrayBuilder();
+                    generator.writeStartArray(name);
+                    // JsonArrayBuilder ab = Json.createArrayBuilder();
                     for(int i=0; i<Array.getLength(val);i++ ) {
                         final Object obj = Array.get(val, i);
                         if ( typePostFix == null ) {
                             if ( obj instanceof String ) {
-                                ab.add((String)obj);
+                                generator.write((String)obj);
                             } else if ( obj instanceof Boolean ) {
-                                ab.add((Boolean)obj);
+                                generator.write((Boolean)obj);
                             } else if ( obj instanceof Long ) {
-                                ab.add((Long)obj);
+                                generator.write((Long)obj);
                             } else if ( obj instanceof Double ) {
-                                ab.add((Double)obj);
+                                generator.write((Double)obj);
                             }
                         } else {
-                            ab.add(obj.toString());
+                            generator.write(obj.toString());
                         }
                     }
-                    cfgValObj.add(name, ab.build());
+
+                    generator.writeEnd();
                 } else {
                     if ( typePostFix == null ) {
                         if ( val instanceof String ) {
-                            cfgValObj.add(name, (String)val);
+                            generator.write(name, (String)val);
                         } else if ( val instanceof Boolean ) {
-                            cfgValObj.add(name, (Boolean)val);
+                            generator.write(name, (Boolean)val);
                         } else if ( val instanceof Long ) {
-                            cfgValObj.add(name, (Long)val);
+                            generator.write(name, (Long)val);
                         } else if ( val instanceof Double ) {
-                            cfgValObj.add(name, (Double)val);
+                            generator.write(name, (Double)val);
                         }
                     } else {
-                        cfgValObj.add(name + typePostFix, val.toString());
+                        generator.write(name + typePostFix, val.toString());
                     }
                 }
             }
-            configObj.add(key, cfgValObj.build());
+
+            generator.writeEnd();
         }
-        return configObj.build();
+
+        generator.writeEnd();
     }
 
-    protected void writeVariables(final JsonObjectBuilder ob, final KeyValueMap vars) {
+    protected void writeVariables(final JsonGenerator generator, final KeyValueMap vars) {
         if ( !vars.isEmpty()) {
-            JsonObjectBuilder varsObj = Json.createObjectBuilder();
+            generator.writeStartObject(JSONConstants.FEATURE_VARIABLES);
+
             for (final Map.Entry<String, String> entry : vars) {
                 String val = entry.getValue();
                 if (val != null)
-                    varsObj.add(entry.getKey(), val);
+                    generator.write(entry.getKey(), val);
                 else
-                    varsObj.addNull(entry.getKey());
+                    generator.writeNull(entry.getKey());
             }
-            ob.add(JSONConstants.FEATURE_VARIABLES, varsObj.build());
+
+            generator.writeEnd();
         }
     }
 
-    protected void writeFrameworkProperties(final JsonObjectBuilder ob, final KeyValueMap props) {
+    protected void writeFrameworkProperties(final JsonGenerator generator, final KeyValueMap props) {
         // framework properties
         if ( !props.isEmpty() ) {
-            JsonObjectBuilder propsObj = Json.createObjectBuilder();
+            generator.writeStartObject(JSONConstants.FEATURE_FRAMEWORK_PROPERTIES);
             for(final Map.Entry<String, String> entry : props) {
-                propsObj.add(entry.getKey(), entry.getValue());
+                generator.write(entry.getKey(), entry.getValue());
             }
-            ob.add(JSONConstants.FEATURE_FRAMEWORK_PROPERTIES, propsObj.build());
+            generator.writeEnd();
         }
     }
 
-    protected void writeExtensions(final JsonObjectBuilder ob,
+    protected void writeExtensions(final JsonGenerator generator,
             final List<Extension> extensions,
             final Configurations allConfigs) {
         for(final Extension ext : extensions) {
@@ -210,11 +218,11 @@ abstract class JSONWriterBase {
                 try ( final StringReader reader = new StringReader(ext.getJSON()) ) {
                     struct = Json.createReader(reader).read();
                 }
-                ob.add(key, struct);
+                generator.write(key, struct);
             } else if ( ext.getType() == ExtensionType.TEXT ) {
-                ob.add(key, ext.getText());
+                generator.write(key, ext.getText());
             } else {
-                JsonArrayBuilder extensionArr = Json.createArrayBuilder();
+                generator.writeStartArray(key);
                 for(final Artifact artifact : ext.getArtifacts()) {
                     final Configurations artifactCfgs = new Configurations();
                     for(final Configuration cfg : allConfigs) {
@@ -224,20 +232,21 @@ abstract class JSONWriterBase {
                         }
                     }
                     if ( artifact.getMetadata().isEmpty() && artifactCfgs.isEmpty() ) {
-                        extensionArr.add(artifact.getId().toMvnId());
+                        generator.write(artifact.getId().toMvnId());
                     } else {
-                        JsonObjectBuilder extObj = Json.createObjectBuilder();
-                        extObj.add(JSONConstants.ARTIFACT_ID, artifact.getId().toMvnId());
+                        generator.writeStartObject();
+                        generator.write(JSONConstants.ARTIFACT_ID, artifact.getId().toMvnId());
 
                         for(final Map.Entry<String, String> me : artifact.getMetadata()) {
-                            extObj.add(me.getKey(), me.getValue());
+                            generator.write(me.getKey(), me.getValue());
                         }
 
-                        writeConfigurations(ob, artifactCfgs);
-                        extensionArr.add(extObj.build());
+                        writeConfigurations(generator, artifactCfgs);
+
+                        generator.writeEnd();
                     }
                 }
-                ob.add(key, extensionArr.build());
+                generator.writeEnd();
             }
         }
     }