From 288a99bcb20f68631af90d28f031083d4b61113f Mon Sep 17 00:00:00 2001 From: Sylvain Wallez Date: Thu, 15 Jun 2023 10:22:14 +0200 Subject: [PATCH 1/2] Fix spurious JSON event emitted by JsonpUtils.copy() (#597) --- .../co/elastic/clients/json/JsonpUtils.java | 1 - .../elastic/clients/json/JsonpUtilsTest.java | 109 +++++++++++++++++- 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/java-client/src/main/java/co/elastic/clients/json/JsonpUtils.java b/java-client/src/main/java/co/elastic/clients/json/JsonpUtils.java index 7975c0c6b..fff4b148d 100644 --- a/java-client/src/main/java/co/elastic/clients/json/JsonpUtils.java +++ b/java-client/src/main/java/co/elastic/clients/json/JsonpUtils.java @@ -175,7 +175,6 @@ public static void copy(JsonParser parser, JsonGenerator generator, JsonParser.E case START_ARRAY: generator.writeStartArray(); - generator.writeStartObject(); while ((event = parser.next()) != Event.END_ARRAY) { copy(parser, generator, event); } diff --git a/java-client/src/test/java/co/elastic/clients/json/JsonpUtilsTest.java b/java-client/src/test/java/co/elastic/clients/json/JsonpUtilsTest.java index 2f82a7e35..0073e497e 100644 --- a/java-client/src/test/java/co/elastic/clients/json/JsonpUtilsTest.java +++ b/java-client/src/test/java/co/elastic/clients/json/JsonpUtilsTest.java @@ -25,13 +25,14 @@ import co.elastic.clients.elasticsearch.security.IndicesPrivileges; import co.elastic.clients.elasticsearch.security.RoleTemplateScript; import co.elastic.clients.elasticsearch.security.UserIndicesPrivileges; -import co.elastic.clients.json.JsonpUtils; import co.elastic.clients.util.AllowForbiddenApis; import jakarta.json.JsonException; import jakarta.json.spi.JsonProvider; import jakarta.json.stream.JsonGenerator; +import jakarta.json.stream.JsonParser; import org.junit.jupiter.api.Test; +import java.io.StringReader; import java.io.StringWriter; import java.net.URL; import java.util.Collections; @@ -209,6 +210,47 @@ public void testJsonString() { } } + @Test + public void testCopy() { + // Tests round-tripping a json document that contains all event types and various kinds of nesting + + String json = "{\n" + + " \"p1\": \"str1\",\n" + + " \"p2\": 42,\n" + + " \"p3\": [\"str31\", \"str32\"],\n" + + " \"p4\": {\n" + + " \"p41\": \"str41\",\n" + + " \"p42\": [\"str421\", \"str422\"],\n" + + " \"p43\": {\n" + + " \"p431\": \"str431\"\n" + + " },\n" + + " \"p44\": true,\n" + + " \"p45\": false,\n" + + " \"p46\": 3.14\n" + + " },\n" + + " \"p5\": [{\n" + + " \"p51\": {\n" + + " \"p511\": \"str511\"\n" + + " }\n" + + " }],\n" + + " \"p6\": null\n" + + "}\n"; + + json = normalizeIndent(json); + + JsonProvider provider = JsonpUtils.provider(); + + JsonParser parser = provider.createParser(new StringReader(json)); + StringWriter sw = new StringWriter(); + JsonGenerator generator = provider.createGenerator(sw); + + JsonpUtils.copy(parser, generator); + parser.close(); + generator.close(); + + assertEquals(json, sw.toString()); + } + private static String orNullHelper(Consumer c) { StringWriter sw = new StringWriter(); JsonGenerator generator = JsonpUtils.provider().createGenerator(sw); @@ -221,4 +263,69 @@ private static String orNullHelper(Consumer c) { return sw.toString(); } + + /** + * Normalizes the whitespace and indentation of a JSON string by parsing it and copying it to a string generator. + */ + private static String normalizeIndent(String json) { + JsonParser parser = JsonpUtils.provider().createParser(new StringReader(json)); + StringWriter sw = new StringWriter(); + JsonGenerator generator = JsonpUtils.provider().createGenerator(sw); + + copyAll(parser, generator); + + parser.close(); + generator.close(); + return sw.toString(); + } + + private static void copyAll(JsonParser parser, JsonGenerator generator) { + while(parser.hasNext()) { + switch (parser.next()) { + case START_OBJECT: + generator.writeStartObject(); + break; + + case END_OBJECT: + generator.writeEnd(); + break; + + case START_ARRAY: + generator.writeStartArray(); + break; + + case END_ARRAY: + generator.writeEnd(); + break; + + case KEY_NAME: + generator.writeKey(parser.getString()); + break; + + case VALUE_STRING: + generator.write(parser.getString()); + break; + + case VALUE_NULL: + generator.writeNull(); + break; + + case VALUE_TRUE: + generator.write(true); + break; + + case VALUE_FALSE: + generator.write(false); + break; + + case VALUE_NUMBER: + if (parser.isIntegralNumber()) { + generator.write(parser.getLong()); + } else { + generator.write(parser.getBigDecimal()); + } + break; + } + } + } } From 80bb250b48b631be77eb07714cb1a89208214970 Mon Sep 17 00:00:00 2001 From: Sylvain Wallez Date: Wed, 21 Jun 2023 19:01:55 +0200 Subject: [PATCH 2/2] Add tests --- .../ElasticsearchTestServer.java | 2 +- .../spec_issues/SpecIssuesTest.java | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/java-client/src/test/java/co/elastic/clients/elasticsearch/ElasticsearchTestServer.java b/java-client/src/test/java/co/elastic/clients/elasticsearch/ElasticsearchTestServer.java index 11fb58f60..c4eee1b93 100644 --- a/java-client/src/test/java/co/elastic/clients/elasticsearch/ElasticsearchTestServer.java +++ b/java-client/src/test/java/co/elastic/clients/elasticsearch/ElasticsearchTestServer.java @@ -77,7 +77,7 @@ public ElasticsearchTestServer(String... plugins) { } public synchronized ElasticsearchTestServer start() { - Version version = Version.VERSION.major() < 8 ? new Version(7,17,5,false) : new Version(8,3,3,false); + Version version = Version.VERSION.major() < 8 ? new Version(7,17,10,false) : new Version(8,3,3,false); // Note we could use version.major() + "." + version.minor() + "-SNAPSHOT" but plugins won't install on a snapshot version String esImage = "docker.elastic.co/elasticsearch/elasticsearch:" + version; diff --git a/java-client/src/test/java/co/elastic/clients/elasticsearch/spec_issues/SpecIssuesTest.java b/java-client/src/test/java/co/elastic/clients/elasticsearch/spec_issues/SpecIssuesTest.java index 7c6fa7df1..3af3b2454 100644 --- a/java-client/src/test/java/co/elastic/clients/elasticsearch/spec_issues/SpecIssuesTest.java +++ b/java-client/src/test/java/co/elastic/clients/elasticsearch/spec_issues/SpecIssuesTest.java @@ -20,15 +20,18 @@ package co.elastic.clients.elasticsearch.spec_issues; import co.elastic.clients.documentation.usage.Product; +import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient; import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.elasticsearch.ElasticsearchTestServer; import co.elastic.clients.elasticsearch._types.ErrorResponse; +import co.elastic.clients.elasticsearch._types.Refresh; import co.elastic.clients.elasticsearch._types.Script; import co.elastic.clients.elasticsearch._types.analysis.LimitTokenCountTokenFilter; import co.elastic.clients.elasticsearch._types.mapping.Property; import co.elastic.clients.elasticsearch._types.mapping.RuntimeField; import co.elastic.clients.elasticsearch._types.mapping.RuntimeFieldType; import co.elastic.clients.elasticsearch.cluster.ClusterStatsResponse; +import co.elastic.clients.elasticsearch.core.GetResponse; import co.elastic.clients.elasticsearch.core.SearchRequest; import co.elastic.clients.elasticsearch.core.SearchResponse; import co.elastic.clients.elasticsearch.core.search.Suggester; @@ -40,12 +43,15 @@ import co.elastic.clients.elasticsearch.snapshot.RestoreResponse; import co.elastic.clients.json.JsonData; import co.elastic.clients.json.JsonpDeserializer; +import co.elastic.clients.util.BinaryData; +import co.elastic.clients.util.ContentType; import jakarta.json.stream.JsonParser; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.io.InputStream; import java.io.StringReader; +import java.nio.charset.StandardCharsets; /** * Test issues related to the API specifications. @@ -54,6 +60,41 @@ */ public class SpecIssuesTest extends ModelTestCase { + @Test + public void i0575_asyncBinaryData() throws Exception { + + ElasticsearchAsyncClient esAsyncClient = ElasticsearchTestServer.global().asyncClient(); + + String index = "binary-ingestion-test"; + String id = "foo-bar"; + + BinaryData data = BinaryData.of( + ("{\"id\":\"27082ce1-d9ab-404e-a810-f2894640edf4\",\"firstName\":\"Jesse\",\"lastName\":\"Pinkman\",\"addresses\":" + + "[{\"street\":\"1001 Central Ave NE\",\"city\":\"Albuquerque\",\"state\":\"NM\",\"zip\":\"87106\"}]}").getBytes(), + ContentType.APPLICATION_JSON + ); + + esAsyncClient.index(i -> i + .index(index) + .id(id) + .document(data) + .refresh(Refresh.True) + ).get(); + + GetResponse getResponse = esAsyncClient.get(g -> g + .index(index) + .id(id) + , BinaryData.class + ).get(); + + assertEquals(id, getResponse.id()); + assertEquals( + "{\"id\":\"27082ce1-d9ab-404e-a810-f2894640edf4\",\"firstName\":\"Jesse\",\"lastName\":\"Pinkman\",\"addresses\":" + + "[{\"street\":\"1001 Central Ave NE\",\"city\":\"Albuquerque\",\"state\":\"NM\",\"zip\":\"87106\"}]}", + new String(getResponse.source().asByteBuffer().array(), StandardCharsets.UTF_8) + ); + } + @Test public void i0328_charFilter() throws Exception { // Both mappings and mappings_path are optional