浏览代码

Move some test-only parsing code to test modules (#104261)

None of this code needs to live in the prod classes, moving it over to
the test code where its used.
Armin Braun 1 年之前
父节点
当前提交
abccea00d1
共有 18 个文件被更改,包括 403 次插入467 次删除
  1. 0 30
      modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/SearchTemplateResponse.java
  2. 25 1
      modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/SearchTemplateResponseTests.java
  3. 16 117
      server/src/main/java/org/elasticsearch/action/admin/cluster/health/ClusterHealthResponse.java
  4. 0 58
      server/src/main/java/org/elasticsearch/action/admin/indices/settings/get/GetSettingsResponse.java
  5. 2 97
      server/src/main/java/org/elasticsearch/action/bulk/BulkItemResponse.java
  6. 4 46
      server/src/main/java/org/elasticsearch/action/bulk/BulkResponse.java
  7. 0 34
      server/src/main/java/org/elasticsearch/action/get/GetResponse.java
  8. 0 31
      server/src/main/java/org/elasticsearch/action/ingest/GetPipelineResponse.java
  9. 0 19
      server/src/main/java/org/elasticsearch/action/ingest/SimulateDocumentVerboseResult.java
  10. 2 23
      server/src/main/java/org/elasticsearch/action/search/ClearScrollResponse.java
  11. 96 1
      server/src/test/java/org/elasticsearch/action/admin/cluster/health/ClusterHealthResponsesTests.java
  12. 54 1
      server/src/test/java/org/elasticsearch/action/admin/indices/settings/get/GetSettingsResponseTests.java
  13. 81 2
      server/src/test/java/org/elasticsearch/action/bulk/BulkItemResponseTests.java
  14. 41 1
      server/src/test/java/org/elasticsearch/action/bulk/BulkResponseTests.java
  15. 18 2
      server/src/test/java/org/elasticsearch/action/get/GetResponseTests.java
  16. 20 2
      server/src/test/java/org/elasticsearch/action/ingest/GetPipelineResponseTests.java
  17. 19 1
      server/src/test/java/org/elasticsearch/action/ingest/SimulateDocumentVerboseResultTests.java
  18. 25 1
      server/src/test/java/org/elasticsearch/search/ClearScrollResponseTests.java

+ 0 - 30
modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/SearchTemplateResponse.java

@@ -14,7 +14,6 @@ import org.elasticsearch.common.bytes.BytesReference;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.common.xcontent.ChunkedToXContent;
-import org.elasticsearch.common.xcontent.XContentHelper;
 import org.elasticsearch.core.AbstractRefCounted;
 import org.elasticsearch.core.RefCounted;
 import org.elasticsearch.rest.RestStatus;
@@ -22,14 +21,10 @@ import org.elasticsearch.transport.LeakTracker;
 import org.elasticsearch.xcontent.ParseField;
 import org.elasticsearch.xcontent.ToXContentObject;
 import org.elasticsearch.xcontent.XContentBuilder;
-import org.elasticsearch.xcontent.XContentFactory;
-import org.elasticsearch.xcontent.XContentParser;
-import org.elasticsearch.xcontent.XContentParserConfiguration;
 import org.elasticsearch.xcontent.XContentType;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Map;
 
 public class SearchTemplateResponse extends ActionResponse implements ToXContentObject {
     public static ParseField TEMPLATE_OUTPUT_FIELD = new ParseField("template_output");
@@ -108,31 +103,6 @@ public class SearchTemplateResponse extends ActionResponse implements ToXContent
         return refCounted.hasReferences();
     }
 
-    public static SearchTemplateResponse fromXContent(XContentParser parser) throws IOException {
-        SearchTemplateResponse searchTemplateResponse = new SearchTemplateResponse();
-        Map<String, Object> contentAsMap = parser.map();
-
-        if (contentAsMap.containsKey(TEMPLATE_OUTPUT_FIELD.getPreferredName())) {
-            Object source = contentAsMap.get(TEMPLATE_OUTPUT_FIELD.getPreferredName());
-            XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON).value(source);
-            searchTemplateResponse.setSource(BytesReference.bytes(builder));
-        } else {
-            XContentType contentType = parser.contentType();
-            XContentBuilder builder = XContentFactory.contentBuilder(contentType).map(contentAsMap);
-            try (
-                XContentParser searchResponseParser = XContentHelper.createParserNotCompressed(
-                    XContentParserConfiguration.EMPTY.withRegistry(parser.getXContentRegistry())
-                        .withDeprecationHandler(parser.getDeprecationHandler()),
-                    BytesReference.bytes(builder),
-                    contentType
-                )
-            ) {
-                searchTemplateResponse.setResponse(SearchResponse.fromXContent(searchResponseParser));
-            }
-        }
-        return searchTemplateResponse;
-    }
-
     @Override
     public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
         builder.startObject();

+ 25 - 1
modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/SearchTemplateResponseTests.java

@@ -12,6 +12,7 @@ import org.apache.lucene.search.TotalHits;
 import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.action.search.ShardSearchFailure;
 import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.xcontent.XContentHelper;
 import org.elasticsearch.search.SearchHit;
 import org.elasticsearch.search.SearchHits;
 import org.elasticsearch.search.SearchResponseUtils;
@@ -20,9 +21,11 @@ import org.elasticsearch.xcontent.ToXContent;
 import org.elasticsearch.xcontent.XContentBuilder;
 import org.elasticsearch.xcontent.XContentFactory;
 import org.elasticsearch.xcontent.XContentParser;
+import org.elasticsearch.xcontent.XContentParserConfiguration;
 import org.elasticsearch.xcontent.XContentType;
 
 import java.io.IOException;
+import java.util.Map;
 import java.util.function.Predicate;
 
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
@@ -42,7 +45,28 @@ public class SearchTemplateResponseTests extends AbstractXContentTestCase<Search
 
     @Override
     protected SearchTemplateResponse doParseInstance(XContentParser parser) throws IOException {
-        return SearchTemplateResponse.fromXContent(parser);
+        SearchTemplateResponse searchTemplateResponse = new SearchTemplateResponse();
+        Map<String, Object> contentAsMap = parser.map();
+
+        if (contentAsMap.containsKey(SearchTemplateResponse.TEMPLATE_OUTPUT_FIELD.getPreferredName())) {
+            Object source = contentAsMap.get(SearchTemplateResponse.TEMPLATE_OUTPUT_FIELD.getPreferredName());
+            XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON).value(source);
+            searchTemplateResponse.setSource(BytesReference.bytes(builder));
+        } else {
+            XContentType contentType = parser.contentType();
+            XContentBuilder builder = XContentFactory.contentBuilder(contentType).map(contentAsMap);
+            try (
+                XContentParser searchResponseParser = XContentHelper.createParserNotCompressed(
+                    XContentParserConfiguration.EMPTY.withRegistry(parser.getXContentRegistry())
+                        .withDeprecationHandler(parser.getDeprecationHandler()),
+                    BytesReference.bytes(builder),
+                    contentType
+                )
+            ) {
+                searchTemplateResponse.setResponse(SearchResponse.fromXContent(searchResponseParser));
+            }
+        }
+        return searchTemplateResponse;
     }
 
     /**

+ 16 - 117
server/src/main/java/org/elasticsearch/action/admin/cluster/health/ClusterHealthResponse.java

@@ -17,132 +17,35 @@ import org.elasticsearch.cluster.health.ClusterStateHealth;
 import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
-import org.elasticsearch.common.util.Maps;
 import org.elasticsearch.core.TimeValue;
 import org.elasticsearch.rest.RestStatus;
-import org.elasticsearch.xcontent.ConstructingObjectParser;
-import org.elasticsearch.xcontent.ObjectParser;
-import org.elasticsearch.xcontent.ParseField;
 import org.elasticsearch.xcontent.ToXContentObject;
 import org.elasticsearch.xcontent.XContentBuilder;
-import org.elasticsearch.xcontent.XContentParser;
 
 import java.io.IOException;
-import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 
-import static java.util.Collections.emptyMap;
-import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
-import static org.elasticsearch.xcontent.ConstructingObjectParser.optionalConstructorArg;
-
 public class ClusterHealthResponse extends ActionResponse implements ToXContentObject {
-    private static final String CLUSTER_NAME = "cluster_name";
-    private static final String STATUS = "status";
-    private static final String TIMED_OUT = "timed_out";
-    private static final String NUMBER_OF_NODES = "number_of_nodes";
-    private static final String NUMBER_OF_DATA_NODES = "number_of_data_nodes";
-    private static final String NUMBER_OF_PENDING_TASKS = "number_of_pending_tasks";
-    private static final String NUMBER_OF_IN_FLIGHT_FETCH = "number_of_in_flight_fetch";
-    private static final String DELAYED_UNASSIGNED_SHARDS = "delayed_unassigned_shards";
+    static final String CLUSTER_NAME = "cluster_name";
+    static final String STATUS = "status";
+    static final String TIMED_OUT = "timed_out";
+    static final String NUMBER_OF_NODES = "number_of_nodes";
+    static final String NUMBER_OF_DATA_NODES = "number_of_data_nodes";
+    static final String NUMBER_OF_PENDING_TASKS = "number_of_pending_tasks";
+    static final String NUMBER_OF_IN_FLIGHT_FETCH = "number_of_in_flight_fetch";
+    static final String DELAYED_UNASSIGNED_SHARDS = "delayed_unassigned_shards";
     private static final String TASK_MAX_WAIT_TIME_IN_QUEUE = "task_max_waiting_in_queue";
-    private static final String TASK_MAX_WAIT_TIME_IN_QUEUE_IN_MILLIS = "task_max_waiting_in_queue_millis";
-    private static final String ACTIVE_SHARDS_PERCENT_AS_NUMBER = "active_shards_percent_as_number";
+    static final String TASK_MAX_WAIT_TIME_IN_QUEUE_IN_MILLIS = "task_max_waiting_in_queue_millis";
+    static final String ACTIVE_SHARDS_PERCENT_AS_NUMBER = "active_shards_percent_as_number";
     private static final String ACTIVE_SHARDS_PERCENT = "active_shards_percent";
-    private static final String ACTIVE_PRIMARY_SHARDS = "active_primary_shards";
-    private static final String ACTIVE_SHARDS = "active_shards";
-    private static final String RELOCATING_SHARDS = "relocating_shards";
-    private static final String INITIALIZING_SHARDS = "initializing_shards";
-    private static final String UNASSIGNED_SHARDS = "unassigned_shards";
-    private static final String INDICES = "indices";
-
-    private static final ConstructingObjectParser<ClusterHealthResponse, Void> PARSER = new ConstructingObjectParser<>(
-        "cluster_health_response",
-        true,
-        parsedObjects -> {
-            int i = 0;
-            // ClusterStateHealth fields
-            int numberOfNodes = (int) parsedObjects[i++];
-            int numberOfDataNodes = (int) parsedObjects[i++];
-            int activeShards = (int) parsedObjects[i++];
-            int relocatingShards = (int) parsedObjects[i++];
-            int activePrimaryShards = (int) parsedObjects[i++];
-            int initializingShards = (int) parsedObjects[i++];
-            int unassignedShards = (int) parsedObjects[i++];
-            double activeShardsPercent = (double) parsedObjects[i++];
-            String statusStr = (String) parsedObjects[i++];
-            ClusterHealthStatus status = ClusterHealthStatus.fromString(statusStr);
-            @SuppressWarnings("unchecked")
-            List<ClusterIndexHealth> indexList = (List<ClusterIndexHealth>) parsedObjects[i++];
-            final Map<String, ClusterIndexHealth> indices;
-            if (indexList == null || indexList.isEmpty()) {
-                indices = emptyMap();
-            } else {
-                indices = Maps.newMapWithExpectedSize(indexList.size());
-                for (ClusterIndexHealth indexHealth : indexList) {
-                    indices.put(indexHealth.getIndex(), indexHealth);
-                }
-            }
-            ClusterStateHealth stateHealth = new ClusterStateHealth(
-                activePrimaryShards,
-                activeShards,
-                relocatingShards,
-                initializingShards,
-                unassignedShards,
-                numberOfNodes,
-                numberOfDataNodes,
-                activeShardsPercent,
-                status,
-                indices
-            );
-
-            // ClusterHealthResponse fields
-            String clusterName = (String) parsedObjects[i++];
-            int numberOfPendingTasks = (int) parsedObjects[i++];
-            int numberOfInFlightFetch = (int) parsedObjects[i++];
-            int delayedUnassignedShards = (int) parsedObjects[i++];
-            long taskMaxWaitingTimeMillis = (long) parsedObjects[i++];
-            boolean timedOut = (boolean) parsedObjects[i];
-            return new ClusterHealthResponse(
-                clusterName,
-                numberOfPendingTasks,
-                numberOfInFlightFetch,
-                delayedUnassignedShards,
-                TimeValue.timeValueMillis(taskMaxWaitingTimeMillis),
-                timedOut,
-                stateHealth
-            );
-        }
-    );
-
-    private static final ObjectParser.NamedObjectParser<ClusterIndexHealth, Void> INDEX_PARSER = (
-        XContentParser parser,
-        Void context,
-        String index) -> ClusterIndexHealth.innerFromXContent(parser, index);
-
-    static {
-        // ClusterStateHealth fields
-        PARSER.declareInt(constructorArg(), new ParseField(NUMBER_OF_NODES));
-        PARSER.declareInt(constructorArg(), new ParseField(NUMBER_OF_DATA_NODES));
-        PARSER.declareInt(constructorArg(), new ParseField(ACTIVE_SHARDS));
-        PARSER.declareInt(constructorArg(), new ParseField(RELOCATING_SHARDS));
-        PARSER.declareInt(constructorArg(), new ParseField(ACTIVE_PRIMARY_SHARDS));
-        PARSER.declareInt(constructorArg(), new ParseField(INITIALIZING_SHARDS));
-        PARSER.declareInt(constructorArg(), new ParseField(UNASSIGNED_SHARDS));
-        PARSER.declareDouble(constructorArg(), new ParseField(ACTIVE_SHARDS_PERCENT_AS_NUMBER));
-        PARSER.declareString(constructorArg(), new ParseField(STATUS));
-        // Can be absent if LEVEL == 'cluster'
-        PARSER.declareNamedObjects(optionalConstructorArg(), INDEX_PARSER, new ParseField(INDICES));
-
-        // ClusterHealthResponse fields
-        PARSER.declareString(constructorArg(), new ParseField(CLUSTER_NAME));
-        PARSER.declareInt(constructorArg(), new ParseField(NUMBER_OF_PENDING_TASKS));
-        PARSER.declareInt(constructorArg(), new ParseField(NUMBER_OF_IN_FLIGHT_FETCH));
-        PARSER.declareInt(constructorArg(), new ParseField(DELAYED_UNASSIGNED_SHARDS));
-        PARSER.declareLong(constructorArg(), new ParseField(TASK_MAX_WAIT_TIME_IN_QUEUE_IN_MILLIS));
-        PARSER.declareBoolean(constructorArg(), new ParseField(TIMED_OUT));
-    }
+    static final String ACTIVE_PRIMARY_SHARDS = "active_primary_shards";
+    static final String ACTIVE_SHARDS = "active_shards";
+    static final String RELOCATING_SHARDS = "relocating_shards";
+    static final String INITIALIZING_SHARDS = "initializing_shards";
+    static final String UNASSIGNED_SHARDS = "unassigned_shards";
+    static final String INDICES = "indices";
 
     private String clusterName;
     private int numberOfPendingTasks = 0;
@@ -370,10 +273,6 @@ public class ClusterHealthResponse extends ActionResponse implements ToXContentO
         return builder;
     }
 
-    public static ClusterHealthResponse fromXContent(XContentParser parser) {
-        return PARSER.apply(parser, null);
-    }
-
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;

+ 0 - 58
server/src/main/java/org/elasticsearch/action/admin/indices/settings/get/GetSettingsResponse.java

@@ -15,15 +15,12 @@ import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.xcontent.ChunkedToXContentObject;
-import org.elasticsearch.common.xcontent.XContentParserUtils;
 import org.elasticsearch.xcontent.ToXContent;
 import org.elasticsearch.xcontent.XContentBuilder;
-import org.elasticsearch.xcontent.XContentParser;
 import org.elasticsearch.xcontent.json.JsonXContent;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Objects;
@@ -91,61 +88,6 @@ public class GetSettingsResponse extends ActionResponse implements ChunkedToXCon
         out.writeMap(indexToDefaultSettings, StreamOutput::writeWriteable);
     }
 
-    private static void parseSettingsField(
-        XContentParser parser,
-        String currentIndexName,
-        Map<String, Settings> indexToSettings,
-        Map<String, Settings> indexToDefaultSettings
-    ) throws IOException {
-
-        if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
-            switch (parser.currentName()) {
-                case "settings" -> indexToSettings.put(currentIndexName, Settings.fromXContent(parser));
-                case "defaults" -> indexToDefaultSettings.put(currentIndexName, Settings.fromXContent(parser));
-                default -> parser.skipChildren();
-            }
-        } else if (parser.currentToken() == XContentParser.Token.START_ARRAY) {
-            parser.skipChildren();
-        }
-        parser.nextToken();
-    }
-
-    private static void parseIndexEntry(
-        XContentParser parser,
-        Map<String, Settings> indexToSettings,
-        Map<String, Settings> indexToDefaultSettings
-    ) throws IOException {
-        String indexName = parser.currentName();
-        parser.nextToken();
-        while (parser.isClosed() == false && parser.currentToken() != XContentParser.Token.END_OBJECT) {
-            parseSettingsField(parser, indexName, indexToSettings, indexToDefaultSettings);
-        }
-    }
-
-    public static GetSettingsResponse fromXContent(XContentParser parser) throws IOException {
-        HashMap<String, Settings> indexToSettings = new HashMap<>();
-        HashMap<String, Settings> indexToDefaultSettings = new HashMap<>();
-
-        if (parser.currentToken() == null) {
-            parser.nextToken();
-        }
-        XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser);
-        parser.nextToken();
-
-        while (parser.isClosed() == false) {
-            if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
-                // we must assume this is an index entry
-                parseIndexEntry(parser, indexToSettings, indexToDefaultSettings);
-            } else if (parser.currentToken() == XContentParser.Token.START_ARRAY) {
-                parser.skipChildren();
-            } else {
-                parser.nextToken();
-            }
-        }
-
-        return new GetSettingsResponse(Map.copyOf(indexToSettings), Map.copyOf(indexToDefaultSettings));
-    }
-
     @Override
     public String toString() {
         try {

+ 2 - 97
server/src/main/java/org/elasticsearch/action/bulk/BulkItemResponse.java

@@ -21,26 +21,17 @@ import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.common.io.stream.Writeable;
-import org.elasticsearch.core.CheckedConsumer;
 import org.elasticsearch.core.RestApiVersion;
 import org.elasticsearch.index.mapper.MapperService;
 import org.elasticsearch.index.seqno.SequenceNumbers;
 import org.elasticsearch.index.shard.ShardId;
 import org.elasticsearch.rest.RestStatus;
-import org.elasticsearch.xcontent.ConstructingObjectParser;
-import org.elasticsearch.xcontent.ParseField;
 import org.elasticsearch.xcontent.ToXContentFragment;
 import org.elasticsearch.xcontent.ToXContentObject;
 import org.elasticsearch.xcontent.XContentBuilder;
-import org.elasticsearch.xcontent.XContentParser;
 
 import java.io.IOException;
 
-import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
-import static org.elasticsearch.common.xcontent.XContentParserUtils.throwUnknownField;
-import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
-import static org.elasticsearch.xcontent.ConstructingObjectParser.optionalConstructorArg;
-
 /**
  * Represents a single item response for an action executed as part of the bulk API. Holds the index/type/id
  * of the relevant action, and if it has failed or not (with the failure message in case it failed).
@@ -49,8 +40,8 @@ public class BulkItemResponse implements Writeable, ToXContentObject {
 
     private static final String _INDEX = "_index";
     private static final String _ID = "_id";
-    private static final String STATUS = "status";
-    private static final String ERROR = "error";
+    static final String STATUS = "status";
+    static final String ERROR = "error";
 
     public RestStatus status() {
         return failure == null ? response.status() : failure.getStatus();
@@ -80,80 +71,6 @@ public class BulkItemResponse implements Writeable, ToXContentObject {
         return builder;
     }
 
-    /**
-     * Reads a {@link BulkItemResponse} from a {@link XContentParser}.
-     *
-     * @param parser the {@link XContentParser}
-     * @param id the id to assign to the parsed {@link BulkItemResponse}. It is usually the index of
-     *           the item in the {@link BulkResponse#getItems} array.
-     */
-    public static BulkItemResponse fromXContent(XContentParser parser, int id) throws IOException {
-        ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser);
-
-        XContentParser.Token token = parser.nextToken();
-        ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser);
-
-        String currentFieldName = parser.currentName();
-        token = parser.nextToken();
-
-        final OpType opType = OpType.fromString(currentFieldName);
-        ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser);
-
-        DocWriteResponse.Builder builder = null;
-        CheckedConsumer<XContentParser, IOException> itemParser = null;
-
-        if (opType == OpType.INDEX || opType == OpType.CREATE) {
-            final IndexResponse.Builder indexResponseBuilder = new IndexResponse.Builder();
-            builder = indexResponseBuilder;
-            itemParser = (indexParser) -> IndexResponse.parseXContentFields(indexParser, indexResponseBuilder);
-
-        } else if (opType == OpType.UPDATE) {
-            final UpdateResponse.Builder updateResponseBuilder = new UpdateResponse.Builder();
-            builder = updateResponseBuilder;
-            itemParser = (updateParser) -> UpdateResponse.parseXContentFields(updateParser, updateResponseBuilder);
-
-        } else if (opType == OpType.DELETE) {
-            final DeleteResponse.Builder deleteResponseBuilder = new DeleteResponse.Builder();
-            builder = deleteResponseBuilder;
-            itemParser = (deleteParser) -> DeleteResponse.parseXContentFields(deleteParser, deleteResponseBuilder);
-        } else {
-            throwUnknownField(currentFieldName, parser);
-        }
-
-        RestStatus status = null;
-        ElasticsearchException exception = null;
-        while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
-            if (token == XContentParser.Token.FIELD_NAME) {
-                currentFieldName = parser.currentName();
-            }
-
-            if (ERROR.equals(currentFieldName)) {
-                if (token == XContentParser.Token.START_OBJECT) {
-                    exception = ElasticsearchException.fromXContent(parser);
-                }
-            } else if (STATUS.equals(currentFieldName)) {
-                if (token == XContentParser.Token.VALUE_NUMBER) {
-                    status = RestStatus.fromCode(parser.intValue());
-                }
-            } else {
-                itemParser.accept(parser);
-            }
-        }
-
-        ensureExpectedToken(XContentParser.Token.END_OBJECT, token, parser);
-        token = parser.nextToken();
-        ensureExpectedToken(XContentParser.Token.END_OBJECT, token, parser);
-
-        BulkItemResponse bulkItemResponse;
-        if (exception != null) {
-            Failure failure = new Failure(builder.getShardId().getIndexName(), builder.getId(), exception, status);
-            bulkItemResponse = BulkItemResponse.failure(id, opType, failure);
-        } else {
-            bulkItemResponse = BulkItemResponse.success(id, opType, builder.build());
-        }
-        return bulkItemResponse;
-    }
-
     /**
      * Represents a failure.
      */
@@ -171,18 +88,6 @@ public class BulkItemResponse implements Writeable, ToXContentObject {
         private final long term;
         private final boolean aborted;
 
-        public static final ConstructingObjectParser<Failure, Void> PARSER = new ConstructingObjectParser<>(
-            "bulk_failures",
-            true,
-            a -> new Failure((String) a[0], (String) a[1], (Exception) a[2], RestStatus.fromCode((int) a[3]))
-        );
-        static {
-            PARSER.declareString(constructorArg(), new ParseField(INDEX_FIELD));
-            PARSER.declareString(optionalConstructorArg(), new ParseField(ID_FIELD));
-            PARSER.declareObject(constructorArg(), (p, c) -> ElasticsearchException.fromXContent(p), new ParseField(CAUSE_FIELD));
-            PARSER.declareInt(constructorArg(), new ParseField(STATUS_FIELD));
-        }
-
         /**
          * For write failures before operation was assigned a sequence number.
          *

+ 4 - 46
server/src/main/java/org/elasticsearch/action/bulk/BulkResponse.java

@@ -15,16 +15,9 @@ import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.common.xcontent.ChunkedToXContentObject;
 import org.elasticsearch.core.TimeValue;
 import org.elasticsearch.xcontent.ToXContent;
-import org.elasticsearch.xcontent.XContentParser;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Iterator;
-import java.util.List;
-
-import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
-import static org.elasticsearch.common.xcontent.XContentParserUtils.throwUnknownField;
-import static org.elasticsearch.common.xcontent.XContentParserUtils.throwUnknownToken;
 
 /**
  * A response of a bulk execution. Holding a response for each item responding (in order) of the
@@ -33,10 +26,10 @@ import static org.elasticsearch.common.xcontent.XContentParserUtils.throwUnknown
  */
 public class BulkResponse extends ActionResponse implements Iterable<BulkItemResponse>, ChunkedToXContentObject {
 
-    private static final String ITEMS = "items";
-    private static final String ERRORS = "errors";
-    private static final String TOOK = "took";
-    private static final String INGEST_TOOK = "ingest_took";
+    static final String ITEMS = "items";
+    static final String ERRORS = "errors";
+    static final String TOOK = "took";
+    static final String INGEST_TOOK = "ingest_took";
 
     public static final long NO_INGEST_TOOK = -1L;
 
@@ -133,41 +126,6 @@ public class BulkResponse extends ActionResponse implements Iterable<BulkItemRes
         out.writeZLong(ingestTookInMillis);
     }
 
-    public static BulkResponse fromXContent(XContentParser parser) throws IOException {
-        XContentParser.Token token = parser.nextToken();
-        ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser);
-
-        long took = -1L;
-        long ingestTook = NO_INGEST_TOOK;
-        List<BulkItemResponse> items = new ArrayList<>();
-
-        String currentFieldName = parser.currentName();
-        while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
-            if (token == XContentParser.Token.FIELD_NAME) {
-                currentFieldName = parser.currentName();
-            } else if (token.isValue()) {
-                if (TOOK.equals(currentFieldName)) {
-                    took = parser.longValue();
-                } else if (INGEST_TOOK.equals(currentFieldName)) {
-                    ingestTook = parser.longValue();
-                } else if (ERRORS.equals(currentFieldName) == false) {
-                    throwUnknownField(currentFieldName, parser);
-                }
-            } else if (token == XContentParser.Token.START_ARRAY) {
-                if (ITEMS.equals(currentFieldName)) {
-                    while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
-                        items.add(BulkItemResponse.fromXContent(parser, items.size()));
-                    }
-                } else {
-                    throwUnknownField(currentFieldName, parser);
-                }
-            } else {
-                throwUnknownToken(token, parser);
-            }
-        }
-        return new BulkResponse(items.toArray(new BulkItemResponse[items.size()]), took, ingestTook);
-    }
-
     @Override
     public Iterator<? extends ToXContent> toXContentChunked(ToXContent.Params params) {
         return Iterators.concat(Iterators.single((builder, p) -> {

+ 0 - 34
server/src/main/java/org/elasticsearch/action/get/GetResponse.java

@@ -10,7 +10,6 @@ package org.elasticsearch.action.get;
 
 import org.elasticsearch.ElasticsearchParseException;
 import org.elasticsearch.action.ActionResponse;
-import org.elasticsearch.common.ParsingException;
 import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.bytes.BytesReference;
 import org.elasticsearch.common.document.DocumentField;
@@ -19,11 +18,9 @@ import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.index.get.GetResult;
 import org.elasticsearch.xcontent.ToXContentObject;
 import org.elasticsearch.xcontent.XContentBuilder;
-import org.elasticsearch.xcontent.XContentParser;
 
 import java.io.IOException;
 import java.util.Iterator;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 
@@ -149,37 +146,6 @@ public class GetResponse extends ActionResponse implements Iterable<DocumentFiel
         return getResult.toXContent(builder, params);
     }
 
-    /**
-     * This method can be used to parse a {@link GetResponse} object when it has been printed out
-     * as a xcontent using the {@link #toXContent(XContentBuilder, Params)} method.
-     * <p>
-     * For forward compatibility reason this method might not fail if it tries to parse a field it
-     * doesn't know. But before returning the result it will check that enough information were
-     * parsed to return a valid {@link GetResponse} instance and throws a {@link ParsingException}
-     * otherwise. This is the case when we get a 404 back, which can be parsed as a normal
-     * {@link GetResponse} with found set to false, or as an elasticsearch exception. The caller
-     * of this method needs a way to figure out whether we got back a valid get response, which
-     * can be done by catching ParsingException.
-     *
-     * @param parser {@link XContentParser} to parse the response from
-     * @return a {@link GetResponse}
-     * @throws IOException is an I/O exception occurs during the parsing
-     */
-    public static GetResponse fromXContent(XContentParser parser) throws IOException {
-        GetResult getResult = GetResult.fromXContent(parser);
-
-        // At this stage we ensure that we parsed enough information to return
-        // a valid GetResponse instance. If it's not the case, we throw an
-        // exception so that callers know it and can handle it correctly.
-        if (getResult.getIndex() == null && getResult.getId() == null) {
-            throw new ParsingException(
-                parser.getTokenLocation(),
-                String.format(Locale.ROOT, "Missing required fields [%s,%s]", GetResult._INDEX, GetResult._ID)
-            );
-        }
-        return new GetResponse(getResult);
-    }
-
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         getResult.writeTo(out);

+ 0 - 31
server/src/main/java/org/elasticsearch/action/ingest/GetPipelineResponse.java

@@ -10,15 +10,12 @@ package org.elasticsearch.action.ingest;
 
 import org.elasticsearch.action.ActionResponse;
 import org.elasticsearch.common.Strings;
-import org.elasticsearch.common.bytes.BytesReference;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.ingest.PipelineConfiguration;
 import org.elasticsearch.rest.RestStatus;
 import org.elasticsearch.xcontent.ToXContentObject;
 import org.elasticsearch.xcontent.XContentBuilder;
-import org.elasticsearch.xcontent.XContentParser;
-import org.elasticsearch.xcontent.XContentParser.Token;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -27,8 +24,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
-
 public class GetPipelineResponse extends ActionResponse implements ToXContentObject {
 
     private final List<PipelineConfiguration> pipelines;
@@ -90,32 +85,6 @@ public class GetPipelineResponse extends ActionResponse implements ToXContentObj
         return builder;
     }
 
-    /**
-     *
-     * @param parser the parser for the XContent that contains the serialized GetPipelineResponse.
-     * @return an instance of GetPipelineResponse read from the parser
-     * @throws IOException If the parsing fails
-     */
-    public static GetPipelineResponse fromXContent(XContentParser parser) throws IOException {
-        ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser);
-        List<PipelineConfiguration> pipelines = new ArrayList<>();
-        while (parser.nextToken().equals(Token.FIELD_NAME)) {
-            String pipelineId = parser.currentName();
-            parser.nextToken();
-            try (XContentBuilder contentBuilder = XContentBuilder.builder(parser.contentType().xContent())) {
-                contentBuilder.generator().copyCurrentStructure(parser);
-                PipelineConfiguration pipeline = new PipelineConfiguration(
-                    pipelineId,
-                    BytesReference.bytes(contentBuilder),
-                    contentBuilder.contentType()
-                );
-                pipelines.add(pipeline);
-            }
-        }
-        ensureExpectedToken(XContentParser.Token.END_OBJECT, parser.currentToken(), parser);
-        return new GetPipelineResponse(pipelines);
-    }
-
     @Override
     public boolean equals(Object other) {
         if (other == null) {

+ 0 - 19
server/src/main/java/org/elasticsearch/action/ingest/SimulateDocumentVerboseResult.java

@@ -9,17 +9,12 @@ package org.elasticsearch.action.ingest;
 
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
-import org.elasticsearch.xcontent.ConstructingObjectParser;
-import org.elasticsearch.xcontent.ParseField;
 import org.elasticsearch.xcontent.XContentBuilder;
-import org.elasticsearch.xcontent.XContentParser;
 
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
-import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
-
 /**
  * Holds the result of what a pipeline did to a sample document via the simulate api, but instead of {@link SimulateDocumentBaseResult}
  * this result class holds the intermediate result each processor did to the sample document.
@@ -28,16 +23,6 @@ public final class SimulateDocumentVerboseResult implements SimulateDocumentResu
     public static final String PROCESSOR_RESULT_FIELD = "processor_results";
     private final List<SimulateProcessorResult> processorResults;
 
-    @SuppressWarnings("unchecked")
-    public static final ConstructingObjectParser<SimulateDocumentVerboseResult, Void> PARSER = new ConstructingObjectParser<>(
-        "simulate_document_verbose_result",
-        true,
-        a -> new SimulateDocumentVerboseResult((List<SimulateProcessorResult>) a[0])
-    );
-    static {
-        PARSER.declareObjectArray(constructorArg(), SimulateProcessorResult.PARSER, new ParseField(PROCESSOR_RESULT_FIELD));
-    }
-
     public SimulateDocumentVerboseResult(List<SimulateProcessorResult> processorResults) {
         this.processorResults = processorResults;
     }
@@ -73,8 +58,4 @@ public final class SimulateDocumentVerboseResult implements SimulateDocumentResu
         builder.endObject();
         return builder;
     }
-
-    public static SimulateDocumentVerboseResult fromXContent(XContentParser parser) {
-        return PARSER.apply(parser, null);
-    }
 }

+ 2 - 23
server/src/main/java/org/elasticsearch/action/search/ClearScrollResponse.java

@@ -12,33 +12,19 @@ import org.elasticsearch.action.ActionResponse;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.rest.RestStatus;
-import org.elasticsearch.xcontent.ConstructingObjectParser;
-import org.elasticsearch.xcontent.ObjectParser;
 import org.elasticsearch.xcontent.ParseField;
 import org.elasticsearch.xcontent.ToXContentObject;
 import org.elasticsearch.xcontent.XContentBuilder;
-import org.elasticsearch.xcontent.XContentParser;
 
 import java.io.IOException;
 
 import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
 import static org.elasticsearch.rest.RestStatus.OK;
-import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
 
 public class ClearScrollResponse extends ActionResponse implements ToXContentObject {
 
-    private static final ParseField SUCCEEDED = new ParseField("succeeded");
-    private static final ParseField NUMFREED = new ParseField("num_freed");
-
-    private static final ConstructingObjectParser<ClosePointInTimeResponse, Void> PARSER = new ConstructingObjectParser<>(
-        "clear_scroll",
-        true,
-        a -> new ClosePointInTimeResponse((boolean) a[0], (int) a[1])
-    );
-    static {
-        PARSER.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), SUCCEEDED, ObjectParser.ValueType.BOOLEAN);
-        PARSER.declareField(constructorArg(), (parser, context) -> parser.intValue(), NUMFREED, ObjectParser.ValueType.INT);
-    }
+    public static final ParseField SUCCEEDED = new ParseField("succeeded");
+    public static final ParseField NUMFREED = new ParseField("num_freed");
 
     private final boolean succeeded;
     private final int numFreed;
@@ -82,13 +68,6 @@ public class ClearScrollResponse extends ActionResponse implements ToXContentObj
         return builder;
     }
 
-    /**
-     * Parse the clear scroll response body into a new {@link ClearScrollResponse} object
-     */
-    public static ClosePointInTimeResponse fromXContent(XContentParser parser) {
-        return PARSER.apply(parser, null);
-    }
-
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeBoolean(succeeded);

+ 96 - 1
server/src/test/java/org/elasticsearch/action/admin/cluster/health/ClusterHealthResponsesTests.java

@@ -23,23 +23,118 @@ import org.elasticsearch.common.util.Maps;
 import org.elasticsearch.core.TimeValue;
 import org.elasticsearch.rest.RestStatus;
 import org.elasticsearch.test.AbstractXContentSerializingTestCase;
+import org.elasticsearch.xcontent.ConstructingObjectParser;
+import org.elasticsearch.xcontent.ObjectParser;
+import org.elasticsearch.xcontent.ParseField;
 import org.elasticsearch.xcontent.ToXContent;
 import org.elasticsearch.xcontent.XContentParser;
 import org.hamcrest.Matchers;
 
 import java.io.IOException;
 import java.util.Collections;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.function.Predicate;
 import java.util.regex.Pattern;
 
+import static java.util.Collections.emptyMap;
+import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
+import static org.elasticsearch.xcontent.ConstructingObjectParser.optionalConstructorArg;
 import static org.hamcrest.CoreMatchers.allOf;
 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.lessThanOrEqualTo;
 
 public class ClusterHealthResponsesTests extends AbstractXContentSerializingTestCase<ClusterHealthResponse> {
+
+    private static final ConstructingObjectParser<ClusterHealthResponse, Void> PARSER = new ConstructingObjectParser<>(
+        "cluster_health_response",
+        true,
+        parsedObjects -> {
+            int i = 0;
+            // ClusterStateHealth fields
+            int numberOfNodes = (int) parsedObjects[i++];
+            int numberOfDataNodes = (int) parsedObjects[i++];
+            int activeShards = (int) parsedObjects[i++];
+            int relocatingShards = (int) parsedObjects[i++];
+            int activePrimaryShards = (int) parsedObjects[i++];
+            int initializingShards = (int) parsedObjects[i++];
+            int unassignedShards = (int) parsedObjects[i++];
+            double activeShardsPercent = (double) parsedObjects[i++];
+            String statusStr = (String) parsedObjects[i++];
+            ClusterHealthStatus status = ClusterHealthStatus.fromString(statusStr);
+            @SuppressWarnings("unchecked")
+            List<ClusterIndexHealth> indexList = (List<ClusterIndexHealth>) parsedObjects[i++];
+            final Map<String, ClusterIndexHealth> indices;
+            if (indexList == null || indexList.isEmpty()) {
+                indices = emptyMap();
+            } else {
+                indices = Maps.newMapWithExpectedSize(indexList.size());
+                for (ClusterIndexHealth indexHealth : indexList) {
+                    indices.put(indexHealth.getIndex(), indexHealth);
+                }
+            }
+            ClusterStateHealth stateHealth = new ClusterStateHealth(
+                activePrimaryShards,
+                activeShards,
+                relocatingShards,
+                initializingShards,
+                unassignedShards,
+                numberOfNodes,
+                numberOfDataNodes,
+                activeShardsPercent,
+                status,
+                indices
+            );
+
+            // ClusterHealthResponse fields
+            String clusterName = (String) parsedObjects[i++];
+            int numberOfPendingTasks = (int) parsedObjects[i++];
+            int numberOfInFlightFetch = (int) parsedObjects[i++];
+            int delayedUnassignedShards = (int) parsedObjects[i++];
+            long taskMaxWaitingTimeMillis = (long) parsedObjects[i++];
+            boolean timedOut = (boolean) parsedObjects[i];
+            return new ClusterHealthResponse(
+                clusterName,
+                numberOfPendingTasks,
+                numberOfInFlightFetch,
+                delayedUnassignedShards,
+                TimeValue.timeValueMillis(taskMaxWaitingTimeMillis),
+                timedOut,
+                stateHealth
+            );
+        }
+    );
+
+    private static final ObjectParser.NamedObjectParser<ClusterIndexHealth, Void> INDEX_PARSER = (
+        XContentParser parser,
+        Void context,
+        String index) -> ClusterIndexHealth.innerFromXContent(parser, index);
+
+    static {
+        // ClusterStateHealth fields
+        PARSER.declareInt(constructorArg(), new ParseField(ClusterHealthResponse.NUMBER_OF_NODES));
+        PARSER.declareInt(constructorArg(), new ParseField(ClusterHealthResponse.NUMBER_OF_DATA_NODES));
+        PARSER.declareInt(constructorArg(), new ParseField(ClusterHealthResponse.ACTIVE_SHARDS));
+        PARSER.declareInt(constructorArg(), new ParseField(ClusterHealthResponse.RELOCATING_SHARDS));
+        PARSER.declareInt(constructorArg(), new ParseField(ClusterHealthResponse.ACTIVE_PRIMARY_SHARDS));
+        PARSER.declareInt(constructorArg(), new ParseField(ClusterHealthResponse.INITIALIZING_SHARDS));
+        PARSER.declareInt(constructorArg(), new ParseField(ClusterHealthResponse.UNASSIGNED_SHARDS));
+        PARSER.declareDouble(constructorArg(), new ParseField(ClusterHealthResponse.ACTIVE_SHARDS_PERCENT_AS_NUMBER));
+        PARSER.declareString(constructorArg(), new ParseField(ClusterHealthResponse.STATUS));
+        // Can be absent if LEVEL == 'cluster'
+        PARSER.declareNamedObjects(optionalConstructorArg(), INDEX_PARSER, new ParseField(ClusterHealthResponse.INDICES));
+
+        // ClusterHealthResponse fields
+        PARSER.declareString(constructorArg(), new ParseField(ClusterHealthResponse.CLUSTER_NAME));
+        PARSER.declareInt(constructorArg(), new ParseField(ClusterHealthResponse.NUMBER_OF_PENDING_TASKS));
+        PARSER.declareInt(constructorArg(), new ParseField(ClusterHealthResponse.NUMBER_OF_IN_FLIGHT_FETCH));
+        PARSER.declareInt(constructorArg(), new ParseField(ClusterHealthResponse.DELAYED_UNASSIGNED_SHARDS));
+        PARSER.declareLong(constructorArg(), new ParseField(ClusterHealthResponse.TASK_MAX_WAIT_TIME_IN_QUEUE_IN_MILLIS));
+        PARSER.declareBoolean(constructorArg(), new ParseField(ClusterHealthResponse.TIMED_OUT));
+    }
+
     private final ClusterStatsLevel level = randomFrom(ClusterStatsLevel.values());
 
     public void testIsTimeout() {
@@ -102,7 +197,7 @@ public class ClusterHealthResponsesTests extends AbstractXContentSerializingTest
 
     @Override
     protected ClusterHealthResponse doParseInstance(XContentParser parser) {
-        return ClusterHealthResponse.fromXContent(parser);
+        return PARSER.apply(parser, null);
     }
 
     @Override

+ 54 - 1
server/src/test/java/org/elasticsearch/action/admin/indices/settings/get/GetSettingsResponseTests.java

@@ -11,6 +11,7 @@ package org.elasticsearch.action.admin.indices.settings.get;
 import org.elasticsearch.common.io.stream.Writeable;
 import org.elasticsearch.common.settings.IndexScopedSettings;
 import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.xcontent.XContentParserUtils;
 import org.elasticsearch.index.RandomCreateIndexGenerator;
 import org.elasticsearch.test.AbstractChunkedSerializingTestCase;
 import org.elasticsearch.xcontent.XContentParser;
@@ -18,6 +19,7 @@ import org.elasticsearch.xcontent.XContentParser;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 import java.util.function.Predicate;
 
@@ -70,7 +72,58 @@ public class GetSettingsResponseTests extends AbstractChunkedSerializingTestCase
 
     @Override
     protected GetSettingsResponse doParseInstance(XContentParser parser) throws IOException {
-        return GetSettingsResponse.fromXContent(parser);
+        HashMap<String, Settings> indexToSettings = new HashMap<>();
+        HashMap<String, Settings> indexToDefaultSettings = new HashMap<>();
+
+        if (parser.currentToken() == null) {
+            parser.nextToken();
+        }
+        XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser);
+        parser.nextToken();
+
+        while (parser.isClosed() == false) {
+            if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
+                // we must assume this is an index entry
+                parseIndexEntry(parser, indexToSettings, indexToDefaultSettings);
+            } else if (parser.currentToken() == XContentParser.Token.START_ARRAY) {
+                parser.skipChildren();
+            } else {
+                parser.nextToken();
+            }
+        }
+
+        return new GetSettingsResponse(Map.copyOf(indexToSettings), Map.copyOf(indexToDefaultSettings));
+    }
+
+    private static void parseIndexEntry(
+        XContentParser parser,
+        Map<String, Settings> indexToSettings,
+        Map<String, Settings> indexToDefaultSettings
+    ) throws IOException {
+        String indexName = parser.currentName();
+        parser.nextToken();
+        while (parser.isClosed() == false && parser.currentToken() != XContentParser.Token.END_OBJECT) {
+            parseSettingsField(parser, indexName, indexToSettings, indexToDefaultSettings);
+        }
+    }
+
+    private static void parseSettingsField(
+        XContentParser parser,
+        String currentIndexName,
+        Map<String, Settings> indexToSettings,
+        Map<String, Settings> indexToDefaultSettings
+    ) throws IOException {
+
+        if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
+            switch (parser.currentName()) {
+                case "settings" -> indexToSettings.put(currentIndexName, Settings.fromXContent(parser));
+                case "defaults" -> indexToDefaultSettings.put(currentIndexName, Settings.fromXContent(parser));
+                default -> parser.skipChildren();
+            }
+        } else if (parser.currentToken() == XContentParser.Token.START_ARRAY) {
+            parser.skipChildren();
+        }
+        parser.nextToken();
     }
 
     @Override

+ 81 - 2
server/src/test/java/org/elasticsearch/action/bulk/BulkItemResponseTests.java

@@ -13,15 +13,18 @@ import org.elasticsearch.ExceptionsHelper;
 import org.elasticsearch.action.DocWriteRequest;
 import org.elasticsearch.action.DocWriteResponse;
 import org.elasticsearch.action.bulk.BulkItemResponse.Failure;
+import org.elasticsearch.action.delete.DeleteResponse;
 import org.elasticsearch.action.delete.DeleteResponseTests;
 import org.elasticsearch.action.index.IndexResponse;
 import org.elasticsearch.action.index.IndexResponseTests;
 import org.elasticsearch.action.update.UpdateResponse;
 import org.elasticsearch.action.update.UpdateResponseTests;
 import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.core.CheckedConsumer;
 import org.elasticsearch.core.RestApiVersion;
 import org.elasticsearch.core.Tuple;
 import org.elasticsearch.index.shard.ShardId;
+import org.elasticsearch.rest.RestStatus;
 import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.xcontent.ToXContent;
 import org.elasticsearch.xcontent.XContentBuilder;
@@ -34,6 +37,8 @@ import java.util.UUID;
 
 import static org.elasticsearch.ElasticsearchExceptionTests.assertDeepEquals;
 import static org.elasticsearch.ElasticsearchExceptionTests.randomExceptions;
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
+import static org.elasticsearch.common.xcontent.XContentParserUtils.throwUnknownField;
 import static org.hamcrest.Matchers.containsString;
 
 public class BulkItemResponseTests extends ESTestCase {
@@ -93,7 +98,7 @@ public class BulkItemResponseTests extends ESTestCase {
             BulkItemResponse parsedBulkItemResponse;
             try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
                 assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
-                parsedBulkItemResponse = BulkItemResponse.fromXContent(parser, bulkItemId);
+                parsedBulkItemResponse = itemResponseFromXContent(parser, bulkItemId);
                 assertNull(parser.nextToken());
             }
             assertBulkItemResponse(expectedBulkItemResponse, parsedBulkItemResponse);
@@ -127,7 +132,7 @@ public class BulkItemResponseTests extends ESTestCase {
         BulkItemResponse parsedBulkItemResponse;
         try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
             assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
-            parsedBulkItemResponse = BulkItemResponse.fromXContent(parser, itemId);
+            parsedBulkItemResponse = itemResponseFromXContent(parser, itemId);
             assertNull(parser.nextToken());
         }
         assertBulkItemResponse(expectedBulkItemResponse, parsedBulkItemResponse);
@@ -161,4 +166,78 @@ public class BulkItemResponseTests extends ESTestCase {
             }
         }
     }
+
+    /**
+     * Reads a {@link BulkItemResponse} from a {@link XContentParser}.
+     *
+     * @param parser the {@link XContentParser}
+     * @param id the id to assign to the parsed {@link BulkItemResponse}. It is usually the index of
+     *           the item in the {@link BulkResponse#getItems} array.
+     */
+    public static BulkItemResponse itemResponseFromXContent(XContentParser parser, int id) throws IOException {
+        ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser);
+
+        XContentParser.Token token = parser.nextToken();
+        ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser);
+
+        String currentFieldName = parser.currentName();
+        token = parser.nextToken();
+
+        final DocWriteRequest.OpType opType = DocWriteRequest.OpType.fromString(currentFieldName);
+        ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser);
+
+        DocWriteResponse.Builder builder = null;
+        CheckedConsumer<XContentParser, IOException> itemParser = null;
+
+        if (opType == DocWriteRequest.OpType.INDEX || opType == DocWriteRequest.OpType.CREATE) {
+            final IndexResponse.Builder indexResponseBuilder = new IndexResponse.Builder();
+            builder = indexResponseBuilder;
+            itemParser = (indexParser) -> IndexResponse.parseXContentFields(indexParser, indexResponseBuilder);
+
+        } else if (opType == DocWriteRequest.OpType.UPDATE) {
+            final UpdateResponse.Builder updateResponseBuilder = new UpdateResponse.Builder();
+            builder = updateResponseBuilder;
+            itemParser = (updateParser) -> UpdateResponse.parseXContentFields(updateParser, updateResponseBuilder);
+
+        } else if (opType == DocWriteRequest.OpType.DELETE) {
+            final DeleteResponse.Builder deleteResponseBuilder = new DeleteResponse.Builder();
+            builder = deleteResponseBuilder;
+            itemParser = (deleteParser) -> DeleteResponse.parseXContentFields(deleteParser, deleteResponseBuilder);
+        } else {
+            throwUnknownField(currentFieldName, parser);
+        }
+
+        RestStatus status = null;
+        ElasticsearchException exception = null;
+        while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
+            if (token == XContentParser.Token.FIELD_NAME) {
+                currentFieldName = parser.currentName();
+            }
+
+            if (BulkItemResponse.ERROR.equals(currentFieldName)) {
+                if (token == XContentParser.Token.START_OBJECT) {
+                    exception = ElasticsearchException.fromXContent(parser);
+                }
+            } else if (BulkItemResponse.STATUS.equals(currentFieldName)) {
+                if (token == XContentParser.Token.VALUE_NUMBER) {
+                    status = RestStatus.fromCode(parser.intValue());
+                }
+            } else {
+                itemParser.accept(parser);
+            }
+        }
+
+        ensureExpectedToken(XContentParser.Token.END_OBJECT, token, parser);
+        token = parser.nextToken();
+        ensureExpectedToken(XContentParser.Token.END_OBJECT, token, parser);
+
+        BulkItemResponse bulkItemResponse;
+        if (exception != null) {
+            Failure failure = new Failure(builder.getShardId().getIndexName(), builder.getId(), exception, status);
+            bulkItemResponse = BulkItemResponse.failure(id, opType, failure);
+        } else {
+            bulkItemResponse = BulkItemResponse.success(id, opType, builder.build());
+        }
+        return bulkItemResponse;
+    }
 }

+ 41 - 1
server/src/test/java/org/elasticsearch/action/bulk/BulkResponseTests.java

@@ -24,11 +24,16 @@ import org.elasticsearch.xcontent.XContentParser;
 import org.elasticsearch.xcontent.XContentType;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 import static org.elasticsearch.ElasticsearchExceptionTests.randomExceptions;
 import static org.elasticsearch.action.bulk.BulkItemResponseTests.assertBulkItemResponse;
 import static org.elasticsearch.action.bulk.BulkResponse.NO_INGEST_TOOK;
 import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
+import static org.elasticsearch.common.xcontent.XContentParserUtils.throwUnknownField;
+import static org.elasticsearch.common.xcontent.XContentParserUtils.throwUnknownToken;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
 import static org.hamcrest.Matchers.equalTo;
 
@@ -78,7 +83,7 @@ public class BulkResponseTests extends ESTestCase {
 
         BulkResponse parsedBulkResponse;
         try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
-            parsedBulkResponse = BulkResponse.fromXContent(parser);
+            parsedBulkResponse = fromXContent(parser);
             assertNull(parser.nextToken());
         }
 
@@ -154,4 +159,39 @@ public class BulkResponseTests extends ESTestCase {
         }
         return randomDocWriteResponses;
     }
+
+    private static BulkResponse fromXContent(XContentParser parser) throws IOException {
+        XContentParser.Token token = parser.nextToken();
+        ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser);
+
+        long took = -1L;
+        long ingestTook = NO_INGEST_TOOK;
+        List<BulkItemResponse> items = new ArrayList<>();
+
+        String currentFieldName = parser.currentName();
+        while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
+            if (token == XContentParser.Token.FIELD_NAME) {
+                currentFieldName = parser.currentName();
+            } else if (token.isValue()) {
+                if (BulkResponse.TOOK.equals(currentFieldName)) {
+                    took = parser.longValue();
+                } else if (BulkResponse.INGEST_TOOK.equals(currentFieldName)) {
+                    ingestTook = parser.longValue();
+                } else if (BulkResponse.ERRORS.equals(currentFieldName) == false) {
+                    throwUnknownField(currentFieldName, parser);
+                }
+            } else if (token == XContentParser.Token.START_ARRAY) {
+                if (BulkResponse.ITEMS.equals(currentFieldName)) {
+                    while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
+                        items.add(BulkItemResponseTests.itemResponseFromXContent(parser, items.size()));
+                    }
+                } else {
+                    throwUnknownField(currentFieldName, parser);
+                }
+            } else {
+                throwUnknownToken(token, parser);
+            }
+        }
+        return new BulkResponse(items.toArray(new BulkItemResponse[items.size()]), took, ingestTook);
+    }
 }

+ 18 - 2
server/src/test/java/org/elasticsearch/action/get/GetResponseTests.java

@@ -23,6 +23,7 @@ import org.elasticsearch.xcontent.XContentType;
 
 import java.io.IOException;
 import java.util.Collections;
+import java.util.Locale;
 import java.util.function.Predicate;
 
 import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
@@ -69,7 +70,7 @@ public class GetResponseTests extends ESTestCase {
         }
         GetResponse parsedGetResponse;
         try (XContentParser parser = createParser(xContentType.xContent(), mutated)) {
-            parsedGetResponse = GetResponse.fromXContent(parser);
+            parsedGetResponse = parseInstance(parser);
             assertNull(parser.nextToken());
         }
         assertEquals(expectedGetResponse.getSourceAsMap(), parsedGetResponse.getSourceAsMap());
@@ -172,7 +173,7 @@ public class GetResponseTests extends ESTestCase {
         BytesReference originalBytes = toShuffledXContent(getResponse, xContentType, ToXContent.EMPTY_PARAMS, randomBoolean());
 
         try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
-            ParsingException exception = expectThrows(ParsingException.class, () -> GetResponse.fromXContent(parser));
+            ParsingException exception = expectThrows(ParsingException.class, () -> parseInstance(parser));
             assertEquals("Missing required fields [_index,_id]", exception.getMessage());
         }
     }
@@ -184,4 +185,19 @@ public class GetResponseTests extends ESTestCase {
     private static GetResponse mutateGetResponse(GetResponse getResponse) {
         return new GetResponse(mutateGetResult(getResponse.getResult));
     }
+
+    private static GetResponse parseInstance(XContentParser parser) throws IOException {
+        GetResult getResult = GetResult.fromXContent(parser);
+
+        // At this stage we ensure that we parsed enough information to return
+        // a valid GetResponse instance. If it's not the case, we throw an
+        // exception so that callers know it and can handle it correctly.
+        if (getResult.getIndex() == null && getResult.getId() == null) {
+            throw new ParsingException(
+                parser.getTokenLocation(),
+                String.format(Locale.ROOT, "Missing required fields [%s,%s]", GetResult._INDEX, GetResult._ID)
+            );
+        }
+        return new GetResponse(getResult);
+    }
 }

+ 20 - 2
server/src/test/java/org/elasticsearch/action/ingest/GetPipelineResponseTests.java

@@ -26,6 +26,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
+
 public class GetPipelineResponseTests extends AbstractXContentSerializingTestCase<GetPipelineResponse> {
 
     private XContentBuilder getRandomXContentBuilder() throws IOException {
@@ -69,7 +71,7 @@ public class GetPipelineResponseTests extends AbstractXContentSerializingTestCas
                 .xContent()
                 .createParser(xContentRegistry(), LoggingDeprecationHandler.INSTANCE, BytesReference.bytes(builder).streamInput())
         ) {
-            parsedResponse = GetPipelineResponse.fromXContent(parser);
+            parsedResponse = doParseInstance(parser);
         }
         List<PipelineConfiguration> actualPipelines = response.pipelines();
         List<PipelineConfiguration> parsedPipelines = parsedResponse.pipelines();
@@ -82,7 +84,23 @@ public class GetPipelineResponseTests extends AbstractXContentSerializingTestCas
 
     @Override
     protected GetPipelineResponse doParseInstance(XContentParser parser) throws IOException {
-        return GetPipelineResponse.fromXContent(parser);
+        ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser);
+        List<PipelineConfiguration> pipelines = new ArrayList<>();
+        while (parser.nextToken().equals(XContentParser.Token.FIELD_NAME)) {
+            String pipelineId = parser.currentName();
+            parser.nextToken();
+            try (XContentBuilder contentBuilder = XContentBuilder.builder(parser.contentType().xContent())) {
+                contentBuilder.generator().copyCurrentStructure(parser);
+                PipelineConfiguration pipeline = new PipelineConfiguration(
+                    pipelineId,
+                    BytesReference.bytes(contentBuilder),
+                    contentBuilder.contentType()
+                );
+                pipelines.add(pipeline);
+            }
+        }
+        ensureExpectedToken(XContentParser.Token.END_OBJECT, parser.currentToken(), parser);
+        return new GetPipelineResponse(pipelines);
     }
 
     @Override

+ 19 - 1
server/src/test/java/org/elasticsearch/action/ingest/SimulateDocumentVerboseResultTests.java

@@ -8,6 +8,8 @@
 package org.elasticsearch.action.ingest;
 
 import org.elasticsearch.test.AbstractXContentTestCase;
+import org.elasticsearch.xcontent.ConstructingObjectParser;
+import org.elasticsearch.xcontent.ParseField;
 import org.elasticsearch.xcontent.XContentParser;
 
 import java.io.IOException;
@@ -17,8 +19,24 @@ import java.util.StringJoiner;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
 
+import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
+
 public class SimulateDocumentVerboseResultTests extends AbstractXContentTestCase<SimulateDocumentVerboseResult> {
 
+    @SuppressWarnings("unchecked")
+    private static final ConstructingObjectParser<SimulateDocumentVerboseResult, Void> PARSER = new ConstructingObjectParser<>(
+        "simulate_document_verbose_result",
+        true,
+        a -> new SimulateDocumentVerboseResult((List<SimulateProcessorResult>) a[0])
+    );
+    static {
+        PARSER.declareObjectArray(
+            constructorArg(),
+            SimulateProcessorResult.PARSER,
+            new ParseField(SimulateDocumentVerboseResult.PROCESSOR_RESULT_FIELD)
+        );
+    }
+
     static SimulateDocumentVerboseResult createTestInstance(boolean withFailures) {
         int numDocs = randomIntBetween(0, 5);
         List<SimulateProcessorResult> results = new ArrayList<>();
@@ -42,7 +60,7 @@ public class SimulateDocumentVerboseResultTests extends AbstractXContentTestCase
 
     @Override
     protected SimulateDocumentVerboseResult doParseInstance(XContentParser parser) {
-        return SimulateDocumentVerboseResult.fromXContent(parser);
+        return PARSER.apply(parser, null);
     }
 
     @Override

+ 25 - 1
server/src/test/java/org/elasticsearch/search/ClearScrollResponseTests.java

@@ -9,9 +9,12 @@
 package org.elasticsearch.search;
 
 import org.elasticsearch.action.search.ClearScrollResponse;
+import org.elasticsearch.action.search.ClosePointInTimeResponse;
 import org.elasticsearch.common.bytes.BytesReference;
 import org.elasticsearch.common.xcontent.XContentHelper;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xcontent.ConstructingObjectParser;
+import org.elasticsearch.xcontent.ObjectParser;
 import org.elasticsearch.xcontent.ToXContent;
 import org.elasticsearch.xcontent.XContentBuilder;
 import org.elasticsearch.xcontent.XContentParser;
@@ -21,9 +24,30 @@ import org.elasticsearch.xcontent.json.JsonXContent;
 import java.io.IOException;
 
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
+import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
 
 public class ClearScrollResponseTests extends ESTestCase {
 
+    private static final ConstructingObjectParser<ClosePointInTimeResponse, Void> PARSER = new ConstructingObjectParser<>(
+        "clear_scroll",
+        true,
+        a -> new ClosePointInTimeResponse((boolean) a[0], (int) a[1])
+    );
+    static {
+        PARSER.declareField(
+            constructorArg(),
+            (parser, context) -> parser.booleanValue(),
+            ClearScrollResponse.SUCCEEDED,
+            ObjectParser.ValueType.BOOLEAN
+        );
+        PARSER.declareField(
+            constructorArg(),
+            (parser, context) -> parser.intValue(),
+            ClearScrollResponse.NUMFREED,
+            ObjectParser.ValueType.INT
+        );
+    }
+
     public void testToXContent() throws IOException {
         ClearScrollResponse clearScrollResponse = new ClearScrollResponse(true, 10);
         try (XContentBuilder builder = JsonXContent.contentBuilder()) {
@@ -39,7 +63,7 @@ public class ClearScrollResponseTests extends ESTestCase {
         BytesReference originalBytes = toShuffledXContent(originalResponse, xContentType, ToXContent.EMPTY_PARAMS, randomBoolean());
         ClearScrollResponse parsedResponse;
         try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
-            parsedResponse = ClearScrollResponse.fromXContent(parser);
+            parsedResponse = PARSER.parse(parser, null);
         }
         assertEquals(originalResponse.isSucceeded(), parsedResponse.isSucceeded());
         assertEquals(originalResponse.getNumFreed(), parsedResponse.getNumFreed());