如何在graphql-java-annotations项目中添加自定义标量Date?
问题描述
使用graphql-java-annotations v8.0.1时,官方文档未明确说明如何通过AnnotationsSchemaCreator构建器添加自定义标量。现有代码中BasePart类包含Date类型字段:
public abstract class BasePart { @GraphQLField @GraphQLNonNull @JsonIgnore public String id; ... @GraphQLField public Date createdOn; ... }
但Schema未定义Date标量,导致GraphiQL报错:
Error: Date fields must be an object with field names as keys or a function which returns such an object.
at invariant (http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:13:12678)
at defineFieldMap (http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:14:16395)
at e.getFields (http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:14:22028)
at http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:15:22055
at typeMapReducer (http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:15:22227)
at http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:15:22200
at Array.forEach ()
at http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:15:22082
at typeMapReducer (http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:15:22227)
at typeMapReducer (http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:15:21564)
现有Schema构建代码如下:
GraphQLSchema schema = AnnotationsSchemaCreator.newAnnotationsSchema() .query(Query.class) // 创建查询对象 .mutation(Mutation.class) // 创建变更对象 .subscription(Subscription.class) // 创建订阅对象 .directive(UpperDirective.class) // 创建指令 .additionalType(AdditionalType.class) // 添加额外类型到Schema .typeFunction(CustomType.class) // 添加类型函数 .setAlwaysPrettify(true) // 全局美化字段名(移除get/set/is前缀) .setRelay(customRelay) // 添加自定义Relay对象 .build();
需要明确如何将Date标量配置传入构建器。
解决方案
添加自定义Date标量需要通过typeFunction实现,具体步骤如下:
1. 定义GraphQL Date标量
可以直接使用graphql-java提供的扩展标量,或自定义实现:
// 方式1:使用官方扩展标量 import graphql.scalars.ExtendedScalars; public static final GraphQLScalarType DATE_SCALAR = ExtendedScalars.Date; // 方式2:自定义标量实现(示例) // import graphql.schema.GraphQLScalarType; // import graphql.schema.Coercing; // import java.text.SimpleDateFormat; // import java.util.Date; // public static final GraphQLScalarType DATE_SCALAR = GraphQLScalarType.newScalar() // .name("Date") // .description("自定义日期标量,遵循ISO-8601格式") // .coercing(new Coercing<Date, String>() { // @Override // public String serialize(Object input) throws CoercingSerializeException { // if (input instanceof Date) { // return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format((Date) input); // } // throw new CoercingSerializeException("无法将对象序列化为Date"); // } // // 实现parseValue、parseLiteral方法(略) // }) // .build();
2. 实现TypeFunction
创建TypeFunction实现类,将Java的Date类型映射到GraphQL标量:
import com.enigmatis.graphql.annotations.typeFunctions.TypeFunction; import graphql.schema.GraphQLScalarType; import java.util.Date; public class DateTypeFunction implements TypeFunction { @Override public boolean suits(Class<?> clazz) { // 匹配Java的Date类型 return Date.class.equals(clazz); } @Override public GraphQLScalarType getGraphQLType() { // 返回定义好的Date标量 return DATE_SCALAR; } }
3. 注册TypeFunction到Schema构建器
修改原Schema构建代码,添加自定义的DateTypeFunction:
GraphQLSchema schema = AnnotationsSchemaCreator.newAnnotationsSchema() .query(Query.class) .mutation(Mutation.class) .subscription(Subscription.class) .directive(UpperDirective.class) .additionalType(AdditionalType.class) .typeFunction(new DateTypeFunction()) // 注册Date类型映射函数 .setAlwaysPrettify(true) .setRelay(customRelay) .build();
4. 验证
重启服务后,Schema会自动生成scalar Date定义,BasePart的createdOn字段将正确关联该标量,GraphiQL的报错会消失。
内容的提问来源于stack exchange,提问作者Bob Kuhar

