Skip to content

Commit

Permalink
XContentBuilder to handle BigInteger and BigDecimal (elastic#32888)
Browse files Browse the repository at this point in the history
Although we allow to index BigInteger and BigDecimal into a keyword
field, source filtering on these fields would fail
as XContentBuilder was not able to deserialize BigInteger and BigDecimal
to json.

This modifies XContentBuilder to allow to handle BigInteger and
BigDecimal.

Closes elastic#32395
  • Loading branch information
mayya-sharipova committed Sep 26, 2018
1 parent f2f4738 commit ed6dfdf
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.file.Path;
import java.time.ZonedDateTime;
import java.util.Arrays;
Expand Down Expand Up @@ -103,7 +105,8 @@ public static XContentBuilder builder(XContent xContent, Set<String> includes, S
writers.put(ZonedDateTime.class, (b, v) -> b.value(v.toString()));
writers.put(Calendar.class, XContentBuilder::timeValue);
writers.put(GregorianCalendar.class, XContentBuilder::timeValue);

writers.put(BigInteger.class, (b, v) -> b.value((BigInteger) v));
writers.put(BigDecimal.class, (b, v) -> b.value((BigDecimal) v));

Map<Class<?>, HumanReadableTransformer> humanReadableTransformer = new HashMap<>();
Map<Class<?>, Function<Object, Object>> dateTransformers = new HashMap<>();
Expand Down Expand Up @@ -546,6 +549,81 @@ public XContentBuilder value(short value) throws IOException {
return this;
}

////////////////////////////////////////////////////////////////////////////
// BigInteger
//////////////////////////////////

public XContentBuilder field(String name, BigInteger value) throws IOException {
if (value == null) {
return nullField(name);
}
ensureNameNotNull(name);
generator.writeNumberField(name, value);
return this;
}

public XContentBuilder array(String name, BigInteger[] values) throws IOException {
return field(name).values(values);
}

private XContentBuilder values(BigInteger[] values) throws IOException {
if (values == null) {
return nullValue();
}
startArray();
for (BigInteger b : values) {
value(b);
}
endArray();
return this;
}

public XContentBuilder value(BigInteger value) throws IOException {
if (value == null) {
return nullValue();
}
generator.writeNumber(value);
return this;
}


////////////////////////////////////////////////////////////////////////////
// BigDecimal
//////////////////////////////////

public XContentBuilder field(String name, BigDecimal value) throws IOException {
if (value == null) {
return nullField(name);
}
ensureNameNotNull(name);
generator.writeNumberField(name, value);
return this;
}

public XContentBuilder array(String name, BigDecimal[] values) throws IOException {
return field(name).values(values);
}

private XContentBuilder values(BigDecimal[] values) throws IOException {
if (values == null) {
return nullValue();
}
startArray();
for (BigDecimal b : values) {
value(b);
}
endArray();
return this;
}

public XContentBuilder value(BigDecimal value) throws IOException {
if (value == null) {
return nullValue();
}
generator.writeNumber(value);
return this;
}

////////////////////////////////////////////////////////////////////////////
// String
//////////////////////////////////
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import java.io.Flushable;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.BigInteger;

public interface XContentGenerator extends Closeable, Flushable {

Expand Down Expand Up @@ -70,6 +72,14 @@ public interface XContentGenerator extends Closeable, Flushable {

void writeNumber(short value) throws IOException;

void writeNumber(BigInteger value) throws IOException;

void writeNumberField(String name, BigInteger value) throws IOException;

void writeNumber(BigDecimal value) throws IOException;

void writeNumberField(String name, BigDecimal value) throws IOException;

void writeStringField(String name, String value) throws IOException;

void writeString(String value) throws IOException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Objects;
import java.util.Set;

Expand Down Expand Up @@ -226,6 +228,19 @@ public void writeNumberField(String name, int value) throws IOException {
generator.writeNumberField(name, value);
}

@Override
public void writeNumberField(String name, BigInteger value) throws IOException {
// as jackson's JsonGenerator doesn't have this method for BigInteger
// we have to implement it ourselves
generator.writeFieldName(name);
generator.writeNumber(value);
}

@Override
public void writeNumberField(String name, BigDecimal value) throws IOException {
generator.writeNumberField(name, value);
}

@Override
public void writeNumber(int value) throws IOException {
generator.writeNumber(value);
Expand All @@ -246,6 +261,16 @@ public void writeNumber(short value) throws IOException {
generator.writeNumber(value);
}

@Override
public void writeNumber(BigInteger value) throws IOException {
generator.writeNumber(value);
}

@Override
public void writeNumber(BigDecimal value) throws IOException {
generator.writeNumber(value);
}

@Override
public void writeStringField(String name, String value) throws IOException {
generator.writeStringField(name, value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,16 @@ setup:
- match: { hits.hits.0._source.bigint: 72057594037927936 }
- is_false: hits.hits.0._source.include.field2


---
"_source filtering on bigint":
- do:
search:
body:
_source: ["bigint"]
query: { match_all: {} }
- match: { hits.hits.0._source.bigint: 72057594037927936 }

---
"fields in body":
- do:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.file.Path;
import java.time.DayOfWeek;
Expand Down Expand Up @@ -266,6 +267,36 @@ public void testShorts() throws IOException {
.endObject());
}

public void testBigIntegers() throws Exception {
assertResult("{'bigint':null}", () -> builder().startObject().field("bigint", (BigInteger) null).endObject());
assertResult("{'bigint':[]}", () -> builder().startObject().array("bigint", new BigInteger[]{}).endObject());

BigInteger bigInteger = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE);
String result = "{'bigint':" + bigInteger.toString() + "}";
assertResult(result, () -> builder().startObject().field("bigint", bigInteger).endObject());

result = "{'bigint':[" + bigInteger.toString() + "," + bigInteger.toString() + "," + bigInteger.toString() +"]}";
assertResult(result, () -> builder()
.startObject()
.array("bigint", bigInteger, bigInteger, bigInteger)
.endObject());
}

public void testBigDecimals() throws Exception {
assertResult("{'bigdecimal':null}", () -> builder().startObject().field("bigdecimal", (BigInteger) null).endObject());
assertResult("{'bigdecimal':[]}", () -> builder().startObject().array("bigdecimal", new BigInteger[]{}).endObject());

BigDecimal bigDecimal = new BigDecimal("234.43");
String result = "{'bigdecimal':" + bigDecimal.toString() + "}";
assertResult(result, () -> builder().startObject().field("bigdecimal", bigDecimal).endObject());

result = "{'bigdecimal':[" + bigDecimal.toString() + "," + bigDecimal.toString() + "," + bigDecimal.toString() +"]}";
assertResult(result, () -> builder()
.startObject()
.array("bigdecimal", bigDecimal, bigDecimal, bigDecimal)
.endObject());
}

public void testStrings() throws IOException {
assertResult("{'string':null}", () -> builder().startObject().field("string", (String) null).endObject());
assertResult("{'string':'value'}", () -> builder().startObject().field("string", "value").endObject());
Expand Down

0 comments on commit ed6dfdf

Please sign in to comment.