All Downloads are FREE. Search and download functionalities are using the official Maven repository.

graphql.kickstart.servlet.BatchedQueryResponseWriter Maven / Gradle / Ivy

package graphql.kickstart.servlet;

import graphql.ExecutionResult;
import graphql.kickstart.execution.GraphQLObjectMapper;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RequiredArgsConstructor
class BatchedQueryResponseWriter implements QueryResponseWriter {
  private final List results;
  private final GraphQLObjectMapper graphQLObjectMapper;

  @Override
  public void write(HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.setCharacterEncoding(StandardCharsets.UTF_8.name());
    response.setContentType(HttpRequestHandler.APPLICATION_JSON_UTF8);
    response.setStatus(HttpRequestHandler.STATUS_OK);

    // Use direct serialization to byte arrays and avoid any string concatenation to save multiple
    // GiB of memory allocation during large response processing.
    List serializedResults = new ArrayList<>(2 * results.size() + 1);

    if (!results.isEmpty()) {
      serializedResults.add("[".getBytes(StandardCharsets.UTF_8));
    } else {
      serializedResults.add("[]".getBytes(StandardCharsets.UTF_8));
    }
    long totalLength = serializedResults.get(0).length;

    // '[', ',' and ']' are all 1 byte in UTF-8.
    for (int i = 0; i < results.size(); i++) {
      byte[] currentResult = graphQLObjectMapper.serializeResultAsBytes(results.get(i));
      serializedResults.add(currentResult);

      if (i != results.size() - 1) {
        serializedResults.add(",".getBytes(StandardCharsets.UTF_8));
      } else {
        serializedResults.add("]".getBytes(StandardCharsets.UTF_8));
      }
      totalLength += currentResult.length + 1; // result.length + ',' or ']'
    }

    if (totalLength > Integer.MAX_VALUE) {
      throw new IllegalStateException(
          "Response size exceed 2GiB. Query will fail. Seen size: " + totalLength);
    }
    response.setContentLength((int) totalLength);

    for (byte[] result : serializedResults) {
      response.getOutputStream().write(result);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy