Browse Source

Ensure meta and document field maps are never null in GetResult (#50112)

This commit ensures deseriable a GetResult from StreamInput does not
leave metaFields and documentFields null. This could cause an NPE in
situations where upsert response for a document that did not exist is
passed back to a node that forwarded the upsert request.

closes #48215
Ryan Ernst 5 years ago
parent
commit
03abcb4a4b

+ 7 - 10
server/src/main/java/org/elasticsearch/index/get/GetResult.java

@@ -65,8 +65,8 @@ public class GetResult implements Writeable, Iterable<DocumentField>, ToXContent
     private long seqNo;
     private long primaryTerm;
     private boolean exists;
-    private Map<String, DocumentField> documentFields;
-    private Map<String, DocumentField> metaFields;
+    private final Map<String, DocumentField> documentFields;
+    private final Map<String, DocumentField> metaFields;
     private Map<String, Object> sourceAsMap;
     private BytesReference source;
     private byte[] sourceAsBytes;
@@ -95,6 +95,9 @@ public class GetResult implements Writeable, Iterable<DocumentField>, ToXContent
                 metaFields = new HashMap<>();
                 splitFieldsByMetadata(fields, documentFields, metaFields);
             }
+        } else {
+            metaFields = Collections.emptyMap();
+            documentFields = Collections.emptyMap();
         }
     }
 
@@ -111,14 +114,8 @@ public class GetResult implements Writeable, Iterable<DocumentField>, ToXContent
         this.version = version;
         this.exists = exists;
         this.source = source;
-        this.documentFields = documentFields;
-        if (this.documentFields == null) {
-            this.documentFields = emptyMap();
-        }
-        this.metaFields = metaFields;
-        if (this.metaFields == null) {
-            this.metaFields = emptyMap();
-        }
+        this.documentFields = documentFields == null ? emptyMap() : documentFields;
+        this.metaFields = metaFields == null ? emptyMap() : metaFields;
     }
 
     /**

+ 13 - 0
server/src/test/java/org/elasticsearch/index/get/GetResultTests.java

@@ -24,6 +24,7 @@ import org.elasticsearch.common.bytes.BytesArray;
 import org.elasticsearch.common.bytes.BytesReference;
 import org.elasticsearch.common.collect.Tuple;
 import org.elasticsearch.common.document.DocumentField;
+import org.elasticsearch.common.io.stream.BytesStreamOutput;
 import org.elasticsearch.common.xcontent.ToXContent;
 import org.elasticsearch.common.xcontent.XContentHelper;
 import org.elasticsearch.common.xcontent.XContentParser;
@@ -138,6 +139,18 @@ public class GetResultTests extends ESTestCase {
         assertEquals("{\"found\":false}", originalBytes.utf8ToString());
     }
 
+    public void testSerializationNotFound() throws IOException {
+        // serializes and deserializes with streamable, then prints back to xcontent
+        GetResult getResult = new GetResult("index", "id", UNASSIGNED_SEQ_NO, 0, 1, false, null, null, null);
+
+        BytesStreamOutput out = new BytesStreamOutput();
+        getResult.writeTo(out);
+        getResult = new GetResult(out.bytes().streamInput());
+
+        BytesReference originalBytes = toXContentEmbedded(getResult, XContentType.JSON, false);
+        assertEquals("{\"found\":false}", originalBytes.utf8ToString());
+    }
+
     public void testGetSourceAsBytes() {
         XContentType xContentType = randomFrom(XContentType.values());
         Tuple<GetResult, GetResult> tuple = randomGetResult(xContentType);