Prechádzať zdrojové kódy

Remove unused xContent serialization logic in transport objects. (#49346)

Previously, request and response objects related to index creation and mappings
were used in both the transport layer and HLRC. Now that they are no longer
shared, we can remove the extra xContent serialization + deserialization logic.
Julie Tibshirani 5 rokov pred
rodič
commit
17e9cd50e4

+ 0 - 45
server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java

@@ -26,12 +26,10 @@ 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.ConstructingObjectParser;
-import org.elasticsearch.common.xcontent.ObjectParser;
 import org.elasticsearch.common.xcontent.ToXContentFragment;
 import org.elasticsearch.common.xcontent.ToXContentObject;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentHelper;
-import org.elasticsearch.common.xcontent.XContentParser;
 import org.elasticsearch.common.xcontent.XContentType;
 import org.elasticsearch.index.mapper.Mapper;
 
@@ -42,8 +40,6 @@ import java.util.Map;
 import java.util.Objects;
 
 import static java.util.Collections.unmodifiableMap;
-import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
-import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
 
 /**
  * Response object for {@link GetFieldMappingsRequest} API
@@ -55,32 +51,6 @@ public class GetFieldMappingsResponse extends ActionResponse implements ToXConte
 
     private static final ParseField MAPPINGS = new ParseField("mappings");
 
-    private static final ObjectParser<Map<String, Map<String, FieldMappingMetaData>>, String> PARSER =
-        new ObjectParser<>(MAPPINGS.getPreferredName(), true, HashMap::new);
-
-    static {
-        PARSER.declareField((p, typeMappings, index) -> {
-            p.nextToken();
-            while (p.currentToken() == XContentParser.Token.FIELD_NAME) {
-                final String typeName = p.currentName();
-
-                if (p.nextToken() == XContentParser.Token.START_OBJECT) {
-                    final Map<String, FieldMappingMetaData> typeMapping = new HashMap<>();
-                    typeMappings.put(typeName, typeMapping);
-
-                    while (p.nextToken() == XContentParser.Token.FIELD_NAME) {
-                        final String fieldName = p.currentName();
-                        final FieldMappingMetaData fieldMappingMetaData = FieldMappingMetaData.fromXContent(p);
-                        typeMapping.put(fieldName, fieldMappingMetaData);
-                    }
-                } else {
-                    p.skipChildren();
-                }
-                p.nextToken();
-            }
-        }, MAPPINGS, ObjectParser.ValueType.OBJECT);
-    }
-
     // TODO remove the middle `type` level of this
     private final Map<String, Map<String, Map<String, FieldMappingMetaData>>> mappings;
 
@@ -178,17 +148,6 @@ public class GetFieldMappingsResponse extends ActionResponse implements ToXConte
                 a -> new FieldMappingMetaData((String)a[0], (BytesReference)a[1])
             );
 
-        static {
-            PARSER.declareField(optionalConstructorArg(),
-                (p, c) -> p.text(), FULL_NAME, ObjectParser.ValueType.STRING);
-            PARSER.declareField(optionalConstructorArg(),
-                (p, c) -> {
-                    final XContentBuilder jsonBuilder = jsonBuilder().copyCurrentStructure(p);
-                    final BytesReference bytes = BytesReference.bytes(jsonBuilder);
-                    return bytes;
-                }, MAPPING, ObjectParser.ValueType.OBJECT);
-        }
-
         private String fullName;
         private BytesReference source;
 
@@ -215,10 +174,6 @@ public class GetFieldMappingsResponse extends ActionResponse implements ToXConte
             return source;
         }
 
-        public static FieldMappingMetaData fromXContent(XContentParser parser) throws IOException {
-            return PARSER.parse(parser, null);
-        }
-
         @Override
         public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
             builder.field(FULL_NAME.getPreferredName(), fullName);

+ 1 - 15
server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java

@@ -32,7 +32,6 @@ import org.elasticsearch.common.bytes.BytesArray;
 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.ToXContentObject;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentFactory;
 import org.elasticsearch.common.xcontent.XContentHelper;
@@ -41,7 +40,6 @@ import org.elasticsearch.index.Index;
 import org.elasticsearch.index.mapper.MapperService;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.UncheckedIOException;
 import java.util.Arrays;
 import java.util.Map;
@@ -60,7 +58,7 @@ import static org.elasticsearch.action.ValidateActions.addValidationError;
  * @see org.elasticsearch.client.IndicesAdminClient#putMapping(PutMappingRequest)
  * @see AcknowledgedResponse
  */
-public class PutMappingRequest extends AcknowledgedRequest<PutMappingRequest> implements IndicesRequest.Replaceable, ToXContentObject {
+public class PutMappingRequest extends AcknowledgedRequest<PutMappingRequest> implements IndicesRequest.Replaceable {
 
     private static ObjectHashSet<String> RESERVED_FIELDS = ObjectHashSet.from(
             "_uid", "_id", "_type", "_source",  "_all", "_analyzer", "_parent", "_routing", "_index",
@@ -306,16 +304,4 @@ public class PutMappingRequest extends AcknowledgedRequest<PutMappingRequest> im
         out.writeOptionalWriteable(concreteIndex);
         out.writeOptionalString(origin);
     }
-
-    @Override
-    public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
-        if (source != null) {
-            try (InputStream stream = new BytesArray(source).streamInput()) {
-                builder.rawValue(stream, XContentType.JSON);
-            }
-        } else {
-            builder.startObject().endObject();
-        }
-        return builder;
-    }
 }

+ 0 - 23
server/src/main/java/org/elasticsearch/action/admin/indices/rollover/RolloverResponse.java

@@ -23,19 +23,14 @@ import org.elasticsearch.action.support.master.ShardsAcknowledgedResponse;
 import org.elasticsearch.common.ParseField;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
-import org.elasticsearch.common.xcontent.ConstructingObjectParser;
-import org.elasticsearch.common.xcontent.ObjectParser;
 import org.elasticsearch.common.xcontent.ToXContentObject;
 import org.elasticsearch.common.xcontent.XContentBuilder;
-import org.elasticsearch.common.xcontent.XContentParser;
 
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 
-import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
-
 
 /**
  * Response object for {@link RolloverRequest} API
@@ -51,20 +46,6 @@ public final class RolloverResponse extends ShardsAcknowledgedResponse implement
     private static final ParseField ROLLED_OVER = new ParseField("rolled_over");
     private static final ParseField CONDITIONS = new ParseField("conditions");
 
-    @SuppressWarnings("unchecked")
-    private static final ConstructingObjectParser<RolloverResponse, Void> PARSER = new ConstructingObjectParser<>("rollover",
-            true, args -> new RolloverResponse((String) args[0], (String) args[1], (Map<String,Boolean>) args[2],
-            (Boolean)args[3], (Boolean)args[4], (Boolean) args[5], (Boolean) args[6]));
-
-    static {
-        PARSER.declareField(constructorArg(), (parser, context) -> parser.text(), OLD_INDEX, ObjectParser.ValueType.STRING);
-        PARSER.declareField(constructorArg(), (parser, context) -> parser.text(), NEW_INDEX, ObjectParser.ValueType.STRING);
-        PARSER.declareObject(constructorArg(), (parser, context) -> parser.map(), CONDITIONS);
-        PARSER.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), DRY_RUN, ObjectParser.ValueType.BOOLEAN);
-        PARSER.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), ROLLED_OVER, ObjectParser.ValueType.BOOLEAN);
-        declareAcknowledgedAndShardsAcknowledgedFields(PARSER);
-    }
-
     private final String oldIndex;
     private final String newIndex;
     private final Map<String, Boolean> conditionStatus;
@@ -168,10 +149,6 @@ public final class RolloverResponse extends ShardsAcknowledgedResponse implement
         builder.endObject();
     }
 
-    public static RolloverResponse fromXContent(XContentParser parser) {
-        return PARSER.apply(parser, null);
-    }
-
     @Override
     public boolean equals(Object o) {
         if (super.equals(o)) {

+ 3 - 40
server/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequest.java

@@ -35,16 +35,13 @@ import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.common.logging.DeprecationLogger;
 import org.elasticsearch.common.settings.Settings;
-import org.elasticsearch.common.xcontent.DeprecationHandler;
 import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
 import org.elasticsearch.common.xcontent.NamedXContentRegistry;
-import org.elasticsearch.common.xcontent.ToXContentObject;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentFactory;
 import org.elasticsearch.common.xcontent.XContentHelper;
 import org.elasticsearch.common.xcontent.XContentParser;
 import org.elasticsearch.common.xcontent.XContentType;
-import org.elasticsearch.common.xcontent.json.JsonXContent;
 import org.elasticsearch.common.xcontent.support.XContentMapValues;
 
 import java.io.IOException;
@@ -58,14 +55,14 @@ import java.util.Set;
 import java.util.stream.Collectors;
 
 import static org.elasticsearch.action.ValidateActions.addValidationError;
+import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS;
 import static org.elasticsearch.common.settings.Settings.readSettingsFromStream;
 import static org.elasticsearch.common.settings.Settings.writeSettingsToStream;
-import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS;
 
 /**
  * A request to create an index template.
  */
-public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateRequest> implements IndicesRequest, ToXContentObject {
+public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateRequest> implements IndicesRequest {
 
     private static final DeprecationLogger deprecationLogger = new DeprecationLogger(LogManager.getLogger(PutIndexTemplateRequest.class));
 
@@ -339,7 +336,7 @@ public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateR
                     List<String> elements = ((List<?>) entry.getValue()).stream().map(Object::toString).collect(Collectors.toList());
                     patterns(elements);
                 } else {
-                    throw new IllegalArgumentException("Malformed [template] value, should be a string or a list of strings");
+                    throw new IllegalArgumentException("Malformed [index_patterns] value, should be a string or a list of strings");
                 }
             } else if (name.equals("order")) {
                 order(XContentMapValues.nodeIntegerValue(entry.getValue(), order()));
@@ -490,38 +487,4 @@ public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateR
         }
         out.writeOptionalVInt(version);
     }
-
-    @Override
-    public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
-        builder.startObject();
-        {
-            builder.field("index_patterns", indexPatterns);
-            builder.field("order", order);
-            if (version != null) {
-                builder.field("version", version);
-            }
-
-            builder.startObject("settings");
-            settings.toXContent(builder, params);
-            builder.endObject();
-
-            builder.startObject("mappings");
-            for (Map.Entry<String, String> entry : mappings.entrySet()) {
-                builder.field(entry.getKey());
-                try (XContentParser parser = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY,
-                        DeprecationHandler.THROW_UNSUPPORTED_OPERATION, entry.getValue())) {
-                    builder.copyCurrentStructure(parser);
-                }
-            }
-            builder.endObject();
-
-            builder.startObject("aliases");
-            for (Alias alias : aliases) {
-                alias.toXContent(builder, params);
-            }
-            builder.endObject();
-        }
-        builder.endObject();
-        return builder;
-    }
 }

+ 0 - 67
server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java

@@ -20,20 +20,10 @@
 package org.elasticsearch.action.admin.indices.mapping.put;
 
 import org.elasticsearch.action.ActionRequestValidationException;
-import org.elasticsearch.common.Strings;
-import org.elasticsearch.common.bytes.BytesReference;
-import org.elasticsearch.common.xcontent.XContentBuilder;
-import org.elasticsearch.common.xcontent.XContentParser;
 import org.elasticsearch.common.xcontent.XContentType;
-import org.elasticsearch.common.xcontent.json.JsonXContent;
 import org.elasticsearch.index.Index;
-import org.elasticsearch.index.RandomCreateIndexGenerator;
 import org.elasticsearch.test.ESTestCase;
 
-import java.io.IOException;
-
-import static org.elasticsearch.common.xcontent.ToXContent.EMPTY_PARAMS;
-
 public class PutMappingRequestTests extends ESTestCase {
 
     public void testValidation() {
@@ -69,61 +59,4 @@ public class PutMappingRequestTests extends ESTestCase {
                 () -> PutMappingRequest.buildFromSimplifiedDef("type", "only_field"));
         assertEquals("mapping source must be pairs of fieldnames and properties definition.", e.getMessage());
     }
-
-    public void testToXContent() throws IOException {
-        PutMappingRequest request = new PutMappingRequest("foo");
-
-        XContentBuilder mapping = JsonXContent.contentBuilder().startObject();
-        mapping.startObject("properties");
-        mapping.startObject("email");
-        mapping.field("type", "text");
-        mapping.endObject();
-        mapping.endObject();
-        mapping.endObject();
-        request.source(mapping);
-
-        String actualRequestBody = Strings.toString(request);
-        String expectedRequestBody = "{\"properties\":{\"email\":{\"type\":\"text\"}}}";
-        assertEquals(expectedRequestBody, actualRequestBody);
-    }
-
-    public void testToXContentWithEmptySource() throws IOException {
-        PutMappingRequest request = new PutMappingRequest("foo");
-
-        String actualRequestBody = Strings.toString(request);
-        String expectedRequestBody = "{}";
-        assertEquals(expectedRequestBody, actualRequestBody);
-    }
-
-    public void testToAndFromXContent() throws IOException {
-
-        final PutMappingRequest putMappingRequest = createTestItem();
-
-        boolean humanReadable = randomBoolean();
-        final XContentType xContentType = randomFrom(XContentType.values());
-        BytesReference originalBytes = toShuffledXContent(putMappingRequest, xContentType, EMPTY_PARAMS, humanReadable);
-
-        PutMappingRequest parsedPutMappingRequest = new PutMappingRequest();
-        parsedPutMappingRequest.source(originalBytes, xContentType);
-
-        assertMappingsEqual(putMappingRequest.source(), parsedPutMappingRequest.source());
-    }
-
-    private void assertMappingsEqual(String expected, String actual) throws IOException {
-
-        try (XContentParser expectedJson = createParser(XContentType.JSON.xContent(), expected);
-            XContentParser actualJson = createParser(XContentType.JSON.xContent(), actual)) {
-            assertEquals(expectedJson.mapOrdered(), actualJson.mapOrdered());
-        }
-    }
-
-    /**
-     * Returns a random {@link PutMappingRequest}.
-     */
-    private static PutMappingRequest createTestItem() throws IOException {
-        String index = randomAlphaOfLength(5);
-        PutMappingRequest request = new PutMappingRequest(index);
-        request.source(RandomCreateIndexGenerator.randomMapping("_doc"));
-        return request;
-    }
 }

+ 6 - 11
server/src/test/java/org/elasticsearch/action/admin/indices/rollover/RolloverResponseTests.java

@@ -19,20 +19,20 @@
 
 package org.elasticsearch.action.admin.indices.rollover;
 
+import org.elasticsearch.Version;
 import org.elasticsearch.common.io.stream.Writeable;
 import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.common.unit.TimeValue;
-import org.elasticsearch.common.xcontent.XContentParser;
-import org.elasticsearch.test.AbstractSerializingTestCase;
+import org.elasticsearch.test.AbstractWireTestCase;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.function.Predicate;
 import java.util.function.Supplier;
 
-public class RolloverResponseTests extends AbstractSerializingTestCase<RolloverResponse> {
+public class RolloverResponseTests extends AbstractWireTestCase<RolloverResponse> {
 
     @Override
     protected RolloverResponse createTestInstance() {
@@ -66,13 +66,8 @@ public class RolloverResponseTests extends AbstractSerializingTestCase<RolloverR
     }
 
     @Override
-    protected RolloverResponse doParseInstance(XContentParser parser) {
-        return RolloverResponse.fromXContent(parser);
-    }
-
-    @Override
-    protected Predicate<String> getRandomFieldsExcludeFilter() {
-        return field -> field.startsWith("conditions");
+    protected RolloverResponse copyInstance(RolloverResponse instance, Version version) throws IOException {
+        return copyWriteable(instance, writableRegistry(), RolloverResponse::new);
     }
 
     @Override

+ 81 - 60
server/src/test/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequestTests.java

@@ -24,25 +24,24 @@ import org.elasticsearch.common.collect.MapBuilder;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentFactory;
-import org.elasticsearch.common.xcontent.XContentParser;
 import org.elasticsearch.common.xcontent.XContentType;
-import org.elasticsearch.test.AbstractXContentTestCase;
+import org.elasticsearch.test.ESTestCase;
 
 import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Map;
 
+import static org.hamcrest.Matchers.containsInAnyOrder;
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasKey;
 import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.nullValue;
 import static org.hamcrest.core.Is.is;
 
-public class PutIndexTemplateRequestTests extends AbstractXContentTestCase<PutIndexTemplateRequest> {
+public class PutIndexTemplateRequestTests extends ESTestCase {
 
-    public void testValidateErrorMessage() throws Exception {
+    public void testValidateErrorMessage() {
         PutIndexTemplateRequest request = new PutIndexTemplateRequest();
         ActionRequestValidationException withoutNameAndPattern = request.validate();
         assertThat(withoutNameAndPattern.getMessage(), containsString("name is missing"));
@@ -119,64 +118,86 @@ public class PutIndexTemplateRequestTests extends AbstractXContentTestCase<PutIn
         }
     }
 
-    @Override
-    protected PutIndexTemplateRequest createTestInstance() {
+    public void testSourceParsing() throws IOException {
+        XContentBuilder indexPatterns = XContentFactory.jsonBuilder().startObject()
+            .array("index_patterns", "index-*", "other-index-*")
+            .field("version", 2)
+            .field("order", 5)
+            .startObject("settings")
+                .field("index.refresh_interval", "-1")
+                .field("index.number_of_replicas", 2)
+            .endObject()
+            .startObject("mappings")
+                .startObject("_doc")
+                    .startObject("properties")
+                        .startObject("field")
+                            .field("type", "keyword")
+                        .endObject()
+                    .endObject()
+                .endObject()
+            .endObject()
+            .startObject("aliases")
+                .startObject("my-alias").endObject()
+            .endObject()
+        .endObject();
+
         PutIndexTemplateRequest request = new PutIndexTemplateRequest();
-        request.name("test");
-        if (randomBoolean()) {
-            request.version(randomInt());
-        }
-        if (randomBoolean()) {
-            request.order(randomInt());
-        }
-        request.patterns(Arrays.asList(generateRandomStringArray(20, 100, false, false)));
-        int numAlias = between(0, 5);
-        for (int i = 0; i < numAlias; i++) {
-            // some ASCII or Latin-1 control characters, especially newline, can lead to
-            // problems with yaml parsers, that's why we filter them here (see #30911)
-            Alias alias = new Alias(randomRealisticUnicodeOfLengthBetween(1, 10).replaceAll("\\p{Cc}", ""));
-            if (randomBoolean()) {
-                alias.indexRouting(randomRealisticUnicodeOfLengthBetween(1, 10));
-            }
-            if (randomBoolean()) {
-                alias.searchRouting(randomRealisticUnicodeOfLengthBetween(1, 10));
-            }
-            request.alias(alias);
-        }
-        if (randomBoolean()) {
-            try {
-                request.mapping("doc", XContentFactory.jsonBuilder().startObject()
-                    .startObject("doc").startObject("properties")
-                    .startObject("field-" + randomInt()).field("type", randomFrom("keyword", "text")).endObject()
-                    .endObject().endObject().endObject());
-            } catch (IOException ex) {
-                throw new UncheckedIOException(ex);
-            }
-        }
-        if (randomBoolean()) {
-            request.settings(Settings.builder().put("setting1", randomLong()).put("setting2", randomTimeValue()).build());
-        }
-        return request;
-    }
+        request.source(indexPatterns);
 
-    @Override
-    protected PutIndexTemplateRequest doParseInstance(XContentParser parser) throws IOException {
-        return new PutIndexTemplateRequest().source(parser.map());
-    }
+        assertThat(request.patterns(), containsInAnyOrder("index-*", "other-index-*"));
+        assertThat(request.version(), equalTo(2));
+        assertThat(request.order(), equalTo(5));
+
+        Settings settings = Settings.builder()
+            .put("index.refresh_interval", "-1")
+            .put("index.number_of_replicas", 2)
+            .build();
+        assertThat(request.settings(), equalTo(settings));
+
+        assertThat(request.mappings(), hasKey("_doc"));
 
-    @Override
-    protected void assertEqualInstances(PutIndexTemplateRequest expected, PutIndexTemplateRequest actual) {
-        assertNotSame(expected, actual);
-        assertThat(actual.version(), equalTo(expected.version()));
-        assertThat(actual.order(), equalTo(expected.order()));
-        assertThat(actual.patterns(), equalTo(expected.patterns()));
-        assertThat(actual.aliases(), equalTo(expected.aliases()));
-        assertThat(actual.mappings(), equalTo(expected.mappings()));
-        assertThat(actual.settings(), equalTo(expected.settings()));
+        Alias alias = new Alias("my-alias");
+        assertThat(request.aliases().size(), equalTo(1));
+        assertThat(request.aliases().iterator().next(), equalTo(alias));
     }
 
-    @Override
-    protected boolean supportsUnknownFields() {
-        return false;
+    public void testSourceValidation() throws IOException {
+        XContentBuilder indexPatterns = XContentFactory.jsonBuilder().startObject()
+            .startObject("index_patterns")
+                .field("my-pattern", "index-*")
+            .endObject()
+        .endObject();
+        IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
+            () -> new PutIndexTemplateRequest().source(indexPatterns));
+        assertThat(e.getCause().getMessage(), containsString("Malformed [index_patterns] value"));
+
+        XContentBuilder version = XContentFactory.jsonBuilder().startObject()
+            .field("version", "v6.5.4")
+        .endObject();
+        e = expectThrows(IllegalArgumentException.class,() -> new PutIndexTemplateRequest().source(version));
+        assertThat(e.getCause().getMessage(), containsString("Malformed [version] value"));
+
+        XContentBuilder settings = XContentFactory.jsonBuilder().startObject()
+            .field("settings", "index.number_of_replicas")
+        .endObject();
+        e = expectThrows(IllegalArgumentException.class, () -> new PutIndexTemplateRequest().source(settings));
+        assertThat(e.getCause().getMessage(), containsString("Malformed [settings] section"));
+
+        XContentBuilder mappings = XContentFactory.jsonBuilder().startObject()
+            .startObject("mappings")
+                .field("_doc", "value")
+            .endObject()
+        .endObject();
+        e = expectThrows(IllegalArgumentException.class, () -> new PutIndexTemplateRequest().source(mappings));
+        assertThat(e.getCause().getMessage(), containsString("Malformed [mappings] section"));
+
+        XContentBuilder extraField = XContentFactory.jsonBuilder().startObject()
+            .startObject("settings")
+                .field("index.number_of_replicas", 2)
+            .endObject()
+            .field("extra-field", "value")
+        .endObject();
+        e = expectThrows(IllegalArgumentException.class, () -> new PutIndexTemplateRequest().source(extraField));
+        assertThat(e.getCause().getMessage(), containsString("unknown key [extra-field] in the template"));
     }
 }