SLING-8064 : Support marking a feature as final
diff --git a/src/main/java/org/apache/sling/feature/io/json/FeatureJSONReader.java b/src/main/java/org/apache/sling/feature/io/json/FeatureJSONReader.java
index 0184c93..33ca6e3 100644
--- a/src/main/java/org/apache/sling/feature/io/json/FeatureJSONReader.java
+++ b/src/main/java/org/apache/sling/feature/io/json/FeatureJSONReader.java
@@ -80,6 +80,13 @@
         this.feature = new Feature(featureId);
         this.feature.setLocation(this.location);
 
+        // final flag
+        if (map.containsKey(JSONConstants.FEATURE_FINAL)) {
+            final Object finalObj = map.get(JSONConstants.FEATURE_FINAL);
+            checkType(JSONConstants.FEATURE_FINAL, finalObj, Boolean.class);
+            this.feature.setFinal(((Boolean) finalObj).booleanValue());
+        }
+
         // title, description, vendor and license
         this.feature.setTitle(getProperty(map, JSONConstants.FEATURE_TITLE));
         this.feature.setDescription(getProperty(map, JSONConstants.FEATURE_DESCRIPTION));
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 6022aec..88dd549 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
@@ -54,6 +54,10 @@
 
         writeFeatureId(generator, feature);
 
+        if (feature.isFinal()) {
+            generator.write(JSONConstants.FEATURE_FINAL, true);
+        }
+
         // title, description, vendor, license
         writeProperty(generator, JSONConstants.FEATURE_TITLE, feature.getTitle());
         writeProperty(generator, JSONConstants.FEATURE_DESCRIPTION, feature.getDescription());
diff --git a/src/main/java/org/apache/sling/feature/io/json/JSONConstants.java b/src/main/java/org/apache/sling/feature/io/json/JSONConstants.java
index 01ab0e0..a5f9144 100644
--- a/src/main/java/org/apache/sling/feature/io/json/JSONConstants.java
+++ b/src/main/java/org/apache/sling/feature/io/json/JSONConstants.java
@@ -47,6 +47,8 @@
 
     static final String FEATURE_LICENSE = "license";
 
+    static final String FEATURE_FINAL = "final";
+
     static final String FEATURE_MODEL_VERSION = "model-version";
 
     static final List<String> FEATURE_KNOWN_PROPERTIES = Arrays.asList(FEATURE_ID,
@@ -55,12 +57,13 @@
             FEATURE_BUNDLES,
             FEATURE_FRAMEWORK_PROPERTIES,
             FEATURE_CONFIGURATIONS,
-        FEATURE_INCLUDE,
+            FEATURE_INCLUDE,
             FEATURE_REQUIREMENTS,
             FEATURE_CAPABILITIES,
             FEATURE_TITLE,
             FEATURE_DESCRIPTION,
             FEATURE_VENDOR,
+            FEATURE_FINAL,
             FEATURE_LICENSE);
 
     static final String ARTIFACT_ID = "id";
diff --git a/src/test/java/org/apache/sling/feature/io/json/FeatureJSONReaderTest.java b/src/test/java/org/apache/sling/feature/io/json/FeatureJSONReaderTest.java
index 0d4537e..6c99042 100644
--- a/src/test/java/org/apache/sling/feature/io/json/FeatureJSONReaderTest.java
+++ b/src/test/java/org/apache/sling/feature/io/json/FeatureJSONReaderTest.java
@@ -16,6 +16,14 @@
  */
 package org.apache.sling.feature.io.json;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
 import org.apache.sling.feature.Configuration;
 import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.Extensions;
@@ -23,12 +31,6 @@
 import org.junit.Test;
 import org.osgi.resource.Capability;
 
-import java.util.Arrays;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
 public class FeatureJSONReaderTest {
 
     @Test public void testRead() throws Exception {
@@ -75,4 +77,13 @@
         final Feature feature = U.readFeature("artifacts-extension");
         ArtifactsExtensions.testReadArtifactsExtensions(feature);
     }
+
+    @Test
+    public void testFinalFlag() throws Exception {
+        final Feature featureA = U.readFeature("test");
+        assertFalse(featureA.isFinal());
+
+        final Feature featureB = U.readFeature("final");
+        assertTrue(featureB.isFinal());
+    }
 }
diff --git a/src/test/java/org/apache/sling/feature/io/json/FeatureJSONWriterTest.java b/src/test/java/org/apache/sling/feature/io/json/FeatureJSONWriterTest.java
index 2389334..011778a 100644
--- a/src/test/java/org/apache/sling/feature/io/json/FeatureJSONWriterTest.java
+++ b/src/test/java/org/apache/sling/feature/io/json/FeatureJSONWriterTest.java
@@ -16,18 +16,24 @@
  */
 package org.apache.sling.feature.io.json;
 
-import org.apache.sling.feature.Feature;
-import org.junit.Assert;
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Arrays;
 
 import javax.json.Json;
 import javax.json.JsonArray;
 import javax.json.JsonObject;
-import java.io.*;
-import java.util.Arrays;
+import javax.json.JsonValue;
+import javax.json.JsonValue.ValueType;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import org.apache.sling.feature.Feature;
+import org.junit.Assert;
+import org.junit.Test;
 
 public class FeatureJSONWriterTest {
 
@@ -103,4 +109,27 @@
             Assert.assertEquals(refJsonArray, resultJsonArray);
         }
     }
+
+    @Test
+    public void testFinalFlag() throws Exception {
+        // no final flag set in test feature
+        final Feature featureA = U.readFeature("test");
+        try (final StringWriter writer = new StringWriter()) {
+            FeatureJSONWriter.write(writer, featureA);
+            final JsonObject resultJson = Json.createReader(new StringReader(writer.toString())).readObject();
+
+            assertNull(resultJson.get(JSONConstants.FEATURE_FINAL));
+        }
+
+        // final flag set in final feature
+        final Feature featureB = U.readFeature("final");
+        try (final StringWriter writer = new StringWriter()) {
+            FeatureJSONWriter.write(writer, featureB);
+            final JsonObject resultJson = Json.createReader(new StringReader(writer.toString())).readObject();
+
+            final JsonValue val = resultJson.get(JSONConstants.FEATURE_FINAL);
+            assertNotNull(val);
+            assertEquals(ValueType.TRUE, val.getValueType());
+        }
+    }
 }
diff --git a/src/test/resources/features/final.json b/src/test/resources/features/final.json
new file mode 100644
index 0000000..ff1d8a0
--- /dev/null
+++ b/src/test/resources/features/final.json
@@ -0,0 +1,5 @@
+{
+    "id" : "org.apache.sling/final-feature/1.1",
+    "description": "The feature description",
+    "final" : true
+}
\ No newline at end of file