Я пытаюсь использовать SPQR для создания схемы GraphQL из класса, созданного Cayenne. Класс Cayenne выглядит так
public class MyCayenneClass {
public static final Property<Integer> A_PROPERTY = Property.create("aProperty", Integer.class);
public static final Property<Integer> ANOTHER_PROPERTY = Property.create("anotherProperty", String.class);
public void setAProperty(Integer aProperty) {
writeProperty("aProperty", aProperty);
}
public Integer getAProperty() {
return (Integer)readProperty("aProperty");
}
public void setAnotherProperty(String anotherProperty) {
writeProperty("anotherProperty", anotherProperty);
}
public String getAnotherProperty() {
return (String)readProperty("anotherProperty");
}
}
Поскольку класс не является простым POJO, SPQR генерирует исключение и схема не создается.
Error: QUERY_ROOT fields must be an object with field names as keys or a function which returns such an object.
Какой здесь лучший подход (без изменения класса cayenne (т.е. аннотирования метода)?
GraphQLEndPoing.java
@WebServlet(urlPatterns = "/graphql")
public class GraphQLEndpoint extends SimpleGraphQLServlet {
public GraphQLEndpoint() {
super(buildSchema());
}
//This method used SPQR
private static GraphQLSchema buildSchema() {
GraphQLSchema schemaGenerator = new GraphQLSchemaGenerator()
.withOperationsFromSingletons(myRepository) //register the beans
.generate();
return schemaGenerator;
}
private static final MyRepository myRepository;
static {
myRepository= new MyRepository ();
}
}
MyRepository.java
public class MyRepository{
private MyLibService libService;
@GraphQLQuery
public MyCayenneClass find(Integer id) {
List<MyCayenneClass> myList= libService.fetchById(new Integer[] {id});
return myList.get(0);
}
}
* К вашему сведению. Если я объявлю схему. Код будет работать нормально
schema {
query: Query
}
type Query {
find(id: Int): MyCayenneClass
}
type ConcContract {
id: ID
aProperty: Int
anotherProperty: String
}
Я не знаю, что делать с этим классом ... Откуда берутся writeProperty и readProperty? Не могли бы вы привести более полный пример, поскольку я совершенно не знаком с Cayenne? Важно увидеть, используется ли этот класс в качестве ввода или вывода, а также как настроен генератор схемы.
Это классы Cayenne. то есть cayenne-server-4.0.B2.jar. Я обновил код
GraphQL прокомментировал, что я виноват при вставке кода сюда. Мое первое предположение о проблеме заключается в том, что SPQR не смог найти геттеры / сеттеры для свойств в классе. т.е. свойство <Integer> A_PROPERTY // получить / установить public void setAProperty (Integer aProperty) {writeProperty ("aProperty", aProperty); } общедоступное целое число getAProperty () {return (Целое число) readProperty ("aProperty"); }
Хм, похоже, репликация невозможна ... Ошибка утверждает, что ничего не было отображено на верхнем уровне. Может быть, поставить точку останова в AnnotatedResolverBuilder#buildQueryResolvers и проверить, возвращает ли он что-нибудь. Если у вас по-прежнему возникают проблемы, свяжитесь со мной по Gitter, и мы сможем разобраться в этом подробнее.




С точки зрения SPQR, это не сильно отличается от POJO, поскольку SPQR заботится только о типах.
По умолчанию для всех вложенных классов (MyCayenneClass в вашем случае) будет показано все, что выглядит как геттер. Для классов верхнего уровня (MyRepository в вашем случае) по умолчанию доступны только аннотированные методы. И хотя бы один метод верхнего уровня должен быть открыт, иначе у вас будет недопустимая схема.
Ошибка в ее нынешнем виде означает, что не было обнаружено ни одного запроса верхнего уровня. Я вижу, что аннотация @GraphQLQuery закомментирована. Это намеренно? С конфигурацией по умолчанию это не приведет к появлению каких-либо запросов.
Вы можете зарегистрировать другой ResolverBuilder, например PublicResolverBuilder (или ваша собственная реализация / расширение), если вы хотите предоставить неаннотированные методы.
Например.
generator.withOperationsFromSingleton(new MyRepository(), new PublicResolverBuilder())
Это откроет все общедоступные методы из этого класса.
Вот немного упрощенный пример, который я пробовал с v0.9.6 и, похоже, работает, как ожидалось (я знаю, что вы используете довольно старую версию из текста ошибки).
public class MyRepository {
@GraphQLQuery //not commented out
public MyCayenneClass find(Integer in) {
return new MyCayenneClass();
}
}
// extends CayenneDataObject because I don't know where to get the
// writeProperty and readProperty from
// but shouldn't change anything from SPQR's perspective
public class MyCayenneClass extends CayenneDataObject {
public static final Property<Integer> A_PROPERTY = Property.create("aProperty", Integer.class);
public static final Property<String> ANOTHER_PROPERTY = Property.create("anotherProperty", String.class);
public void setAProperty(Integer aProperty) {
writeProperty("aProperty", aProperty);
}
public Integer getAProperty() {
return (Integer)readProperty("aProperty");
}
public void setAnotherProperty(String anotherProperty) {
writeProperty("anotherProperty", anotherProperty);
}
public String getAnotherProperty() {
return (String)readProperty("anotherProperty");
}
}
Есть еще много настроек, которые вы можете применить, в зависимости от того, что вам в конечном итоге понадобится, но, исходя из поставленного вопроса, похоже, что вам не нужно ничего лишнего ...
Чтобы переопределить ResolverBuilder, используемый для вложенных классов, у вас есть 2 варианта.
1) Зарегистрируйте его глобально, чтобы его использовали все вложенные типы:
generator.withNestedResolverBuilders(customBuilder)
2) Или по типу:
.withNestedResolverBuildersForType(MyCayenneClass.class, new BeanResolverBuilder())
Но это очень редко нужно ...
Используя 0.9.1, при построении схемы Вызвано: java.lang.IndexOutOfBoundsException: Индекс: 0, Размер: 0 в java.base / java.util.LinkedList.checkElementIndex (LinkedList. java: 559) в java.base /java.util.LinkedList.get(LinkedList.java:480) в io.leangen.graphql.util.ClassUtils.getCommonSuperType (ClassU tils.java:396) в io.leangen.graphql.metadata.strategy.queryBDefaultO Uilder.resolveJavaTy pe (DefaultOperationB uilder.java:58) в io.leangen.graphql.metadata.strategy.query.DefaultOperationB uilder.buildQuery (De faultOperationBuilde r.java:33) в io.leangen.graphql .generator.Opera
Попробую с 0.9.6
Нашел проблему (это на моей стороне). 0.9.6 дает лучшее сообщение об ошибке. Вызвано: io.leangen.graphql.generator.exceptions.TypeMappingException: для операции «XYZ» обнаружено несколько методов с разными типами возвращаемых значений. Найденные типы: [boolean, java.lang.String]. Если это сделано намеренно и вы хотите, чтобы GraphQL SPQR автоматически определял наиболее распространенный супертип, см. github.com/leangen/graphql-spqr/wiki/… в io.leangen.graphql.metadata.strategy.query.DefaultOperationB uilder.resolveJavaTy pe (DefaultOperationB uilder.java:122)
@Graciano А, понятно. В каждом выпуске есть множество улучшений и исправлений ошибок, поэтому следите за обновлениями.
Сначала попробуйте установить последнюю версию SPQR (на данный момент 0.9.6). Кажется, что этот класс должен работать нормально. Я попробую позже и дам вам больше информации. Кстати, это не класс верхнего уровня, который вы регистрируете в SPQR, верно?