Custom Scalar in Graphql-java

2019-02-19 23:11发布

问题:

We are planning use Graphql as backend server in our application. We choose Graphql-Java to develop our POC. We came across a stituation to create our own scalartype to handle java.util.Map object type.

we havent found any documentation regarding creating a custom scalar type. In example code as below

RuntimeWiring buildRuntimeWiring() {
    return RuntimeWiring.newRuntimeWiring()
            .scalar(CustomScalar)

how to was the implementation done for CustomScalar object. need help.

回答1:

To get a general idea how to make a scalar, just take a look into the existing ones and do something similar.

For a dynamic object scalar, take a look at graphql-spqr's object scalar implementation and do something similar:

public static GraphQLScalarType graphQLObjectScalar(String name) {
        return new GraphQLScalarType(name, "Built-in object scalar", new Coercing() {

            @Override
            public Object serialize(Object input) {
                return input;
            }

            @Override
            public Object parseValue(Object input) {
                return input;
            }

            @Override
            public Object parseLiteral(Object input) {
                return parseFieldValue((Value) input);
            }

            //recursively parse the input into a Map
            private Object parseFieldValue(Value value) {
                if (value instanceof StringValue) {
                    return ((StringValue) value).getValue();
                }
                if (value instanceof IntValue) {
                    return ((IntValue) value).getValue();
                }
                if (value instanceof FloatValue) {
                    return ((FloatValue) value).getValue();
                }
                if (value instanceof BooleanValue) {
                    return ((BooleanValue) value).isValue();
                }
                if (value instanceof EnumValue) {
                    return ((EnumValue) value).getName();
                }
                if (value instanceof NullValue) {
                    return null;
                }
                if (value instanceof ArrayValue) {
                    return ((ArrayValue) value).getValues().stream()
                            .map(this::parseFieldValue)
                            .collect(Collectors.toList());
                }
                if (value instanceof ObjectValue) {
                    return ((ObjectValue) value).getObjectFields().stream()
                            .collect(Collectors.toMap(ObjectField::getName, field -> parseFieldValue(field.getValue())));
                }
                //Should never happen, as it would mean the variable was not replaced by the parser
                throw new IllegalArgumentException("Unsupported scalar value type: " + value.getClass().getName());
            }
        });
    }


回答2:

In code first approach (SPQR v0.9.6) adding @GraphQLScalar is enough. Or, as alternative, add scalar definition to GraphQLSchemaGenerator:

new GraphQLSchemaGenerator()
.withScalarMappingStrategy(new MyScalarStrategy())

And define MyScalarStrategy:

class MyScalarStrategy extends DefaultScalarStrategy {

@Override
public boolean supports(AnnotatedType type) {
  return super.supports(type) || GenericTypeReflector.isSuperType(MyScalarStrategy.class, type.getType());
}
}