private Map<String, Object> resolveArguments(Map<String, Object> objectMap, Operation.Variables variables) { Map<String, Object> result = new TreeMap<>(argumentNameComparator); for (Map.Entry<String, Object> entry : objectMap.entrySet()) { if (entry.getValue() instanceof Map) { Map<String, Object> nestedObjectMap = (Map<String, Object>) entry.getValue(); if (ResponseField.isArgumentValueVariableType(nestedObjectMap)) { result.put(entry.getKey(), resolveVariableArgument(nestedObjectMap, variables)); } else { result.put(entry.getKey(), resolveArguments(nestedObjectMap, variables)); } } else { result.put(entry.getKey(), entry.getValue()); } } return result; }
/** * Factory method for creating a Field instance representing a custom {@link Type#OBJECT}. * * @param responseName alias for the result of a field * @param fieldName name of the field in the GraphQL operation * @param arguments arguments to be passed along with the field * @param optional whether the arguments passed along are optional or required * @param conditions list of conditions for this field * @return Field instance representing custom {@link Type#OBJECT} */ public static ResponseField forObject(String responseName, String fieldName, Map<String, Object> arguments, boolean optional, List<Condition> conditions) { return new ResponseField(Type.OBJECT, responseName, fieldName, arguments, optional, conditions); }
private static void checkFieldValue(ResponseField field, Object value) { if (!field.optional() && value == null) { throw new NullPointerException(String.format("Mandatory response field `%s` resolved with null value", field.responseName())); } }
@Override public void willResolve(ResponseField field, Operation.Variables variables) { try { jsonWriter.name(field.responseName()); if (field.type() == ResponseField.Type.LIST) { jsonWriter.beginArray(); } } catch (IOException e) { throw new RuntimeException(e); } }
private String orderIndependentKey(Map<String, Object> objectMap, Operation.Variables variables) { if (isArgumentValueVariableType(objectMap)) { return orderIndependentKeyForVariableArgument(objectMap, variables); boolean isArgumentVariable = isArgumentValueVariableType(objectArg); independentKey .append(argument.getKey()) .append(":") .append(isArgumentVariable ? "" : "[") .append(orderIndependentKey(objectArg, variables)) .append(isArgumentVariable ? "" : "]"); } else {
@SuppressWarnings("unchecked") @Override public <T> T valueFor(Map<String, Object> map, ResponseField field) { return (T) map.get(field.responseName()); } }
@Override public <T> T readConditional(ResponseField field, ConditionalTypeReader<T> conditionalTypeReader) { if (shouldSkip(field)) { return null; } willResolve(field); String value = fieldValueResolver.valueFor(recordSet, field); checkValue(field, value); if (value == null) { resolveDelegate.didResolveNull(); didResolve(field); return null; } else { resolveDelegate.didResolveScalar(value); didResolve(field); if (field.type() == ResponseField.Type.INLINE_FRAGMENT) { for (ResponseField.Condition condition : field.conditions()) { if (condition instanceof ResponseField.TypeNameCondition) { if (((ResponseField.TypeNameCondition) condition).typeName().equals(value)) { return conditionalTypeReader.read(value, this); } } } return null; } else { return conditionalTypeReader.read(value, this); } } }
public String cacheKey(Operation.Variables variables) { if (arguments.isEmpty()) { return fieldName(); } return String.format("%s(%s)", fieldName(), orderIndependentKey(arguments, variables)); }
@NotNull @Override public String build(@NotNull ResponseField field, @NotNull Operation.Variables variables) { checkNotNull(field, "field == null"); checkNotNull(variables, "variables == null"); if (field.arguments().isEmpty()) { return field.fieldName(); } Object resolvedArguments = resolveArguments(field.arguments(), variables); try { Buffer buffer = new Buffer(); JsonWriter jsonWriter = JsonWriter.of(buffer); jsonWriter.setSerializeNulls(true); Utils.writeToJson(resolvedArguments, jsonWriter); jsonWriter.close(); return String.format("%s(%s)", field.fieldName(), buffer.readUtf8()); } catch (IOException e) { throw new RuntimeException(e); } }
@SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) @Override public <T> T valueFor(Record record, ResponseField field) { switch (field.type()) { case OBJECT: return (T) valueForObject(record, field); case LIST: { return (T) valueForList((List) fieldValue(record, field)); } default: return fieldValue(record, field); } }
@SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) private <T> T fieldValue(Record record, ResponseField field) { String fieldKey = cacheKeyBuilder.build(field, variables); if (!record.hasField(fieldKey)) { throw new NullPointerException("Missing value: " + field.fieldName()); } return (T) record.field(fieldKey); } }
private boolean shouldSkip(ResponseField field) { for (ResponseField.Condition condition : field.conditions()) { if (condition instanceof ResponseField.BooleanCondition) { ResponseField.BooleanCondition booleanCondition = (ResponseField.BooleanCondition) condition; Boolean conditionValue = (Boolean) variableValues.get(booleanCondition.variableName()); if (booleanCondition.inverted()) { // means it's a skip directive if (Boolean.TRUE.equals(conditionValue)) { return true; } } else { // means it's an include directive if (Boolean.FALSE.equals(conditionValue)) { return true; } } } } return false; }
@Override public void willResolve(ResponseField field, Operation.Variables variables) { String key = field.cacheKey(variables); path.add(key); }
private String orderIndependentKeyForVariableArgument(Map<String, Object> objectMap, Operation.Variables variables) { Object variable = objectMap.get(VARIABLE_NAME_KEY); //noinspection SuspiciousMethodCalls Object resolvedVariable = variables.valueMap().get(variable); if (resolvedVariable == null) { return null; } else if (resolvedVariable instanceof Map) { //noinspection unchecked return orderIndependentKey((Map<String, Object>) resolvedVariable, variables); } else { return resolvedVariable.toString(); } }
private String orderIndependentKey(Map<String, Object> objectMap, Operation.Variables variables) { if (isArgumentValueVariableType(objectMap)) { return orderIndependentKeyForVariableArgument(objectMap, variables); boolean isArgumentVariable = isArgumentValueVariableType(objectArg); independentKey .append(argument.getKey()) .append(":") .append(isArgumentVariable ? "" : "[") .append(orderIndependentKey(objectArg, variables)) .append(isArgumentVariable ? "" : "]"); } else {
@Override public void writeList(@NotNull ResponseField field, @Nullable List values, @NotNull ListWriter listWriter) { checkFieldValue(field, values); if (values == null) { buffer.put(field.responseName(), new FieldDescriptor(field, null)); return; } List accumulated = new ArrayList(); listWriter.write(values, new ListItemWriter(operationVariables, scalarTypeAdapters, accumulated)); buffer.put(field.responseName(), new FieldDescriptor(field, accumulated)); }
private static void checkFieldValue(ResponseField field, Object value) { if (!field.optional() && value == null) { throw new NullPointerException(String.format("Mandatory response field `%s` resolved with null value", field.responseName())); } }
@Override public <T> T readConditional(ResponseField field, ConditionalTypeReader<T> conditionalTypeReader) { if (shouldSkip(field)) { return null; } willResolve(field); String value = fieldValueResolver.valueFor(recordSet, field); checkValue(field, value); if (value == null) { readerShadow.didResolveNull(); didResolve(field); return null; } else { readerShadow.didResolveScalar(value); didResolve(field); if (field.type() == ResponseField.Type.INLINE_FRAGMENT) { for (ResponseField.Condition condition : field.conditions()) { if (condition instanceof ResponseField.TypeNameCondition) { if (((ResponseField.TypeNameCondition) condition).typeName().equals(value)) { return (T) conditionalTypeReader.read(value, this); } } } return null; } else { return (T) conditionalTypeReader.read(value, this); } } }