You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by sa...@apache.org on 2016/11/02 23:59:24 UTC
[27/50] [abbrv] lucene-solr:apiv2: SOLR-9442: Adds Array of
NamedValuePair (json.nl=arrnvp) style to JSONResponseWriter. (Jonny Marks,
Christine Poerschke)
SOLR-9442: Adds Array of NamedValuePair (json.nl=arrnvp) style to JSONResponseWriter. (Jonny Marks, Christine Poerschke)
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/87c6ec4c
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/87c6ec4c
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/87c6ec4c
Branch: refs/heads/apiv2
Commit: 87c6ec4cb0a91e1952e4dff31d6e1f92ed0806bf
Parents: 72bdbd2
Author: Christine Poerschke <cp...@apache.org>
Authored: Mon Oct 31 11:17:47 2016 +0000
Committer: Christine Poerschke <cp...@apache.org>
Committed: Mon Oct 31 11:19:39 2016 +0000
----------------------------------------------------------------------
solr/CHANGES.txt | 3 +
.../solr/response/JSONResponseWriter.java | 173 ++++++++++++++++++-
.../apache/solr/response/JSONWriterTest.java | 102 ++++++++++-
3 files changed, 274 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/87c6ec4c/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 2f46416..09bf007 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -86,6 +86,9 @@ New Features
Example: { type:terms, field:category, filter:"user:yonik" }
(yonik)
+* SOLR-9442: Adds Array of NamedValuePair (json.nl=arrnvp) style to JSONResponseWriter.
+ (Jonny Marks, Christine Poerschke)
+
Optimizations
----------------------
* SOLR-9704: Facet Module / JSON Facet API: Optimize blockChildren facets that have
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/87c6ec4c/solr/core/src/java/org/apache/solr/response/JSONResponseWriter.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/response/JSONResponseWriter.java b/solr/core/src/java/org/apache/solr/response/JSONResponseWriter.java
index cd6648b..ad128d2 100644
--- a/solr/core/src/java/org/apache/solr/response/JSONResponseWriter.java
+++ b/solr/core/src/java/org/apache/solr/response/JSONResponseWriter.java
@@ -26,6 +26,7 @@ import java.util.Set;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.request.SolrQueryRequest;
@@ -50,7 +51,19 @@ public class JSONResponseWriter implements QueryResponseWriter {
@Override
public void write(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp) throws IOException {
- JSONWriter w = new JSONWriter(writer, req, rsp);
+ final SolrParams params = req.getParams();
+ final String wrapperFunction = params.get(JSONWriter.JSON_WRAPPER_FUNCTION);
+ final String namedListStyle = params.get(JSONWriter.JSON_NL_STYLE, JSONWriter.JSON_NL_FLAT).intern();
+
+ final JSONWriter w;
+ if (namedListStyle.equals(JSONWriter.JSON_NL_ARROFNVP)) {
+ w = new ArrayOfNamedValuePairJSONWriter(
+ writer, req, rsp, wrapperFunction, namedListStyle);
+ } else {
+ w = new JSONWriter(
+ writer, req, rsp, wrapperFunction, namedListStyle);
+ }
+
try {
w.writeResponse();
} finally {
@@ -66,13 +79,14 @@ public class JSONResponseWriter implements QueryResponseWriter {
class JSONWriter extends TextResponseWriter {
protected String wrapperFunction;
- final private String namedListStyle;
+ final protected String namedListStyle;
static final String JSON_NL_STYLE="json.nl";
static final String JSON_NL_MAP="map";
static final String JSON_NL_FLAT="flat";
static final String JSON_NL_ARROFARR="arrarr";
static final String JSON_NL_ARROFMAP="arrmap";
+ static final String JSON_NL_ARROFNVP="arrnvp";
static final String JSON_WRAPPER_FUNCTION="json.wrf";
public JSONWriter(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp) {
@@ -306,6 +320,9 @@ class JSONWriter extends TextResponseWriter {
writeNamedListAsArrArr(name,val);
} else if (namedListStyle==JSON_NL_ARROFMAP) {
writeNamedListAsArrMap(name,val);
+ } else if (namedListStyle==JSON_NL_ARROFNVP) {
+ throw new UnsupportedOperationException(namedListStyle
+ + " namedListStyle must only be used with "+ArrayOfNamedValuePairJSONWriter.class.getSimpleName());
}
}
@@ -588,6 +605,158 @@ class JSONWriter extends TextResponseWriter {
}
+/**
+ * Writes NamedLists directly as an array of NamedValuePair JSON objects...
+ * NamedList("a"=1,"b"=2,null=3) => [{"name":"a","int":1},{"name":"b","int":2},{"int":3}]
+ * NamedList("a"=1,"bar"="foo",null=3.4f) => [{"name":"a","int":1},{"name":"bar","str":"foo"},{"float":3.4}]
+ */
+class ArrayOfNamedValuePairJSONWriter extends JSONWriter {
+ private boolean writeTypeAsKey = false;
+
+ public ArrayOfNamedValuePairJSONWriter(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp,
+ String wrapperFunction, String namedListStyle) {
+ super(writer, req, rsp, wrapperFunction, namedListStyle);
+ if (namedListStyle != JSON_NL_ARROFNVP) {
+ throw new UnsupportedOperationException(ArrayOfNamedValuePairJSONWriter.class.getSimpleName()+" must only be used with "
+ + JSON_NL_ARROFNVP + " style");
+ }
+ }
+
+ @Override
+ public void writeNamedList(String name, NamedList val) throws IOException {
+
+ if (val instanceof SimpleOrderedMap) {
+ super.writeNamedList(name, val);
+ return;
+ }
+
+ final int sz = val.size();
+ indent();
+
+ writeArrayOpener(sz);
+ incLevel();
+
+ boolean first = true;
+ for (int i=0; i<sz; i++) {
+ if (first) {
+ first = false;
+ } else {
+ writeArraySeparator();
+ }
+
+ indent();
+
+ final String elementName = val.getName(i);
+ final Object elementVal = val.getVal(i);
+
+ /*
+ * JSONWriter's writeNamedListAsArrMap turns NamedList("bar"="foo") into [{"foo":"bar"}]
+ * but we here wish to turn it into [ {"name":"bar","str":"foo"} ] instead.
+ *
+ * So first we write the <code>{"name":"bar",</code> portion ...
+ */
+ writeMapOpener(-1);
+ if (elementName != null) {
+ writeKey("name", false);
+ writeVal("name", elementName);
+ writeMapSeparator();
+ }
+
+ /*
+ * ... and then we write the <code>"str":"foo"}</code> portion.
+ */
+ writeTypeAsKey = true;
+ writeVal(null, elementVal); // passing null since writeVal doesn't actually use name (and we already wrote elementName above)
+ if (writeTypeAsKey) {
+ throw new RuntimeException("writeTypeAsKey should have been reset to false by writeVal('"+elementName+"','"+elementVal+"')");
+ }
+ writeMapCloser();
+ }
+
+ decLevel();
+ writeArrayCloser();
+ }
+
+ private void ifNeededWriteTypeAsKey(String type) throws IOException {
+ if (writeTypeAsKey) {
+ writeTypeAsKey = false;
+ writeKey(type, false);
+ }
+ }
+
+ @Override
+ public void writeInt(String name, String val) throws IOException {
+ ifNeededWriteTypeAsKey("int");
+ super.writeInt(name, val);
+ }
+
+ @Override
+ public void writeLong(String name, String val) throws IOException {
+ ifNeededWriteTypeAsKey("long");
+ super.writeLong(name, val);
+ }
+
+ @Override
+ public void writeFloat(String name, String val) throws IOException {
+ ifNeededWriteTypeAsKey("float");
+ super.writeFloat(name, val);
+ }
+
+ @Override
+ public void writeDouble(String name, String val) throws IOException {
+ ifNeededWriteTypeAsKey("double");
+ super.writeDouble(name, val);
+ }
+
+ @Override
+ public void writeBool(String name, String val) throws IOException {
+ ifNeededWriteTypeAsKey("bool");
+ super.writeBool(name, val);
+ }
+
+ @Override
+ public void writeDate(String name, String val) throws IOException {
+ ifNeededWriteTypeAsKey("date");
+ super.writeDate(name, val);
+ }
+
+ @Override
+ public void writeStr(String name, String val, boolean needsEscaping) throws IOException {
+ ifNeededWriteTypeAsKey("str");
+ super.writeStr(name, val, needsEscaping);
+ }
+
+ @Override
+ public void writeSolrDocument(String name, SolrDocument doc, ReturnFields returnFields, int idx) throws IOException {
+ ifNeededWriteTypeAsKey("doc");
+ super.writeSolrDocument(name, doc, returnFields, idx);
+ }
+
+ @Override
+ public void writeStartDocumentList(String name, long start, int size, long numFound, Float maxScore) throws IOException {
+ ifNeededWriteTypeAsKey("doclist");
+ super.writeStartDocumentList(name, start, size, numFound, maxScore);
+ }
+
+ @Override
+ public void writeMap(String name, Map val, boolean excludeOuter, boolean isFirstVal) throws IOException {
+ ifNeededWriteTypeAsKey("map");
+ super.writeMap(name, val, excludeOuter, isFirstVal);
+ }
+
+ @Override
+ public void writeArray(String name, Iterator val) throws IOException {
+ ifNeededWriteTypeAsKey("array");
+ super.writeArray(name, val);
+ }
+
+ @Override
+ public void writeNull(String name) throws IOException {
+ ifNeededWriteTypeAsKey("null");
+ super.writeNull(name);
+ }
+}
+
abstract class NaNFloatWriter extends JSONWriter {
abstract protected String getNaN();
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/87c6ec4c/solr/core/src/test/org/apache/solr/response/JSONWriterTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/response/JSONWriterTest.java b/solr/core/src/test/org/apache/solr/response/JSONWriterTest.java
index ad390cb..a61cff3 100644
--- a/solr/core/src/test/org/apache/solr/response/JSONWriterTest.java
+++ b/solr/core/src/test/org/apache/solr/response/JSONWriterTest.java
@@ -18,7 +18,11 @@ package org.apache.solr.response;
import java.io.IOException;
import java.io.StringWriter;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
@@ -72,7 +76,8 @@ public class JSONWriterTest extends SolrTestCaseJ4 {
@Test
public void testJSON() throws IOException {
- SolrQueryRequest req = req("wt","json","json.nl","arrarr");
+ final String namedListStyle = (random().nextBoolean() ? JSONWriter.JSON_NL_ARROFARR : JSONWriter.JSON_NL_ARROFNVP);
+ SolrQueryRequest req = req("wt","json","json.nl",namedListStyle);
SolrQueryResponse rsp = new SolrQueryResponse();
JSONResponseWriter w = new JSONResponseWriter();
@@ -87,7 +92,18 @@ public class JSONWriterTest extends SolrTestCaseJ4 {
rsp.add("bytes", "abc".getBytes(StandardCharsets.UTF_8));
w.write(buf, req, rsp);
- jsonEq("{\"nl\":[[\"data1\",\"he\\u2028llo\\u2029!\"],[null,42]],\"byte\":-3,\"short\":-4,\"bytes\":\"YWJj\"}", buf.toString());
+
+ final String expectedNLjson;
+ if (namedListStyle == JSONWriter.JSON_NL_ARROFARR) {
+ expectedNLjson = "\"nl\":[[\"data1\",\"he\\u2028llo\\u2029!\"],[null,42]]";
+ } else if (namedListStyle == JSONWriter.JSON_NL_ARROFNVP) {
+ expectedNLjson = "\"nl\":[{\"name\":\"data1\",\"str\":\"he\\u2028llo\\u2029!\"},{\"int\":42}]";
+ } else {
+ expectedNLjson = null;
+ fail("unexpected namedListStyle="+namedListStyle);
+ }
+
+ jsonEq("{"+expectedNLjson+",\"byte\":-3,\"short\":-4,\"bytes\":\"YWJj\"}", buf.toString());
req.close();
}
@@ -130,6 +146,87 @@ public class JSONWriterTest extends SolrTestCaseJ4 {
req.close();
}
+
+ @Test
+ public void testArrnvpWriterOverridesAllWrites() {
+ // List rather than Set because two not-overridden methods could share name but not signature
+ final List<String> methodsExpectedNotOverriden = new ArrayList<>(14);
+ methodsExpectedNotOverriden.add("writeResponse");
+ methodsExpectedNotOverriden.add("writeKey");
+ methodsExpectedNotOverriden.add("writeNamedListAsMapMangled");
+ methodsExpectedNotOverriden.add("writeNamedListAsMapWithDups");
+ methodsExpectedNotOverriden.add("writeNamedListAsArrMap");
+ methodsExpectedNotOverriden.add("writeNamedListAsArrArr");
+ methodsExpectedNotOverriden.add("writeNamedListAsFlat");
+ methodsExpectedNotOverriden.add("writeEndDocumentList");
+ methodsExpectedNotOverriden.add("writeMapOpener");
+ methodsExpectedNotOverriden.add("writeMapSeparator");
+ methodsExpectedNotOverriden.add("writeMapCloser");
+ methodsExpectedNotOverriden.add("writeArrayOpener");
+ methodsExpectedNotOverriden.add("writeArraySeparator");
+ methodsExpectedNotOverriden.add("writeArrayCloser");
+
+ final Class<?> subClass = ArrayOfNamedValuePairJSONWriter.class;
+ final Class<?> superClass = subClass.getSuperclass();
+
+ for (final Method superClassMethod : superClass.getDeclaredMethods()) {
+ final String methodName = superClassMethod.getName();
+ if (!methodName.startsWith("write")) continue;
+
+ final int modifiers = superClassMethod.getModifiers();
+ if (Modifier.isFinal(modifiers)) continue;
+ if (Modifier.isStatic(modifiers)) continue;
+ if (Modifier.isPrivate(modifiers)) continue;
+
+ final boolean expectOverriden = !methodsExpectedNotOverriden.contains(methodName);
+
+ try {
+ final Method subClassMethod = subClass.getDeclaredMethod(
+ superClassMethod.getName(),
+ superClassMethod.getParameterTypes());
+
+ if (expectOverriden) {
+ assertEquals("getReturnType() difference",
+ superClassMethod.getReturnType(),
+ subClassMethod.getReturnType());
+ } else {
+ fail(subClass + " must not override '" + superClassMethod + "'");
+ }
+ } catch (NoSuchMethodException e) {
+ if (expectOverriden) {
+ fail(subClass + " needs to override '" + superClassMethod + "'");
+ } else {
+ assertTrue(methodName+" not found in remaining "+methodsExpectedNotOverriden, methodsExpectedNotOverriden.remove(methodName));
+ }
+ }
+ }
+
+ assertTrue("methodsExpected NotOverriden but NotFound instead: "+methodsExpectedNotOverriden,
+ methodsExpectedNotOverriden.isEmpty());
+ }
+
+ @Test
+ public void testArrnvpWriterLacksMethodsOfItsOwn() {
+ final Class<?> subClass = ArrayOfNamedValuePairJSONWriter.class;
+ final Class<?> superClass = subClass.getSuperclass();
+ // ArrayOfNamedValuePairJSONWriter is a simple sub-class
+ // which should have (almost) no methods of its own
+ for (final Method subClassMethod : subClass.getDeclaredMethods()) {
+ // only own private method of its own
+ if (subClassMethod.getName().equals("ifNeededWriteTypeAsKey")) continue;
+ try {
+ final Method superClassMethod = superClass.getDeclaredMethod(
+ subClassMethod.getName(),
+ subClassMethod.getParameterTypes());
+
+ assertEquals("getReturnType() difference",
+ subClassMethod.getReturnType(),
+ superClassMethod.getReturnType());
+ } catch (NoSuchMethodException e) {
+ fail(subClass + " should not have '" + subClassMethod + "' method of its own");
+ }
+ }
+ }
@Test
public void testConstantsUnchanged() {
@@ -138,6 +235,7 @@ public class JSONWriterTest extends SolrTestCaseJ4 {
assertEquals("flat", JSONWriter.JSON_NL_FLAT);
assertEquals("arrarr", JSONWriter.JSON_NL_ARROFARR);
assertEquals("arrmap", JSONWriter.JSON_NL_ARROFMAP);
+ assertEquals("arrnvp", JSONWriter.JSON_NL_ARROFNVP);
assertEquals("json.wrf", JSONWriter.JSON_WRAPPER_FUNCTION);
}