diff --git a/spring-boot-actuator/pom.xml b/spring-boot-actuator/pom.xml
index cf323298cb..1b23af54ca 100644
--- a/spring-boot-actuator/pom.xml
+++ b/spring-boot-actuator/pom.xml
@@ -46,6 +46,11 @@
jackson-dataformat-xml
true
+
+ io.searchbox
+ jest
+ true
+
org.springframework.hateoas
spring-hateoas
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CompositeHealthIndicatorConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CompositeHealthIndicatorConfiguration.java
new file mode 100644
index 0000000000..33dc0885e6
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CompositeHealthIndicatorConfiguration.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed 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.springframework.boot.actuate.autoconfigure;
+
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.actuate.health.CompositeHealthIndicator;
+import org.springframework.boot.actuate.health.HealthAggregator;
+import org.springframework.boot.actuate.health.HealthIndicator;
+import org.springframework.core.ResolvableType;
+
+/**
+ * Base class for configurations that can combine source beans using a
+ * {@link CompositeHealthIndicator}.
+ *
+ * @param The health indicator type
+ * @param T he bean source type
+ * @since 1.4.0
+ */
+public abstract class CompositeHealthIndicatorConfiguration {
+
+ @Autowired
+ private HealthAggregator healthAggregator;
+
+ protected HealthIndicator createHealthIndicator(Map beans) {
+ if (beans.size() == 1) {
+ return createHealthIndicator(beans.values().iterator().next());
+ }
+ CompositeHealthIndicator composite = new CompositeHealthIndicator(
+ this.healthAggregator);
+ for (Map.Entry entry : beans.entrySet()) {
+ composite.addHealthIndicator(entry.getKey(),
+ createHealthIndicator(entry.getValue()));
+ }
+ return composite;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected H createHealthIndicator(S source) {
+ Class>[] generics = ResolvableType
+ .forClass(CompositeHealthIndicatorConfiguration.class, getClass())
+ .resolveGenerics();
+ Class indicatorClass = (Class) generics[0];
+ Class sourceClass = (Class) generics[1];
+ try {
+ return indicatorClass.getConstructor(sourceClass).newInstance(source);
+ }
+ catch (Exception ex) {
+ throw new IllegalStateException("Unable to create indicator "
+ + indicatorClass + " for source " + sourceClass, ex);
+ }
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ElasticsearchHealthIndicatorConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ElasticsearchHealthIndicatorConfiguration.java
new file mode 100644
index 0000000000..fd5e81915b
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ElasticsearchHealthIndicatorConfiguration.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed 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.springframework.boot.actuate.autoconfigure;
+
+import java.util.Map;
+
+import io.searchbox.client.JestClient;
+import org.elasticsearch.client.Client;
+
+import org.springframework.boot.actuate.health.ElasticsearchHealthIndicator;
+import org.springframework.boot.actuate.health.ElasticsearchHealthIndicatorProperties;
+import org.springframework.boot.actuate.health.ElasticsearchJestHealthIndicator;
+import org.springframework.boot.actuate.health.HealthIndicator;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Actual ElasticSearch health indicator configurations imported by
+ * {@link HealthIndicatorAutoConfiguration}.
+ *
+ * @author Stephane Nicoll
+ */
+class ElasticsearchHealthIndicatorConfiguration {
+
+ @Configuration
+ @ConditionalOnBean(Client.class)
+ @ConditionalOnEnabledHealthIndicator("elasticsearch")
+ @EnableConfigurationProperties(ElasticsearchHealthIndicatorProperties.class)
+ static class SpringData extends
+ CompositeHealthIndicatorConfiguration {
+
+ private final Map clients;
+
+ private final ElasticsearchHealthIndicatorProperties properties;
+
+ SpringData(Map clients,
+ ElasticsearchHealthIndicatorProperties properties) {
+ this.clients = clients;
+ this.properties = properties;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(name = "elasticsearchHealthIndicator")
+ public HealthIndicator elasticsearchHealthIndicator() {
+ return createHealthIndicator(this.clients);
+ }
+
+ @Override
+ protected ElasticsearchHealthIndicator createHealthIndicator(Client client) {
+ return new ElasticsearchHealthIndicator(client, this.properties);
+ }
+
+ }
+
+ @Configuration
+ @ConditionalOnBean(JestClient.class)
+ @ConditionalOnEnabledHealthIndicator("elasticsearch")
+ static class Jest extends
+ CompositeHealthIndicatorConfiguration {
+
+ private final Map clients;
+
+ Jest(Map clients) {
+ this.clients = clients;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(name = "elasticsearchHealthIndicator")
+ public HealthIndicator elasticsearchHealthIndicator() {
+ return createHealthIndicator(this.clients);
+ }
+
+ @Override
+ protected ElasticsearchJestHealthIndicator createHealthIndicator(JestClient client) {
+ return new ElasticsearchJestHealthIndicator(client);
+ }
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java
index c6ee089620..5b9dd66540 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java
@@ -25,21 +25,16 @@ import javax.sql.DataSource;
import com.couchbase.client.java.Bucket;
import com.datastax.driver.core.Cluster;
import org.apache.solr.client.solrj.SolrClient;
-import org.elasticsearch.client.Client;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ObjectProvider;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.ApplicationHealthIndicator;
import org.springframework.boot.actuate.health.CassandraHealthIndicator;
-import org.springframework.boot.actuate.health.CompositeHealthIndicator;
import org.springframework.boot.actuate.health.CouchbaseHealthIndicator;
import org.springframework.boot.actuate.health.DataSourceHealthIndicator;
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicator;
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorProperties;
-import org.springframework.boot.actuate.health.ElasticsearchHealthIndicator;
-import org.springframework.boot.actuate.health.ElasticsearchHealthIndicatorProperties;
import org.springframework.boot.actuate.health.HealthAggregator;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.JmsHealthIndicator;
@@ -66,6 +61,7 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadata;
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvider;
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProviders;
+import org.springframework.boot.autoconfigure.jest.JestAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
import org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
@@ -73,7 +69,7 @@ import org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.core.ResolvableType;
+import org.springframework.context.annotation.Import;
import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
@@ -96,12 +92,14 @@ import org.springframework.mail.javamail.JavaMailSenderImpl;
@AutoConfigureBefore({ EndpointAutoConfiguration.class })
@AutoConfigureAfter({ CassandraAutoConfiguration.class,
CassandraDataAutoConfiguration.class, CouchbaseAutoConfiguration.class,
- DataSourceAutoConfiguration.class, MongoAutoConfiguration.class,
- MongoDataAutoConfiguration.class, RedisAutoConfiguration.class,
- RabbitAutoConfiguration.class, SolrAutoConfiguration.class,
- MailSenderAutoConfiguration.class, JmsAutoConfiguration.class,
- ElasticsearchAutoConfiguration.class })
+ DataSourceAutoConfiguration.class, ElasticsearchAutoConfiguration.class,
+ JestAutoConfiguration.class, JmsAutoConfiguration.class,
+ MailSenderAutoConfiguration.class, MongoAutoConfiguration.class,
+ MongoDataAutoConfiguration.class, RabbitAutoConfiguration.class,
+ RedisAutoConfiguration.class, SolrAutoConfiguration.class })
@EnableConfigurationProperties({ HealthIndicatorProperties.class })
+@Import({ ElasticsearchHealthIndicatorConfiguration.SpringData.class,
+ ElasticsearchHealthIndicatorConfiguration.Jest.class })
public class HealthIndicatorAutoConfiguration {
private final HealthIndicatorProperties properties;
@@ -126,48 +124,6 @@ public class HealthIndicatorAutoConfiguration {
return new ApplicationHealthIndicator();
}
- /**
- * Base class for configurations that can combine source beans using a
- * {@link CompositeHealthIndicator}.
- * @param The health indicator type
- * @param The bean source type
- */
- protected static abstract class CompositeHealthIndicatorConfiguration {
-
- @Autowired
- private HealthAggregator healthAggregator;
-
- protected HealthIndicator createHealthIndicator(Map beans) {
- if (beans.size() == 1) {
- return createHealthIndicator(beans.values().iterator().next());
- }
- CompositeHealthIndicator composite = new CompositeHealthIndicator(
- this.healthAggregator);
- for (Map.Entry entry : beans.entrySet()) {
- composite.addHealthIndicator(entry.getKey(),
- createHealthIndicator(entry.getValue()));
- }
- return composite;
- }
-
- @SuppressWarnings("unchecked")
- protected H createHealthIndicator(S source) {
- Class>[] generics = ResolvableType
- .forClass(CompositeHealthIndicatorConfiguration.class, getClass())
- .resolveGenerics();
- Class indicatorClass = (Class) generics[0];
- Class sourceClass = (Class) generics[1];
- try {
- return indicatorClass.getConstructor(sourceClass).newInstance(source);
- }
- catch (Exception ex) {
- throw new IllegalStateException("Unable to create indicator "
- + indicatorClass + " for source " + sourceClass, ex);
- }
- }
-
- }
-
@Configuration
@ConditionalOnClass({ CassandraOperations.class, Cluster.class })
@ConditionalOnBean(CassandraOperations.class)
@@ -401,34 +357,4 @@ public class HealthIndicatorAutoConfiguration {
}
- @Configuration
- @ConditionalOnBean(Client.class)
- @ConditionalOnEnabledHealthIndicator("elasticsearch")
- @EnableConfigurationProperties(ElasticsearchHealthIndicatorProperties.class)
- public static class ElasticsearchHealthIndicatorConfiguration extends
- CompositeHealthIndicatorConfiguration {
-
- private final Map clients;
-
- private final ElasticsearchHealthIndicatorProperties properties;
-
- public ElasticsearchHealthIndicatorConfiguration(Map clients,
- ElasticsearchHealthIndicatorProperties properties) {
- this.clients = clients;
- this.properties = properties;
- }
-
- @Bean
- @ConditionalOnMissingBean(name = "elasticsearchHealthIndicator")
- public HealthIndicator elasticsearchHealthIndicator() {
- return createHealthIndicator(this.clients);
- }
-
- @Override
- protected ElasticsearchHealthIndicator createHealthIndicator(Client client) {
- return new ElasticsearchHealthIndicator(client, this.properties);
- }
-
- }
-
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ElasticsearchJestHealthIndicator.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ElasticsearchJestHealthIndicator.java
new file mode 100644
index 0000000000..792a7d81eb
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ElasticsearchJestHealthIndicator.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed 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.springframework.boot.actuate.health;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import io.searchbox.client.JestClient;
+import io.searchbox.client.JestResult;
+import io.searchbox.indices.Stats;
+
+/**
+ * {@link HealthIndicator} for Elasticsearch using a {@link JestClient}.
+ *
+ * @author Stephane Nicoll
+ * @since 1.4.0
+ */
+public class ElasticsearchJestHealthIndicator extends AbstractHealthIndicator {
+
+ private final JestClient jestClient;
+
+ public ElasticsearchJestHealthIndicator(JestClient jestClient) {
+ this.jestClient = jestClient;
+ }
+
+ @Override
+ protected void doHealthCheck(Health.Builder builder) throws Exception {
+ JestResult aliases = this.jestClient.execute(new Stats.Builder().build());
+ JsonParser jsonParser = new JsonParser();
+ JsonElement root = jsonParser.parse(aliases.getJsonString());
+ JsonObject shards = root.getAsJsonObject().get("_shards").getAsJsonObject();
+ int failedShards = shards.get("failed").getAsInt();
+ if (failedShards != 0) {
+ builder.outOfService();
+ }
+ else {
+ builder.up();
+ }
+ }
+
+}
diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java
index 7d9f2d5579..090564f60f 100644
--- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java
+++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java
@@ -20,6 +20,7 @@ import java.util.Map;
import javax.sql.DataSource;
+import io.searchbox.client.JestClient;
import org.junit.After;
import org.junit.Test;
@@ -29,6 +30,7 @@ import org.springframework.boot.actuate.health.CouchbaseHealthIndicator;
import org.springframework.boot.actuate.health.DataSourceHealthIndicator;
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicator;
import org.springframework.boot.actuate.health.ElasticsearchHealthIndicator;
+import org.springframework.boot.actuate.health.ElasticsearchJestHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.JmsHealthIndicator;
@@ -46,6 +48,7 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration;
+import org.springframework.boot.autoconfigure.jest.JestAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration;
import org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
@@ -395,7 +398,8 @@ public class HealthIndicatorAutoConfigurationTests {
EnvironmentTestUtils.addEnvironment(this.context,
"spring.data.elasticsearch.properties.path.home:target",
"management.health.diskspace.enabled:false");
- this.context.register(ElasticsearchAutoConfiguration.class,
+ this.context.register(JestClientConfiguration.class,
+ JestAutoConfiguration.class, ElasticsearchAutoConfiguration.class,
ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class);
this.context.refresh();
@@ -406,13 +410,30 @@ public class HealthIndicatorAutoConfigurationTests {
.isEqualTo(ElasticsearchHealthIndicator.class);
}
+ @Test
+ public void elasticSearchJestHealthIndicator() {
+ EnvironmentTestUtils.addEnvironment(this.context,
+ "management.health.diskspace.enabled:false");
+ this.context.register(JestClientConfiguration.class,
+ JestAutoConfiguration.class, ManagementServerProperties.class,
+ HealthIndicatorAutoConfiguration.class);
+ this.context.refresh();
+
+ Map beans = this.context
+ .getBeansOfType(HealthIndicator.class);
+ assertThat(beans).hasSize(1);
+ assertThat(beans.values().iterator().next().getClass())
+ .isEqualTo(ElasticsearchJestHealthIndicator.class);
+ }
+
@Test
public void notElasticSearchHealthIndicator() {
EnvironmentTestUtils.addEnvironment(this.context,
"management.health.elasticsearch.enabled:false",
"spring.data.elasticsearch.properties.path.home:target",
"management.health.diskspace.enabled:false");
- this.context.register(ElasticsearchAutoConfiguration.class,
+ this.context.register(JestClientConfiguration.class,
+ JestAutoConfiguration.class, ElasticsearchAutoConfiguration.class,
ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class);
this.context.refresh();
@@ -502,4 +523,12 @@ public class HealthIndicatorAutoConfigurationTests {
}
+ protected static class JestClientConfiguration {
+
+ @Bean
+ public JestClient jestClient() {
+ return mock(JestClient.class);
+ }
+ }
+
}
diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ElasticsearchJestHealthIndicatorTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ElasticsearchJestHealthIndicatorTests.java
new file mode 100644
index 0000000000..2724b8d653
--- /dev/null
+++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ElasticsearchJestHealthIndicatorTests.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed 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.springframework.boot.actuate.health;
+
+import java.io.IOException;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonParser;
+import io.searchbox.action.Action;
+import io.searchbox.client.JestClient;
+import io.searchbox.client.JestResult;
+import io.searchbox.client.config.exception.CouldNotConnectException;
+import io.searchbox.core.SearchResult;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link ElasticsearchJestHealthIndicator}.
+ *
+ * @author Stephane Nicoll
+ */
+public class ElasticsearchJestHealthIndicatorTests {
+
+ private final JestClient jestClient = mock(JestClient.class);
+
+ private final ElasticsearchJestHealthIndicator healthIndicator =
+ new ElasticsearchJestHealthIndicator(this.jestClient);
+
+ @Test
+ public void elasticSearchIsUp() throws IOException {
+ given(this.jestClient.execute(any(Action.class)))
+ .willReturn(createJestResult(4, 0));
+
+ Health health = this.healthIndicator.health();
+ assertThat(health.getStatus()).isEqualTo(Status.UP);
+ }
+ @Test
+ public void elasticSearchIsDown() throws IOException {
+ given(this.jestClient.execute(any(Action.class))).willThrow(
+ new CouldNotConnectException("http://localhost:9200", new IOException()));
+
+ Health health = this.healthIndicator.health();
+ assertThat(health.getStatus()).isEqualTo(Status.DOWN);
+ }
+
+ @Test
+ public void elasticSearchIsOutOfService() throws IOException {
+ given(this.jestClient.execute(any(Action.class)))
+ .willReturn(createJestResult(4, 1));
+
+ Health health = this.healthIndicator.health();
+ assertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);
+ }
+
+ private static JestResult createJestResult(int shards, int failedShards) {
+ String json = String.format("{_shards: {\n" +
+ "total: %s,\n" +
+ "successful: %s,\n" +
+ "failed: %s\n" +
+ "}}", shards, shards - failedShards, failedShards);
+
+ SearchResult searchResult = new SearchResult(new Gson());
+ searchResult.setJsonString(json);
+ searchResult.setJsonObject(new JsonParser().parse(json).getAsJsonObject());
+ return searchResult;
+ }
+
+}