title: Using CompletableFuture with @Async returns an empty response for spring boot API
body: <p>Here is my controller. I used postman to test if it's working but I am getting an empty response. I used <code>@EnableAsync</code> in application configuration and <code>@Async</code> on the service. If I remove <code>@Async</code> on service layer it works but it doesn't run asynchronously.</p>
  
  <pre><code>@ApiOperation(value = "search person by passing search criteria event/title/role/host/is_current", response = ElasticSearchResultData.class)
  @RequestMapping(value = "/async2/searchPerson", produces = "application/json", method = RequestMethod.POST)
  public @ResponseBody CompletableFuture&lt;ElasticSearchResultData&gt; searchPersonAsync2(@RequestBody SearchCriteriaTo criteriaForDivNetFolderTo,
          HttpServletRequest request, HttpServletResponse response){
      LOGGER.info("searchPerson controller start");
      SearchCriteria searchCriteria = criteriaForDivNetFolderTo.getSearchCriteria();
      if (Util.isNull(searchCriteria)) 
          throw new IllegalArgumentException("search criteria should not be null.");
  
      try {
          CompletableFuture&lt;ElasticSearchResultData&gt; searchPerson = cubService.searchPersonAsync2(criteriaForDivNetFolderTo);
          ObjectMapper mapper = new ObjectMapper();
          LOGGER.info("search Person "+mapper.writeValueAsString(searchPerson));
          return searchPerson;
      } catch (Exception e) {
          LOGGER.error("Exception in searchPersonAsync controller "+e.getMessage());
      }
      return null;
  }
  </code></pre>
  
  <p>Service</p>
  
  <pre><code>@Async
  @Override
  public CompletableFuture&lt;ElasticSearchResultData&gt; searchPersonAsync2(SearchCriteriaTo searchCriteriaForDivNetFolderTo) {
     Long start = System.currentTimeMillis();
     LOGGER.info(":in searchPerson");
     CompletableFuture&lt;ElasticSearchResultData&gt; completableFuture = new CompletableFuture&lt;&gt;();
     ElasticSearchResultData searchResultData = null;
     SearchCriteria searchCriteria = searchCriteriaForDivNetFolderTo.getSearchCriteria();
     try {
          LOGGER.info("************ Started searchPerson by criteria ************");
          StringBuilder url = new StringBuilder();
          url.append(equilarSearchEngineApiUrl)
          .append(focusCompanySearchUrl)
          .append("/")
          .append("searchPerson")
          .append("?view=").append(VIEW_ALL)
          .append("&amp;isProcessing=true");
  
          LOGGER.debug("Calling equilar search engine for focused company search, URL : " + url);
          LOGGER.info(searchCriteria.toString());
          String output = null;
          if (redisEnable != null &amp;&amp; redisEnable) {
              output = cacheDao.getDataFromRestApi(url.toString(), RequestMethod.POST.name(), searchCriteria);
          } else {
              output = Util.getDataFromRestApi(url.toString(), RequestMethod.POST.name(), searchCriteria);
          }
          if (!Util.isEmptyString(output)) {
              ObjectMapper objectMapper = new ObjectMapper();
              objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
              objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
              searchResultData = objectMapper.readValue(output,
                              objectMapper.getTypeFactory().constructType(ElasticSearchResultData.class));
          }
          List&lt;PersonSearchDetails&gt; newPersonDetails = new ArrayList&lt;PersonSearchDetails&gt;();
          if (!Util.isNull(searchResultData) &amp;&amp; !Util.isNullOrEmptyCollection(searchResultData.getPersonDetails())
                  &amp;&amp; !Util.isNullOrEmptyCollection(searchCriteriaForDivNetFolderTo.getNetworkFoldersData())) {
              for (PersonSearchDetails personDetail : searchResultData.getPersonDetails()) {
                  String logoUrl = null;
                  if(!Util.isNull(searchCriteria.getTargetFolderId())){
                      List&lt;DiversityNetworkFolderTo&gt; filteredFolderTos = searchCriteriaForDivNetFolderTo
                              .getNetworkFoldersData()
                              .stream()
                              .filter(folder -&gt; folder.getId()
                              .longValue() == searchCriteria
                              .getTargetFolderId())
                              .collect(Collectors.toList());
                      logoUrl = getLogoUrl(personDetail.getPersonId(),
                              filteredFolderTos);
                  } else {
                      logoUrl = getLogoUrl(personDetail.getPersonId(),
                              searchCriteriaForDivNetFolderTo.getNetworkFoldersData());
                  }
                  personDetail.setLogoUrl(logoUrl);
                  newPersonDetails.add(personDetail);
              }
              searchResultData.setPersonDetails(newPersonDetails);
          }
          completableFuture.complete(searchResultData);
          return completableFuture;
      } catch (Exception e) {
          completableFuture.completeExceptionally(e);
          LOGGER.error(
                  " ************** Error in proccessing searchPerson by criteria ************** " + e.getMessage());
      }
      Long end = System.currentTimeMillis();
      LOGGER.info(TIME_DURATION+(end - start)+"ms");
      return null;
  }
  </code></pre>