Связь нового типа регистра GraphQL с аргументом сборщика данных

Имея схему GraphQL:

type TypeA {
   id: ID,
   name: String,
   other: TypeC
}

type TypeB {
   id: ID,
   name: String,
   other: TypeC
}

Как мне реализовать проводку TypeC независимо от типа исходного объекта? Я знаю, что могу:

RuntimeWiring.newRuntimeWiring()
  .type(TypeRuntimeWiring.newTypeWiring("TypeA")
    .dataFetcher("other", dataFetcher_typeC.get())
  .type(TypeRuntimeWiring.newTypeWiring("TypeB")
    .dataFetcher("other", dataFetcher_typeC.get())
  .build()

но тогда сборщик данных зависит от типа исходного объекта:

DataFetcher<CompletableFuture<Collection<TypeC>>> get() {
  return dataFetchingEnvironment -> {
    <??> sourceObj = dataFetchingEnvironment.getSource();
    return getObject(sourceObj.someProperty);
  };
}

Учитывая, что оба POJO (TypeA и TypeB) имеют поле ссылки на TypeC, как разрешить поле TypeC по данной ссылке, а не по исходному объекту?

2 ответа

Из документации здесь

dataFetchingEnvironment предоставляет метод getExecutionStepInfo(), который возвращает объект ExecutionStepInfo. Оттуда вы можете получить информацию о родителях.

ExecutionStepInfo executionStepInfo = environment.getExecutionStepInfo();
ExecutionStepInfo parentInfo = executionStepInfo.getParent();
GraphQLObjectType parentType = (GraphQLObjectType) parentInfo.getUnwrappedNonNullType();

// parentType.getName() returns you "TypeA" or "TypeB"

На самом деле я нашел два возможных решения проблемы:

  1. При определении новой проводки получите исходный объект и от него поле. Вызвать метод dataFetcher с параметром, как обычный метод Java:
  2. Внутренний сборщик данных получает имя поля из DataFetcherEnvironment. Используйте отражение, чтобы получить поле из исходного объекта

Пример №1:

RuntimeWiring.newRuntimeWiring()
  .type(TypeRuntimeWiring.newTypeWiring("TypeA")
    .dataFetcher("other", environment -> {
        TypeA sourceObj = environment.getSource();
        return dataFetcher_typeC.get(sourceObj.other)})
  .type(TypeRuntimeWiring.newTypeWiring("TypeB")
        TypeB sourceObj = environment.getSource();
        return dataFetcher_typeC.get(sourceObj.other)})
  .build()

Пример №2:

DataFetcher<CompletableFuture<Collection<TypeC>>> get() {
  return dataFetchingEnvironment -> {
    Field  declaredField = dataFetchingEnvironment.getSource().getClass()
                  .getDeclaredField(dataFetchingEnvironment.getField().getName());
    declaredField.setAccessible(true);

    String value = (String) declaredField.get(dataFetchingEnvironment.getSource());
    return getObject(sourceObj.someProperty);
  };
}

Второй вариант выглядит лучше, но все еще не уверен, что это правильный подход.

Другие вопросы по тегам