From a76809dd0a56666214f596d6de633cfe425d377b Mon Sep 17 00:00:00 2001 From: Jakub Vavrik Date: Tue, 19 Nov 2013 10:44:53 +0100 Subject: [PATCH] Added DefaultMapper support to map only partial fields from result instead of whole source field. --- .../core/DefaultResultMapper.java | 44 ++++++++++++++++++- .../core/DefaultResultMapperTests.java | 40 +++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/springframework/data/elasticsearch/core/DefaultResultMapper.java b/src/main/java/org/springframework/data/elasticsearch/core/DefaultResultMapper.java index 6da45520c..ab293b418 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/DefaultResultMapper.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/DefaultResultMapper.java @@ -1,14 +1,23 @@ package org.springframework.data.elasticsearch.core; + import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.common.base.Strings; +import org.elasticsearch.common.jackson.core.JsonEncoding; +import org.elasticsearch.common.jackson.core.JsonFactory; +import org.elasticsearch.common.jackson.core.JsonGenerator; import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.SearchHitField; import org.elasticsearch.search.facet.Facet; import org.springframework.data.domain.Pageable; import org.springframework.data.elasticsearch.core.facet.DefaultFacetMapper; import org.springframework.data.elasticsearch.core.facet.FacetResult; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.List; /** @@ -30,7 +39,11 @@ public class DefaultResultMapper extends AbstractResultMapper { List results = new ArrayList(); for (SearchHit hit : response.getHits()) { if (hit != null) { - results.add(mapEntity(hit.sourceAsString(), clazz)); + if (!Strings.isNullOrEmpty(hit.sourceAsString())) { + results.add(mapEntity(hit.sourceAsString(), clazz)); + } else { + results.add(mapEntity(hit.getFields().values(), clazz)); + } } } List facets = new ArrayList(); @@ -46,6 +59,35 @@ public class DefaultResultMapper extends AbstractResultMapper { return new FacetedPageImpl(results, pageable, totalHits, facets); } + private T mapEntity(Collection values, Class clazz) { + return mapEntity(buildJSONFromFields(values), clazz); + } + + private String buildJSONFromFields(Collection values) { + JsonFactory nodeFactory = new JsonFactory(); + try { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + JsonGenerator generator = nodeFactory.createGenerator(stream, JsonEncoding.UTF8); + generator.writeStartObject(); + for (SearchHitField value : values) { + if (value.getValues().size() > 1) { + generator.writeArrayFieldStart(value.getName()); + for (Object val : value.getValues()) { + generator.writeObject(val); + } + generator.writeEndArray(); + } else { + generator.writeObjectField(value.getName(), value.getValue()); + } + } + generator.writeEndObject(); + generator.flush(); + return new String(stream.toByteArray()); + } catch (IOException e) { + return null; + } + } + @Override public T mapResult(GetResponse response, Class clazz) { return mapEntity(response.getSourceAsString(),clazz); diff --git a/src/test/java/org/springframework/data/elasticsearch/core/DefaultResultMapperTests.java b/src/test/java/org/springframework/data/elasticsearch/core/DefaultResultMapperTests.java index 845832246..5f3a29d6e 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/DefaultResultMapperTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/DefaultResultMapperTests.java @@ -3,14 +3,22 @@ package org.springframework.data.elasticsearch.core; import org.apache.commons.collections.iterators.ArrayIterator; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.index.get.GetField; import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.SearchHitField; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.internal.InternalSearchHitField; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.springframework.data.elasticsearch.Car; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertThat; @@ -51,6 +59,24 @@ public class DefaultResultMapperTests { assertThat(page.getContent().get(0).getName(), is("Ford")); } + @Test + public void shouldMapPartialSearchRequestToObject() { + //Given + SearchHit[] hits = {createCarPartialHit("Ford", "Grat"), createCarPartialHit("BMW", "Arrow")}; + SearchHits searchHits = mock(SearchHits.class); + when(searchHits.totalHits()).thenReturn(2L); + when(searchHits.iterator()).thenReturn(new ArrayIterator(hits)); + when(response.getHits()).thenReturn(searchHits); + + //When + FacetedPage page = resultMapper.mapResults(response, Car.class, null); + + //Then + assertThat(page.hasContent(), is(true)); + assertThat(page.getTotalElements(), is(2L)); + assertThat(page.getContent().get(0).getName(), is("Ford")); + } + @Test public void shouldMapGetRequestToObject() { //Given @@ -72,6 +98,13 @@ public class DefaultResultMapperTests { return hit; } + private SearchHit createCarPartialHit(String name, String model) { + SearchHit hit = mock(SearchHit.class); + when(hit.sourceAsString()).thenReturn(null); + when(hit.getFields()).thenReturn(createCarFields(name, model)); + return hit; + } + private String createJsonCar(String name, String model) { final String q = "\""; StringBuffer sb = new StringBuffer(); @@ -80,4 +113,11 @@ public class DefaultResultMapperTests { return sb.toString(); } + private Map createCarFields(String name, String model) { + Map result = new HashMap(); + result.put("name", new InternalSearchHitField("name", Arrays.asList(name))); + result.put("model", new InternalSearchHitField("model", Arrays.asList(model))); + return result; + } + }