AssertValidName 抛出一个可能由库本身生成的名称

AssertValidName throws on a name presumably generated by the library itself

这使用了一个相当复杂的实体集合,它主要由 JPA 实体组成,但也包括从 API 获取的代理和实体。我只是真正注释了基础 class 我正在尝试使用 @GraphQLQuery 注释获取,但它进入了下面的层次结构,并且在某些时候找到了一个 属性 这是一个带有硬编码内容的静态 HashMap<String, String[]>。 (我学会了不问...)此时它抛出这个异常并且一切都停止了:

graphql.AssertException: Name must be non-null, non-empty and match [_A-Za-z][_0-9A-Za-z]* - was 'Map_String_String[]Scalar'
at graphql.Assert.assertValidName(Assert.java:58)
at graphql.schema.GraphQLScalarType.<init>(GraphQLScalarType.java:50)
at graphql.schema.GraphQLScalarType.<init>(GraphQLScalarType.java:45)
at io.leangen.graphql.util.Scalars.graphQLMapScalar(Scalars.java:325)
at io.leangen.graphql.generator.mapping.common.ObjectScalarAdapter.toGraphQLType(ObjectScalarAdapter.java:20)
at io.leangen.graphql.generator.mapping.common.ObjectScalarAdapter.toGraphQLType(ObjectScalarAdapter.java:16)
at io.leangen.graphql.generator.mapping.common.CachingMapper.toGraphQLType(CachingMapper.java:30)
at io.leangen.graphql.generator.OperationMapper.toGraphQLType(OperationMapper.java:179)
at io.leangen.graphql.generator.OperationMapper.toGraphQLType(OperationMapper.java:165)
at io.leangen.graphql.generator.OperationMapper.toGraphQLField(OperationMapper.java:138)
at io.leangen.graphql.generator.mapping.common.ObjectTypeMapper.lambda$getFields(ObjectTypeMapper.java:88)
at java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:193)
at java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1625)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at io.leangen.graphql.generator.mapping.common.ObjectTypeMapper.getFields(ObjectTypeMapper.java:89)
at io.leangen.graphql.generator.mapping.common.ObjectTypeMapper.toGraphQLType(ObjectTypeMapper.java:41)
at io.leangen.graphql.generator.mapping.common.ObjectTypeMapper.toGraphQLType(ObjectTypeMapper.java:33)
at io.leangen.graphql.generator.mapping.common.CachingMapper.toGraphQLType(CachingMapper.java:30)
at io.leangen.graphql.generator.OperationMapper.toGraphQLType(OperationMapper.java:179)
at io.leangen.graphql.generator.OperationMapper.toGraphQLType(OperationMapper.java:165)
at io.leangen.graphql.generator.OperationMapper.toGraphQLField(OperationMapper.java:138)
at io.leangen.graphql.generator.mapping.common.ObjectTypeMapper.lambda$getFields(ObjectTypeMapper.java:88)
at java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:193)
at java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1625)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at io.leangen.graphql.generator.mapping.common.ObjectTypeMapper.getFields(ObjectTypeMapper.java:89)
at io.leangen.graphql.generator.mapping.common.ObjectTypeMapper.toGraphQLType(ObjectTypeMapper.java:41)
at io.leangen.graphql.generator.mapping.common.ObjectTypeMapper.toGraphQLType(ObjectTypeMapper.java:33)
at io.leangen.graphql.generator.mapping.common.CachingMapper.toGraphQLType(CachingMapper.java:30)
at io.leangen.graphql.generator.OperationMapper.toGraphQLType(OperationMapper.java:179)
at io.leangen.graphql.generator.OperationMapper.toGraphQLType(OperationMapper.java:165)
at io.leangen.graphql.generator.OperationMapper.toGraphQLField(OperationMapper.java:138)
at io.leangen.graphql.generator.OperationMapper.lambda$generateQueries[=10=](OperationMapper.java:91)
at java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:193)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at io.leangen.graphql.generator.OperationMapper.generateQueries(OperationMapper.java:92)
at io.leangen.graphql.generator.OperationMapper.<init>(OperationMapper.java:75)
at io.leangen.graphql.GraphQLSchemaGenerator.generate(GraphQLSchemaGenerator.java:868)
at com.ist.exam.graphql.services.GraphQLService.init(GraphQLService.java:27)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:349)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:300)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133)
... 39 more

我不知道这个名称是如何生成的,但它是 "Map_String_String[]Scalar",然后会引发 assertValidName。

我会用 @GraphQLQuery(name="somethingClever") 注释 属性 ,但此时我们在整个公司共享的库中,在这里所做的更改必须通过更改请求和其他东西。

我试图用 withBasePackages 排除这个代理包,但似乎没有效果。这是尝试创建架构的方法:

GraphQLSchema schema = new GraphQLSchemaGenerator()
                    .withBasePackages("entities")
                    .withResolverBuilders(new AnnotatedResolverBuilder())
                    .withOperationsFromSingleton(examService)
                    .withValueMapperFactory(new JacksonValueMapperFactory())
                    .generate();
            graphQL = GraphQL.newGraphQL(schema).build();

有没有人以前遇到过这些问题?我可以将包裹列入黑名单而不是白名单吗?例如withBasePackages("!proxies")

它是 a bug,因为永远不应生成无效名称。我会在下一个版本的 GraphQL SPQR 中立即解决这个问题(在撰写本文时当前版本是 0.9.9)。

至于它最终如何成为 Map_String_String[]Scalar,它相当涉及......地图非常棘手,因为在 GraphQL 中没有什么比得上地图。这些选项基本上是将映射视为键入的键值对列表或仅作为未知的动态结构(所谓的 JSON 标量 )。 SPQR 支持这两种方法,但默认情况下将映射视为复杂 (JSON) 标量。为了保持对内部内容的一些了解,它将为每个基础 Java 类型生成一个不同名称的标量。在这样做时,它必须为每个生成一个唯一的名称。在您的情况下,它会找到一个 Map<String, String[]> 生成您看到的无效名称 - Map_String_String[]Scalar.

您可以通过注册一个自定义 TypeMapper 来轻松解决这个问题,该自定义 TypeMapper 可以捕获这种情况,或者所有复杂的标量,并为它们指定相同的名称而不是唯一的名称。

例如

public class CustomObjectScalarMapper extends ObjectScalarMapper {
    private static final String OBJECT_SCALAR_NAME = "ObjectScalar";

    @Override
    protected String getTypeName(AnnotatedType type, BuildContext buildContext) {
        return OBJECT_SCALAR_NAME;
    }

    @Override
    protected String getInputTypeName(AnnotatedType type, BuildContext buildContext) {
        return OBJECT_SCALAR_NAME;
    }
}

并通过以下方式替换现有的 ObjectScalarMapper

generator.withTypeMappers((conf, current) -> current.replace(ObjectScalarMapper.class, new CustomObjectScalarMapper()))

有了这个,所有复数标量都将被调用 ObjectScalar,你就不会有问题了。

如果您希望更精细,也可以覆盖 supports 方法。


注意一点,您的生成器配置不必要地将一堆东西设置为默认值。

GraphQLSchema schema = new GraphQLSchemaGenerator()
                    .withBasePackages("entities")
                    .withResolverBuilders(new AnnotatedResolverBuilder())
                    .withOperationsFromSingleton(examService)
                    .withValueMapperFactory(new JacksonValueMapperFactory())
                    .generate();

等同于

GraphQLSchema schema = new GraphQLSchemaGenerator()
                    .withBasePackages("entities")
                    .withOperationsFromSingleton(examService)
                    .generate();