1

My project is based on Java 8 and uses Spring throughout I have a service that returns a bean which contains a list of beans in it.

Here is the code API Method

@RequestMapping(value = "/search",", produces = { MediaType.APPLICATION_JSON_VALUE }, method = RequestMethod.POST)
@ResponseBody
public DeferredResult<EmpAdvancedSearchPageBean> getSearch(
        @RequestBody final EmpBean empBean) {

    LOGGER.info("Pre getSearch");
    EmpSearchPageBean searchPageBean = dataService.getSearch(empBean);
    LOGGER.info("Post getSearch");

    LOGGER.info("Pre set deffered result");
    DeferredResult<EmpSearchPageBean> deferredResult = new DeferredResult<>();
    deferredResult.setResult(searchPageBean);
    LOGGER.info("Post set deffered result");

    return deferredResult;
}

EmpSearchPageBean

public class EmpSearchPageBean implements java.io.Serializable   {

    private static final long serialVersionUID = 8085664391632415982L;

    @JsonProperty("draw")
    private Integer draw;

    @JsonProperty("recordsTotal")
    private Integer recordsTotal;

    @JsonProperty("recordsFiltered")
    private Integer recordsFiltered;

    @JsonProperty("data")
    private List<EmpSearch> data;   
}   

EmpSearch

public class EmpSearch implements java.io.Serializable   {

    private static final long serialVersionUID = -7665557350420327753L;

    @JsonProperty("divisionDesc")
    private String divisionDesc;

    @JsonProperty("corpId")
    private String corpId;

    @JsonProperty("businessUnitDesc")
    private String businessUnitDesc;

    @JsonProperty("fdirName")
    private String fdirName;

}

If the list of data ( List data; ) contains 500 records - this service returns in about 2 seconds However if it contains around 2000 records (which is a common use case), it can take up to 2 minutes to return

Based on my log statements - it takes about 2 seconds to return this data from the database and the rest of the time is taken up producing the json.

I am using Spring Web version 4.3.3.RELEASE. from the debug logs I can see that it is using the class org.springframework.http.converter.json.MappingJackson2HttpMessageConverter

Can anyone offer any advise on what I need to do in order to render large quantities of json data successfully?

Damien
  • 4,081
  • 12
  • 75
  • 126
  • 1
    Are you sure you have to return 2k records one shot ? Second question how many "few seconds" does it need for 500 record ; perhaps 4*"few second" = 2 minutes... – Zorglube Nov 16 '16 at 14:12
  • Unfortunately yes we need to return this number of records. When I say a few - I mean 2 seconds – Damien Nov 16 '16 at 14:15
  • I'm sure you have to return 2k records, but perhaps you can return them in tow, three even four request ? – Zorglube Nov 16 '16 at 14:17
  • The database calls are working 100%, are optimized and have appropriate caching in place. We could separate out the calls but it is not something we want to do at this time as we cannot guarantee the number of results for any 1 query. There could be 2 thousand records returned - another time there could be 2 records – Damien Nov 16 '16 at 14:19
  • @Damo, ok, if the DB request is good, perhaps the transfer via isn't the best choise... Can you use file tranfer instead of Json ? – Zorglube Nov 16 '16 at 14:21
  • File transfer is not an option - if it was we would have gone that route. I am looking for an answer on this post to definitively say how much data can be returned in a call or if there are options available to us – Damien Nov 16 '16 at 14:23
  • @Damo, did you tried to return different size of list to see how the time evolve ? – AxelH Nov 16 '16 at 14:26
  • @AxelH - I have yes - 2 / 3 records returns fast. Up to 100 records return in about 1 second, about 500 records return in 2 seconds. – Damien Nov 16 '16 at 14:27
  • @Damo, the answer you're looking for is probably : you can return any size of record BUT the more you return the more you'll have to wait. Othe question, is your big chunk of record destinated to an grid or an end user interface ? An so subsidiary question, what is the interface ? – Zorglube Nov 16 '16 at 14:27
  • More test, 1, 10, 100, 200, 500, 1000, 2000. From what you are saying, this is not linear ... which is not logic. – AxelH Nov 16 '16 at 14:28
  • 2
    I don't know how you measured the time, but with large amount of data, you could write directly to the outputstream, and read that from client side if it's an option. (With spring for example you can use `ResponseExtractor`.) – grape_mao Nov 16 '16 at 14:29
  • @grape_mao - excellent - would you be able to point me at any examples of this? – Damien Nov 16 '16 at 15:31
  • Well, you could jsut google that, like: [here](http://stackoverflow.com/questions/3146461/does-spring-mvc-have-response-write-to-output-to-the-browser-directly) and [here](http://stackoverflow.com/questions/32988370/download-large-file-from-server-using-rest-template-java-spring-mvc) – grape_mao Nov 16 '16 at 15:36
  • @grape_mao - just tried this approach and unfortunately it shows the same issues – Damien Nov 16 '16 at 15:48
  • I just saw you are using `DeferredResult`, don't know if it has an impact. Could you test without it and manually convert result to json using `ObjectMapper` and write to the stream. Also the part that may be slow is `List`, you may need to convert this list little by little with a customized `JsonSerializer`. – grape_mao Nov 16 '16 at 16:05
  • @grape_mao I have tried all those steps except the customized JsonSerializer and it is still the same case unfortunately. Will try that now – Damien Nov 17 '16 at 09:34
  • 1
    Well, like I said I don't know how you measured the time...If creating a large JSON takes too much time, you probably need to write the list item by item to the output stream instead of the a JSON string of the whole object. – grape_mao Nov 17 '16 at 09:44
  • 1
    An easier way is ignore the 3 Integer fields and return of the list, Customized `JsonSerializer` may not change anything, it will return a JSON of the whole object. – grape_mao Nov 17 '16 at 09:49
  • We have decided to refactor the code to not return as much data. Changing the return type to an array or just returning the list or the custom JsonSerializer didnt provide much gains. Thanks for your help @grape_mao – Damien Nov 17 '16 at 11:38
  • 1
    Ok, just change the return type will do nothing, what I mean is write little by little to the outputstream (even flush manually). But anyway, if you can use pagination, then it's better. – grape_mao Nov 17 '16 at 11:43

1 Answers1

1

Decided to refactor code to not return as much json data. Tried multiple suggestions based on question feedback but did not get the required gains

Damien
  • 4,081
  • 12
  • 75
  • 126
  • 1
    IMHO this is just a workaround for some strange bug. My server using Mysql+Hibernate+Gson+java.util.zip on my old i5-2400 @ 3.10GHz returns 4500 items (1.7 MB uncompressed) in 300 ms. There's no superlinear slowdown there. – maaartinus Nov 20 '16 at 10:51
  • If the JSON is not too complicated, you could construct it yourself using `com.google.gson.stream.JsonWriter`. This is what I'm doing and it works well. I'm serializing and streaming back 300KiB of uncompressed json using gson's `JsonWriter` in between 50-150ms on an `i7-8650U @ 1.90GHz`. I'm not sure how this compares to using the `@JsonProperty`, etc for automatic serialization. – theferrit32 Jul 03 '19 at 23:02