在GraphQL SPQR中如何将自定义子类BestDecimal视为父类BigDecimal处理
问题根因
你当前的GraphQL Schema将BestDecimal定义为了输入对象类型(BestDecimalInput),而非标量类型,GraphQL的序列化层只会按照对象结构解析对应输入,无法识别直接传入的数字值,你自行添加的构造方法不会被GraphQL的解析逻辑感知,因此不生效。
解决方案
1. 调整Schema定义
将BestDecimal声明为自定义标量,删除原有BestDecimalInput定义:
# 保留内置BigDecimal标量 scalar BigDecimal # 新增自定义BestDecimal标量 scalar BestDecimal
2. 实现自定义标量的序列化/反序列化逻辑
不同GraphQL Java框架的注册方式略有差异,以下是Spring GraphQL场景的实现示例:
import graphql.schema.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.math.BigDecimal; @Configuration public class CustomScalarConfig { @Bean public GraphQLScalarType bestDecimalScalar() { return GraphQLScalarType.newScalar() .name("BestDecimal") .description("封装了BigDecimal的自定义数值标量") .coercing(new Coercing<BestDecimal, Number>() { // 序列化:服务端返回数据给客户端时的转换逻辑 @Override public Number serialize(Object input) { if (input instanceof BestDecimal bd) { return bd.doubleValue(); } if (input instanceof Number num) { return num.doubleValue(); } throw new CoercingSerializeException("不支持的BestDecimal序列化类型:" + input.getClass().getName()); } // 反序列化:解析客户端传递的变量值 @Override public BestDecimal parseValue(Object input) { if (input instanceof Number num) { return new BestDecimal(num.doubleValue()); } if (input instanceof String str) { return new BestDecimal(new BigDecimal(str).doubleValue()); } throw new CoercingParseValueException("无法将输入转为BestDecimal类型"); } // 反序列化:解析查询语句中直接写的字面量值(如示例中的10) @Override public BestDecimal parseLiteral(Object input) { if (input instanceof IntValue intVal) { return new BestDecimal(intVal.getValue().doubleValue()); } if (input instanceof FloatValue floatVal) { return new BestDecimal(floatVal.getValue().doubleValue()); } if (input instanceof StringValue strVal) { return new BestDecimal(new BigDecimal(strVal.getValue()).doubleValue()); } throw new CoercingParseLiteralException("无法将字面量转为BestDecimal类型"); } }) .build(); } }
3. 调整字段类型声明
将对应接口中number字段的输入类型从BestDecimalInput改为BestDecimal标量即可,修改后你示例中的查询语句就可以正常运行:
myquery(number: 10){ whatever }
注意事项
直接使用double参数构造BigDecimal存在精度丢失风险,建议你补充BestDecimal(String val)构造方法,在反序列化逻辑中优先使用字符串数值进行转换,避免精度问题。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

