GraphQl Java, как я могу вслепую вернуть все переменные, связанные с объектом, из запроса и вопроса об обработке подклассов - PullRequest
0 голосов
/ 21 июня 2019

Я новичок в GraphQL и в настоящее время внедряю API-интерфейс GraphQL в установленный Java-код, используя GraphQL-SPQR, и у меня возникают проблемы с извлечением данных из иерархических классов.

Проблемы, с которыми я сталкиваюсь, заключаются в следующем.

Во-первых, я не знаю, есть ли простой способ получить все данные, связанные с возвращаемым узлом. Если это так, это было бы наиболее полезно для моих более сложных классов.

Во-вторых, когда метод возвращает абстрактный класс, мне кажется, что я могу только запросить переменные в абстрактном классе. Я уверен, что это возможно, я просто бью себя головой о стену.

В качестве простого примера

public abstract class Animal {
   private String name;
   private int age;

   // Constructor

   @GraphQLQuery(name = "name")
   public String getName() {
       return name;
   }

   // Age getter
}


public class Dog extends Animal {
   private String favouriteFood;

   // Constructor

   @GraphQLQuery(name = "favouriteFood")
   public String getFavouriteFood() {
       return favouriteFood;
   }
}


public class Database {
    @GraphQLQuery(name = "getanimal")
    public Animal getAnimal(@GraphQLArgument(name = "animalname") String animalname) {
        return database.get(name);
    }
}

Итак, в моем первом вопросе я сейчас спрашиваю. "{имя животного (имя: \" Ромашка \ ") {имя возраста}}" Это работает нормально, как и ожидалось. Однако, если вы представите, что класс имеет 10 переменных, я хотел бы просто написать эквивалент следующего без необходимости искать их. "{узел (имя: \" Ромашка \ ") {ВСЕ}}" Это возможно?

С точки зрения моего второго вопроса. Следующий запрос выдает ошибку ('Поле' favouriteFood 'в типе' Животное 'не определено')

"{animalname(name: \"Bones\") {name age favouriteFood}}"

аналогично (чтение встроенных фрагментов https://graphql.org/learn/queries/)

"{animalname(name: \"Bones\") {name age ... on Dog{favouriteFood}}}"

выдает ошибку Неизвестный тип Dog

Это раздражает, так как у меня есть несколько подклассов, которые могут быть возвращены и могут потребовать обработки в разных модах. Я думаю, что могу понять, почему это происходит, поскольку GraphQL не знает, что такое истинный класс, только суперкласс, который я возвратил. Однако мне интересно, есть ли способ исправить это.

В конечном итоге, хотя я могу обойти обе эти проблемы, просто сериализовав все данные в JSON и отправив их обратно, это как бы избавляет от смысла GraphQL, и я бы предпочел найти альтернативное решение.

Спасибо за любой ответ. Извиняюсь, если это основные вопросы.

1 Ответ

0 голосов
/ 26 июня 2019

Отвечая на мой вопрос, чтобы помочь кому-то еще, кто имеет эту проблему.

В абстрактном классе должен быть включен @GraphQLInterface, как показано ниже

@GraphQLInterface(name = "Animal ", implementationAutoDiscovery = true)
public abstract class Animal {
   private String name;
   private int age;

   // Constructor

   @GraphQLQuery(name = "name")
   public String getName() {
       return name;
   }

   // Age getter
}

Следующий код был найден после большого решения и был создан создателем SPQR. По сути, при настройке схемы вам необходимо объявить стратегию отображения интерфейса. Приведенный ниже код можно скопировать оптом, заменив только переменную «nodeQuery» службой, которую вы используете для хранения ваших методов «@GraphQLQuery» и «@GraphQLMutation».

final GraphQLSchema schema = new GraphQLSchemaGenerator()
                .withInterfaceMappingStrategy(new InterfaceMappingStrategy() {
                    @Override
                    public boolean supports(final AnnotatedType interfase) {
                        return interfase.isAnnotationPresent(GraphQLInterface.class);
                    }

                    @Override
                    public Collection<AnnotatedType> getInterfaces(final AnnotatedType type) {
                        Class clazz = ClassUtils.getRawType(type.getType());
                        final Set<AnnotatedType> interfaces = new HashSet<>();
                        do {
                            final AnnotatedType currentType = GenericTypeReflector.getExactSuperType(type, clazz);
                            if (supports(currentType)) {
                                interfaces.add(currentType);
                            }
                            Arrays.stream(clazz.getInterfaces())
                                    .map(inter -> GenericTypeReflector.getExactSuperType(type, inter))
                                    .filter(this::supports).forEach(interfaces::add);
                        } while ((clazz = clazz.getSuperclass()) != Object.class && clazz != null);
                        return interfaces;
                    }
                }).withOperationsFromSingleton(nodeQuery)// register the service
                .generate(); // done ;)
        graphQL = new GraphQL.Builder(schema).build();

Поскольку это решение заняло некоторое время, я скоро начну вести блог с другими решениями, на которые я наткнулся.

Что касается запроса, который просто возвращает все результаты. Это невозможно в GraphQL. Один из обходных путей, который я мог бы написать, - это иметь конечную точку, которая возвращает JSON всего объекта и имя объекта, тогда я могу просто использовать ObjectMapper, чтобы преобразовать его обратно.

Надеюсь, это поможет другим людям. Я все еще ищу ответ на свой первый вопрос и обновлю этот пост, когда найду один.

...