You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 19:06:01