Skip to content

Commit 4570f18

Browse files
authored
fix(clients): correctly deserialize SearchResult (#4756)
1 parent b8d1876 commit 4570f18

File tree

3 files changed

+54
-10
lines changed

3 files changed

+54
-10
lines changed

playground/java/src/main/java/com/algolia/playground/Search.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import io.github.cdimascio.dotenv.Dotenv;
77
import java.util.Arrays;
88
import java.util.List;
9-
import java.util.Map;
109

1110
class Actor extends Hit {
1211

@@ -47,6 +46,7 @@ public static void main(String[] args) throws Exception {
4746

4847
singleSearch(client, indexName, query);
4948
multiSearch(indexName, query, client);
49+
multiSearchHits(indexName, query, client);
5050
client.close();
5151
}
5252

@@ -73,13 +73,27 @@ private static void multiSearch(String indexName, String query, SearchClient cli
7373
searchMethodParams.setRequests(requests);
7474

7575
var responses = client.search(searchMethodParams, Actor.class);
76-
var results = responses.getResults();
7776
System.out.println("-> Multi Index Search:");
78-
for (var result : results) {
79-
var response = (SearchResponse) result;
80-
for (var hit : response.getHits()) {
81-
var record = (Map) hit;
82-
System.out.println("> " + record.get("name"));
77+
for (var result : responses.getResults()) {
78+
for (var hit : ((SearchResponse<Actor>) result).getHits()) {
79+
System.out.println("> " + hit.name);
80+
}
81+
}
82+
}
83+
84+
private static void multiSearchHits(String indexName, String query, SearchClient client) {
85+
var searchQuery = new SearchForHits()
86+
.setIndexName(indexName)
87+
.setQuery(query)
88+
.addAttributesToSnippet("title")
89+
.addAttributesToSnippet("alternative_titles");
90+
List<SearchForHits> requests = List.of(searchQuery);
91+
// with searchForHits, all the types are known, no need to cast
92+
var responses = client.searchForHits(requests, Actor.class);
93+
System.out.println("-> Multi Index SearchForHits:");
94+
for (var result : responses) {
95+
for (var hit : result.getHits()) {
96+
System.out.println("> " + hit.name);
8397
}
8498
}
8599
}

specs/search/paths/search/search.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ post:
1515
1616
- Different indices for different purposes, such as, one index for products, another one for marketing content.
1717
- Multiple searches to the same index—for example, with different filters.
18+
19+
Use the helper `searchForHits` or `searchForFacets` to get the results in a more convenient format, if you already know the return type you want.
1820
requestBody:
1921
required: true
2022
description: Muli-search request body. Results are returned in the same order as the requests.

templates/java/oneof_interface.mustache

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import com.fasterxml.jackson.databind.annotation.*;
55
import com.fasterxml.jackson.core.type.TypeReference;
66
import com.algolia.exceptions.AlgoliaRuntimeException;
77
import com.algolia.utils.CompoundType;
8+
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
9+
import com.fasterxml.jackson.databind.BeanProperty;
810

911
import java.io.IOException;
1012
import java.util.List;
@@ -87,19 +89,45 @@ public interface {{classname}}{{#vendorExtensions.x-has-child-generic}}<T>{{/ven
8789
{{/isModel}}
8890
{{/composedSchemas.oneOf}}
8991

90-
class Deserializer{{#vendorExtensions.x-has-child-generic}}<T>{{/vendorExtensions.x-has-child-generic}} extends JsonDeserializer<{{classname}}{{#vendorExtensions.x-has-child-generic}}<T>{{/vendorExtensions.x-has-child-generic}}> {
92+
class Deserializer{{#vendorExtensions.x-has-child-generic}}<T>{{/vendorExtensions.x-has-child-generic}} extends JsonDeserializer<{{classname}}{{#vendorExtensions.x-has-child-generic}}<T>{{/vendorExtensions.x-has-child-generic}}>{{#vendorExtensions.x-has-child-generic}} implements ContextualDeserializer{{/vendorExtensions.x-has-child-generic}} {
9193
9294
private static final Logger LOGGER = Logger.getLogger(Deserializer.class.getName());
9395
96+
{{#vendorExtensions.x-has-child-generic}}
97+
private JavaType returnType;
98+
99+
public Deserializer() {}
100+
101+
private Deserializer(JavaType returnType) {
102+
this.returnType = returnType;
103+
}
104+
105+
@Override
106+
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
107+
JavaType contextualType = ctxt.getContextualType().containedType(0);
108+
return new Deserializer(contextualType);
109+
}
110+
{{/vendorExtensions.x-has-child-generic}}
111+
94112
@Override
95113
public {{classname}}{{#vendorExtensions.x-has-child-generic}}<T>{{/vendorExtensions.x-has-child-generic}} deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
96114
JsonNode tree = jp.readValueAsTree();
97115
{{#composedSchemas.oneOf}}
98116
// deserialize {{{datatypeWithEnum}}}
99117
if (tree.{{#isModel}}isObject(){{#vendorExtensions.x-discriminator-fields}} && tree.has("{{{.}}}"){{/vendorExtensions.x-discriminator-fields}}{{/isModel}}{{#isEnumRef}}isTextual(){{/isEnumRef}}{{#isArray}}isArray(){{/isArray}}{{#isInteger}}isInt(){{/isInteger}}{{#isLong}}isLong(){{/isLong}}{{#isDouble}}isDouble(){{/isDouble}}{{#isBoolean}}isBoolean(){{/isBoolean}}{{#isString}}isTextual(){{/isString}}{{^isEnumRef}}{{^isModel}}{{^isArray}}{{^isInteger}}{{^isLong}}{{^isDouble}}{{^isBoolean}}{{^isString}}isObject(){{/isString}}{{/isBoolean}}{{/isDouble}}{{/isLong}}{{/isInteger}}{{/isArray}}{{/isModel}}{{/isEnumRef}}){
100-
try(JsonParser parser = tree.traverse(jp.getCodec())) {
118+
try(JsonParser parser = tree.traverse(jp.getCodec())) {
101119
{{#isModel}}
102-
return parser.readValueAs({{#vendorExtensions.x-has-child-generic}}new TypeReference<{{datatypeWithEnum}}<T>>() {}{{/vendorExtensions.x-has-child-generic}}{{^vendorExtensions.x-has-child-generic}}{{{datatypeWithEnum}}}.class{{/vendorExtensions.x-has-child-generic}});
120+
{{#vendorExtensions.x-has-child-generic}}
121+
// For generic types, the innerType is erased by Java, we need to use the contextual type.
122+
JavaType innerType = ctxt.getTypeFactory().constructParametricType({{dataType}}.class, returnType);
123+
if (parser.getCurrentToken() == null) {
124+
parser.nextToken();
125+
}
126+
return ctxt.readValue(parser, innerType);
127+
{{/vendorExtensions.x-has-child-generic}}
128+
{{^vendorExtensions.x-has-child-generic}}
129+
return parser.readValueAs({{{datatypeWithEnum}}}.class);
130+
{{/vendorExtensions.x-has-child-generic}}
103131
{{/isModel}}
104132
{{#isEnumRef}}
105133
return parser.readValueAs({{{datatypeWithEnum}}}.class);

0 commit comments

Comments
 (0)