From 5c5b1141d169eb3d5fbc8584f7a8d61a7dca9b30 Mon Sep 17 00:00:00 2001 From: Jai2305 Date: Tue, 2 Jul 2024 23:24:18 +0530 Subject: [PATCH] 588 - [FEATURE] serialize requests to JSON --- CHANGELOG.md | 1 + .../client/json/JsonpSerializable.java | 19 ++++ .../opensearch/client/json/JsonpUtils.java | 35 +++++++ .../json/JsonpSerializableTest.java | 94 +++++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 java-client/src/test/java/org/opensearch/client/opensearch/json/JsonpSerializableTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 31361c34a7..9a0b12a8ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ This section is for maintaining a changelog for all breaking changes for the cli ### Added - Document HTTP/2 support ([#330](https://github.com/opensearch-project/opensearch-java/pull/330)) - Add support for phase_took & search_pipeline request params ([#1036](https://github.com/opensearch-project/opensearch-java/pull/1036)) +- Add a serializer method for classes implementing JsonpSerializable.([#1064](https://github.com/opensearch-project/opensearch-java/pull/1064)) ### Dependencies diff --git a/java-client/src/main/java/org/opensearch/client/json/JsonpSerializable.java b/java-client/src/main/java/org/opensearch/client/json/JsonpSerializable.java index 0b4d9b5290..59340ce7a7 100644 --- a/java-client/src/main/java/org/opensearch/client/json/JsonpSerializable.java +++ b/java-client/src/main/java/org/opensearch/client/json/JsonpSerializable.java @@ -33,6 +33,7 @@ package org.opensearch.client.json; import jakarta.json.stream.JsonGenerator; +import java.io.StringWriter; /** * An object that is its own JsonP serializer @@ -40,4 +41,22 @@ public interface JsonpSerializable { void serialize(JsonGenerator generator, JsonpMapper mapper); + + /** + * A default method which returns string representation for the instances of classes + * implementing JsonpSerializable interface.
+ * Usage : Eg for SearchRequest.class
{@code SearchRequest implements JsonpSerializable{..}
+     * SearchRequest searchRequest = SearchRequest.of(request -> request...);
+     * String searchRequestString = searchRequest.writeValueAsString();}

+ * + */ + default String writeValueAsString() { + StringWriter writer = new StringWriter(); + try (JsonGenerator generator = JsonpUtils.DEFAULT_PROVIDER.createGenerator(writer)) { + serialize(generator, JsonpUtils.DEFAULT_JSONP_MAPPER); + } + + return writer.toString(); + } + } diff --git a/java-client/src/main/java/org/opensearch/client/json/JsonpUtils.java b/java-client/src/main/java/org/opensearch/client/json/JsonpUtils.java index 604bf2791e..fc492a72c5 100644 --- a/java-client/src/main/java/org/opensearch/client/json/JsonpUtils.java +++ b/java-client/src/main/java/org/opensearch/client/json/JsonpUtils.java @@ -32,9 +32,11 @@ package org.opensearch.client.json; +import jakarta.json.JsonException; import jakarta.json.JsonObject; import jakarta.json.JsonString; import jakarta.json.JsonValue; +import jakarta.json.spi.JsonProvider; import jakarta.json.stream.JsonGenerator; import jakarta.json.stream.JsonLocation; import jakarta.json.stream.JsonParser; @@ -59,6 +61,39 @@ public class JsonpUtils { * JSON when advancing to next state. * @throws java.util.NoSuchElementException if there are no more parsing states. */ + + static final JsonProvider DEFAULT_PROVIDER = provider(); + + static JsonProvider provider() { + return JsonProvider.provider(); + } + + static final JsonpMapper DEFAULT_JSONP_MAPPER = new JsonpMapperBase() { + @Override + public JsonProvider jsonProvider() { + return DEFAULT_PROVIDER; + } + + @Override + public void serialize(T value, JsonGenerator generator) { + if (value instanceof JsonpSerializable) { + ((JsonpSerializable) value).serialize(generator, this); + return; + } + + throw new JsonException( + "Cannot find a serializer for type " + value.getClass().getName() + ". Consider using a full-featured JsonpMapper" + ); + } + + @Override + protected JsonpDeserializer getDefaultDeserializer(Class clazz) { + throw new JsonException( + "Cannot find a default deserializer for type " + clazz.getName() + ". Consider using a full-featured JsonpMapper" + ); + } + }; + public static JsonParser.Event expectNextEvent(JsonParser parser, JsonParser.Event expected) { JsonParser.Event event = parser.next(); expectEvent(parser, expected, event); diff --git a/java-client/src/test/java/org/opensearch/client/opensearch/json/JsonpSerializableTest.java b/java-client/src/test/java/org/opensearch/client/opensearch/json/JsonpSerializableTest.java new file mode 100644 index 0000000000..ca3c0c2aff --- /dev/null +++ b/java-client/src/test/java/org/opensearch/client/opensearch/json/JsonpSerializableTest.java @@ -0,0 +1,94 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.client.opensearch.json; + +import java.util.Collections; +import org.junit.Assert; +import org.junit.Test; +import org.opensearch.client.opensearch._types.FieldValue; +import org.opensearch.client.opensearch._types.Result; +import org.opensearch.client.opensearch.core.IndexResponse; +import org.opensearch.client.opensearch.core.SearchRequest; + +public class JsonpSerializableTest extends Assert { + + // Test IndexResponse which extends WriteResponseBase which implements JsonpSerializable + @Test + public void testIndexResponse() { + + String expectedStringValue = + "{\"_id\":\"id\",\"_index\":\"index\",\"_primary_term\":1,\"result\":\"created\",\"_seq_no\":2,\"_shards\":{\"failed\":1.0,\"successful\":1.0,\"total\":3.0,\"failures\":[{\"index\":\"index\",\"node\":\"node\",\"reason\":{\"type\":\"query_shard_exception\",\"reason\":\"Failed to create query.\"},\"shard\":1,\"status\":\"Failed\"}],\"skipped\":1.0},\"_version\":3}"; + IndexResponse indexResponse = IndexResponse.of( + response -> response.result(Result.Created) + .index("index") + .id("id") + .primaryTerm(1) + .seqNo(2) + .version(3) + .shards( + shardStats -> shardStats.total(3) + .successful(1) + .skipped(1) + .failed(1) + .failures( + shardFailure -> shardFailure.index("index") + .node("node") + .shard(1) + .status("Failed") + .reason(cause -> cause.type("query_shard_exception").reason("Failed to create query.")) + ) + ) + ); + + String indexResponseString = indexResponse.writeValueAsString(); + assertEquals(expectedStringValue, indexResponseString); + } + + // Test SearchRequest which implements JsonpSerializable + @Test + public void testSearchResponse() { + + String expectedStringValue = + "{\"aggregations\":{},\"query\":{\"match\":{\"name\":{\"query\":\"OpenSearch\"}}},\"terminate_after\":5}"; + SearchRequest searchRequest = SearchRequest.of( + request -> request.index("index1", "index2") + .aggregations(Collections.emptyMap()) + .terminateAfter(5L) + .query(q -> q.match(t -> t.field("name").query(FieldValue.of("OpenSearch")))) + ); + String searchRequestString = searchRequest.writeValueAsString(); + assertEquals(expectedStringValue, searchRequestString); + + } + +}