Skip to content

[Bug]: IllegalStateException when deseralizing "error" #239

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

Closed
terrettazmaxime opened this issue Mar 15, 2023 · 7 comments · Fixed by #242
Closed

[Bug]: IllegalStateException when deseralizing "error" #239

terrettazmaxime opened this issue Mar 15, 2023 · 7 comments · Fixed by #242
Labels
triage Issue is being researched

Comments

@terrettazmaxime
Copy link

Software Version

6.3.0

Language Version

11

Operating System

Linux

What happened?

We have noticed a bug in the software that occurs every time there is a validation errors when performing a One-Call Buy Shipment with Purolator and they return multiple validation errors.
The bug is related to the deserialization of the JSON errors, which is not functioning as expected.
Specifically, we have identified that when your code is deserializing the error node, it expects the message to be either a string or an array, but in this case, it is an object, it cashes in your internal code, and we do not get an EasyPostException.
This issue is causing us significant trouble as we are currently unable to move forward with our production process.

I have included the JSON that is causing the problem below, as an example:

{
    "error": {
        "code": "UNPROCESSABLE_ENTITY",
        "message": {
            "errors": [
                "1100156: From On Label address is an invalid Service Point.",
                "1100674: Postal Code XXX is only valid for XXX."
            ]
        },
        "errors": [
            {
                "message": "1100156: From On Label address is an invalid Service Point."
            },
            {
                "message": "1100674: Postal Code XXX is only valid for XXX."
            }
        ]
    }
}

Code of your Error class
package com.easypost.model;

import java.util.List;

public final class Error {
    private String message;
    private String code;
    private List<Error> errors;
    private String suggestion;
    private String field;

    public Error() {
    }

    void setMessage(String message) {
        this.message = message;
    }

    void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return this.message;
    }

    public String getCode() {
        return this.code;
    }

    public List<Error> getErrors() {
        return this.errors;
    }

    public String getSuggestion() {
        return this.suggestion;
    }

    public String getField() {
        return this.field;
    }
}

When your deserializer, do the work, the message node is not a string, neither an array but and object and it crash.

public final class ErrorDeserializer implements JsonDeserializer<Error> {
    public ErrorDeserializer() {
    }

    public Error deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonObject jo = json.getAsJsonObject();
        JsonElement results = jo.get("error");
        Gson gson = new Gson();
        if (results == null) {
            Error error = new Error();
            error.setMessage("API did not return error details.");
            error.setCode("NO RESPONSE CODE");
            return error;
        } else {
            JsonElement errorMessage = results.getAsJsonObject().get("message");
            if (errorMessage.isJsonArray()) { // This does not handle cases where it is an object
                JsonArray jsonArray = errorMessage.getAsJsonArray();
                ArrayList<String> messages = new ArrayList();

                for(int i = 0; i < jsonArray.size(); ++i) {
                    messages.add(jsonArray.get(i).getAsString());
                }

                JsonPrimitive value = new JsonPrimitive(String.join(", ", messages));
                results.getAsJsonObject().add("message", value);
            }

            return (Error)gson.fromJson(results, Error.class);
        }
    }
}

What was expected?

The library to return a EasyPostException and beeing able to parse Errors correctly.

Sample Code

No response

Relevant logs

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected STRING but was BEGIN_OBJECT at path $.message
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226)
        at com.google.gson.Gson.fromJson(Gson.java:932)
        at com.google.gson.Gson.fromJson(Gson.java:1003)
        at com.google.gson.Gson.fromJson(Gson.java:975)
        at com.easypost.model.ErrorDeserializer.deserialize(ErrorDeserializer.java:53)
        at com.easypost.model.ErrorDeserializer.deserialize(ErrorDeserializer.java:16)
        at com.google.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:69)
        at com.google.gson.Gson.fromJson(Gson.java:932)
        at com.google.gson.Gson.fromJson(Gson.java:897)
        at com.google.gson.Gson.fromJson(Gson.java:846)
        at com.google.gson.Gson.fromJson(Gson.java:817)
        at com.easypost.http.Requestor.handleAPIError(Requestor.java:530)
        at com.easypost.http.Requestor.httpRequest(Requestor.java:514)
        at com.easypost.http.Requestor.request(Requestor.java:438)
        at com.easypost.service.ShipmentService.create(ShipmentService.java:58)
        at com.easypost.service.ShipmentService.create(ShipmentService.java:40)
        at com.easypost.service.ShipmentService$create.call(Unknown Source)
@jchen293
Copy link
Contributor

Hi @terrettazmaxime

Thank you for bringing this issue to our attention. I am glad that you are using our latest Java library version.

A similar issue was previously reported by another user regarding Purolator returning an array in the error message. In response, we implemented a guard clause in our client libraries to handle such edge cases during error deserialization.

Regarding your reported issue, we have created an internal task to investigate whether this issue is occurring at the API level. If it is found to be the case, we will patch the issue at the API level, rather than making changes in all seven client libraries. We will keep you informed of any updates on this matter.

Thank you again for your valuable feedback.

@terrettazmaxime
Copy link
Author

@jchen293 Do you have any EAT for a fix, this is currently breaking our elements using Purolator.

@jchen293
Copy link
Contributor

Hello @terrettazmaxime , I've left a comment on your PR #240. If you can address the feedback, we can proceed with merging the PR. Please let me know if you would like me to take care of the rest of the PR.

@terrettazmaxime
Copy link
Author

Hello @jchen293 , I will appreciate if you can handle the PR and move this forward.

@jchen293
Copy link
Contributor

@terrettazmaxime I have opened PR #242 for this issue and it's waiting for reviews, I will let you know when we make a release. Thanks for reporting this issue again!

@jchen293
Copy link
Contributor

@terrettazmaxime I have merged PR #242 to handle these edge cases when deserializing error JSON, we are planning to release it tomorrow. Stay tuned and thanks for reporting this issue again!

@jchen293
Copy link
Contributor

@terrettazmaxime Exciting news, we have just released v6.3.1 for the patch of this issue😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triage Issue is being researched
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants