2017-01-03 30 views
5

的,我在我的项目中使用 & graphql的Java(graphql-java的注释)。 对于检索数据部分,我使用DataFetcher从服务(从数据库)获取数据。进样豆成DataFetcher GraphQL

奇怪的是:myService总是null。任何人都知道原因?

DataFetcher

@Component 
public class MyDataFetcher implements DataFetcher { 

    // get data from database 
    @Autowired 
    private MyService myService; 

    @Override 
    public Object get(DataFetchingEnvironment environment) { 
     return myService.getData(); 
    } 
} 

架构

@Component 
@GraphQLName("Query") 
public class MyGraphSchema { 

    @GraphQLField 
    @GraphQLDataFetcher(MyDataFetcher.class) 
    public Data getData() { 
     return null; 
    } 
} 

为MyService

@Service 
public class MyService { 

    @Autowired 
    private MyRepository myRepo; 

    @Transactional(readOnly = true) 
    public Data getData() { 
     return myRepo.getData(); 
    } 
} 

主要测试

@Bean 
public String testGraphql(){ 
    GraphQLObjectType object = GraphQLAnnotations.object(MyGraphSchema.class); 
    GraphQLSchema schema = newSchema().query(object).build(); 
    GraphQL graphql = new GraphQL(schema); 

    ExecutionResult result = graphql.execute("{getData {id name desc}}");; 
    Map<String, Object> v = (Map<String, Object>) result.getData(); 
    System.out.println(v); 
    return v.toString(); 
} 
+0

你可以发布MyService.java吗? – Jobin

+0

我发布了MyService.java @jobin – JasonS

+0

启动应用程序时是否有错误? – Jobin

回答

5

由于graphql-java的注释数据提取器是由注释中定义的,它由框架构造(使用反射来得到的构造),从而它不能是豆。

我找到的解决方法是将其设置为ApplicationContextAware,然后我可以初始化一些静态字段而不是bean。不是最好的东西,但它的工作原理:

@Component 
public class MyDataFetcher implements DataFetcher, ApplicationContextAware { 

    private static MyService myService; 
    private static ApplicationContext context; 

    @Override 
    public Object get(DataFetchingEnvironment environment) { 
     return myService.getData(); 
    } 

    @override 
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansExcepion { 
     context = applicationContext; 
     myService = context.getBean(MyService.class); 
    } 
} 

基本上你还是会获得通过graphQL初始化的数据提取器的新实例,也是春天将进行初始化,并且由于myService是静态的,你会得到初始化的一个。

+0

真的很感激,它的作品! @尼尔征费 – JasonS

+0

我不认为这是一个好的解决方案。 MyDataFetcher是一个单例,setApplicationContext被调用一次。为什么myService必须是静态的? –

0

@Nir Levy提供的解决方案非常完美。只是为了让它在这里更加可重用。我们可以提取一个封装了bean查找逻辑的抽象类,并为其子类自动布线。

public abstract class SpringContextAwareDataFetcher implements DataFetcher, ApplicationContextAware { 

    private static ApplicationContext applicationContext; 

    @Override 
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
     this.applicationContext = applicationContext; 
    } 

    @Override 
    public final Object get(DataFetchingEnvironment environment) { 
     return applicationContext.getBean(this.getClass()).fetch(environment); 
    } 

    protected abstract Object fetch(DataFetchingEnvironment environment); 
} 

而子类可以是这样的:

@Component 
public class UserDataFetcher extends SpringContextAwareDataFetcher { 

    @Autowired 
    private UserService userService; 

    @Override 
    public String fetch(DataFetchingEnvironment environment) { 
     User user = (User) environment.getSource(); 
     return userService.getUser(user.getId()).getName(); 
    } 
} 
0

虽然@尼尔方法工作(我经常用它JPA事件监听器内),该DataFetcher对象是单身,通过静态属性,以便注入是一个小黑客。

然而,GraphQL的execute方法可以让你在传递一个对象作为背景,然后将在您的DataFetchingEnvironment对象的DataFetcher的(见graphql.execute()线以下)内:

@Component 
public class GraphQLService { 

    @Autowired 
    MyService myService; 

    public Object getGraphQLResult() { 
     GraphQLObjectType object = GraphQLAnnotations.object(MyGraphSchema.class); 
     GraphQLSchema schema = newSchema().query(object).build(); 
     GraphQL graphql = new GraphQL(schema); 

     ExecutionResult result = graphql.execute("{getData {id name desc}}", myService); 

     return result.getData(); 
    } 
} 

public class MyDataFetcher implements DataFetcher { 

    @Override 
    public Object get(DataFetchingEnvironment environment) { 
     MyService myService = (MyService) environment.getContext(); 

     return myService.getData(); 
    } 
}