diff --git a/CHANGELOG.md b/CHANGELOG.md index e331fa12d2..346e5790b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,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 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..e3a5b0ee48 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..a03a964d06 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,42 @@ 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..ac2ef2d793 --- /dev/null +++ b/java-client/src/test/java/org/opensearch/client/opensearch/json/JsonpSerializableTest.java @@ -0,0 +1,100 @@ +/* + * 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 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; +import org.opensearch.client.util.MissingRequiredPropertyException; + +import java.util.Collections; + +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); + + } + +}