SOLR-9787, SOLR-9442: Replace json.nl=arrnvp with json.nl=arrntv (array of Name Type Value) style in JSONResponseWriter

This commit is contained in:
Christine Poerschke 2016-12-28 10:41:17 +00:00
parent bc55d8bc42
commit 73e50ceceb
3 changed files with 60 additions and 50 deletions

View File

@ -74,8 +74,8 @@ New Features
Example: { type:terms, field:category, filter:"user:yonik" } Example: { type:terms, field:category, filter:"user:yonik" }
(yonik) (yonik)
* SOLR-9442: Adds Array of NamedValuePair (json.nl=arrnvp) style to JSONResponseWriter. * SOLR-9442, SOLR-9787: Adds Array of Name Type Value (json.nl=arrntv) style to JSONResponseWriter.
(Jonny Marks, Christine Poerschke) (Jonny Marks, Christine Poerschke, hossman)
* SOLR-9055: Make collection backup/restore extensible. (Hrishikesh Gadre, Varun Thacker, Mark Miller) * SOLR-9055: Make collection backup/restore extensible. (Hrishikesh Gadre, Varun Thacker, Mark Miller)

View File

@ -59,9 +59,9 @@ public class JSONResponseWriter implements QueryResponseWriter {
final String namedListStyle = params.get(JSONWriter.JSON_NL_STYLE, JSONWriter.JSON_NL_FLAT).intern(); final String namedListStyle = params.get(JSONWriter.JSON_NL_STYLE, JSONWriter.JSON_NL_FLAT).intern();
final JSONWriter w; final JSONWriter w;
if (namedListStyle.equals(JSONWriter.JSON_NL_ARROFNVP)) { if (namedListStyle.equals(JSONWriter.JSON_NL_ARROFNTV)) {
w = new ArrayOfNamedValuePairJSONWriter( w = new ArrayOfNameTypeValueJSONWriter(
writer, req, rsp, wrapperFunction, namedListStyle); writer, req, rsp, wrapperFunction, namedListStyle, true);
} else { } else {
w = new JSONWriter( w = new JSONWriter(
writer, req, rsp, wrapperFunction, namedListStyle); writer, req, rsp, wrapperFunction, namedListStyle);
@ -96,7 +96,7 @@ class JSONWriter extends TextResponseWriter {
static final String JSON_NL_FLAT="flat"; static final String JSON_NL_FLAT="flat";
static final String JSON_NL_ARROFARR="arrarr"; static final String JSON_NL_ARROFARR="arrarr";
static final String JSON_NL_ARROFMAP="arrmap"; static final String JSON_NL_ARROFMAP="arrmap";
static final String JSON_NL_ARROFNVP="arrnvp"; static final String JSON_NL_ARROFNTV="arrntv";
static final String JSON_WRAPPER_FUNCTION="json.wrf"; static final String JSON_WRAPPER_FUNCTION="json.wrf";
@ -331,9 +331,9 @@ class JSONWriter extends TextResponseWriter {
writeNamedListAsArrArr(name,val); writeNamedListAsArrArr(name,val);
} else if (namedListStyle==JSON_NL_ARROFMAP) { } else if (namedListStyle==JSON_NL_ARROFMAP) {
writeNamedListAsArrMap(name,val); writeNamedListAsArrMap(name,val);
} else if (namedListStyle==JSON_NL_ARROFNVP) { } else if (namedListStyle==JSON_NL_ARROFNTV) {
throw new UnsupportedOperationException(namedListStyle throw new UnsupportedOperationException(namedListStyle
+ " namedListStyle must only be used with "+ArrayOfNamedValuePairJSONWriter.class.getSimpleName()); + " namedListStyle must only be used with "+ArrayOfNameTypeValueJSONWriter.class.getSimpleName());
} }
} }
@ -675,20 +675,25 @@ class JSONWriter extends TextResponseWriter {
} }
/** /**
* Writes NamedLists directly as an array of NamedValuePair JSON objects... * Writes NamedLists directly as an array of NameTypeValue JSON objects...
* NamedList("a"=1,"b"=2,null=3,null=null) => [{"name":"a","int":1},{"name":"b","int":2},{"int":3},{"null":null}] * NamedList("a"=1,"b"=null,null=3,null=null) =>
* NamedList("a"=1,"bar"="foo",null=3.4f) => [{"name":"a","int":1},{"name":"bar","str":"foo"},{"float":3.4}] * [{"name":"a","type":"int","value":1},
* {"name":"b","type":"null","value":null},
* {"name":null,"type":"int","value":3},
* {"name":null,"type":"null","value":null}]
* NamedList("a"=1,"bar"="foo",null=3.4f) =>
* [{"name":"a","type":"int","value":1},
* {"name":"bar","type":"str","value":"foo"},
* {"name":null,"type":"float","value":3.4}]
*/ */
class ArrayOfNamedValuePairJSONWriter extends JSONWriter { class ArrayOfNameTypeValueJSONWriter extends JSONWriter {
private boolean writeTypeAsKey = false; protected boolean writeTypeAndValueKey = false;
private final boolean writeNullName;
public ArrayOfNamedValuePairJSONWriter(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp, public ArrayOfNameTypeValueJSONWriter(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp,
String wrapperFunction, String namedListStyle) { String wrapperFunction, String namedListStyle, boolean writeNullName) {
super(writer, req, rsp, wrapperFunction, namedListStyle); super(writer, req, rsp, wrapperFunction, namedListStyle);
if (namedListStyle != JSON_NL_ARROFNVP) { this.writeNullName = writeNullName;
throw new UnsupportedOperationException(ArrayOfNamedValuePairJSONWriter.class.getSimpleName()+" must only be used with "
+ JSON_NL_ARROFNVP + " style");
}
} }
@Override @Override
@ -720,24 +725,24 @@ class ArrayOfNamedValuePairJSONWriter extends JSONWriter {
/* /*
* JSONWriter's writeNamedListAsArrMap turns NamedList("bar"="foo") into [{"foo":"bar"}] * JSONWriter's writeNamedListAsArrMap turns NamedList("bar"="foo") into [{"foo":"bar"}]
* but we here wish to turn it into [ {"name":"bar","str":"foo"} ] instead. * but we here wish to turn it into [ {"name":"bar","type":"str","value":"foo"} ] instead.
* *
* So first we write the <code>{"name":"bar",</code> portion ... * So first we write the <code>{"name":"bar",</code> portion ...
*/ */
writeMapOpener(-1); writeMapOpener(-1);
if (elementName != null) { if (elementName != null || writeNullName) {
writeKey("name", false); writeKey("name", false);
writeVal("name", elementName); writeVal("name", elementName);
writeMapSeparator(); writeMapSeparator();
} }
/* /*
* ... and then we write the <code>"str":"foo"}</code> portion. * ... and then we write the <code>"type":"str","value":"foo"}</code> portion.
*/ */
writeTypeAsKey = true; writeTypeAndValueKey = true;
writeVal(null, elementVal); // passing null since writeVal doesn't actually use name (and we already wrote elementName above) writeVal(null, elementVal); // passing null since writeVal doesn't actually use name (and we already wrote elementName above)
if (writeTypeAsKey) { if (writeTypeAndValueKey) {
throw new RuntimeException("writeTypeAsKey should have been reset to false by writeVal('"+elementName+"','"+elementVal+"')"); throw new RuntimeException("writeTypeAndValueKey should have been reset to false by writeVal('"+elementName+"','"+elementVal+"')");
} }
writeMapCloser(); writeMapCloser();
} }
@ -746,82 +751,85 @@ class ArrayOfNamedValuePairJSONWriter extends JSONWriter {
writeArrayCloser(); writeArrayCloser();
} }
private void ifNeededWriteTypeAsKey(String type) throws IOException { protected void ifNeededWriteTypeAndValueKey(String type) throws IOException {
if (writeTypeAsKey) { if (writeTypeAndValueKey) {
writeTypeAsKey = false; writeTypeAndValueKey = false;
writeKey(type, false); writeKey("type", false);
writeVal("type", type);
writeMapSeparator();
writeKey("value", false);
} }
} }
@Override @Override
public void writeInt(String name, String val) throws IOException { public void writeInt(String name, String val) throws IOException {
ifNeededWriteTypeAsKey("int"); ifNeededWriteTypeAndValueKey("int");
super.writeInt(name, val); super.writeInt(name, val);
} }
@Override @Override
public void writeLong(String name, String val) throws IOException { public void writeLong(String name, String val) throws IOException {
ifNeededWriteTypeAsKey("long"); ifNeededWriteTypeAndValueKey("long");
super.writeLong(name, val); super.writeLong(name, val);
} }
@Override @Override
public void writeFloat(String name, String val) throws IOException { public void writeFloat(String name, String val) throws IOException {
ifNeededWriteTypeAsKey("float"); ifNeededWriteTypeAndValueKey("float");
super.writeFloat(name, val); super.writeFloat(name, val);
} }
@Override @Override
public void writeDouble(String name, String val) throws IOException { public void writeDouble(String name, String val) throws IOException {
ifNeededWriteTypeAsKey("double"); ifNeededWriteTypeAndValueKey("double");
super.writeDouble(name, val); super.writeDouble(name, val);
} }
@Override @Override
public void writeBool(String name, String val) throws IOException { public void writeBool(String name, String val) throws IOException {
ifNeededWriteTypeAsKey("bool"); ifNeededWriteTypeAndValueKey("bool");
super.writeBool(name, val); super.writeBool(name, val);
} }
@Override @Override
public void writeDate(String name, String val) throws IOException { public void writeDate(String name, String val) throws IOException {
ifNeededWriteTypeAsKey("date"); ifNeededWriteTypeAndValueKey("date");
super.writeDate(name, val); super.writeDate(name, val);
} }
@Override @Override
public void writeStr(String name, String val, boolean needsEscaping) throws IOException { public void writeStr(String name, String val, boolean needsEscaping) throws IOException {
ifNeededWriteTypeAsKey("str"); ifNeededWriteTypeAndValueKey("str");
super.writeStr(name, val, needsEscaping); super.writeStr(name, val, needsEscaping);
} }
@Override @Override
public void writeSolrDocument(String name, SolrDocument doc, ReturnFields returnFields, int idx) throws IOException { public void writeSolrDocument(String name, SolrDocument doc, ReturnFields returnFields, int idx) throws IOException {
ifNeededWriteTypeAsKey("doc"); ifNeededWriteTypeAndValueKey("doc");
super.writeSolrDocument(name, doc, returnFields, idx); super.writeSolrDocument(name, doc, returnFields, idx);
} }
@Override @Override
public void writeStartDocumentList(String name, long start, int size, long numFound, Float maxScore) throws IOException { public void writeStartDocumentList(String name, long start, int size, long numFound, Float maxScore) throws IOException {
ifNeededWriteTypeAsKey("doclist"); ifNeededWriteTypeAndValueKey("doclist");
super.writeStartDocumentList(name, start, size, numFound, maxScore); super.writeStartDocumentList(name, start, size, numFound, maxScore);
} }
@Override @Override
public void writeMap(String name, Map val, boolean excludeOuter, boolean isFirstVal) throws IOException { public void writeMap(String name, Map val, boolean excludeOuter, boolean isFirstVal) throws IOException {
ifNeededWriteTypeAsKey("map"); ifNeededWriteTypeAndValueKey("map");
super.writeMap(name, val, excludeOuter, isFirstVal); super.writeMap(name, val, excludeOuter, isFirstVal);
} }
@Override @Override
public void writeArray(String name, Iterator val) throws IOException { public void writeArray(String name, Iterator val) throws IOException {
ifNeededWriteTypeAsKey("array"); ifNeededWriteTypeAndValueKey("array");
super.writeArray(name, val); super.writeArray(name, val);
} }
@Override @Override
public void writeNull(String name) throws IOException { public void writeNull(String name) throws IOException {
ifNeededWriteTypeAsKey("null"); ifNeededWriteTypeAndValueKey("null");
super.writeNull(name); super.writeNull(name);
} }
} }

View File

@ -81,7 +81,7 @@ public class JSONWriterTest extends SolrTestCaseJ4 {
JSONWriter.JSON_NL_MAP, JSONWriter.JSON_NL_MAP,
JSONWriter.JSON_NL_ARROFARR, JSONWriter.JSON_NL_ARROFARR,
JSONWriter.JSON_NL_ARROFMAP, JSONWriter.JSON_NL_ARROFMAP,
JSONWriter.JSON_NL_ARROFNVP, JSONWriter.JSON_NL_ARROFNTV,
}; };
for (final String namedListStyle : namedListStyles) { for (final String namedListStyle : namedListStyles) {
implTestJSON(namedListStyle); implTestJSON(namedListStyle);
@ -116,8 +116,10 @@ public class JSONWriterTest extends SolrTestCaseJ4 {
expectedNLjson = "\"nl\":[[\"data1\",\"he\\u2028llo\\u2029!\"],[null,42],[null,null]]"; expectedNLjson = "\"nl\":[[\"data1\",\"he\\u2028llo\\u2029!\"],[null,42],[null,null]]";
} else if (namedListStyle == JSONWriter.JSON_NL_ARROFMAP) { } else if (namedListStyle == JSONWriter.JSON_NL_ARROFMAP) {
expectedNLjson = "\"nl\":[{\"data1\":\"he\\u2028llo\\u2029!\"},42,null]"; expectedNLjson = "\"nl\":[{\"data1\":\"he\\u2028llo\\u2029!\"},42,null]";
} else if (namedListStyle == JSONWriter.JSON_NL_ARROFNVP) { } else if (namedListStyle == JSONWriter.JSON_NL_ARROFNTV) {
expectedNLjson = "\"nl\":[{\"name\":\"data1\",\"str\":\"he\\u2028llo\\u2029!\"},{\"int\":42},{\"null\":null}]"; expectedNLjson = "\"nl\":[{\"name\":\"data1\",\"type\":\"str\",\"value\":\"he\\u2028llo\\u2029!\"}," +
"{\"name\":null,\"type\":\"int\",\"value\":42}," +
"{\"name\":null,\"type\":\"null\",\"value\":null}]";
} else { } else {
expectedNLjson = null; expectedNLjson = null;
fail("unexpected namedListStyle="+namedListStyle); fail("unexpected namedListStyle="+namedListStyle);
@ -168,7 +170,7 @@ public class JSONWriterTest extends SolrTestCaseJ4 {
} }
@Test @Test
public void testArrnvpWriterOverridesAllWrites() { public void testArrntvWriterOverridesAllWrites() {
// List rather than Set because two not-overridden methods could share name but not signature // List rather than Set because two not-overridden methods could share name but not signature
final List<String> methodsExpectedNotOverriden = new ArrayList<>(14); final List<String> methodsExpectedNotOverriden = new ArrayList<>(14);
methodsExpectedNotOverriden.add("writeResponse"); methodsExpectedNotOverriden.add("writeResponse");
@ -189,7 +191,7 @@ public class JSONWriterTest extends SolrTestCaseJ4 {
methodsExpectedNotOverriden.add("public void org.apache.solr.response.JSONWriter.writeMap(org.apache.solr.common.MapWriter) throws java.io.IOException"); methodsExpectedNotOverriden.add("public void org.apache.solr.response.JSONWriter.writeMap(org.apache.solr.common.MapWriter) throws java.io.IOException");
methodsExpectedNotOverriden.add("public void org.apache.solr.response.JSONWriter.writeIterator(org.apache.solr.common.IteratorWriter) throws java.io.IOException"); methodsExpectedNotOverriden.add("public void org.apache.solr.response.JSONWriter.writeIterator(org.apache.solr.common.IteratorWriter) throws java.io.IOException");
final Class<?> subClass = ArrayOfNamedValuePairJSONWriter.class; final Class<?> subClass = ArrayOfNameTypeValueJSONWriter.class;
final Class<?> superClass = subClass.getSuperclass(); final Class<?> superClass = subClass.getSuperclass();
for (final Method superClassMethod : superClass.getDeclaredMethods()) { for (final Method superClassMethod : superClass.getDeclaredMethods()) {
@ -231,14 +233,14 @@ public class JSONWriterTest extends SolrTestCaseJ4 {
} }
@Test @Test
public void testArrnvpWriterLacksMethodsOfItsOwn() { public void testArrntvWriterLacksMethodsOfItsOwn() {
final Class<?> subClass = ArrayOfNamedValuePairJSONWriter.class; final Class<?> subClass = ArrayOfNameTypeValueJSONWriter.class;
final Class<?> superClass = subClass.getSuperclass(); final Class<?> superClass = subClass.getSuperclass();
// ArrayOfNamedValuePairJSONWriter is a simple sub-class // ArrayOfNamedValuePairJSONWriter is a simple sub-class
// which should have (almost) no methods of its own // which should have (almost) no methods of its own
for (final Method subClassMethod : subClass.getDeclaredMethods()) { for (final Method subClassMethod : subClass.getDeclaredMethods()) {
// only own private method of its own // only own private method of its own
if (subClassMethod.getName().equals("ifNeededWriteTypeAsKey")) continue; if (subClassMethod.getName().equals("ifNeededWriteTypeAndValueKey")) continue;
try { try {
final Method superClassMethod = superClass.getDeclaredMethod( final Method superClassMethod = superClass.getDeclaredMethod(
subClassMethod.getName(), subClassMethod.getName(),
@ -260,7 +262,7 @@ public class JSONWriterTest extends SolrTestCaseJ4 {
assertEquals("flat", JSONWriter.JSON_NL_FLAT); assertEquals("flat", JSONWriter.JSON_NL_FLAT);
assertEquals("arrarr", JSONWriter.JSON_NL_ARROFARR); assertEquals("arrarr", JSONWriter.JSON_NL_ARROFARR);
assertEquals("arrmap", JSONWriter.JSON_NL_ARROFMAP); assertEquals("arrmap", JSONWriter.JSON_NL_ARROFMAP);
assertEquals("arrnvp", JSONWriter.JSON_NL_ARROFNVP); assertEquals("arrntv", JSONWriter.JSON_NL_ARROFNTV);
assertEquals("json.wrf", JSONWriter.JSON_WRAPPER_FUNCTION); assertEquals("json.wrf", JSONWriter.JSON_WRAPPER_FUNCTION);
} }