cc.voox.graphql.GraphqlResolverFactory Maven / Gradle / Ivy
package cc.voox.graphql;
import cc.voox.graphql.annotation.Query;
import cc.voox.graphql.annotation.QueryField;
import cc.voox.graphql.annotation.QueryMethod;
import cc.voox.graphql.utils.AOPUtil;
import cc.voox.graphql.utils.BeanUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import graphql.GraphQLException;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.idl.TypeRuntimeWiring;
import org.dataloader.DataLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring;
@Component
public class GraphqlResolverFactory implements ApplicationContextAware {
private Logger logger = LoggerFactory.getLogger(getClass());
private ApplicationContext context;
@Autowired
private GraphqlProperties graphqlProperties;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = context;
}
@Bean
public ObjectMapper objectMapper() {
ObjectMapper responseMapper = new ObjectMapper();
responseMapper.addMixIn(Object.class, JsonIgnore.class);
responseMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return responseMapper;
}
@Autowired
private ObjectMapper objectMapper;
private final Map> dataLoaders = new ConcurrentHashMap();
private Map> wfResolvers = new HashMap<>();
private Set scalarSet = new HashSet<>();
private Set directiveSet = new HashSet<>();
private Set interceptors = new HashSet<>();
public Set getInterceptors() {
return interceptors;
}
protected Set getScalarSet() {
return scalarSet;
}
protected Set getDirectiveSet() {
return directiveSet;
}
protected Map> getDataLoaders() {
return dataLoaders;
}
@PostConstruct
void init() {
if (graphqlProperties.isLog()) {
logger.info("init GraphQL start");
}
ClassPathScanningCandidateComponentProvider cp = new ClassPathScanningCandidateComponentProvider(false);
cp.addIncludeFilter(new AnnotationTypeFilter(Query.class));
cp.addIncludeFilter(new AssignableTypeFilter(IGraphQL.class));
cp.addIncludeFilter(new AssignableTypeFilter(IScalar.class));
cp.addIncludeFilter(new AssignableTypeFilter(IDirective.class));
cp.addIncludeFilter(new AssignableTypeFilter(IDataLoader.class));
cp.addIncludeFilter(new AssignableTypeFilter(GraphQLInterceptor.class));
if (StringUtils.isEmpty(graphqlProperties.getScanPath())) {
throw new GraphQLException("Scan path is empty. please set scan path in GraphqlProperties bean.");
}
Set bd = cp.findCandidateComponents(graphqlProperties.getScanPath());
ClassLoader loader = GraphqlResolverFactory.class.getClassLoader();
Map> resolvers = new HashMap();
Map>> originClassResolvers = new HashMap();
Iterator var5 = bd.iterator();
while (var5.hasNext()) {
BeanDefinition b = (BeanDefinition) var5.next();
String beanName = b.getBeanClassName();
try {
Class> c = loader.loadClass(beanName);
Class>[] interfaces = c.getInterfaces();
Set> set = new HashSet<>();
for (Class> inter : interfaces) {
set.add(inter);
}
if (set.contains(IScalar.class) || IScalar.class.isAssignableFrom(c)) {
IScalar iScalar = null;
try {
} catch (Exception e) {
try {
iScalar = (IScalar) c.newInstance();
} catch (Exception ex) {
}
if (iScalar == null) {
throw new GraphQLException("Cannot initial scalar" + c);
}
}
scalarSet.add(iScalar);
continue;
} else if (set.contains(IDirective.class) || IDirective.class.isAssignableFrom(c)) {
IDirective directive = null;
try {
directive = (IDirective) this.context.getBean(c);
} catch (Exception e) {
try {
directive = (IDirective) c.newInstance();
} catch (Exception illegalAccessException) {
}
if (directive == null) {
throw new GraphQLException("Cannot initial directive" + c);
}
}
directiveSet.add(directive);
continue;
} else if (set.contains(IDataLoader.class) || IDataLoader.class.isAssignableFrom(c)) {
IDataLoader dataLoader = null;
try {
dataLoader = (IDataLoader) this.context.getBean(c);
} catch (Exception e) {
try {
dataLoader = (IDataLoader) c.newInstance();
} catch (Exception illegalAccessException) {
}
if (dataLoader == null) {
throw new GraphQLException("Cannot initial dataLoader" + c);
}
}
dataLoaders.put(c.getSimpleName(), dataLoader.useTryMode() ? dataLoader.getTry() : dataLoader.get());
continue;
} else if (set.contains(GraphQLInterceptor.class) || GraphQLInterceptor.class.isAssignableFrom(c)) {
try {
GraphQLInterceptor interceptor = (GraphQLInterceptor) this.context.getBean(c);
this.interceptors.add(interceptor);
} catch (Exception e) {
throw new GraphQLException("Cannot initial interceptor" + c);
}
continue;
}
String queryValue = null;
if (c.isAnnotationPresent(Query.class)) {
Query q = c.getAnnotation(Query.class);
queryValue = q.value();
} else {
if (set.contains(IGraphQL.class) || IGraphQL.class.isAssignableFrom(c)) {
queryValue = c.getSimpleName();
}
}
String value = queryValue;
if (StringUtils.isEmpty(value)) {
value = "Query";
}
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
method.setAccessible(true);
if (method.isAnnotationPresent(QueryMethod.class)) {
String methodQueryValue = value;
QueryMethod methodAnnotation = method.getAnnotation(QueryMethod.class);
String type = methodAnnotation.type();
String methodValue = methodAnnotation.value();
if (!StringUtils.isEmpty(type)) {
methodQueryValue = type;
} else if (method.isAnnotationPresent(Query.class)) {
Query q = method.getAnnotation(Query.class);
methodQueryValue = StringUtils.isEmpty(q.value()) ? value : q.value();
} else {
methodQueryValue = value;
}
// final String resolverType = methodQueryValue;
Map resolverMap = resolvers.get(methodQueryValue);
Map> resolverClassMap = originClassResolvers.get(methodQueryValue);
if (resolverMap == null) {
resolverMap = new LinkedHashMap<>();
}
if (resolverClassMap == null) {
resolverClassMap = new LinkedHashMap<>();
}
if (StringUtils.isEmpty(methodValue)) {
methodValue = method.getName();
}
DataFetcher df = dataFetchingEnvironment -> {
GraphQLContextUtil.add(dataFetchingEnvironment);
Class>[] clsTypes = method.getParameterTypes();
List