【问题标题】:Schema Generator for ApacheCayenne classesApacheCayenne 类的模式生成器
【发布时间】:2018-09-02 13:08:51
【问题描述】:

我正在尝试使用 SPQR 从 Cayenne 生成的类生成 GraphQL 架构。 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        
}

【问题讨论】:

  • 请先试用最新版本的 SPQR(目前为 0.9.6)。这个类似乎应该可以正常工作。稍后我会尝试并为您提供更多信息。顺便说一句,这不是您在 SPQR 注册的顶级课程,对吧?
  • 我不知道如何处理这个类... writeProperty 和 readProperty 来自哪里?你能提供一个更完整的例子吗,因为我对 Cayenne 完全不熟悉?看看这个类是用作输入还是输出,以及模式生成器是如何配置的,这一点很重要。
  • 它们是 Cayenne 类。即 cayenne-server-4.0.B2.jar。我更新了代码
  • GraphQL 注释是我在此处粘贴代码时的错。我对这个问题的第一个猜测是 SPQR 找不到类中属性的 getter/setter。即 Property A_PROPERTY //get/set public void setAProperty(Integer aProperty) { writeProperty("aProperty", aProperty); } public Integer getAProperty() { return (Integer)readProperty("aProperty"); }
  • 嗯,似乎无法复制...该错误声称没有在顶层映射任何内容。也许在AnnotatedResolverBuilder#buildQueryResolvers 中放置一个断点并检查它是否返回任何内容。如果您仍然遇到问题,请在Gitter 上联系我,我们可以深入调查。

标签: java graphql-java


【解决方案1】:

从 SPQR 的角度来看,这与 POJO 并没有什么不同,因为 SPQR 只关心类型。

默认情况下,对于所有嵌套类(在您的情况下为MyCayenneClass),所有看起来像 getter 的东西都会被暴露。对于顶级类(在您的情况下为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(ClassUtils.java:396) 在 io.leangen.graphql.metadata.strategy .query.DefaultOperationBuilder.resolveJavaType(DefaultOperationBuilder.java:58) 在 io.leangen.graphql.metadata.strategy.query.DefaultOperationBuilder.buildQuery(DefaultOperationBuilder.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/… at io.leangen.graphql.metadata.strategy.query.DefaultOperationBuilder.resolveJavaType(DefaultOperationBuilder.java:122)
  • @Graciano 啊,我明白了。每个版本都有大量改进和错误修复,因此请确保始终保持最新状态。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-27
  • 1970-01-01
  • 1970-01-01
  • 2014-11-29
  • 2013-03-24
相关资源
最近更新 更多