From b1735aa93b557f173abf4c2337917cabdfcd30e0 Mon Sep 17 00:00:00 2001 From: Julie Tibshirani Date: Sun, 27 Jan 2019 16:02:22 -0800 Subject: [PATCH] Support both typed and typeless 'get mapping' requests in the HLRC. (#37796) From previous PRs, we've already added support for include_type_name to the get mapping API. We had also taken an approach to the HLRC where the server-side `GetMappingResponse#fromXContent` could only handle typeless input. This PR updates the HLRC for 'get mapping' to be in line with our new approach: * Add a typeless 'get mappings' method to the Java HLRC, that accepts new client-side request and response objects. This new response only handles typeless mapping definitions. * Switch the old version of `GetMappingResponse` back to expecting typed mappings, and deprecate the corresponding method on the HLRC. Finally, the PR also does some small, related clean-up around 'get field mappings'. --- .../elasticsearch/client/IndicesClient.java | 78 ++++++++++-- .../client/IndicesRequestConverters.java | 21 ++- .../client/indices/GetMappingsRequest.java | 74 +++++++++++ .../client/indices/GetMappingsResponse.java | 71 +++++++++++ .../elasticsearch/client/IndicesClientIT.java | 54 +++++++- .../client/IndicesRequestConvertersTests.java | 80 ++++++++---- .../IndicesClientDocumentationIT.java | 19 ++- .../GetFieldMappingsResponseTests.java | 7 +- .../indices/GetMappingsResponseTests.java | 120 ++++++++++++++++++ .../high-level/indices/get_mappings.asciidoc | 7 +- .../mapping/get/GetMappingsResponse.java | 21 +-- .../admin/indices/RestGetMappingAction.java | 4 +- .../get/GetFieldMappingsResponseTests.java | 4 +- .../mapping/get/GetMappingsResponseTests.java | 70 ++-------- 14 files changed, 494 insertions(+), 136 deletions(-) create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/indices/GetMappingsRequest.java create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/indices/GetMappingsResponse.java create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetMappingsResponseTests.java diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java index 24c0175b7e8..c93c9c67e8f 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java @@ -37,8 +37,6 @@ import org.elasticsearch.action.admin.indices.get.GetIndexRequest; import org.elasticsearch.action.admin.indices.get.GetIndexResponse; import org.elasticsearch.client.indices.GetFieldMappingsRequest; import org.elasticsearch.client.indices.GetFieldMappingsResponse; -import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; -import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; @@ -61,6 +59,8 @@ import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.CreateIndexResponse; import org.elasticsearch.client.indices.FreezeIndexRequest; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; +import org.elasticsearch.client.indices.GetMappingsRequest; +import org.elasticsearch.client.indices.GetMappingsResponse; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; import org.elasticsearch.client.indices.PutMappingRequest; import org.elasticsearch.client.indices.UnfreezeIndexRequest; @@ -261,8 +261,11 @@ public final class IndicesClient { * @throws IOException in case there is a problem sending the request or parsing back the response */ public GetMappingsResponse getMapping(GetMappingsRequest getMappingsRequest, RequestOptions options) throws IOException { - return restHighLevelClient.performRequestAndParseEntity(getMappingsRequest, IndicesRequestConverters::getMappings, options, - GetMappingsResponse::fromXContent, emptySet()); + return restHighLevelClient.performRequestAndParseEntity(getMappingsRequest, + IndicesRequestConverters::getMappings, + options, + GetMappingsResponse::fromXContent, + emptySet()); } /** @@ -275,8 +278,60 @@ public final class IndicesClient { */ public void getMappingAsync(GetMappingsRequest getMappingsRequest, RequestOptions options, ActionListener listener) { - restHighLevelClient.performRequestAsyncAndParseEntity(getMappingsRequest, IndicesRequestConverters::getMappings, options, - GetMappingsResponse::fromXContent, listener, emptySet()); + restHighLevelClient.performRequestAsyncAndParseEntity(getMappingsRequest, + IndicesRequestConverters::getMappings, + options, + GetMappingsResponse::fromXContent, + listener, + emptySet()); + } + + /** + * Retrieves the mappings on an index or indices using the Get Mapping API. + * See + * Get Mapping API on elastic.co + * @param getMappingsRequest the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return the response + * @throws IOException in case there is a problem sending the request or parsing back the response + * + * @deprecated This method uses old request and response objects which still refer to types, a deprecated + * feature. The method {@link #getMapping(GetMappingsRequest, RequestOptions)} should be used instead, which + * accepts a new request object. + */ + @Deprecated + public org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse getMapping( + org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest getMappingsRequest, + RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(getMappingsRequest, + IndicesRequestConverters::getMappings, + options, + org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse::fromXContent, + emptySet()); + } + + /** + * Asynchronously retrieves the mappings on an index on indices using the Get Mapping API. + * See + * Get Mapping API on elastic.co + * @param getMappingsRequest the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param listener the listener to be notified upon request completion + * + * @deprecated This method uses old request and response objects which still refer to types, a deprecated feature. + * The method {@link #getMapping(GetMappingsRequest, RequestOptions)} should be used instead, which accepts a new + * request object. + */ + @Deprecated + public void getMappingAsync(org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest getMappingsRequest, + RequestOptions options, + ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(getMappingsRequest, + IndicesRequestConverters::getMappings, + options, + org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse::fromXContent, + listener, + emptySet()); } /** @@ -288,8 +343,9 @@ public final class IndicesClient { * @return the response * @throws IOException in case there is a problem sending the request or parsing back the response * - * @deprecated This method uses an old request object which still refers to types, a deprecated feature. The method - * {@link #getFieldMapping(GetFieldMappingsRequest, RequestOptions)} should be used instead, which accepts a new request object. + * @deprecated This method uses old request and response objects which still refer to types, a deprecated feature. + * The method {@link #getFieldMapping(GetFieldMappingsRequest, RequestOptions)} should be used instead, which + * accepts a new request object. */ @Deprecated public org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse getFieldMapping( @@ -307,9 +363,9 @@ public final class IndicesClient { * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @param listener the listener to be notified upon request completion * - * @deprecated This method uses an old request object which still refers to types, a deprecated feature. The - * method {@link #getFieldMappingAsync(GetFieldMappingsRequest, RequestOptions, ActionListener)} should be used instead, - * which accepts a new request object. + * @deprecated This method uses old request and response objects which still refer to types, a deprecated feature. + * The method {@link #getFieldMappingAsync(GetFieldMappingsRequest, RequestOptions, ActionListener)} should be + * used instead, which accepts a new request object. */ @Deprecated public void getFieldMappingAsync(org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest getFieldMappingsRequest, diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java index 2b44e3006b1..4889ead93b7 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java @@ -35,7 +35,6 @@ import org.elasticsearch.action.admin.indices.flush.SyncedFlushRequest; import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest; import org.elasticsearch.action.admin.indices.get.GetIndexRequest; import org.elasticsearch.client.indices.GetFieldMappingsRequest; -import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; import org.elasticsearch.action.admin.indices.rollover.RolloverRequest; @@ -49,6 +48,7 @@ import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryReques import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.FreezeIndexRequest; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; +import org.elasticsearch.client.indices.GetMappingsRequest; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; import org.elasticsearch.client.indices.PutMappingRequest; import org.elasticsearch.client.indices.UnfreezeIndexRequest; @@ -148,6 +148,7 @@ final class IndicesRequestConverters { return request; } + @Deprecated static Request putMapping(org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest putMappingRequest) throws IOException { // The concreteIndex is an internal concept, not applicable to requests made over the REST API. if (putMappingRequest.getConcreteIndex() != null) { @@ -166,7 +167,21 @@ final class IndicesRequestConverters { return request; } - static Request getMappings(GetMappingsRequest getMappingsRequest) throws IOException { + static Request getMappings(GetMappingsRequest getMappingsRequest) { + String[] indices = getMappingsRequest.indices() == null ? Strings.EMPTY_ARRAY : getMappingsRequest.indices(); + + Request request = new Request(HttpGet.METHOD_NAME, RequestConverters.endpoint(indices, "_mapping")); + + RequestConverters.Params parameters = new RequestConverters.Params(request); + parameters.withMasterTimeout(getMappingsRequest.masterNodeTimeout()); + parameters.withIndicesOptions(getMappingsRequest.indicesOptions()); + parameters.withLocal(getMappingsRequest.local()); + + return request; + } + + @Deprecated + static Request getMappings(org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest getMappingsRequest) { String[] indices = getMappingsRequest.indices() == null ? Strings.EMPTY_ARRAY : getMappingsRequest.indices(); String[] types = getMappingsRequest.types() == null ? Strings.EMPTY_ARRAY : getMappingsRequest.types(); @@ -176,6 +191,7 @@ final class IndicesRequestConverters { parameters.withMasterTimeout(getMappingsRequest.masterNodeTimeout()); parameters.withIndicesOptions(getMappingsRequest.indicesOptions()); parameters.withLocal(getMappingsRequest.local()); + parameters.putParam(INCLUDE_TYPE_NAME_PARAMETER, "true"); return request; } @@ -201,6 +217,7 @@ final class IndicesRequestConverters { return request; } + @Deprecated static Request getFieldMapping(org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest getFieldMappingsRequest) { String[] indices = getFieldMappingsRequest.indices() == null ? Strings.EMPTY_ARRAY : getFieldMappingsRequest.indices(); String[] types = getFieldMappingsRequest.types() == null ? Strings.EMPTY_ARRAY : getFieldMappingsRequest.types(); diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/GetMappingsRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/GetMappingsRequest.java new file mode 100644 index 00000000000..0bc4ba4af77 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/GetMappingsRequest.java @@ -0,0 +1,74 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.indices; + +import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.client.TimedRequest; +import org.elasticsearch.common.Strings; + +public class GetMappingsRequest extends TimedRequest { + + private boolean local = false; + private boolean includeDefaults = false; + private String[] indices = Strings.EMPTY_ARRAY; + private IndicesOptions indicesOptions = IndicesOptions.strictExpandOpen(); + + /** + * Indicates whether the receiving node should operate based on local index information or + * forward requests, where needed, to other nodes. If running locally, request will not + * raise errors if local index information is missing. + */ + public GetMappingsRequest local(boolean local) { + this.local = local; + return this; + } + + public boolean local() { + return local; + } + + public GetMappingsRequest indices(String... indices) { + this.indices = indices; + return this; + } + + public GetMappingsRequest indicesOptions(IndicesOptions indicesOptions) { + this.indicesOptions = indicesOptions; + return this; + } + + public String[] indices() { + return indices; + } + + public IndicesOptions indicesOptions() { + return indicesOptions; + } + + public boolean includeDefaults() { + return includeDefaults; + } + + /** Indicates whether default mapping settings should be returned */ + public GetMappingsRequest includeDefaults(boolean includeDefaults) { + this.includeDefaults = includeDefaults; + return this; + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/GetMappingsResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/GetMappingsResponse.java new file mode 100644 index 00000000000..54f569ab94b --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/GetMappingsResponse.java @@ -0,0 +1,71 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.indices; + +import org.elasticsearch.cluster.metadata.MappingMetaData; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentParserUtils; +import org.elasticsearch.index.mapper.MapperService; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class GetMappingsResponse { + + static final ParseField MAPPINGS = new ParseField("mappings"); + + private Map mappings; + + public GetMappingsResponse(Map mappings) { + this.mappings = mappings; + } + + public Map mappings() { + return mappings; + } + + public static GetMappingsResponse fromXContent(XContentParser parser) throws IOException { + if (parser.currentToken() == null) { + parser.nextToken(); + } + + XContentParserUtils.ensureExpectedToken(parser.currentToken(), + XContentParser.Token.START_OBJECT, + parser::getTokenLocation); + + Map parts = parser.map(); + + Map mappings = new HashMap<>(); + for (Map.Entry entry : parts.entrySet()) { + String indexName = entry.getKey(); + assert entry.getValue() instanceof Map : "expected a map as type mapping, but got: " + entry.getValue().getClass(); + + @SuppressWarnings("unchecked") + final Map fieldMappings = (Map) ((Map) entry.getValue()) + .get(MAPPINGS.getPreferredName()); + + mappings.put(indexName, new MappingMetaData(MapperService.SINGLE_MAPPING_NAME, fieldMappings)); + } + + return new GetMappingsResponse(mappings); + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java index fe175b217bd..708cb6687ce 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java @@ -41,8 +41,6 @@ import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest; import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeResponse; import org.elasticsearch.action.admin.indices.get.GetIndexRequest; import org.elasticsearch.action.admin.indices.get.GetIndexResponse; -import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; -import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; @@ -72,6 +70,8 @@ import org.elasticsearch.client.indices.FreezeIndexRequest; import org.elasticsearch.client.indices.GetFieldMappingsRequest; import org.elasticsearch.client.indices.GetFieldMappingsResponse; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; +import org.elasticsearch.client.indices.GetMappingsRequest; +import org.elasticsearch.client.indices.GetMappingsResponse; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; import org.elasticsearch.client.indices.PutMappingRequest; import org.elasticsearch.client.indices.UnfreezeIndexRequest; @@ -95,6 +95,7 @@ import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.action.admin.indices.RestCreateIndexAction; import org.elasticsearch.rest.action.admin.indices.RestGetFieldMappingAction; +import org.elasticsearch.rest.action.admin.indices.RestGetMappingAction; import org.elasticsearch.rest.action.admin.indices.RestPutMappingAction; import java.io.IOException; @@ -527,8 +528,9 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase { mappingBuilder.endObject().endObject().endObject(); putMappingRequest.source(mappingBuilder); - AcknowledgedResponse putMappingResponse = - execute(putMappingRequest, highLevelClient().indices()::putMapping, highLevelClient().indices()::putMappingAsync); + AcknowledgedResponse putMappingResponse = execute(putMappingRequest, + highLevelClient().indices()::putMapping, + highLevelClient().indices()::putMappingAsync); assertTrue(putMappingResponse.isAcknowledged()); Map getIndexResponse = getAsMap(indexName); @@ -536,8 +538,48 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase { GetMappingsRequest request = new GetMappingsRequest().indices(indexName); - GetMappingsResponse getMappingsResponse = - execute(request, highLevelClient().indices()::getMapping, highLevelClient().indices()::getMappingAsync); + GetMappingsResponse getMappingsResponse = execute( + request, + highLevelClient().indices()::getMapping, + highLevelClient().indices()::getMappingAsync); + + Map mappings = getMappingsResponse.mappings().get(indexName).sourceAsMap(); + Map type = new HashMap<>(); + type.put("type", "text"); + Map field = new HashMap<>(); + field.put("field", type); + Map expected = new HashMap<>(); + expected.put("properties", field); + assertThat(mappings, equalTo(expected)); + } + + public void testGetMappingWithTypes() throws IOException { + String indexName = "test"; + createIndex(indexName, Settings.EMPTY); + + PutMappingRequest putMappingRequest = new PutMappingRequest(indexName); + XContentBuilder mappingBuilder = JsonXContent.contentBuilder(); + mappingBuilder.startObject().startObject("properties").startObject("field"); + mappingBuilder.field("type", "text"); + mappingBuilder.endObject().endObject().endObject(); + putMappingRequest.source(mappingBuilder); + + AcknowledgedResponse putMappingResponse = execute(putMappingRequest, + highLevelClient().indices()::putMapping, + highLevelClient().indices()::putMappingAsync); + assertTrue(putMappingResponse.isAcknowledged()); + + Map getIndexResponse = getAsMap(indexName); + assertEquals("text", XContentMapValues.extractValue(indexName + ".mappings.properties.field.type", getIndexResponse)); + + org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest request = + new org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest().indices(indexName); + + org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse getMappingsResponse = execute( + request, + highLevelClient().indices()::getMapping, + highLevelClient().indices()::getMappingAsync, + expectWarnings(RestGetMappingAction.TYPES_DEPRECATION_MESSAGE)); Map mappings = getMappingsResponse.getMappings().get(indexName).get("_doc").sourceAsMap(); Map type = new HashMap<>(); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java index 5e08381720e..409690eaa69 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java @@ -37,7 +37,6 @@ import org.elasticsearch.action.admin.indices.flush.FlushRequest; import org.elasticsearch.action.admin.indices.flush.SyncedFlushRequest; import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest; import org.elasticsearch.action.admin.indices.get.GetIndexRequest; -import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; import org.elasticsearch.action.admin.indices.rollover.RolloverRequest; @@ -50,11 +49,12 @@ import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateReque import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest; import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.client.indices.CreateIndexRequest; -import org.elasticsearch.client.indices.RandomCreateIndexGenerator; +import org.elasticsearch.client.indices.GetFieldMappingsRequest; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; +import org.elasticsearch.client.indices.GetMappingsRequest; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; import org.elasticsearch.client.indices.PutMappingRequest; -import org.elasticsearch.client.indices.GetFieldMappingsRequest; +import org.elasticsearch.client.indices.RandomCreateIndexGenerator; import org.elasticsearch.common.CheckedFunction; import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Settings; @@ -231,22 +231,53 @@ public class IndicesRequestConvertersTests extends ESTestCase { RequestConvertersTests.assertToXContentBody(putMappingRequest, request.getEntity()); } - public void testGetMapping() throws IOException { + public void testGetMapping() { GetMappingsRequest getMappingRequest = new GetMappingsRequest(); String[] indices = Strings.EMPTY_ARRAY; - if (ESTestCase.randomBoolean()) { + if (randomBoolean()) { indices = RequestConvertersTests.randomIndicesNames(0, 5); getMappingRequest.indices(indices); - } else if (ESTestCase.randomBoolean()) { + } else if (randomBoolean()) { + getMappingRequest.indices((String[]) null); + } + + Map expectedParams = new HashMap<>(); + RequestConvertersTests.setRandomIndicesOptions(getMappingRequest::indicesOptions, + getMappingRequest::indicesOptions, expectedParams); + RequestConvertersTests.setRandomMasterTimeout(getMappingRequest, expectedParams); + RequestConvertersTests.setRandomLocal(getMappingRequest::local, expectedParams); + + Request request = IndicesRequestConverters.getMappings(getMappingRequest); + StringJoiner endpoint = new StringJoiner("/", "/", ""); + String index = String.join(",", indices); + if (Strings.hasLength(index)) { + endpoint.add(index); + } + endpoint.add("_mapping"); + + Assert.assertThat(endpoint.toString(), equalTo(request.getEndpoint())); + Assert.assertThat(expectedParams, equalTo(request.getParameters())); + Assert.assertThat(HttpGet.METHOD_NAME, equalTo(request.getMethod())); + } + + public void testGetMappingWithTypes() { + org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest getMappingRequest = + new org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest(); + + String[] indices = Strings.EMPTY_ARRAY; + if (randomBoolean()) { + indices = RequestConvertersTests.randomIndicesNames(0, 5); + getMappingRequest.indices(indices); + } else if (randomBoolean()) { getMappingRequest.indices((String[]) null); } String type = null; - if (ESTestCase.randomBoolean()) { - type = ESTestCase.randomAlphaOfLengthBetween(3, 10); + if (randomBoolean()) { + type = randomAlphaOfLengthBetween(3, 10); getMappingRequest.types(type); - } else if (ESTestCase.randomBoolean()) { + } else if (randomBoolean()) { getMappingRequest.types((String[]) null); } @@ -256,6 +287,7 @@ public class IndicesRequestConvertersTests extends ESTestCase { getMappingRequest::indicesOptions, expectedParams); RequestConvertersTests.setRandomMasterTimeout(getMappingRequest, expectedParams); RequestConvertersTests.setRandomLocal(getMappingRequest, expectedParams); + expectedParams.put(INCLUDE_TYPE_NAME_PARAMETER, "true"); Request request = IndicesRequestConverters.getMappings(getMappingRequest); StringJoiner endpoint = new StringJoiner("/", "/", ""); @@ -277,21 +309,21 @@ public class IndicesRequestConvertersTests extends ESTestCase { GetFieldMappingsRequest getFieldMappingsRequest = new GetFieldMappingsRequest(); String[] indices = Strings.EMPTY_ARRAY; - if (ESTestCase.randomBoolean()) { + if (randomBoolean()) { indices = RequestConvertersTests.randomIndicesNames(0, 5); getFieldMappingsRequest.indices(indices); - } else if (ESTestCase.randomBoolean()) { + } else if (randomBoolean()) { getFieldMappingsRequest.indices((String[]) null); } String[] fields = null; - if (ESTestCase.randomBoolean()) { - fields = new String[ESTestCase.randomIntBetween(1, 5)]; + if (randomBoolean()) { + fields = new String[randomIntBetween(1, 5)]; for (int i = 0; i < fields.length; i++) { - fields[i] = ESTestCase.randomAlphaOfLengthBetween(3, 10); + fields[i] = randomAlphaOfLengthBetween(3, 10); } getFieldMappingsRequest.fields(fields); - } else if (ESTestCase.randomBoolean()) { + } else if (randomBoolean()) { getFieldMappingsRequest.fields((String[]) null); } @@ -321,29 +353,29 @@ public class IndicesRequestConvertersTests extends ESTestCase { new org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest(); String[] indices = Strings.EMPTY_ARRAY; - if (ESTestCase.randomBoolean()) { + if (randomBoolean()) { indices = RequestConvertersTests.randomIndicesNames(0, 5); getFieldMappingsRequest.indices(indices); - } else if (ESTestCase.randomBoolean()) { + } else if (randomBoolean()) { getFieldMappingsRequest.indices((String[]) null); } String type = null; - if (ESTestCase.randomBoolean()) { - type = ESTestCase.randomAlphaOfLengthBetween(3, 10); + if (randomBoolean()) { + type = randomAlphaOfLengthBetween(3, 10); getFieldMappingsRequest.types(type); - } else if (ESTestCase.randomBoolean()) { + } else if (randomBoolean()) { getFieldMappingsRequest.types((String[]) null); } String[] fields = null; - if (ESTestCase.randomBoolean()) { - fields = new String[ESTestCase.randomIntBetween(1, 5)]; + if (randomBoolean()) { + fields = new String[randomIntBetween(1, 5)]; for (int i = 0; i < fields.length; i++) { - fields[i] = ESTestCase.randomAlphaOfLengthBetween(3, 10); + fields[i] = randomAlphaOfLengthBetween(3, 10); } getFieldMappingsRequest.fields(fields); - } else if (ESTestCase.randomBoolean()) { + } else if (randomBoolean()) { getFieldMappingsRequest.fields((String[]) null); } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java index 0951d05b0ab..cfd5ac4de2f 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java @@ -42,8 +42,6 @@ import org.elasticsearch.action.admin.indices.get.GetIndexRequest; import org.elasticsearch.action.admin.indices.get.GetIndexResponse; import org.elasticsearch.client.indices.GetFieldMappingsRequest; import org.elasticsearch.client.indices.GetFieldMappingsResponse; -import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; -import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; @@ -76,6 +74,8 @@ import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.CreateIndexResponse; import org.elasticsearch.client.indices.FreezeIndexRequest; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; +import org.elasticsearch.client.indices.GetMappingsRequest; +import org.elasticsearch.client.indices.GetMappingsResponse; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; import org.elasticsearch.client.indices.PutMappingRequest; import org.elasticsearch.client.indices.UnfreezeIndexRequest; @@ -591,8 +591,7 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase // end::get-mappings-request // tag::get-mappings-request-masterTimeout - request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> - request.masterNodeTimeout("1m"); // <2> + request.setMasterTimeout(TimeValue.timeValueMinutes(1)); // <1> // end::get-mappings-request-masterTimeout // tag::get-mappings-request-indicesOptions @@ -604,9 +603,9 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase // end::get-mappings-execute // tag::get-mappings-response - ImmutableOpenMap> allMappings = getMappingResponse.mappings(); // <1> - MappingMetaData typeMapping = allMappings.get("twitter").get("_doc"); // <2> - Map mapping = typeMapping.sourceAsMap(); // <3> + Map allMappings = getMappingResponse.mappings(); // <1> + MappingMetaData indexMapping = allMappings.get("twitter"); // <2> + Map mapping = indexMapping.sourceAsMap(); // <3> // end::get-mappings-response Map type = new HashMap<>(); @@ -662,9 +661,9 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase final CountDownLatch latch = new CountDownLatch(1); final ActionListener latchListener = new LatchedActionListener<>(listener, latch); listener = ActionListener.wrap(r -> { - ImmutableOpenMap> allMappings = r.mappings(); - MappingMetaData typeMapping = allMappings.get("twitter").get("_doc"); - Map mapping = typeMapping.sourceAsMap(); + Map allMappings = r.mappings(); + MappingMetaData indexMapping = allMappings.get("twitter"); + Map mapping = indexMapping.sourceAsMap(); Map type = new HashMap<>(); type.put("type", "text"); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetFieldMappingsResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetFieldMappingsResponseTests.java index aa8ce3bb6c0..827b2f005ae 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetFieldMappingsResponseTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetFieldMappingsResponseTests.java @@ -44,14 +44,14 @@ public class GetFieldMappingsResponseTests extends ESTestCase { .test(); } - Predicate getRandomFieldsExcludeFilter() { + private Predicate getRandomFieldsExcludeFilter() { // allow random fields at the level of `index` and `index.mappings.field` // otherwise random field could be evaluated as index name or type name return s -> false == (s.matches("(?[^.]+)") || s.matches("(?[^.]+)\\.mappings\\.(?[^.]+)")); } - static GetFieldMappingsResponse createTestInstance() { + private static GetFieldMappingsResponse createTestInstance() { Map> mappings = new HashMap<>(); // if mappings is empty, means that fields are not found if (randomBoolean()) { @@ -72,12 +72,11 @@ public class GetFieldMappingsResponseTests extends ESTestCase { } // As the client class GetFieldMappingsResponse doesn't have toXContent method, adding this method here only for the test - static void toXContent(GetFieldMappingsResponse response, XContentBuilder builder) throws IOException { + private static void toXContent(GetFieldMappingsResponse response, XContentBuilder builder) throws IOException { builder.startObject(); for (Map.Entry> indexEntry : response.mappings().entrySet()) { builder.startObject(indexEntry.getKey()); builder.startObject("mappings"); - Map mappings = null; for (Map.Entry fieldEntry : indexEntry.getValue().entrySet()) { builder.startObject(fieldEntry.getKey()); builder.field("full_name", fieldEntry.getValue().fullName()); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetMappingsResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetMappingsResponseTests.java new file mode 100644 index 00000000000..0601609a8a7 --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetMappingsResponseTests.java @@ -0,0 +1,120 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.indices; + +import org.elasticsearch.cluster.metadata.MappingMetaData; +import org.elasticsearch.common.collect.ImmutableOpenMap; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.ToXContent.Params; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.index.mapper.MapperService; +import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.test.ESTestCase; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Predicate; + +import static org.elasticsearch.client.indices.GetMappingsResponse.MAPPINGS; +import static org.elasticsearch.test.AbstractXContentTestCase.xContentTester; + +public class GetMappingsResponseTests extends ESTestCase { + + // Because the client-side class does not have a toXContent method, we test xContent serialization by creating + // a random client object, converting it to a server object then serializing it to xContent, and finally + // parsing it back as a client object. We check equality between the original client object, and the parsed one. + public void testFromXContent() throws IOException { + xContentTester( + this::createParser, + GetMappingsResponseTests::createTestInstance, + GetMappingsResponseTests::toXContent, + GetMappingsResponse::fromXContent) + .supportsUnknownFields(true) + .assertEqualsConsumer(GetMappingsResponseTests::assertEqualInstances) + .randomFieldsExcludeFilter(randomFieldsExcludeFilter()) + .test(); + } + + private static GetMappingsResponse createTestInstance() { + Map mappings = Collections.singletonMap( + "index-" + randomAlphaOfLength(5), randomMappingMetaData()); + return new GetMappingsResponse(mappings); + } + + private static void assertEqualInstances(GetMappingsResponse expected, GetMappingsResponse actual) { + assertEquals(expected.mappings(), actual.mappings()); + } + + private Predicate randomFieldsExcludeFilter() { + return field -> !field.equals(MAPPINGS.getPreferredName()); + } + + public static MappingMetaData randomMappingMetaData() { + Map mappings = new HashMap<>(); + + if (frequently()) { // rarely have no fields + mappings.put("field1", randomFieldMapping()); + if (randomBoolean()) { + mappings.put("field2", randomFieldMapping()); + } + } + + try { + return new MappingMetaData(MapperService.SINGLE_MAPPING_NAME, mappings); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static Map randomFieldMapping() { + Map mappings = new HashMap<>(); + if (randomBoolean()) { + mappings.put("type", randomFrom("text", "keyword")); + mappings.put("index", "analyzed"); + mappings.put("analyzer", "english"); + } else { + mappings.put("type", randomFrom("integer", "float", "long", "double")); + mappings.put("index", Objects.toString(randomBoolean())); + } + return mappings; + } + + private static void toXContent(GetMappingsResponse response, XContentBuilder builder) throws IOException { + Params params = new ToXContent.MapParams( + Collections.singletonMap(BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER, "false")); + ImmutableOpenMap.Builder> allMappings = ImmutableOpenMap.builder(); + + for (Map.Entry indexEntry : response.mappings().entrySet()) { + ImmutableOpenMap.Builder mappings = ImmutableOpenMap.builder(); + mappings.put(MapperService.SINGLE_MAPPING_NAME, indexEntry.getValue()); + allMappings.put(indexEntry.getKey(), mappings.build()); + } + + org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse serverResponse = + new org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse(allMappings.build()); + + builder.startObject(); + serverResponse.toXContent(builder, params); + builder.endObject(); + } +} diff --git a/docs/java-rest/high-level/indices/get_mappings.asciidoc b/docs/java-rest/high-level/indices/get_mappings.asciidoc index a42a8ac77b3..516e0633f83 100644 --- a/docs/java-rest/high-level/indices/get_mappings.asciidoc +++ b/docs/java-rest/high-level/indices/get_mappings.asciidoc @@ -10,13 +10,13 @@ [id="{upid}-{api}-request"] ==== Get Mappings Request -A +{request}+ can have an optional list of indices and optional list of types: +A +{request}+ can have an optional list of indices: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- include-tagged::{doc-tests-file}[{api}-request] -------------------------------------------------- -<1> An empty request that will return all indices and types +<1> An empty request that will return all indices <2> Setting the indices to fetch mapping for ==== Optional arguments @@ -27,7 +27,6 @@ The following arguments can also optionally be provided: include-tagged::{doc-tests-file}[{api}-request-masterTimeout] -------------------------------------------------- <1> Timeout to connect to the master node as a `TimeValue` -<2> Timeout to connect to the master node as a `String` ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- @@ -48,5 +47,5 @@ executed operation as follows: include-tagged::{doc-tests-file}[{api}-response] -------------------------------------------------- <1> Returning all indices' mappings -<2> Retrieving the mappings for a particular index and type +<2> Retrieving the mappings for a particular index <3> Getting the mappings as a Java Map diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetMappingsResponse.java b/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetMappingsResponse.java index 50b7a364268..7abbea9c1d9 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetMappingsResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetMappingsResponse.java @@ -20,7 +20,6 @@ package org.elasticsearch.action.admin.indices.mapping.get; import com.carrotsearch.hppc.cursors.ObjectObjectCursor; - import org.elasticsearch.action.ActionResponse; import org.elasticsearch.cluster.metadata.MappingMetaData; import org.elasticsearch.common.ParseField; @@ -31,7 +30,6 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ToXContentFragment; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.rest.BaseRestHandler; import java.io.IOException; @@ -45,7 +43,7 @@ public class GetMappingsResponse extends ActionResponse implements ToXContentFra private ImmutableOpenMap> mappings = ImmutableOpenMap.of(); - GetMappingsResponse(ImmutableOpenMap> mappings) { + public GetMappingsResponse(ImmutableOpenMap> mappings) { this.mappings = mappings; } @@ -102,17 +100,20 @@ public class GetMappingsResponse extends ActionResponse implements ToXContentFra for (Map.Entry entry : parts.entrySet()) { final String indexName = entry.getKey(); assert entry.getValue() instanceof Map : "expected a map as type mapping, but got: " + entry.getValue().getClass(); + final Map mapping = (Map) ((Map) entry.getValue()).get(MAPPINGS.getPreferredName()); + ImmutableOpenMap.Builder typeBuilder = new ImmutableOpenMap.Builder<>(); - @SuppressWarnings("unchecked") - final Map fieldMappings = (Map) ((Map) entry.getValue()) - .get(MAPPINGS.getPreferredName()); - if (fieldMappings.isEmpty() == false) { - assert fieldMappings instanceof Map : "expected a map as inner type mapping, but got: " + fieldMappings.getClass(); - MappingMetaData mmd = new MappingMetaData(MapperService.SINGLE_MAPPING_NAME, fieldMappings); - typeBuilder.put(MapperService.SINGLE_MAPPING_NAME, mmd); + for (Map.Entry typeEntry : mapping.entrySet()) { + final String typeName = typeEntry.getKey(); + assert typeEntry.getValue() instanceof Map : "expected a map as inner type mapping, but got: " + + typeEntry.getValue().getClass(); + final Map fieldMappings = (Map) typeEntry.getValue(); + MappingMetaData mmd = new MappingMetaData(typeName, fieldMappings); + typeBuilder.put(typeName, mmd); } builder.put(indexName, typeBuilder.build()); } + return new GetMappingsResponse(builder.build()); } diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetMappingAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetMappingAction.java index 8826932e252..74f451ab30c 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetMappingAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetMappingAction.java @@ -60,8 +60,8 @@ import static org.elasticsearch.rest.RestRequest.Method.HEAD; public class RestGetMappingAction extends BaseRestHandler { private static final Logger logger = LogManager.getLogger(RestGetMappingAction.class); private static final DeprecationLogger deprecationLogger = new DeprecationLogger(logger); - static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Using include_type_name in get mapping requests is deprecated. " - + "The parameter will be removed in the next major version."; + public static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Using include_type_name in get" + + " mapping requests is deprecated. The parameter will be removed in the next major version."; public RestGetMappingAction(final Settings settings, final RestController controller) { super(settings); diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponseTests.java index 734de94b1c4..2b8db458eb8 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponseTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponseTests.java @@ -124,8 +124,8 @@ public class GetFieldMappingsResponseTests extends AbstractStreamableXContentTes } /** - * For now, we only unit test the legacy typed responses. This will soon no longer be the case, - * as we introduce support for typeless xContent parsing in {@link GetFieldMappingsResponse}. + * For xContent roundtrip testing we force the xContent output to still contain types because the parser + * still expects them. The new typeless parsing is implemented in the client side GetFieldMappingsResponse. */ @Override protected ToXContent.Params getToXContentParams() { diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/get/GetMappingsResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/get/GetMappingsResponseTests.java index 7d1a19c65ed..677a7b4b7ec 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/get/GetMappingsResponseTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/get/GetMappingsResponseTests.java @@ -20,13 +20,11 @@ package org.elasticsearch.action.admin.indices.mapping.get; import com.carrotsearch.hppc.cursors.ObjectCursor; - import org.elasticsearch.cluster.metadata.MappingMetaData; import org.elasticsearch.common.collect.ImmutableOpenMap; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent.Params; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.test.AbstractStreamableXContentTestCase; @@ -41,8 +39,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import static org.elasticsearch.test.AbstractXContentTestCase.xContentTester; - public class GetMappingsResponseTests extends AbstractStreamableXContentTestCase { @Override @@ -117,15 +113,20 @@ public class GetMappingsResponseTests extends AbstractStreamableXContentTestCase return typeBuilder.build(); } + /** + * For xContent roundtrip testing we force the xContent output to still contain types because the parser + * still expects them. The new typeless parsing is implemented in the client side GetMappingsResponse. + */ @Override - protected GetMappingsResponse createTestInstance() { - return createTestInstance(true); + protected Params getToXContentParams() { + return new ToXContent.MapParams(Collections.singletonMap(BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER, "true")); } - private GetMappingsResponse createTestInstance(boolean randomTypeNames) { + @Override + protected GetMappingsResponse createTestInstance() { ImmutableOpenMap.Builder> indexBuilder = ImmutableOpenMap.builder(); int typeCount = rarely() ? 0 : 1; - indexBuilder.put("index-" + randomAlphaOfLength(5), createMappingsForIndex(typeCount, randomTypeNames)); + indexBuilder.put("index-" + randomAlphaOfLength(5), createMappingsForIndex(typeCount, randomBoolean())); GetMappingsResponse resp = new GetMappingsResponse(indexBuilder.build()); logger.debug("--> created: {}", resp); return resp; @@ -163,57 +164,4 @@ public class GetMappingsResponseTests extends AbstractStreamableXContentTestCase } return mappings; } - - @Override - protected GetMappingsResponse createXContextTestInstance(XContentType xContentType) { - // don't use random type names for XContent roundtrip tests because we cannot parse them back anymore - return createTestInstance(false); - } - - /** - * check that the "old" legacy response format with types works as expected - */ - public void testToXContentWithTypes() throws IOException { - Params params = new ToXContent.MapParams(Collections.singletonMap(BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER, "true")); - xContentTester(this::createParser, t -> createTestInstance(), params, this::fromXContentWithTypes) - .numberOfTestRuns(NUMBER_OF_TEST_RUNS) - .supportsUnknownFields(supportsUnknownFields()) - .shuffleFieldsExceptions(getShuffleFieldsExceptions()) - .randomFieldsExcludeFilter(getRandomFieldsExcludeFilter()) - .assertEqualsConsumer(this::assertEqualInstances) - .assertToXContentEquivalence(true) - .test(); - } - - /** - * including the pre-7.0 parsing code here to test that older HLRC clients using this can parse the responses that are - * returned when "include_type_name=true" - */ - private GetMappingsResponse fromXContentWithTypes(XContentParser parser) throws IOException { - if (parser.currentToken() == null) { - parser.nextToken(); - } - assert parser.currentToken() == XContentParser.Token.START_OBJECT; - Map parts = parser.map(); - - ImmutableOpenMap.Builder> builder = new ImmutableOpenMap.Builder<>(); - for (Map.Entry entry : parts.entrySet()) { - final String indexName = entry.getKey(); - assert entry.getValue() instanceof Map : "expected a map as type mapping, but got: " + entry.getValue().getClass(); - final Map mapping = (Map) ((Map) entry.getValue()).get("mappings"); - - ImmutableOpenMap.Builder typeBuilder = new ImmutableOpenMap.Builder<>(); - for (Map.Entry typeEntry : mapping.entrySet()) { - final String typeName = typeEntry.getKey(); - assert typeEntry.getValue() instanceof Map : "expected a map as inner type mapping, but got: " - + typeEntry.getValue().getClass(); - final Map fieldMappings = (Map) typeEntry.getValue(); - MappingMetaData mmd = new MappingMetaData(typeName, fieldMappings); - typeBuilder.put(typeName, mmd); - } - builder.put(indexName, typeBuilder.build()); - } - - return new GetMappingsResponse(builder.build()); - } }