Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: option to retrieve original json body if parse exception occurred #886

Merged
merged 16 commits into from
Oct 17, 2024

Conversation

l-trotta
Copy link
Contributor

@l-trotta l-trotta commented Oct 1, 2024

To help with issue debugging. The option can be set with:

RestClientOptions options = new RestClientOptions(RequestOptions.DEFAULT, true);

ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper(), options);

ElasticsearchClient esClientOptions = new ElasticsearchClient(transport);

(the name retrieveOriginalJsonResponseOnException is clearly up to debate)

@l-trotta l-trotta requested a review from swallez October 1, 2024 15:14
JsonParser parser = mapper.jsonProvider().createParser(content)
) {
response = responseParser.deserialize(parser, mapper);
} catch (Exception e) {
throw new TransportException(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

custom exception to avoid changing too many lines around

@@ -64,6 +64,11 @@ public Function<List<String>, Boolean> onWarnings() {
return null;
}

@Override
public boolean retrieveOriginalJsonResponseOnException() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename it to something shorter like keepResponseBodyOnException()? With a javadoc saying something like "Should the response body always be buffered and made available in TransportException.response.body()?"


// if the option to print the original body has been set, the body has to be
// copied first to another stream to be read again by the exception class
if(options().retrieveOriginalJsonResponseOnException()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have something similar for error responses:

// We may have to replay it.
if (!entity.isRepeatable()) {
entity = new ByteArrayBinaryData(entity);
}

We could do the same here. Or even factorize it in a new method BinaryData ensureRepeatable() in BinaryData

* The original response body, before json deserialization.
*/
@Nullable
public String originalBody() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a different kind of exception depending on the "capture body" flag is a bit confusing.

Another approach would be to add a new implementation of TransportHttpClient.Response, e.g. RepeatableBodyResponse that would wrap another response to ensure its body (if any) is repeatable, and delegate everything else to the wrapped response. This could even replace the entity = new ByteArrayBinaryData(entity) suggestion above.

@@ -181,6 +192,11 @@ public TransportOptions.Builder onWarnings(Function<List<String>, Boolean> liste
return this;
}

@Override
public TransportOptions.Builder retrieveOriginalJsonResponseOnException(boolean value) {
return this;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it empty? It should set a boolean flag in the builder, and setRetrieveOriginalJsonResponseOnException on RestClientOptions should be removed to keep it immutable.

@l-trotta
Copy link
Contributor Author

l-trotta commented Oct 8, 2024

@swallez entire PRs has been refactored based on our latest discussion

@@ -88,6 +88,11 @@ public Function<List<String>, Boolean> onWarnings() {
return onWarnings;
}

@Override
public boolean keepResponseBodyOnException() {
return false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a new field here, that is initialized from the builder's keepResponseBodyOnException.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the default one, shouldn't it be false by default?

return repeatableBody;
}

public String getOriginalBodyAsString() throws IOException {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is used only in tests. Let's not add in the public API some things that aren't required to use the library.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually wanted to provide this as a utility method to let users get the string directly

@@ -112,6 +119,9 @@ public CompletableFuture<Response> performRequestAsync(
future.cancellable = restClient.performRequestAsync(restRequest, new ResponseListener() {
@Override
public void onSuccess(org.elasticsearch.client.Response response) {
if (options.keepResponseBodyOnException()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be moved to ElasticsearchTransportBase, which will allow it to be independent of the actual HttpClient implementation, and also RepeatableBodyResponse which will then implement TransportHttpClient.Response.

@@ -63,7 +65,8 @@ static RestClientOptions of(@Nullable TransportOptions options) {
return builder.build();
}

public RestClientOptions(RequestOptions options) {
public RestClientOptions(RequestOptions options, boolean keepResponseBodyOnException) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should keep the existing constructor without the additional parameter to avoid a breaking change (and default the additional parameter to false).

Also, to be future proof if we add more options in the features, what about changing this constructor to RestClientOptions(RequestOptions.Builder builder) so that we can add more properties without impacting the constructor's signature?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the future proof constructor will make more sense when we'll have control over RequestOptions in the low level client!

Copy link
Member

@swallez swallez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! We should also mention it in the release highlights and the troubleshooting docs.

@l-trotta l-trotta merged commit d9cb8c5 into main Oct 17, 2024
7 checks passed
@l-trotta l-trotta deleted the json-deser-exc branch October 17, 2024 15:46
github-actions bot pushed a commit that referenced this pull request Oct 17, 2024
…urred (#886)

* base working impl

* twr, remove unused constructor

* unit test

* license

* complete refactor

* reverting old changes

* codestyle

* leave ElasticsearchTransportBase untouched

* Update java-client/src/main/java/co/elastic/clients/transport/TransportOptions.java

Co-authored-by: Sylvain Wallez <[email protected]>

* Update java-client/src/main/java/co/elastic/clients/transport/TransportOptions.java

Co-authored-by: Sylvain Wallez <[email protected]>

* custom generic response, checking in transport base

* license header

* asciidocs

---------

Co-authored-by: Sylvain Wallez <[email protected]>
github-actions bot pushed a commit that referenced this pull request Oct 17, 2024
…urred (#886)

* base working impl

* twr, remove unused constructor

* unit test

* license

* complete refactor

* reverting old changes

* codestyle

* leave ElasticsearchTransportBase untouched

* Update java-client/src/main/java/co/elastic/clients/transport/TransportOptions.java

Co-authored-by: Sylvain Wallez <[email protected]>

* Update java-client/src/main/java/co/elastic/clients/transport/TransportOptions.java

Co-authored-by: Sylvain Wallez <[email protected]>

* custom generic response, checking in transport base

* license header

* asciidocs

---------

Co-authored-by: Sylvain Wallez <[email protected]>
l-trotta added a commit that referenced this pull request Oct 17, 2024
…urred (#886) (#898)

* base working impl

* twr, remove unused constructor

* unit test

* license

* complete refactor

* reverting old changes

* codestyle

* leave ElasticsearchTransportBase untouched

* Update java-client/src/main/java/co/elastic/clients/transport/TransportOptions.java



* Update java-client/src/main/java/co/elastic/clients/transport/TransportOptions.java



* custom generic response, checking in transport base

* license header

* asciidocs

---------

Co-authored-by: Laura Trotta <[email protected]>
Co-authored-by: Sylvain Wallez <[email protected]>
l-trotta added a commit that referenced this pull request Oct 17, 2024
…urred (#886) (#897)

* base working impl

* twr, remove unused constructor

* unit test

* license

* complete refactor

* reverting old changes

* codestyle

* leave ElasticsearchTransportBase untouched

* Update java-client/src/main/java/co/elastic/clients/transport/TransportOptions.java



* Update java-client/src/main/java/co/elastic/clients/transport/TransportOptions.java



* custom generic response, checking in transport base

* license header

* asciidocs

---------

Co-authored-by: Laura Trotta <[email protected]>
Co-authored-by: Sylvain Wallez <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants