gpt4 book ai didi

java - Java GraphQL 模式中的 HashMap

转载 作者:行者123 更新时间:2023-11-30 12:05:51 25 4
gpt4 key购买 nike

我正在尝试创建一个 GraphQL Spring Boot 应用程序以在现有 REST Web API 之上创建一个 GraphQL 层,但我在处理架构中的 HashMap 时遇到了问题。

Timeline 类有一个名为 dataReference 的字段,它是一个 HashMap。我尝试在 graphql 模式中将其定义为 DataReference 类型的列表,这是一个键/值对,但我收到以下错误:

Exception in thread "main" org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:155)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:540)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
at com.foo.bar.graphql.AppLauncher.main(AppLauncher.java:43)
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:125)
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:86)
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:414)
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:174)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:179)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:152)
... 8 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'servletRegistrationBean' defined in com.foo.bar.graphql.AppLauncher: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.ServletRegistrationBean]: Factory method 'servletRegistrationBean' threw exception; nested exception is com.coxautodev.graphql.tools.SchemaClassScannerError: Unable to match type definition (ListType{type=TypeName{name='DataReference'}}) with java type (java.util.Map<java.lang.String, java.lang.String>): Java class is not a List or generic type information was lost: java.util.Map<java.lang.String, java.lang.String>
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:625)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:455)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1288)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204)
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:236)
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:224)
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addServletContextInitializerBeans(ServletContextInitializerBeans.java:100)
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.<init>(ServletContextInitializerBeans.java:88)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getServletContextInitializerBeans(ServletWebServerApplicationContext.java:250)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize(ServletWebServerApplicationContext.java:237)
at org.springframework.boot.web.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:54)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5098)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1429)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419)
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
at java.util.concurrent.FutureTask.run(FutureTask.java)
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:944)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:839)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1429)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419)
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
at java.util.concurrent.FutureTask.run(FutureTask.java)
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:944)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:261)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:422)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:770)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.startup.Tomcat.start(Tomcat.java:370)
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:106)
... 13 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.ServletRegistrationBean]: Factory method 'servletRegistrationBean' threw exception; nested exception is com.coxautodev.graphql.tools.SchemaClassScannerError: Unable to match type definition (ListType{type=TypeName{name='DataReference'}}) with java type (java.util.Map<java.lang.String, java.lang.String>): Java class is not a List or generic type information was lost: java.util.Map<java.lang.String, java.lang.String>
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:620)
... 55 more
Caused by: com.coxautodev.graphql.tools.SchemaClassScannerError: Unable to match type definition (ListType{type=TypeName{name='DataReference'}}) with java type (java.util.Map<java.lang.String, java.lang.String>): Java class is not a List or generic type information was lost: java.util.Map<java.lang.String, java.lang.String>
at com.coxautodev.graphql.tools.TypeClassMatcher.error(TypeClassMatcher.kt:22)
at com.coxautodev.graphql.tools.TypeClassMatcher.match(TypeClassMatcher.kt:65)
at com.coxautodev.graphql.tools.TypeClassMatcher.match(TypeClassMatcher.kt:28)
at com.coxautodev.graphql.tools.SchemaClassScanner.scanResolverInfoForPotentialMatches(SchemaClassScanner.kt:215)
at com.coxautodev.graphql.tools.SchemaClassScanner.scanQueueItemForPotentialMatches(SchemaClassScanner.kt:206)
at com.coxautodev.graphql.tools.SchemaClassScanner.scanQueue(SchemaClassScanner.kt:103)
at com.coxautodev.graphql.tools.SchemaClassScanner.scanForClasses(SchemaClassScanner.kt:81)
at com.coxautodev.graphql.tools.SchemaParserBuilder.scan(SchemaParserBuilder.kt:149)
at com.coxautodev.graphql.tools.SchemaParserBuilder.build(SchemaParserBuilder.kt:155)
at com.foo.bar.graphql.AppLauncher.servletRegistrationBean(AppLauncher.java:55)
at com.foo.bar.graphql.AppLauncher$$EnhancerBySpringCGLIB$$1ac15725.CGLIB$servletRegistrationBean$0(<generated>)
at com.foo.bar.graphql.AppLauncher$$EnhancerBySpringCGLIB$$1ac15725$$FastClassBySpringCGLIB$$c7dabbfc.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363)
at com.foo.bar.graphql.AppLauncher$$EnhancerBySpringCGLIB$$1ac15725.servletRegistrationBean(<generated>)
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.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 56 more

这是我的架构文件:

extend type Query {
getFoo: Timeline
}

type Timeline {
dataReference: [DataReference]
}

type DataReference {
key: String
value: String
}

还有我的模型类:

package com.foo.bar.graphql.model;

import lombok.Getter;
import lombok.Setter;

import java.util.HashMap;
import java.util.Map;

@Getter @Setter
public class Timeline {
private Map<String, String> dataReference = new HashMap<>();
}

我找到了这个帖子 Return HashMap<String, Object> from GraphQL-Java关于在模式中定义 map 的问题。在接受的答案中,选项 1) 对我来说不可行,因为模型是从现有的 Web API 中获取的并且不能更改。上面列出了我对选项 2 的尝试,但没有奏效。我还尝试了选项 3(使用标量):

架构:

extend type Query {
getFoo: Timeline
}

scalar Object

type Timeline {
dataReference: Object
}

Servlet 注册:

@Bean
public ServletRegistrationBean servletRegistrationBean() {

GraphQLSchema schema = SchemaParser.newParser()
.resolvers(fooResolver)
.file("graphql/foo.graphqls")
.scalars(ExtendedScalars.Object)
.build()
.makeExecutableSchema();
ExecutionStrategy executionStrategy = new AsyncExecutionStrategy();
GraphQLServlet servlet = new SimpleGraphQLServlet(schema, executionStrategy);
ServletRegistrationBean bean = new ServletRegistrationBean(servlet, "/graphql");
return bean;
}

pom.xml:

<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-extended-scalars</artifactId>
<version>1.0</version>
</dependency>

但我收到此错误:Caused by: com.coxautodev.graphql.tools.SchemaClassScannerError: Expected a user-defined GraphQL scalar type with name 'Object' but found none!

如果有人可以帮助我实现它,我更喜欢在模式中包含键/值对的方法。

最佳答案

最简单的方法是使用 DTO。使用像 mapstruct 这样的 DTO 映射器例如,将允许您自动映射除 Map 字段之外的所有字段,您将在其中应用转换。

你像这样创建一个 DTO :

@Data
@NoArgsConstructor
@AllArgsConstructor
public class TimelineDTO {

private List<DataReference> dataReference = new ArrayList();
}

获取到TimeLine对象后,将其映射到TimelineDTO,进行Map到List的转换。

List<DataReference> dataReferences = new ArrayList<>();
for (Map.Entry<String,String> entry : super.getDataReference().entrySet()) {

dataReferences.add(new DataReference(entry.getKey(), entry.getValue()));

}

return dataReferences;

在您的 GraphQL 合约中,您改为返回 DTO:

 extend type Query {
getFoo: TimelineDTO
}

type TimelineDTO {
dataReference: [DataReference]
}

type DataReference {
key: String
value: String
}

关于java - Java GraphQL 模式中的 HashMap,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55970945/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com