Treat path object as a simple value objects instead of Iterable in XContentBuilder, using toString() to create String representation.

This addresses #11771
This commit is contained in:
szroland 2015-06-28 01:12:52 +02:00 committed by Adrien Grand
parent 7c3ea748e2
commit 2c453820e4
2 changed files with 100 additions and 19 deletions

View File

@ -20,6 +20,7 @@
package org.elasticsearch.common.xcontent; package org.elasticsearch.common.xcontent;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesArray;
@ -41,6 +42,7 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.nio.file.Path;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
@ -650,21 +652,33 @@ public final class XContentBuilder implements BytesStream, Releasable {
return this; return this;
} }
public XContentBuilder field(String name, Iterable value) throws IOException { public XContentBuilder field(String name, Iterable<?> value) throws IOException {
startArray(name); if (value instanceof Path) {
for (Object o : value) { //treat Paths as single value
value(o); field(name);
value(value);
} else {
startArray(name);
for (Object o : value) {
value(o);
}
endArray();
} }
endArray();
return this; return this;
} }
public XContentBuilder field(XContentBuilderString name, Iterable value) throws IOException { public XContentBuilder field(XContentBuilderString name, Iterable<?> value) throws IOException {
startArray(name); if (value instanceof Path) {
for (Object o : value) { //treat Paths as single value
value(o); field(name);
value(value);
} else {
startArray(name);
for (Object o : value) {
value(o);
}
endArray();
} }
endArray();
return this; return this;
} }
@ -1140,26 +1154,31 @@ public final class XContentBuilder implements BytesStream, Releasable {
return this; return this;
} }
public XContentBuilder value(Iterable value) throws IOException { public XContentBuilder value(Iterable<?> value) throws IOException {
if (value == null) { if (value == null) {
return nullValue(); return nullValue();
} }
startArray(); if (value instanceof Path) {
for (Object o : value) { //treat as single value
value(o); writeValue(value);
} else {
startArray();
for (Object o : value) {
value(o);
}
endArray();
} }
endArray();
return this; return this;
} }
public XContentBuilder latlon(String name, double lat, double lon) throws IOException { public XContentBuilder latlon(String name, double lat, double lon) throws IOException {
return startObject(name).field("lat", lat).field("lon", lon).endObject(); return startObject(name).field("lat", lat).field("lon", lon).endObject();
} }
public XContentBuilder latlon(double lat, double lon) throws IOException { public XContentBuilder latlon(double lat, double lon) throws IOException {
return startObject().field("lat", lat).field("lon", lon).endObject(); return startObject().field("lat", lat).field("lon", lon).endObject();
} }
public XContentBuilder copyCurrentStructure(XContentParser parser) throws IOException { public XContentBuilder copyCurrentStructure(XContentParser parser) throws IOException {
generator.copyCurrentStructure(parser); generator.copyCurrentStructure(parser);
return this; return this;
@ -1231,7 +1250,7 @@ public final class XContentBuilder implements BytesStream, Releasable {
generator.writeNull(); generator.writeNull();
return; return;
} }
Class type = value.getClass(); Class<?> type = value.getClass();
if (type == String.class) { if (type == String.class) {
generator.writeString((String) value); generator.writeString((String) value);
} else if (type == Integer.class) { } else if (type == Integer.class) {
@ -1255,9 +1274,12 @@ public final class XContentBuilder implements BytesStream, Releasable {
generator.writeEndObject(); generator.writeEndObject();
} else if (value instanceof Map) { } else if (value instanceof Map) {
writeMap((Map) value); writeMap((Map) value);
} else if (value instanceof Path) {
//Path implements Iterable<Path> and causes endless recursion and a StackOverFlow if treated as an Iterable here
generator.writeString(value.toString());
} else if (value instanceof Iterable) { } else if (value instanceof Iterable) {
generator.writeStartArray(); generator.writeStartArray();
for (Object v : (Iterable) value) { for (Object v : (Iterable<?>) value) {
writeValue(v); writeValue(v);
} }
generator.writeEndArray(); generator.writeEndArray();

View File

@ -20,14 +20,17 @@
package org.elasticsearch.common.xcontent.builder; package org.elasticsearch.common.xcontent.builder;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.io.FastCharArrayWriter; import org.elasticsearch.common.io.FastCharArrayWriter;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.xcontent.*; import org.elasticsearch.common.xcontent.*;
import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.test.ElasticsearchTestCase;
import org.junit.Test; import org.junit.Test;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path;
import java.util.*; import java.util.*;
import static org.elasticsearch.common.xcontent.XContentBuilder.FieldCaseConversion.CAMELCASE; import static org.elasticsearch.common.xcontent.XContentBuilder.FieldCaseConversion.CAMELCASE;
@ -260,4 +263,60 @@ public class XContentBuilderTests extends ElasticsearchTestCase {
assertThat(i, equalTo(terms.size())); assertThat(i, equalTo(terms.size()));
} }
@Test
public void testHandlingOfPath() throws IOException {
Path path = PathUtils.get("path");
checkPathSerialization(path);
}
@Test
public void testHandlingOfPath_relative() throws IOException {
Path path = PathUtils.get("..", "..", "path");
checkPathSerialization(path);
}
@Test
public void testHandlingOfPath_absolute() throws IOException {
Path path = createTempDir().toAbsolutePath();
checkPathSerialization(path);
}
private void checkPathSerialization(Path path) throws IOException {
XContentBuilder pathBuilder = XContentFactory.contentBuilder(XContentType.JSON);
pathBuilder.startObject().field("file", path).endObject();
XContentBuilder stringBuilder = XContentFactory.contentBuilder(XContentType.JSON);
stringBuilder.startObject().field("file", path.toString()).endObject();
assertThat(pathBuilder.string(), equalTo(stringBuilder.string()));
}
@Test
public void testHandlingOfPath_XContentBuilderStringName() throws IOException {
Path path = PathUtils.get("path");
XContentBuilderString name = new XContentBuilderString("file");
XContentBuilder pathBuilder = XContentFactory.contentBuilder(XContentType.JSON);
pathBuilder.startObject().field(name, path).endObject();
XContentBuilder stringBuilder = XContentFactory.contentBuilder(XContentType.JSON);
stringBuilder.startObject().field(name, path.toString()).endObject();
assertThat(pathBuilder.string(), equalTo(stringBuilder.string()));
}
@Test
public void testHandlingOfCollectionOfPaths() throws IOException {
Path path = PathUtils.get("path");
XContentBuilder pathBuilder = XContentFactory.contentBuilder(XContentType.JSON);
pathBuilder.startObject().field("file", Arrays.asList(path)).endObject();
XContentBuilder stringBuilder = XContentFactory.contentBuilder(XContentType.JSON);
stringBuilder.startObject().field("file", Arrays.asList(path.toString())).endObject();
assertThat(pathBuilder.string(), equalTo(stringBuilder.string()));
}
} }