3
\$\begingroup\$

I am working on a project in which I am making a call to one of my servers using RestTemplate which is running a RESTful service and getting the response back from them.

The response that I will be getting from my server can be either of these error responses (that's all I have for error response) if something has gone wrong:

{"warning": "user_id not found", "user_id": some_user_id}
{"error": "user_id for wrong partition", "user_id": some_user_id, "partition": some_partition}
{"error": "missing client id", "client_id":2000}

or below successful response if there is no failures (it can be any random json string, key can be different as well) -

{"@data": {"oo":"1205000384","p":"2047935"}}
  1. If I am getting any error response as mentioned above, then I am deserializing it so that I can log them as an error with a specific error or warning I got front the server which can be for example - user_id not found or missing client id.
  2. If it is a successful response, then I am also deserializing it, which I don't need for my use case as we don't have any POJO. I just need to return the response as is which I receive from the server.

In my use case, I don't need to deserialize my response string if it is a successful response as we don't have any POJO for that and we are returning the response string as it is which we have got from the server. But just for logging specific error messages (if I am getting error response from the server) I am deserializing it which I am thinking is unnecessary. There might be better solution for my use case.

Here is my Java client which is calling a Callable task using future.get:

public class TestingClient implements IClient {

    private ExecutorService service = Executors.newFixedThreadPool(10);
    private RestTemplate restTemplate = new RestTemplate();

    @Override
    public String executeSync(ClientKey keys) {

        String response = null;
        try {

            ClientTask ClientTask = new ClientTask(keys, restTemplate);
            Future<String> future = service.submit(ClientTask);
            response = handle.get(keys.getTimeout(), TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {

        } catch (Exception e) {

        }

        return response;
    }
}

And here is my ClientTask class, which implements the Callable interface. In the call method, I am generating a URL and then hit the server using RestTemplate and get the response back:

class ClientTask implements Callable<String> {

    private ClientKey cKeys;
    private RestTemplate restTemplate;

    public ClientTask(ClientKey cKeys, RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
        this.cKeys = cKeys;
    }

    @Override
    public String call() throws Exception {

        // .. some code here
        String url = "some_url";            
        String response = restTemplate.getForObject(url, String.class);

        String test = checkJSONResponse(response);

        return test;
    }

    private String checkJSONResponse(final String response) throws Exception {

        // may be there are some better way of doing it for my scenario instead of using GSON
        Gson gson = new Gson();
        String str = null;
        JsonObject jsonObject = gson.fromJson(response, JsonObject.class); // parse it, may be performance issues here/
        if (jsonObject.has("error") || jsonObject.has("warning")) {

        final String error = jsonObject.get("error") != null ? jsonObject.get("error").getAsString() : jsonObject
        .get("warning").getAsString();

        // log specific `error` here using log4j
        str = response;
        } else {
            str = response;
        }

        return str;
    }
}

As you can see, we are deserializing the JSON string only to log specific error messages if we are getting any error response back. But for successful response we don't need any deserialization but still we are doing it.

Is there any better way of solving this problem? I am currently seeing some performance issues with the GSON deserialization. The only way I can identify successful response is error response will have error or warning in the response. I guess there might be some better way of solving this problem without paying the cost for deserialization.

\$\endgroup\$
2
\$\begingroup\$

If you have indeed identified the json deserialization to be a performance problem (by profiling it) then you can

  1. Try using a different json serializer (GSon was reported at least in the past to be a fair bit slower than for example Jackson)
  2. Don't deserialize and check the string manually.

From "one of my servers" I conclude that you control exactly what responses the server can send and how they are composed. In which case a simple:

if (response.contains("error") || response.contains("warning")) {
    ...
}

might suffice and be robust enough. When handling the error case you could then either still deserialize the message or just use some string splitting or regular expressions in order to extract the data for logging. Or you could simply log the entire json - it's human readable and a log parser could easily extract the relevant data for analysis afterwards.

\$\endgroup\$
  • \$\begingroup\$ Thanks Chris. For your second option, it might be possible for some of my successful response string, it has error or warning in it, I don't know when and it is very unlikely to happen but to be on the safer side, I am not trying that option. I might want to try regular expression option which can check whether my response string has error or warning as the first key, if it is there then extract the specific error message and log it. If possible can you provide an example on that. Thanks. \$\endgroup\$ – david Jan 26 '14 at 16:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.