1919
2020package org .elasticsearch .common .xcontent ;
2121
22+ import org .elasticsearch .common .ParseField ;
2223import org .elasticsearch .common .ParsingException ;
24+ import org .elasticsearch .common .bytes .BytesReference ;
2325import org .elasticsearch .common .xcontent .json .JsonXContent ;
2426import org .elasticsearch .test .ESTestCase ;
2527
2628import java .io .IOException ;
29+ import java .util .ArrayList ;
30+ import java .util .List ;
2731
32+ import static org .elasticsearch .common .xcontent .XContentHelper .toXContent ;
2833import static org .elasticsearch .common .xcontent .XContentParserUtils .ensureExpectedToken ;
34+ import static org .elasticsearch .common .xcontent .XContentParserUtils .parseTypedKeysObject ;
2935
3036public class XContentParserUtilsTests extends ESTestCase {
37+
3138 public void testEnsureExpectedToken () throws IOException {
3239 final XContentParser .Token randomToken = randomFrom (XContentParser .Token .values ());
3340 try (XContentParser parser = createParser (JsonXContent .jsonXContent , "{}" )) {
@@ -40,4 +47,68 @@ public void testEnsureExpectedToken() throws IOException {
4047 ensureExpectedToken (XContentParser .Token .END_OBJECT , parser .nextToken (), parser ::getTokenLocation );
4148 }
4249 }
50+
51+ public void testParseTypedKeysObject () throws IOException {
52+ final String delimiter = randomFrom ("#" , ":" , "/" , "-" , "_" , "|" , "_delim_" );
53+ final XContentType xContentType = randomFrom (XContentType .values ());
54+
55+ List <NamedXContentRegistry .Entry > namedXContents = new ArrayList <>();
56+ namedXContents .add (new NamedXContentRegistry .Entry (Boolean .class , new ParseField ("bool" ), parser -> {
57+ ensureExpectedToken (XContentParser .Token .VALUE_BOOLEAN , parser .nextToken (), parser ::getTokenLocation );
58+ return parser .booleanValue ();
59+ }));
60+ namedXContents .add (new NamedXContentRegistry .Entry (Long .class , new ParseField ("long" ), parser -> {
61+ ensureExpectedToken (XContentParser .Token .VALUE_NUMBER , parser .nextToken (), parser ::getTokenLocation );
62+ return parser .longValue ();
63+ }));
64+ final NamedXContentRegistry namedXContentRegistry = new NamedXContentRegistry (namedXContents );
65+
66+ BytesReference bytes = toXContent ((builder , params ) -> builder .field ("test" , 0 ), xContentType , randomBoolean ());
67+ try (XContentParser parser = xContentType .xContent ().createParser (namedXContentRegistry , bytes )) {
68+ parser .nextToken ();
69+ ParsingException e = expectThrows (ParsingException .class , () -> parseTypedKeysObject (parser , delimiter , Boolean .class ));
70+ assertEquals ("Failed to parse object: expecting token of type [FIELD_NAME] but found [START_OBJECT]" , e .getMessage ());
71+
72+ parser .nextToken ();
73+ e = expectThrows (ParsingException .class , () -> parseTypedKeysObject (parser , delimiter , Boolean .class ));
74+ assertEquals ("Cannot parse object of class [Boolean] without type information. Set [typed_keys] parameter " +
75+ "on the request to ensure the type information is added to the response output" , e .getMessage ());
76+ }
77+
78+ bytes = toXContent ((builder , params ) -> builder .field ("type" + delimiter + "name" , 0 ), xContentType , randomBoolean ());
79+ try (XContentParser parser = xContentType .xContent ().createParser (namedXContentRegistry , bytes )) {
80+ ensureExpectedToken (XContentParser .Token .START_OBJECT , parser .nextToken (), parser ::getTokenLocation );
81+ ensureExpectedToken (XContentParser .Token .FIELD_NAME , parser .nextToken (), parser ::getTokenLocation );
82+
83+ NamedXContentRegistry .UnknownNamedObjectException e = expectThrows (NamedXContentRegistry .UnknownNamedObjectException .class ,
84+ () -> parseTypedKeysObject (parser , delimiter , Boolean .class ));
85+ assertEquals ("Unknown Boolean [type]" , e .getMessage ());
86+ assertEquals ("type" , e .getName ());
87+ assertEquals ("java.lang.Boolean" , e .getCategoryClass ());
88+ }
89+
90+ final long longValue = randomLong ();
91+ final boolean boolValue = randomBoolean ();
92+ bytes = toXContent ((builder , params ) -> {
93+ builder .field ("long" + delimiter + "l" , longValue );
94+ builder .field ("bool" + delimiter + "b" , boolValue );
95+ return builder ;
96+ }, xContentType , randomBoolean ());
97+
98+ try (XContentParser parser = xContentType .xContent ().createParser (namedXContentRegistry , bytes )) {
99+ ensureExpectedToken (XContentParser .Token .START_OBJECT , parser .nextToken (), parser ::getTokenLocation );
100+
101+ ensureExpectedToken (XContentParser .Token .FIELD_NAME , parser .nextToken (), parser ::getTokenLocation );
102+ Long parsedLong = parseTypedKeysObject (parser , delimiter , Long .class );
103+ assertNotNull (parsedLong );
104+ assertEquals (longValue , parsedLong .longValue ());
105+
106+ ensureExpectedToken (XContentParser .Token .FIELD_NAME , parser .nextToken (), parser ::getTokenLocation );
107+ Boolean parsedBoolean = parseTypedKeysObject (parser , delimiter , Boolean .class );
108+ assertNotNull (parsedBoolean );
109+ assertEquals (boolValue , parsedBoolean );
110+
111+ ensureExpectedToken (XContentParser .Token .END_OBJECT , parser .nextToken (), parser ::getTokenLocation );
112+ }
113+ }
43114}
0 commit comments