From 261cab4cf79e176b0892cfb44fad7c8cfaf44204 Mon Sep 17 00:00:00 2001 From: Brett Findlay Date: Fri, 1 Dec 2023 15:35:21 +1100 Subject: [PATCH] Fix MissingRequiredPropertyException on node stats response (#745) * fix stats null issues Signed-off-by: bfindlay * update changelog Signed-off-by: bfindlay * updated changelog Signed-off-by: bfindlay * use existing nodes itest Signed-off-by: bfindlay * fix test typo Signed-off-by: bfindlay * update itests Signed-off-by: bfindlay * spotless apply Signed-off-by: bfindlay --------- Signed-off-by: bfindlay --- CHANGELOG.md | 1 + .../client/opensearch/nodes/Stats.java | 194 +++++++++++------- .../opensearch/integTest/AbstractNodesIT.java | 49 +++++ 3 files changed, 174 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d97e1365f..632043471a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ This section is for maintaining a changelog for all breaking changes for the cli ### Fixed - Fix partial success results for msearch_template ([#709](https://github.com/opensearch-project/opensearch-java/pull/709)) +- Fix deserialization of node stats response ([#745](https://github.com/opensearch-project/opensearch-java/pull/745)) ### Security diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/nodes/Stats.java b/java-client/src/main/java/org/opensearch/client/opensearch/nodes/Stats.java index 36369fbe2c..dc9d840e38 100644 --- a/java-client/src/main/java/org/opensearch/client/opensearch/nodes/Stats.java +++ b/java-client/src/main/java/org/opensearch/client/opensearch/nodes/Stats.java @@ -53,38 +53,51 @@ @JsonpDeserializable public class Stats implements JsonpSerializable { + + @Nullable private final Map adaptiveSelection; + @Nullable private final Map breakers; + @Nullable private final FileSystem fs; private final String host; + @Nullable private final Http http; + @Nullable private final IndexStats indices; + @Nullable private final Ingest ingest; private final List ip; + @Nullable private final Jvm jvm; private final String name; + @Nullable private final OperatingSystem os; + @Nullable private final Process process; private final List roles; + @Nullable private final Scripting script; + @Nullable private final Map threadPool; private final long timestamp; + @Nullable private final Transport transport; private final String transportAddress; @@ -96,23 +109,23 @@ public class Stats implements JsonpSerializable { private Stats(Builder builder) { - this.adaptiveSelection = ApiTypeHelper.unmodifiableRequired(builder.adaptiveSelection, this, "adaptiveSelection"); - this.breakers = ApiTypeHelper.unmodifiableRequired(builder.breakers, this, "breakers"); - this.fs = ApiTypeHelper.requireNonNull(builder.fs, this, "fs"); + this.adaptiveSelection = builder.adaptiveSelection; + this.breakers = builder.breakers; + this.fs = builder.fs; this.host = ApiTypeHelper.requireNonNull(builder.host, this, "host"); - this.http = ApiTypeHelper.requireNonNull(builder.http, this, "http"); - this.indices = ApiTypeHelper.requireNonNull(builder.indices, this, "indices"); - this.ingest = ApiTypeHelper.requireNonNull(builder.ingest, this, "ingest"); + this.http = builder.http; + this.indices = builder.indices; + this.ingest = builder.ingest; this.ip = ApiTypeHelper.unmodifiableRequired(builder.ip, this, "ip"); - this.jvm = ApiTypeHelper.requireNonNull(builder.jvm, this, "jvm"); + this.jvm = builder.jvm; this.name = ApiTypeHelper.requireNonNull(builder.name, this, "name"); - this.os = ApiTypeHelper.requireNonNull(builder.os, this, "os"); - this.process = ApiTypeHelper.requireNonNull(builder.process, this, "process"); + this.os = builder.os; + this.process = builder.process; this.roles = ApiTypeHelper.unmodifiableRequired(builder.roles, this, "roles"); - this.script = ApiTypeHelper.requireNonNull(builder.script, this, "script"); - this.threadPool = ApiTypeHelper.unmodifiableRequired(builder.threadPool, this, "threadPool"); + this.script = builder.script; + this.threadPool = builder.threadPool; this.timestamp = ApiTypeHelper.requireNonNull(builder.timestamp, this, "timestamp"); - this.transport = ApiTypeHelper.requireNonNull(builder.transport, this, "transport"); + this.transport = builder.transport; this.transportAddress = ApiTypeHelper.requireNonNull(builder.transportAddress, this, "transportAddress"); this.attributes = builder.attributes; @@ -123,22 +136,25 @@ public static Stats of(Function> fn) { } /** - * Required - API name: {@code adaptive_selection} + * API name: {@code adaptive_selection} */ + @Nullable public final Map adaptiveSelection() { return this.adaptiveSelection; } /** - * Required - API name: {@code breakers} + * API name: {@code breakers} */ + @Nullable public final Map breakers() { return this.breakers; } /** - * Required - API name: {@code fs} + * API name: {@code fs} */ + @Nullable public final FileSystem fs() { return this.fs; } @@ -151,22 +167,25 @@ public final String host() { } /** - * Required - API name: {@code http} + * API name: {@code http} */ + @Nullable public final Http http() { return this.http; } /** - * Required - API name: {@code indices} + * API name: {@code indices} */ + @Nullable public final IndexStats indices() { return this.indices; } /** - * Required - API name: {@code ingest} + * API name: {@code ingest} */ + @Nullable public final Ingest ingest() { return this.ingest; } @@ -179,8 +198,9 @@ public final List ip() { } /** - * Required - API name: {@code jvm} + * API name: {@code jvm} */ + @Nullable public final Jvm jvm() { return this.jvm; } @@ -193,15 +213,17 @@ public final String name() { } /** - * Required - API name: {@code os} + * API name: {@code os} */ + @Nullable public final OperatingSystem os() { return this.os; } /** - * Required - API name: {@code process} + * API name: {@code process} */ + @Nullable public final Process process() { return this.process; } @@ -214,15 +236,17 @@ public final List roles() { } /** - * Required - API name: {@code script} + * API name: {@code script} */ + @Nullable public final Scripting script() { return this.script; } /** - * Required - API name: {@code thread_pool} + * API name: {@code thread_pool} */ + @Nullable public final Map threadPool() { return this.threadPool; } @@ -235,8 +259,9 @@ public final long timestamp() { } /** - * Required - API name: {@code transport} + * API name: {@code transport} */ + @Nullable public final Transport transport() { return this.transport; } @@ -251,6 +276,7 @@ public final String transportAddress() { /** * API name: {@code attributes} */ + @Nullable public final Map attributes() { return this.attributes; } @@ -288,21 +314,26 @@ protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { generator.writeEnd(); } - generator.writeKey("fs"); - this.fs.serialize(generator, mapper); - - generator.writeKey("host"); - generator.write(this.host); - - generator.writeKey("http"); - this.http.serialize(generator, mapper); - - generator.writeKey("indices"); - this.indices.serialize(generator, mapper); - - generator.writeKey("ingest"); - this.ingest.serialize(generator, mapper); - + if (this.fs != null) { + generator.writeKey("fs"); + this.fs.serialize(generator, mapper); + } + if (this.host != null) { + generator.writeKey("host"); + generator.write(this.host); + } + if (this.http != null) { + generator.writeKey("http"); + this.http.serialize(generator, mapper); + } + if (this.indices != null) { + generator.writeKey("indices"); + this.indices.serialize(generator, mapper); + } + if (this.ingest != null) { + generator.writeKey("ingest"); + this.ingest.serialize(generator, mapper); + } if (ApiTypeHelper.isDefined(this.ip)) { generator.writeKey("ip"); generator.writeStartArray(); @@ -313,17 +344,23 @@ protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { generator.writeEnd(); } - generator.writeKey("jvm"); - this.jvm.serialize(generator, mapper); + if (this.jvm != null) { + generator.writeKey("jvm"); + this.jvm.serialize(generator, mapper); + } generator.writeKey("name"); generator.write(this.name); - generator.writeKey("os"); - this.os.serialize(generator, mapper); + if (this.os != null) { + generator.writeKey("os"); + this.os.serialize(generator, mapper); + } - generator.writeKey("process"); - this.process.serialize(generator, mapper); + if (this.process != null) { + generator.writeKey("process"); + this.process.serialize(generator, mapper); + } if (ApiTypeHelper.isDefined(this.roles)) { generator.writeKey("roles"); @@ -334,8 +371,10 @@ protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { generator.writeEnd(); } - generator.writeKey("script"); - this.script.serialize(generator, mapper); + if (this.script != null) { + generator.writeKey("script"); + this.script.serialize(generator, mapper); + } if (ApiTypeHelper.isDefined(this.threadPool)) { generator.writeKey("thread_pool"); @@ -351,8 +390,10 @@ protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { generator.writeKey("timestamp"); generator.write(this.timestamp); - generator.writeKey("transport"); - this.transport.serialize(generator, mapper); + if (this.transport != null) { + generator.writeKey("transport"); + this.transport.serialize(generator, mapper); + } generator.writeKey("transport_address"); generator.write(this.transportAddress); @@ -378,38 +419,51 @@ protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { */ public static class Builder extends ObjectBuilderBase implements ObjectBuilder { + + @Nullable private Map adaptiveSelection; + @Nullable private Map breakers; + @Nullable private FileSystem fs; private String host; + @Nullable private Http http; + @Nullable private IndexStats indices; + @Nullable private Ingest ingest; private List ip; + @Nullable private Jvm jvm; private String name; + @Nullable private OperatingSystem os; + @Nullable private Process process; private List roles; + @Nullable private Scripting script; + @Nullable private Map threadPool; private Long timestamp; + @Nullable private Transport transport; private String transportAddress; @@ -422,7 +476,7 @@ public static class Builder extends ObjectBuilderBase implements ObjectBuilder * Adds all entries of map to adaptiveSelection. */ - public final Builder adaptiveSelection(Map map) { + public final Builder adaptiveSelection(@Nullable Map map) { this.adaptiveSelection = _mapPutAll(this.adaptiveSelection, map); return this; } @@ -451,7 +505,7 @@ public final Builder adaptiveSelection(String key, Function * Adds all entries of map to breakers. */ - public final Builder breakers(Map map) { + public final Builder breakers(@Nullable Map map) { this.breakers = _mapPutAll(this.breakers, map); return this; } @@ -478,7 +532,7 @@ public final Builder breakers(String key, Function> fn) { /** * Required - API name: {@code indices} */ - public final Builder indices(IndexStats value) { + public final Builder indices(@Nullable IndexStats value) { this.indices = value; return this; } @@ -531,7 +585,7 @@ public final Builder indices(Function> fn) { return this.script(fn.apply(new Scripting.Builder()).build()); } /** - * Required - API name: {@code thread_pool} + * API name: {@code thread_pool} *

* Adds all entries of map to threadPool. */ - public final Builder threadPool(Map map) { + public final Builder threadPool(@Nullable Map map) { this.threadPool = _mapPutAll(this.threadPool, map); return this; } /** - * Required - API name: {@code thread_pool} + * API name: {@code thread_pool} *

* Adds an entry to threadPool. */ @@ -672,7 +726,7 @@ public final Builder threadPool(String key, ThreadCount value) { } /** - * Required - API name: {@code thread_pool} + * API name: {@code thread_pool} *

* Adds an entry to threadPool using a builder lambda. */ @@ -689,15 +743,15 @@ public final Builder timestamp(long value) { } /** - * Required - API name: {@code transport} + * API name: {@code transport} */ - public final Builder transport(Transport value) { + public final Builder transport(@Nullable Transport value) { this.transport = value; return this; } /** - * Required - API name: {@code transport} + * API name: {@code transport} */ public final Builder transport(Function> fn) { return this.transport(fn.apply(new Transport.Builder()).build()); @@ -716,7 +770,7 @@ public final Builder transportAddress(String value) { *

* Adds all entries of map to attributes. */ - public final Builder attributes(Map map) { + public final Builder attributes(@Nullable Map map) { this.attributes = _mapPutAll(this.attributes, map); return this; } diff --git a/java-client/src/test/java/org/opensearch/client/opensearch/integTest/AbstractNodesIT.java b/java-client/src/test/java/org/opensearch/client/opensearch/integTest/AbstractNodesIT.java index e8376e572a..2ad2864c04 100644 --- a/java-client/src/test/java/org/opensearch/client/opensearch/integTest/AbstractNodesIT.java +++ b/java-client/src/test/java/org/opensearch/client/opensearch/integTest/AbstractNodesIT.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.util.Arrays; +import org.junit.Test; import org.opensearch.client.opensearch.nodes.NodesStatsResponse; import org.opensearch.client.opensearch.tasks.ListRequest; import org.opensearch.client.opensearch.tasks.ListResponse; @@ -30,4 +31,52 @@ public void testNodesList() throws IOException { ListResponse listResponse = javaClient().tasks().list(); assertThat(listResponse.nodes(), not(anEmptyMap())); } + + @Test + public void stats_fsMetricRequested_returnsFsStatsWithoutException() throws IOException { + final NodesStatsResponse statsResponse = javaClient().nodes().stats(s -> s.metric("fs")); + statsResponse.nodes().values().forEach((v) -> { assertNotNull(v.fs()); }); + } + + @Test + public void stats_httpMetricRequested_returnsHttpStatsWithoutException() throws IOException { + final NodesStatsResponse statsResponse = javaClient().nodes().stats(s -> s.metric("http")); + statsResponse.nodes().values().forEach((v) -> { assertNotNull(v.http()); }); + } + + @Test + public void stats_indicesMetricRequested_returnsIndicesStatsWithoutException() throws IOException { + final NodesStatsResponse statsResponse = javaClient().nodes().stats(s -> s.metric("indices")); + statsResponse.nodes().values().forEach((v) -> { assertNotNull(v.indices()); }); + } + + @Test + public void stats_ingestMetricRequested_returnsIngestStatsWithoutException() throws IOException { + final NodesStatsResponse statsResponse = javaClient().nodes().stats(s -> s.metric("ingest")); + statsResponse.nodes().values().forEach((v) -> { assertNotNull(v.ingest()); }); + } + + @Test + public void stats_jvmMetricRequested_returnsJvmStatsWithoutException() throws IOException { + final NodesStatsResponse statsResponse = javaClient().nodes().stats(s -> s.metric("jvm")); + statsResponse.nodes().values().forEach((v) -> { assertNotNull(v.jvm()); }); + } + + @Test + public void stats_osMetricRequested_returnsOsStatsWithoutException() throws IOException { + final NodesStatsResponse statsResponse = javaClient().nodes().stats(s -> s.metric("os")); + statsResponse.nodes().values().forEach((v) -> { assertNotNull(v.os()); }); + } + + @Test + public void stats_processMetricRequested_returnsProcessStatsWithoutException() throws IOException { + final NodesStatsResponse statsResponse = javaClient().nodes().stats(s -> s.metric("process")); + statsResponse.nodes().values().forEach((v) -> { assertNotNull(v.process()); }); + } + + @Test + public void stats_scriptMetricRequested_returnsScriptStatsWithoutException() throws IOException { + final NodesStatsResponse statsResponse = javaClient().nodes().stats(s -> s.metric("script")); + statsResponse.nodes().values().forEach((v) -> { assertNotNull(v.script()); }); + } }