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

rmannibucau pushed a commit to branch 
rmannibucau/jsonpointer-compliance-proposal
in repository https://gitbox.apache.org/repos/asf/johnzon.git

commit 437dad68a726883a7ca4588690478f7fd3301d30
Author: Romain Manni-Bucau <rmannibu...@gmail.com>
AuthorDate: Wed Dec 2 13:09:28 2020 +0100

    [JOHNZON-325] jsonp-strict module
---
 .../johnzon/core/DefaultJsonPointerFactory.java    |  31 +++++
 .../org/apache/johnzon/core/JsonPatchImpl.java     |  39 ++----
 .../org/apache/johnzon/core/JsonPointerImpl.java   |   2 +-
 .../org/apache/johnzon/core/JsonProviderImpl.java  |  15 +-
 .../johnzon/core/spi/JsonPointerFactory.java       |  30 ++++
 .../org/apache/johnzon/core/JsonPointerTest.java   | 113 +--------------
 johnzon-jsonp-strict/pom.xml                       |  81 +++++++++++
 .../jsonp/strict/StrictJsonPointerFactory.java     |  42 ++++++
 .../org.apache.johnzon.core.spi.JsonPointerFactory |   1 +
 .../jsonp/strict/StrictJsonPointerFactoryTest.java | 153 +++++++++++++++++++++
 pom.xml                                            |   4 +-
 src/site/markdown/index.md                         |  16 +++
 12 files changed, 386 insertions(+), 141 deletions(-)

diff --git 
a/johnzon-core/src/main/java/org/apache/johnzon/core/DefaultJsonPointerFactory.java
 
b/johnzon-core/src/main/java/org/apache/johnzon/core/DefaultJsonPointerFactory.java
new file mode 100644
index 0000000..152f029
--- /dev/null
+++ 
b/johnzon-core/src/main/java/org/apache/johnzon/core/DefaultJsonPointerFactory.java
@@ -0,0 +1,31 @@
+/*
+ * 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.johnzon.core;
+
+import org.apache.johnzon.core.spi.JsonPointerFactory;
+
+import javax.json.JsonPointer;
+import javax.json.spi.JsonProvider;
+
+public class DefaultJsonPointerFactory implements JsonPointerFactory {
+    @Override
+    public JsonPointer createPointer(final JsonProvider provider, final String 
path) {
+        return new JsonPointerImpl(provider, path);
+    }
+}
diff --git 
a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchImpl.java 
b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchImpl.java
index 390c438..41ceedf 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchImpl.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchImpl.java
@@ -29,6 +29,7 @@ import javax.json.JsonException;
 import javax.json.JsonObject;
 import javax.json.JsonObjectBuilder;
 import javax.json.JsonPatch;
+import javax.json.JsonPointer;
 import javax.json.JsonStructure;
 import javax.json.JsonValue;
 import javax.json.spi.JsonProvider;
@@ -147,9 +148,11 @@ class JsonPatchImpl implements JsonPatch {
     static class PatchValue {
         private final JsonProvider provider;
         private final JsonPatch.Operation operation;
-        private final JsonPointerImpl path;
-        private final JsonPointerImpl from;
+        private final JsonPointer path;
+        private final JsonPointer from;
         private final JsonValue value;
+        private final String pathPtr;
+        private final String fromPtr;
 
         private volatile String str;
         private volatile JsonObject json;
@@ -162,11 +165,13 @@ class JsonPatchImpl implements JsonPatch {
                    final JsonValue value) {
             this.provider = provider;
             this.operation = operation;
-            this.path = new JsonPatchPointerImpl(provider, path);
+            this.path = provider.createPointer(path);
+            this.pathPtr = path;
+            this.fromPtr = from;
 
             // ignore from if we do not need it
             if (operation == JsonPatch.Operation.MOVE || operation == 
JsonPatch.Operation.COPY) {
-                this.from = new JsonPatchPointerImpl(provider, from);
+                this.from = provider.createPointer(from);
             } else {
                 this.from = null;
             }
@@ -233,10 +238,10 @@ class JsonPatchImpl implements JsonPatch {
                     if (json == null) {
                         JsonObjectBuilder builder = 
provider.createObjectBuilder()
                                 .add("op", operation.name().toLowerCase())
-                                .add("path", path.getJsonPointer());
+                                .add("path", pathPtr);
 
-                        if (from != null) {
-                            builder.add("from", from.getJsonPointer());
+                        if (fromPtr != null) {
+                            builder.add("from", fromPtr);
                         }
 
                         if (value != null) {
@@ -250,24 +255,4 @@ class JsonPatchImpl implements JsonPatch {
             return json;
         }
     }
-
-    public static class JsonPatchPointerImpl extends JsonPointerImpl {
-
-        /**
-         * Constructs and initializes a JsonPointer.
-         *
-         * @param provider the JsonProvider
-         * @param jsonPointer the JSON Pointer string
-         * @throws NullPointerException if {@code jsonPointer} is {@code null}
-         * @throws JsonException        if {@code jsonPointer} is not a valid 
JSON Pointer
-         */
-        public JsonPatchPointerImpl(final JsonProvider provider, final String 
jsonPointer) {
-            super(provider, jsonPointer);
-        }
-
-        @Override
-        protected int minusShift() {
-            return 1;
-        }
-    }
 }
diff --git 
a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPointerImpl.java 
b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPointerImpl.java
index 2f1a76d..036986e 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPointerImpl.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPointerImpl.java
@@ -499,7 +499,7 @@ public class JsonPointerImpl implements JsonPointer {
      * @return the shift to apply on minus. For pointer, it's 0 because we 
need the element right after the last.
      */
     protected int minusShift() {
-        return 0;
+        return 1;
     }
 
     private void validateJsonPointer(JsonValue target, int size) throws 
NullPointerException, JsonException {
diff --git 
a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonProviderImpl.java 
b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonProviderImpl.java
index 282f286..c3147d9 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonProviderImpl.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonProviderImpl.java
@@ -18,6 +18,8 @@
  */
 package org.apache.johnzon.core;
 
+import org.apache.johnzon.core.spi.JsonPointerFactory;
+
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.Reader;
@@ -27,7 +29,9 @@ import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.Collection;
 import java.util.Map;
+import java.util.ServiceLoader;
 import java.util.function.Supplier;
+import java.util.stream.StreamSupport;
 
 import javax.json.JsonArray;
 import javax.json.JsonArrayBuilder;
@@ -52,6 +56,8 @@ import javax.json.stream.JsonGeneratorFactory;
 import javax.json.stream.JsonParser;
 import javax.json.stream.JsonParserFactory;
 
+import static java.util.Comparator.comparing;
+
 public class JsonProviderImpl extends JsonProvider implements Serializable {
     private final Supplier<BufferStrategy.BufferProvider<char[]>> 
bufferProvider = new Cached<>(() ->
         
BufferStrategyFactory.valueOf(System.getProperty(AbstractJsonFactory.BUFFER_STRATEGY,
 "QUEUE"))
@@ -63,6 +69,13 @@ public class JsonProviderImpl extends JsonProvider 
implements Serializable {
     private final JsonWriterFactory writerFactory = new 
JsonWriterFactoryImpl(null);
     private final Supplier<JsonBuilderFactory> builderFactory = new 
Cached<>(() ->
             new JsonBuilderFactoryImpl(null, bufferProvider.get()));
+    private final JsonPointerFactory jsonPointerFactory;
+
+    public JsonProviderImpl() {
+        jsonPointerFactory = 
StreamSupport.stream(ServiceLoader.load(JsonPointerFactory.class).spliterator(),
 false)
+                .min(comparing(JsonPointerFactory::ordinal))
+                .orElseGet(DefaultJsonPointerFactory::new);
+    }
 
     @Override
     public JsonParser createParser(final InputStream in) {
@@ -203,7 +216,7 @@ public class JsonProviderImpl extends JsonProvider 
implements Serializable {
 
     @Override
     public JsonPointer createPointer(String path) {
-        return new JsonPointerImpl(this, path);
+        return jsonPointerFactory.createPointer(this, path);
     }
 
     @Override
diff --git 
a/johnzon-core/src/main/java/org/apache/johnzon/core/spi/JsonPointerFactory.java
 
b/johnzon-core/src/main/java/org/apache/johnzon/core/spi/JsonPointerFactory.java
new file mode 100644
index 0000000..1b0a51a
--- /dev/null
+++ 
b/johnzon-core/src/main/java/org/apache/johnzon/core/spi/JsonPointerFactory.java
@@ -0,0 +1,30 @@
+/*
+ * 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.johnzon.core.spi;
+
+import javax.json.JsonPointer;
+import javax.json.spi.JsonProvider;
+
+public interface JsonPointerFactory {
+    JsonPointer createPointer(JsonProvider provider, String path);
+
+    default int ordinal() {
+        return 0;
+    }
+}
diff --git 
a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonPointerTest.java 
b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonPointerTest.java
index f9e782c..8389f41 100644
--- a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonPointerTest.java
+++ b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonPointerTest.java
@@ -455,21 +455,8 @@ public class JsonPointerTest {
         assertEquals("[[\"bar\",\"baz\"]]", result.toString()); // 
[["bar","baz"]]
     }
 
-    @Test(expected = JsonException.class)
-    public void testRemoveLastArrayElement() {
-        JsonPointerImpl jsonPointer = new 
JsonPointerImpl(JsonProvider.provider(), "/0/-");
-        JsonStructure target = Json.createArrayBuilder()
-                                   .add(Json.createArrayBuilder()
-                                            .add("bar")
-                                            .add("qux")
-                                            .add("baz")).build(); // 
[["bar","qux","baz"]]
-
-        JsonStructure result = jsonPointer.remove(target);
-        assertEquals("[[\"bar\",\"qux\"]]", result.toString()); // 
[["bar","qux"]]
-    }
-
     public void testRemoveLastArrayElementWithPatch() {
-        JsonPointerImpl jsonPointer = new 
JsonPatchImpl.JsonPatchPointerImpl(JsonProvider.provider(), "/0/-");
+        JsonPointerImpl jsonPointer = new 
JsonPointerImpl(JsonProvider.provider(), "/0/-");
         JsonStructure target = Json.createArrayBuilder()
                                    .add(Json.createArrayBuilder()
                                             .add("bar")
@@ -480,78 +467,6 @@ public class JsonPointerTest {
         assertEquals("[[\"bar\",\"qux\"]]", result.toString()); // 
[["bar","qux"]]
     }
 
-    @Test(expected = JsonException.class)
-    public void testGetLastArrayElementSimple() {
-        final JsonPointerImpl jsonPointer = new 
JsonPointerImpl(JsonProvider.provider(), "/-");
-        final JsonStructure target = Json.createArrayBuilder()
-                                         .add("bar")
-                                         .add("qux")
-                                         .add("baz")
-                                         .build();
-
-        jsonPointer.getValue(target);
-    }
-
-    @Test(expected = JsonException.class)
-    public void testGetLastArrayElement() {
-        final JsonPointerImpl jsonPointer = new 
JsonPointerImpl(JsonProvider.provider(), "/-");
-        final JsonStructure target = Json.createArrayBuilder()
-                                         .add(Json.createArrayBuilder()
-                                                  .add("bar")
-                                                  .add("qux")
-                                                  .add("baz")).build(); // 
[["bar","qux","baz"]]
-
-        jsonPointer.getValue(target);
-    }
-
-    @Test(expected = JsonException.class)
-    public void testGetLastArrayElement2() {
-        final JsonPointerImpl jsonPointer = new 
JsonPointerImpl(JsonProvider.provider(), "/0/-");
-        final JsonStructure target = Json.createArrayBuilder()
-                                         .add(Json.createArrayBuilder()
-                                                  .add("bar")
-                                                  .add("qux")
-                                                  .add("baz")).build(); // 
[["bar","qux","baz"]]
-
-        jsonPointer.getValue(target);
-    }
-
-    @Test(expected = JsonException.class)
-    public void testReplaceLastArrayElementSimple() {
-        final JsonPointerImpl jsonPointer = new 
JsonPointerImpl(JsonProvider.provider(), "/-");
-        final JsonStructure target = Json.createArrayBuilder()
-                                         .add("bar")
-                                         .add("qux")
-                                         .add("baz")
-                                         .build();
-
-        jsonPointer.replace(target, new JsonStringImpl("won't work"));
-    }
-
-    @Test(expected = JsonException.class)
-    public void testReplaceLastArrayElement() {
-        final JsonPointerImpl jsonPointer = new 
JsonPointerImpl(JsonProvider.provider(), "/-");
-        final JsonStructure target = Json.createArrayBuilder()
-                                         .add(Json.createArrayBuilder()
-                                                  .add("bar")
-                                                  .add("qux")
-                                                  .add("baz")).build(); // 
[["bar","qux","baz"]]
-
-        jsonPointer.replace(target, new JsonStringImpl("won't work"));
-    }
-
-    @Test(expected = JsonException.class)
-    public void testReplaceLastArrayElement2() {
-        final JsonPointerImpl jsonPointer = new 
JsonPointerImpl(JsonProvider.provider(), "/0/-");
-        final JsonStructure target = Json.createArrayBuilder()
-                                         .add(Json.createArrayBuilder()
-                                                  .add("bar")
-                                                  .add("qux")
-                                                  .add("baz")).build(); // 
[["bar","qux","baz"]]
-
-        jsonPointer.replace(target, new JsonStringImpl("won't work"));
-    }
-
     @Test
     public void testAddLastArrayElementSimple() {
         final JsonPointerImpl jsonPointer = new 
JsonPointerImpl(JsonProvider.provider(), "/-");
@@ -591,22 +506,9 @@ public class JsonPointerTest {
         assertEquals("[[\"bar\",\"qux\",\"baz\",\"xyz\"]]", result.toString());
     }
 
-    @Test(expected = JsonException.class)
-    public void testRemoveLastArrayElementSimple() {
-        JsonPointerImpl jsonPointer = new 
JsonPointerImpl(JsonProvider.provider(), "/-");
-        JsonStructure target = Json.createArrayBuilder()
-                .add("bar")
-                .add("qux")
-                .add("baz")
-                .build();
-
-        JsonStructure result = jsonPointer.remove(target);
-        assertEquals("[\"bar\",\"qux\"]", result.toString());
-    }
-
     @Test
     public void testRemoveLastArrayElementSimpleWithPatch() {
-        JsonPointerImpl jsonPointer = new 
JsonPatchImpl.JsonPatchPointerImpl(JsonProvider.provider(), "/-");
+        JsonPointerImpl jsonPointer = new 
JsonPointerImpl(JsonProvider.provider(), "/-");
         JsonStructure target = Json.createArrayBuilder()
                                    .add("bar")
                                    .add("qux")
@@ -624,17 +526,6 @@ public class JsonPointerTest {
         jsonPointer.remove(target);
     }
 
-    @Test(expected = JsonException.class)
-    public void testRemoveLastArrayElementFromEmpty() {
-        final JsonPointerImpl jsonPointer = new 
JsonPointerImpl(JsonProvider.provider(), "/0/-");
-        final JsonStructure target = Json.createArrayBuilder()
-                                   .add(Json.createArrayBuilder()
-                                            .add("bar")
-                                            .add("qux")
-                                            .add("baz")).build(); // 
[["bar","qux","baz"]]
-        jsonPointer.remove(target);
-    }
-
     @Test
     public void testRemoveObjectMember() {
         JsonPointerImpl jsonPointer = new 
JsonPointerImpl(JsonProvider.provider(), "/baz");
diff --git a/johnzon-jsonp-strict/pom.xml b/johnzon-jsonp-strict/pom.xml
new file mode 100644
index 0000000..04a9ee7
--- /dev/null
+++ b/johnzon-jsonp-strict/pom.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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/xsd/maven-4.0.0.xsd";>
+  <parent>
+    <artifactId>johnzon</artifactId>
+    <groupId>org.apache.johnzon</groupId>
+    <version>1.2.9-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>johnzon-jsonp-strict</artifactId>
+  <name>Johnzon :: JSON-P Strict JSON Pointer Implementation (spec 
compliant)</name>
+  <packaging>bundle</packaging>
+
+  <properties>
+    
<staging.directory>${project.parent.reporting.outputDirectory}</staging.directory>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.johnzon</groupId>
+      <artifactId>johnzon-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <version>3.2.2</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Import-Package>
+              *
+            </Import-Package>
+            <Require-Capability>
+              
osgi.extender;filter:="(osgi.extender=osgi.serviceloader.registrar)"
+            </Require-Capability>
+            <_contract>
+              !JavaAnnotation,
+              !JavaCDI,
+              !JavaJAXRS,
+              JavaJSONP
+            </_contract>
+            
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.apache.johnzon.core.spi.JsonPointerFactory</Provide-Capability>
+          </instructions>
+        </configuration>
+        <dependencies>
+          <dependency>
+            <groupId>biz.aQute.bnd</groupId>
+            <artifactId>biz.aQute.bndlib</artifactId>
+            <version>4.3.1</version>
+          </dependency>
+        </dependencies>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git 
a/johnzon-jsonp-strict/src/main/java/org/apache/johnzon/jsonp/strict/StrictJsonPointerFactory.java
 
b/johnzon-jsonp-strict/src/main/java/org/apache/johnzon/jsonp/strict/StrictJsonPointerFactory.java
new file mode 100644
index 0000000..915aeb2
--- /dev/null
+++ 
b/johnzon-jsonp-strict/src/main/java/org/apache/johnzon/jsonp/strict/StrictJsonPointerFactory.java
@@ -0,0 +1,42 @@
+/*
+ * 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.johnzon.jsonp.strict;
+
+import org.apache.johnzon.core.JsonPointerImpl;
+import org.apache.johnzon.core.spi.JsonPointerFactory;
+
+import javax.json.JsonPointer;
+import javax.json.spi.JsonProvider;
+
+public class StrictJsonPointerFactory implements JsonPointerFactory {
+    @Override
+    public JsonPointer createPointer(final JsonProvider provider, final String 
path) {
+        return new StrictJsonPointerImpl(provider, path);
+    }
+
+    private static class StrictJsonPointerImpl extends JsonPointerImpl {
+        public StrictJsonPointerImpl(final JsonProvider provider, final String 
path) {
+            super(provider, path);
+        }
+
+        protected int minusShift() {
+            return 0;
+        }
+    }
+}
diff --git 
a/johnzon-jsonp-strict/src/main/resources/META-INF/services/org.apache.johnzon.core.spi.JsonPointerFactory
 
b/johnzon-jsonp-strict/src/main/resources/META-INF/services/org.apache.johnzon.core.spi.JsonPointerFactory
new file mode 100644
index 0000000..088626a
--- /dev/null
+++ 
b/johnzon-jsonp-strict/src/main/resources/META-INF/services/org.apache.johnzon.core.spi.JsonPointerFactory
@@ -0,0 +1 @@
+org.apache.johnzon.jsonp.strict.StrictJsonPointerFactory
diff --git 
a/johnzon-jsonp-strict/src/test/java/org/apache/johnzon/jsonp/strict/StrictJsonPointerFactoryTest.java
 
b/johnzon-jsonp-strict/src/test/java/org/apache/johnzon/jsonp/strict/StrictJsonPointerFactoryTest.java
new file mode 100644
index 0000000..bd6e0ec
--- /dev/null
+++ 
b/johnzon-jsonp-strict/src/test/java/org/apache/johnzon/jsonp/strict/StrictJsonPointerFactoryTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.johnzon.jsonp.strict;
+
+import org.apache.johnzon.core.JsonPointerImpl;
+import org.junit.Test;
+
+import javax.json.Json;
+import javax.json.JsonException;
+import javax.json.JsonPointer;
+import javax.json.JsonStructure;
+import javax.json.spi.JsonProvider;
+
+import static org.junit.Assert.assertEquals;
+
+public class StrictJsonPointerFactoryTest {
+    @Test
+    public void validMinusUsage() {
+        final JsonPointerImpl jsonPointer = new 
JsonPointerImpl(JsonProvider.provider(), "/-");
+        final JsonStructure target = Json.createArrayBuilder()
+                .add(Json.createArrayBuilder()
+                        .add("bar")
+                        .add("qux")
+                        .add("baz")).build(); // [["bar","qux","baz"]]
+
+        final JsonStructure result = jsonPointer.add(target, 
Json.createValue("xyz"));
+        assertEquals("[[\"bar\",\"qux\",\"baz\"],\"xyz\"]", result.toString());
+    }
+
+    @Test(expected = JsonException.class)
+    public void testReplaceLastArrayElement2() {
+        final JsonPointer jsonPointer = Json.createPointer("/0/-");
+        final JsonStructure target = Json.createArrayBuilder()
+                .add(Json.createArrayBuilder()
+                        .add("bar")
+                        .add("qux")
+                        .add("baz")).build(); // [["bar","qux","baz"]]
+        jsonPointer.replace(target, Json.createValue("won't work"));
+    }
+
+    @Test(expected = JsonException.class)
+    public void testRemoveLastArrayElement() {
+        JsonPointer jsonPointer = Json.createPointer("/0/-");
+        JsonStructure target = Json.createArrayBuilder()
+                .add(Json.createArrayBuilder()
+                        .add("bar")
+                        .add("qux")
+                        .add("baz")).build(); // [["bar","qux","baz"]]
+
+        JsonStructure result = jsonPointer.remove(target);
+        assertEquals("[[\"bar\",\"qux\"]]", result.toString()); // 
[["bar","qux"]]
+    }
+
+    @Test(expected = JsonException.class)
+    public void testReplaceLastArrayElement() {
+        final JsonPointer jsonPointer = Json.createPointer("/-");
+        final JsonStructure target = Json.createArrayBuilder()
+                .add(Json.createArrayBuilder()
+                        .add("bar")
+                        .add("qux")
+                        .add("baz")).build(); // [["bar","qux","baz"]]
+
+        jsonPointer.replace(target, Json.createValue("won't work"));
+    }
+
+    @Test(expected = JsonException.class)
+    public void testGetLastArrayElementSimple() {
+        final JsonPointer jsonPointer = Json.createPointer("/-");
+        final JsonStructure target = Json.createArrayBuilder()
+                .add("bar")
+                .add("qux")
+                .add("baz")
+                .build();
+
+        jsonPointer.getValue(target);
+    }
+
+    @Test(expected = JsonException.class)
+    public void testGetLastArrayElement2() {
+        final JsonPointer jsonPointer = Json.createPointer("/0/-");
+        final JsonStructure target = Json.createArrayBuilder()
+                .add(Json.createArrayBuilder()
+                        .add("bar")
+                        .add("qux")
+                        .add("baz")).build(); // [["bar","qux","baz"]]
+
+        jsonPointer.getValue(target);
+    }
+
+    @Test(expected = JsonException.class)
+    public void testRemoveLastArrayElementFromEmpty() {
+        final JsonPointer jsonPointer = Json.createPointer("/0/-");
+        final JsonStructure target = Json.createArrayBuilder()
+                .add(Json.createArrayBuilder()
+                        .add("bar")
+                        .add("qux")
+                        .add("baz")).build(); // [["bar","qux","baz"]]
+        jsonPointer.remove(target);
+    }
+
+    @Test(expected = JsonException.class)
+    public void testRemoveLastArrayElementSimple() {
+        JsonPointer jsonPointer = Json.createPointer("/-");
+        JsonStructure target = Json.createArrayBuilder()
+                .add("bar")
+                .add("qux")
+                .add("baz")
+                .build();
+
+        JsonStructure result = jsonPointer.remove(target);
+        assertEquals("[\"bar\",\"qux\"]", result.toString());
+    }
+
+    @Test(expected = JsonException.class)
+    public void testGetLastArrayElement() {
+        final JsonPointer jsonPointer = Json.createPointer("/-");
+        final JsonStructure target = Json.createArrayBuilder()
+                .add(Json.createArrayBuilder()
+                        .add("bar")
+                        .add("qux")
+                        .add("baz")).build(); // [["bar","qux","baz"]]
+
+        jsonPointer.getValue(target);
+    }
+
+    @Test(expected = JsonException.class)
+    public void testReplaceLastArrayElementSimple() {
+        final JsonPointer jsonPointer = Json.createPointer("/-");
+        final JsonStructure target = Json.createArrayBuilder()
+                .add("bar")
+                .add("qux")
+                .add("baz")
+                .build();
+
+        jsonPointer.replace(target, Json.createValue("won't work"));
+    }
+}
diff --git a/pom.xml b/pom.xml
index d64f601..7cd7ce6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,6 +65,7 @@
     <module>johnzon-jsonschema</module>
     <module>johnzon-osgi</module>
     <module>johnzon-jsonlogic</module>
+    <module>johnzon-jsonp-strict</module>
   </modules>
 
   <dependencyManagement>
@@ -150,6 +151,7 @@
         <groupId>org.apache.rat</groupId>
         <artifactId>apache-rat-plugin</artifactId>
         <configuration>
+          <consoleOutput>true</consoleOutput>
           <includes>
             <include>src/**/*</include>
             <include>pom.xml</include>
@@ -162,7 +164,7 @@
             <exclude>*.iws</exclude>
             <exclude>*.iml</exclude>
             <exclude>*.ipr</exclude>
-            <exclude>**/META-INF/services/javax.*</exclude>
+            <exclude>**/META-INF/services/*</exclude>
             <exclude>**/*.json</exclude>
             <exclude>**/*.yml</exclude>
             <exclude>**/bench/*.txt</exclude>
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
index 3ee6c0e..52cead3 100644
--- a/src/site/markdown/index.md
+++ b/src/site/markdown/index.md
@@ -52,6 +52,22 @@ You'll surely want to add the API as dependency too:
 </dependency>
 ]]></pre>
 
+### JSON-P Strict Compliance (stable)
+
+<pre class="prettyprint linenums"><![CDATA[
+<dependency>
+  <groupId>org.apache.johnzon</groupId>
+  <artifactId>johnzon-jsonp-strict</artifactId>
+  <version>${johnzon.version}</version>
+</dependency>
+]]></pre>
+
+This module enables to enforce a strict compliance of JsonPointer behavior on 
`/-` usage.
+Johnzon default implementation enables to use it as "remove last element" when 
using a remove patch (or not add semantic).
+This module enforces this case to be invalid to be closer to the intended 
wording of the JSON Pointer underlying specs.
+
+Note that you can even customize this behavior implementing your own 
`JsonPointerFactory` and changing the ordinal value to take a highest priority.
+
 ### Mapper (stable)
 
 <pre class="prettyprint linenums"><![CDATA[

Reply via email to