Skip to content

Commit 4a548b0

Browse files
committed
Fix serialization of empty field capabilities response (#33263)
Fix serialization of empty field capabilities response When no response are required (no indices match the requested patterns) the empty response throws an NPE in the transport serialization (writeTo).
1 parent 27af04d commit 4a548b0

File tree

7 files changed

+54
-20
lines changed

7 files changed

+54
-20
lines changed

server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilities.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,14 @@ public String getName() {
166166
}
167167

168168
/**
169-
* Whether this field is indexed for search on all indices.
169+
* Whether this field can be aggregated on all indices.
170170
*/
171171
public boolean isAggregatable() {
172172
return isAggregatable;
173173
}
174174

175175
/**
176-
* Whether this field can be aggregated on all indices.
176+
* Whether this field is indexed for search on all indices.
177177
*/
178178
public boolean isSearchable() {
179179
return isSearchable;

server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java

-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ public String[] fields() {
123123
}
124124

125125
/**
126-
*
127126
* The list of indices to lookup
128127
*/
129128
public FieldCapabilitiesRequest indices(String... indices) {

server/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesResponse.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import java.util.HashMap;
3737
import java.util.List;
3838
import java.util.Map;
39+
import java.util.Objects;
3940
import java.util.stream.Collectors;
4041

4142
/**
@@ -57,15 +58,15 @@ public class FieldCapabilitiesResponse extends ActionResponse implements ToXCont
5758

5859
private FieldCapabilitiesResponse(Map<String, Map<String, FieldCapabilities>> responseMap,
5960
List<FieldCapabilitiesIndexResponse> indexResponses) {
60-
this.responseMap = responseMap;
61-
this.indexResponses = indexResponses;
61+
this.responseMap = Objects.requireNonNull(responseMap);
62+
this.indexResponses = Objects.requireNonNull(indexResponses);
6263
}
6364

6465
/**
6566
* Used for serialization
6667
*/
6768
FieldCapabilitiesResponse() {
68-
this.responseMap = Collections.emptyMap();
69+
this(Collections.emptyMap(), Collections.emptyList());
6970
}
7071

7172
/**
@@ -82,6 +83,7 @@ public Map<String, Map<String, FieldCapabilities>> get() {
8283
List<FieldCapabilitiesIndexResponse> getIndexResponses() {
8384
return indexResponses;
8485
}
86+
8587
/**
8688
*
8789
* Get the field capabilities per type for the provided {@code field}.

server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ protected void doExecute(FieldCapabilitiesRequest request,
8989
}
9090
};
9191
if (totalNumRequest == 0) {
92-
listener.onResponse(new FieldCapabilitiesResponse());
92+
listener.onResponse(new FieldCapabilitiesResponse(Collections.emptyMap()));
9393
} else {
9494
ActionListener<FieldCapabilitiesIndexResponse> innerListener = new ActionListener<FieldCapabilitiesIndexResponse>() {
9595
@Override

server/src/main/java/org/elasticsearch/client/Client.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ public interface Client extends ElasticsearchClient, Releasable {
455455
/**
456456
* Builder for the field capabilities request.
457457
*/
458-
FieldCapabilitiesRequestBuilder prepareFieldCaps();
458+
FieldCapabilitiesRequestBuilder prepareFieldCaps(String... indices);
459459

460460
/**
461461
* An action that returns the field capabilities from the provided request

server/src/main/java/org/elasticsearch/client/support/AbstractClient.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -669,8 +669,8 @@ public ActionFuture<FieldCapabilitiesResponse> fieldCaps(FieldCapabilitiesReques
669669
}
670670

671671
@Override
672-
public FieldCapabilitiesRequestBuilder prepareFieldCaps() {
673-
return new FieldCapabilitiesRequestBuilder(this, FieldCapabilitiesAction.INSTANCE);
672+
public FieldCapabilitiesRequestBuilder prepareFieldCaps(String... indices) {
673+
return new FieldCapabilitiesRequestBuilder(this, FieldCapabilitiesAction.INSTANCE, indices);
674674
}
675675

676676
static class Admin implements AdminClient {

server/src/test/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesResponseTests.java

+43-10
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,15 @@
2828
import org.elasticsearch.test.AbstractStreamableXContentTestCase;
2929

3030
import java.io.IOException;
31+
import java.util.ArrayList;
3132
import java.util.Collections;
3233
import java.util.HashMap;
34+
import java.util.List;
3335
import java.util.Map;
3436
import java.util.function.Predicate;
3537

38+
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomAsciiLettersOfLength;
39+
3640

3741
public class FieldCapabilitiesResponseTests extends AbstractStreamableXContentTestCase<FieldCapabilitiesResponse> {
3842

@@ -48,22 +52,46 @@ protected FieldCapabilitiesResponse createBlankInstance() {
4852

4953
@Override
5054
protected FieldCapabilitiesResponse createTestInstance() {
51-
Map<String, Map<String, FieldCapabilities>> responses = new HashMap<>();
55+
if (randomBoolean()) {
56+
// merged responses
57+
Map<String, Map<String, FieldCapabilities>> responses = new HashMap<>();
58+
59+
String[] fields = generateRandomStringArray(5, 10, false, true);
60+
assertNotNull(fields);
61+
62+
for (String field : fields) {
63+
Map<String, FieldCapabilities> typesToCapabilities = new HashMap<>();
64+
String[] types = generateRandomStringArray(5, 10, false, false);
65+
assertNotNull(types);
66+
67+
for (String type : types) {
68+
typesToCapabilities.put(type, FieldCapabilitiesTests.randomFieldCaps(field));
69+
}
70+
responses.put(field, typesToCapabilities);
71+
}
72+
return new FieldCapabilitiesResponse(responses);
73+
} else {
74+
// non-merged responses
75+
List<FieldCapabilitiesIndexResponse> responses = new ArrayList<>();
76+
int numResponse = randomIntBetween(0, 10);
77+
for (int i = 0; i < numResponse; i++) {
78+
responses.add(createRandomIndexResponse());
79+
}
80+
return new FieldCapabilitiesResponse(responses);
81+
}
82+
}
83+
84+
85+
private FieldCapabilitiesIndexResponse createRandomIndexResponse() {
86+
Map<String, FieldCapabilities> responses = new HashMap<>();
5287

5388
String[] fields = generateRandomStringArray(5, 10, false, true);
5489
assertNotNull(fields);
5590

5691
for (String field : fields) {
57-
Map<String, FieldCapabilities> typesToCapabilities = new HashMap<>();
58-
String[] types = generateRandomStringArray(5, 10, false, false);
59-
assertNotNull(types);
60-
61-
for (String type : types) {
62-
typesToCapabilities.put(type, FieldCapabilitiesTests.randomFieldCaps(field));
63-
}
64-
responses.put(field, typesToCapabilities);
92+
responses.put(field, FieldCapabilitiesTests.randomFieldCaps(field));
6593
}
66-
return new FieldCapabilitiesResponse(responses);
94+
return new FieldCapabilitiesIndexResponse(randomAsciiLettersOfLength(10), responses);
6795
}
6896

6997
@Override
@@ -138,6 +166,11 @@ public void testToXContent() throws IOException {
138166
"}").replaceAll("\\s+", ""), generatedResponse);
139167
}
140168

169+
public void testEmptyResponse() throws IOException {
170+
FieldCapabilitiesResponse testInstance = new FieldCapabilitiesResponse();
171+
assertSerialization(testInstance);
172+
}
173+
141174
private static FieldCapabilitiesResponse createSimpleResponse() {
142175
Map<String, FieldCapabilities> titleCapabilities = new HashMap<>();
143176
titleCapabilities.put("text", new FieldCapabilities("title", "text", true, false));

0 commit comments

Comments
 (0)