Skip to content

Commit 80c5d30

Browse files
XContentBuilder to handle BigInteger and BigDecimal (#32888)
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 #32395
1 parent de8bfb9 commit 80c5d30

File tree

5 files changed

+155
-1
lines changed

5 files changed

+155
-1
lines changed

libs/x-content/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import java.io.IOException;
2626
import java.io.InputStream;
2727
import java.io.OutputStream;
28+
import java.math.BigDecimal;
29+
import java.math.BigInteger;
2830
import java.nio.file.Path;
2931
import java.time.ZonedDateTime;
3032
import java.util.Arrays;
@@ -103,7 +105,8 @@ public static XContentBuilder builder(XContent xContent, Set<String> includes, S
103105
writers.put(ZonedDateTime.class, (b, v) -> b.value(v.toString()));
104106
writers.put(Calendar.class, XContentBuilder::timeValue);
105107
writers.put(GregorianCalendar.class, XContentBuilder::timeValue);
106-
108+
writers.put(BigInteger.class, (b, v) -> b.value((BigInteger) v));
109+
writers.put(BigDecimal.class, (b, v) -> b.value((BigDecimal) v));
107110

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

552+
////////////////////////////////////////////////////////////////////////////
553+
// BigInteger
554+
//////////////////////////////////
555+
556+
public XContentBuilder field(String name, BigInteger value) throws IOException {
557+
if (value == null) {
558+
return nullField(name);
559+
}
560+
ensureNameNotNull(name);
561+
generator.writeNumberField(name, value);
562+
return this;
563+
}
564+
565+
public XContentBuilder array(String name, BigInteger[] values) throws IOException {
566+
return field(name).values(values);
567+
}
568+
569+
private XContentBuilder values(BigInteger[] values) throws IOException {
570+
if (values == null) {
571+
return nullValue();
572+
}
573+
startArray();
574+
for (BigInteger b : values) {
575+
value(b);
576+
}
577+
endArray();
578+
return this;
579+
}
580+
581+
public XContentBuilder value(BigInteger value) throws IOException {
582+
if (value == null) {
583+
return nullValue();
584+
}
585+
generator.writeNumber(value);
586+
return this;
587+
}
588+
589+
590+
////////////////////////////////////////////////////////////////////////////
591+
// BigDecimal
592+
//////////////////////////////////
593+
594+
public XContentBuilder field(String name, BigDecimal value) throws IOException {
595+
if (value == null) {
596+
return nullField(name);
597+
}
598+
ensureNameNotNull(name);
599+
generator.writeNumberField(name, value);
600+
return this;
601+
}
602+
603+
public XContentBuilder array(String name, BigDecimal[] values) throws IOException {
604+
return field(name).values(values);
605+
}
606+
607+
private XContentBuilder values(BigDecimal[] values) throws IOException {
608+
if (values == null) {
609+
return nullValue();
610+
}
611+
startArray();
612+
for (BigDecimal b : values) {
613+
value(b);
614+
}
615+
endArray();
616+
return this;
617+
}
618+
619+
public XContentBuilder value(BigDecimal value) throws IOException {
620+
if (value == null) {
621+
return nullValue();
622+
}
623+
generator.writeNumber(value);
624+
return this;
625+
}
626+
549627
////////////////////////////////////////////////////////////////////////////
550628
// String
551629
//////////////////////////////////

libs/x-content/src/main/java/org/elasticsearch/common/xcontent/XContentGenerator.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import java.io.Flushable;
2424
import java.io.IOException;
2525
import java.io.InputStream;
26+
import java.math.BigDecimal;
27+
import java.math.BigInteger;
2628

2729
public interface XContentGenerator extends Closeable, Flushable {
2830

@@ -70,6 +72,14 @@ public interface XContentGenerator extends Closeable, Flushable {
7072

7173
void writeNumber(short value) throws IOException;
7274

75+
void writeNumber(BigInteger value) throws IOException;
76+
77+
void writeNumberField(String name, BigInteger value) throws IOException;
78+
79+
void writeNumber(BigDecimal value) throws IOException;
80+
81+
void writeNumberField(String name, BigDecimal value) throws IOException;
82+
7383
void writeStringField(String name, String value) throws IOException;
7484

7585
void writeString(String value) throws IOException;

libs/x-content/src/main/java/org/elasticsearch/common/xcontent/json/JsonXContentGenerator.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
import java.io.IOException;
4343
import java.io.InputStream;
4444
import java.io.OutputStream;
45+
import java.math.BigDecimal;
46+
import java.math.BigInteger;
4547
import java.util.Objects;
4648
import java.util.Set;
4749

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

231+
@Override
232+
public void writeNumberField(String name, BigInteger value) throws IOException {
233+
// as jackson's JsonGenerator doesn't have this method for BigInteger
234+
// we have to implement it ourselves
235+
generator.writeFieldName(name);
236+
generator.writeNumber(value);
237+
}
238+
239+
@Override
240+
public void writeNumberField(String name, BigDecimal value) throws IOException {
241+
generator.writeNumberField(name, value);
242+
}
243+
229244
@Override
230245
public void writeNumber(int value) throws IOException {
231246
generator.writeNumber(value);
@@ -246,6 +261,16 @@ public void writeNumber(short value) throws IOException {
246261
generator.writeNumber(value);
247262
}
248263

264+
@Override
265+
public void writeNumber(BigInteger value) throws IOException {
266+
generator.writeNumber(value);
267+
}
268+
269+
@Override
270+
public void writeNumber(BigDecimal value) throws IOException {
271+
generator.writeNumber(value);
272+
}
273+
249274
@Override
250275
public void writeStringField(String name, String value) throws IOException {
251276
generator.writeStringField(name, value);

rest-api-spec/src/main/resources/rest-api-spec/test/search/10_source_filtering.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ setup:
112112
- match: { hits.hits.0._source.bigint: 72057594037927936 }
113113
- is_false: hits.hits.0._source.include.field2
114114

115+
116+
---
117+
"_source filtering on bigint":
118+
- do:
119+
search:
120+
body:
121+
_source: ["bigint"]
122+
query: { match_all: {} }
123+
- match: { hits.hits.0._source.bigint: 72057594037927936 }
124+
115125
---
116126
"fields in body":
117127
- do:

server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import java.io.ByteArrayInputStream;
4949
import java.io.ByteArrayOutputStream;
5050
import java.io.IOException;
51+
import java.math.BigDecimal;
5152
import java.math.BigInteger;
5253
import java.nio.file.Path;
5354
import java.time.DayOfWeek;
@@ -266,6 +267,36 @@ public void testShorts() throws IOException {
266267
.endObject());
267268
}
268269

270+
public void testBigIntegers() throws Exception {
271+
assertResult("{'bigint':null}", () -> builder().startObject().field("bigint", (BigInteger) null).endObject());
272+
assertResult("{'bigint':[]}", () -> builder().startObject().array("bigint", new BigInteger[]{}).endObject());
273+
274+
BigInteger bigInteger = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE);
275+
String result = "{'bigint':" + bigInteger.toString() + "}";
276+
assertResult(result, () -> builder().startObject().field("bigint", bigInteger).endObject());
277+
278+
result = "{'bigint':[" + bigInteger.toString() + "," + bigInteger.toString() + "," + bigInteger.toString() +"]}";
279+
assertResult(result, () -> builder()
280+
.startObject()
281+
.array("bigint", bigInteger, bigInteger, bigInteger)
282+
.endObject());
283+
}
284+
285+
public void testBigDecimals() throws Exception {
286+
assertResult("{'bigdecimal':null}", () -> builder().startObject().field("bigdecimal", (BigInteger) null).endObject());
287+
assertResult("{'bigdecimal':[]}", () -> builder().startObject().array("bigdecimal", new BigInteger[]{}).endObject());
288+
289+
BigDecimal bigDecimal = new BigDecimal("234.43");
290+
String result = "{'bigdecimal':" + bigDecimal.toString() + "}";
291+
assertResult(result, () -> builder().startObject().field("bigdecimal", bigDecimal).endObject());
292+
293+
result = "{'bigdecimal':[" + bigDecimal.toString() + "," + bigDecimal.toString() + "," + bigDecimal.toString() +"]}";
294+
assertResult(result, () -> builder()
295+
.startObject()
296+
.array("bigdecimal", bigDecimal, bigDecimal, bigDecimal)
297+
.endObject());
298+
}
299+
269300
public void testStrings() throws IOException {
270301
assertResult("{'string':null}", () -> builder().startObject().field("string", (String) null).endObject());
271302
assertResult("{'string':'value'}", () -> builder().startObject().field("string", "value").endObject());

0 commit comments

Comments
 (0)