This is an automated email from the ASF dual-hosted git repository.
npeltier pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-pipes.git
The following commit(s) were added to refs/heads/master by this push:
new 5660af9 SLING-10251 make JsonPipe able to loop on objects
5660af9 is described below
commit 5660af99a75f36915bbd5b226c459952cb972f30
Author: Nicolas Peltier <[email protected]>
AuthorDate: Tue Mar 23 18:55:24 2021 +0100
SLING-10251 make JsonPipe able to loop on objects
---
.../java/org/apache/sling/pipes/OutputWriter.java | 2 -
.../sling/pipes/internal/inputstream/JsonPipe.java | 56 +++++++++++++++-------
.../pipes/internal/inputstream/JsonPipeTest.java | 24 +++++++++-
src/test/resources/json.json | 1 +
4 files changed, 62 insertions(+), 21 deletions(-)
diff --git a/src/main/java/org/apache/sling/pipes/OutputWriter.java
b/src/main/java/org/apache/sling/pipes/OutputWriter.java
index 9c020d0..9e22a70 100644
--- a/src/main/java/org/apache/sling/pipes/OutputWriter.java
+++ b/src/main/java/org/apache/sling/pipes/OutputWriter.java
@@ -25,14 +25,12 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.Writer;
-import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
-import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
diff --git
a/src/main/java/org/apache/sling/pipes/internal/inputstream/JsonPipe.java
b/src/main/java/org/apache/sling/pipes/internal/inputstream/JsonPipe.java
index a1a2803..8ff0a91 100644
--- a/src/main/java/org/apache/sling/pipes/internal/inputstream/JsonPipe.java
+++ b/src/main/java/org/apache/sling/pipes/internal/inputstream/JsonPipe.java
@@ -16,6 +16,7 @@
*/
package org.apache.sling.pipes.internal.inputstream;
+import org.apache.commons.collections.keyvalue.DefaultKeyValue;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.Resource;
@@ -34,11 +35,13 @@ import javax.json.JsonValue.ValueType;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
+import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
/**
* Pipe outputting binding related to a json stream: either an object
@@ -52,6 +55,11 @@ public class JsonPipe extends AbstractInputStreamPipe {
*/
protected static final String PN_VALUEPATH = "valuePath";
+ /**
+ * property specifying wether we should bind the computed json as a whole,
or loop over it (not set or raw=false)
+ */
+ protected static final String PN_RAW = "raw";
+
protected static final String JSONPATH_ROOT = "$";
protected static final String ARRAY_START = "[";
@@ -59,12 +67,24 @@ public class JsonPipe extends AbstractInputStreamPipe {
protected static final String OBJ_START = ".";
protected static final Pattern JSONPATH_FIRSTTOKEN = Pattern.compile("^\\"
+ JSONPATH_ROOT + "([\\" + OBJ_START + "\\" + ARRAY_START + "])([^\\" +
OBJ_START + "\\]\\" + ARRAY_START + "]+)\\]?");
- ArrayBasedIterator internalIterator;
+
+ JsonBindingIterator internalIterator;
public JsonPipe(Plumber plumber, Resource resource, PipeBindings
upperBindings) {
super(plumber, resource, upperBindings);
}
+ boolean isRaw() {
+ if (properties.containsKey(PN_RAW)) {
+ Object raw = bindings.instantiateObject(properties.get(PN_RAW,
String.class));
+ if (raw != null && raw instanceof Boolean) {
+ return (Boolean) raw;
+ }
+ return Boolean.parseBoolean((String)raw);
+ }
+ return false;
+ }
+
/**
* in case there is no successful retrieval of some JSON data, we cut the
pipe here
* @return input resource of the pipe, can be reouputed N times in case
output json binding is an array of
@@ -86,12 +106,12 @@ public class JsonPipe extends AbstractInputStreamPipe {
if (StringUtils.isNotBlank(valuePath)) {
json = getValue(json, valuePath);
}
- if (json.getValueType() != ValueType.ARRAY) {
+ if (isRaw() || !(json.getValueType() == ValueType.ARRAY ||
json.getValueType() == ValueType.OBJECT)) {
binding = JsonUtil.unbox(json);
output = inputSingletonIterator;
} else {
binding = json;
- output = internalIterator = new
ArrayBasedIterator((JsonArray)binding, getInput());
+ output = internalIterator = new
JsonBindingIterator(json, getInput());
}
}
}
@@ -101,32 +121,32 @@ public class JsonPipe extends AbstractInputStreamPipe {
return output;
}
- private class ArrayBasedIterator implements Iterator<Resource> {
- int index = 0;
- JsonArray array;
-
+ class JsonBindingIterator implements Iterator<Resource> {
+ Collection<Object> jsonValues;
+ Iterator<Object> internal;
final Resource inputResource;
- ArrayBasedIterator(JsonArray array, Resource inputResource) {
- this.array = array;
+ JsonBindingIterator(JsonStructure json, Resource inputResource) {
+ jsonValues = json.getValueType() == ValueType.ARRAY ?
+ ((JsonArray)
json).stream().map(JsonUtil::unbox).collect(Collectors.toList()):
+ ((JsonObject) json).entrySet().stream()
+ .map(e -> new DefaultKeyValue(e.getKey(),
+
JsonUtil.unbox(e.getValue()))).collect(Collectors.toList());
+ internal = jsonValues.iterator();
this.inputResource = inputResource;
}
+
@Override
public boolean hasNext() {
- return index < array.size();
+ return internal.hasNext();
}
@Override
public Resource next() {
- try {
- if (index >= array.size()) {
- throw new NoSuchElementException();
- }
- binding = JsonUtil.unbox(array.get(index));
- } catch (Exception e) {
- logger.error("Unable to retrieve {}nth item of jsonarray",
index, e);
+ if (! internal.hasNext()) {
+ throw new NoSuchElementException();
}
- index++;
+ binding = internal.next();
return inputResource;
}
}
diff --git
a/src/test/java/org/apache/sling/pipes/internal/inputstream/JsonPipeTest.java
b/src/test/java/org/apache/sling/pipes/internal/inputstream/JsonPipeTest.java
index 6597f40..6539fad 100644
---
a/src/test/java/org/apache/sling/pipes/internal/inputstream/JsonPipeTest.java
+++
b/src/test/java/org/apache/sling/pipes/internal/inputstream/JsonPipeTest.java
@@ -17,6 +17,7 @@
package org.apache.sling.pipes.internal.inputstream;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
+import org.apache.commons.collections4.IteratorUtils;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
@@ -29,10 +30,12 @@ import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
+import java.util.List;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -107,13 +110,32 @@ public class JsonPipeTest extends AbstractPipeTest {
http.givenThat(get(urlEqualTo("/get/foo.json"))
.willReturn(aResponse().withStatus(200).withBody("{\"args\":{\"foo1\":\"bar\"}}")));
ExecutionResult results = execute("echo /content " +
- "| json " + baseUrl + "/get/foo.json @ name data " +
+ "| json " + baseUrl + "/get/foo.json @ name data @ with
raw=true " +
"| mkdir ${data.args.foo1}");
assertEquals(1, results.size());
assertEquals("/content/bar",
results.getCurrentPathSet().iterator().next());
}
@Test
+ public void testLoopOverObject() throws InvocationTargetException,
IllegalAccessException {
+ ExecutionResult results = execute("echo /content " +
+ "| json {'k1':'v1','k2':'v2'} @ name j" +
+ "| mkdir ${j.key}/${j.value}");
+ assertEquals(2, results.size());
+ List<String> array =
IteratorUtils.toList(results.getCurrentPathSet().iterator());
+ assertArrayEquals(new String[] {"/content/k2/v2", "/content/k1/v1"},
array.toArray());
+ }
+
+ @Test
+ public void testRaw() throws InvocationTargetException,
IllegalAccessException {
+ ExecutionResult results = execute("echo /content " +
+ "| json {'k1':'v1','k2':'v2'} @ name j @ with raw=true" +
+ "| write test=${j.k2}");
+ assertEquals(1, results.size());
+ assertEquals("v2",
context.resourceResolver().getResource("/content").getValueMap().get("test",
String.class));
+ }
+
+ @Test
@Ignore
public void testAuthentifiedRemoteJson() throws InvocationTargetException,
IllegalAccessException {
http.givenThat(get(urlEqualTo("/get/profile.json")).withBasicAuth("jdoe","jdoe")
diff --git a/src/test/resources/json.json b/src/test/resources/json.json
index 60465df..9d06afa 100644
--- a/src/test/resources/json.json
+++ b/src/test/resources/json.json
@@ -25,6 +25,7 @@
"weather": {
"jcr:primaryType": "nt:unstructured",
"sling:resourceType": "slingPipes/json",
+ "raw": true,
"expr": "{'query':{'ro':{'city':'Bucharest','temp':'12°'},
'fr':{'city':'Paris','temp':'13°'}}}"
},
"write": {