package com.apollographql.apollo.internal.interceptor; import com.apollographql.apollo.api.Error; import com.apollographql.apollo.api.Operation; import com.apollographql.apollo.api.Response; import com.apollographql.apollo.api.ResponseFieldMapper; import com.apollographql.apollo.api.ScalarType; import com.apollographql.apollo.CustomTypeAdapter; import com.apollographql.apollo.internal.cache.normalized.ResponseNormalizer; import com.apollographql.apollo.internal.field.MapFieldValueResolver; import com.apollographql.apollo.internal.json.BufferedSourceJsonReader; import com.apollographql.apollo.internal.reader.RealResponseReader; import com.apollographql.apollo.internal.json.ResponseJsonStreamReader; import java.io.IOException; import java.util.List; import java.util.Map; import okhttp3.ResponseBody; import static com.apollographql.apollo.internal.json.ApolloJsonReader.responseJsonStreamReader; final class HttpResponseBodyParser<D extends Operation.Data, W> { private final Operation<D, W, ?> operation; private final ResponseFieldMapper responseFieldMapper; private final Map<ScalarType, CustomTypeAdapter> customTypeAdapters; HttpResponseBodyParser(Operation<D, W, ?> operation, ResponseFieldMapper responseFieldMapper, Map<ScalarType, CustomTypeAdapter> customTypeAdapters) { this.operation = operation; this.responseFieldMapper = responseFieldMapper; this.customTypeAdapters = customTypeAdapters; } public Response<W> parse(ResponseBody responseBody, final ResponseNormalizer<Map<String, Object>> networkResponseNormalizer) throws IOException { networkResponseNormalizer.willResolveRootQuery(operation); BufferedSourceJsonReader jsonReader = null; try { jsonReader = new BufferedSourceJsonReader(responseBody.source()); jsonReader.beginObject(); ResponseJsonStreamReader responseStreamReader = responseJsonStreamReader(jsonReader); D data = null; List<Error> errors = null; while (responseStreamReader.hasNext()) { String name = responseStreamReader.nextName(); if ("data".equals(name)) { //noinspection unchecked data = (D) responseStreamReader.nextObject(true, new ResponseJsonStreamReader.ObjectReader<Object>() { @Override public Object read(ResponseJsonStreamReader reader) throws IOException { Map<String, Object> buffer = reader.buffer(); RealResponseReader<Map<String, Object>> realResponseReader = new RealResponseReader<>( operation.variables(), buffer, new MapFieldValueResolver(), customTypeAdapters, networkResponseNormalizer); return responseFieldMapper.map(realResponseReader); } }); } else if ("errors".equals(name)) { errors = readResponseErrors(responseStreamReader); } else { responseStreamReader.skipNext(); } } jsonReader.endObject(); return new Response<>(operation, operation.wrapData(data), errors, networkResponseNormalizer.dependentKeys()); } finally { if (jsonReader != null) { jsonReader.close(); } } } private List<Error> readResponseErrors(ResponseJsonStreamReader reader) throws IOException { return reader.nextList(true, new ResponseJsonStreamReader.ListReader<Error>() { @Override public Error read(ResponseJsonStreamReader reader) throws IOException { return reader.nextObject(true, new ResponseJsonStreamReader.ObjectReader<Error>() { @Override public Error read(ResponseJsonStreamReader reader) throws IOException { return readError(reader); } }); } }); } private Error readError(ResponseJsonStreamReader reader) throws IOException { String message = null; List<Error.Location> locations = null; while (reader.hasNext()) { String name = reader.nextName(); if ("message".equals(name)) { message = reader.nextString(false); } else if ("locations".equals(name)) { locations = reader.nextList(true, new ResponseJsonStreamReader.ListReader<Error.Location>() { @Override public Error.Location read(ResponseJsonStreamReader reader) throws IOException { return reader.nextObject(false, new ResponseJsonStreamReader.ObjectReader<Error.Location>() { @Override public Error.Location read(ResponseJsonStreamReader reader) throws IOException { return readErrorLocation(reader); } }); } }); } else { reader.skipNext(); } } return new Error(message, locations); } @SuppressWarnings("ConstantConditions") private Error.Location readErrorLocation(ResponseJsonStreamReader reader) throws IOException { long line = -1; long column = -1; while (reader.hasNext()) { String name = reader.nextName(); if ("line".equals(name)) { line = reader.nextLong(false); } else if ("column".equals(name)) { column = reader.nextLong(false); } else { reader.skipNext(); } } return new Error.Location(line, column); } }