如何在 graphql-java 中使用 java.util.objects 列表定义类型

How to define a type with list of java.util.objects in graphql-java

我有一个模式,其中 json 可以有一个 Int 和 String 列表作为值。我想知道如何为我的场景定义一种类型的解析器。

type Total {
  key: String
  values: [Object]
}

type Query {
  filter (key : String!) : Total
}

GraphQL 中没有一般对象(如Java 中的对象)的概念。事实上,定义的类型如下(如here所述):

  1. Int:一个带符号的 32 位整数;
  2. Float:带符号的双精度浮点值;
  3. 字符串:UTF-8 字符序列;
  4. 布尔值:真或假;
  5. ID:ID 标量类型表示唯一标识符,通常用于重新获取对象或用作缓存的键。 ID 类型以与 String 相同的方式序列化;但是,将其定义为 ID 意味着它不是人类可读的。

您可以定义一个新的标量,但这意味着您必须自己定义它的 serialized/deserialized 和验证方式。它增加了更多的复杂性而没有太多价值。此外,我觉得 Graphql 的 strong 类型完全失去了这种特定类型。

我认为最好的选择是使用 Interfaces。通过接口并使用 wrapper types,您就可以对您正在谈论的这个 general object 进行建模,并帮助您编写架构如下:

interface MyInterface {
    // must have a field at least (cannot be empty)
    id: ID!
}

type MyInt implements MyInteface {
    // Inherited by MyInterface
    id: ID!

    myIntValue: Int
}

type MyString implements MyInteface {
    // Inherited by MyInterface
    id: ID!

    myStringValue: String
}

type Total {
    key : String
    values: [MyInterface]
}

type Query {
    filter(key: String!) : Total
}

注意:请注意界面不允许为空(无字段)。为此,我添加了一个由实现 随机 生成的 ID 字段。

有了这样的架构,我们就可以执行如下查询:

filter("someFilter") {
    key
    values {
        ... on MyString {
            myStringValue
        }
        ... on MyInt {
            myIntValue
        }
    }
}

为此,您需要定义一个 TypeResolver,如下所示:

private class MyInterfaceTypeResolver implements TypeResolver {
    @Override
    public GraphQLObjectType getType(TypeResolutionEnvironment env) {
        Object obj = env.getObject();

        if (obj instanceOf MyInt) {
            env.getSchema().getObjectType("MyInt");
        } else if (obj instanceOf MyString) {
            env.getSchema().getObjectType("MyString");
        } else {
            return null;
        }
    }
}

具有以下 Java 类型定义:

abstract class MyInterface {
    private String id;

    public MyInterface() {
        // Generated just to avoid empty graphql interface
        id = UUID.randomUUID().toString();
    }

    public String getId() {
        return id;
    }
}

class MyInt extends MyInterface {
    private Integer myIntValue;

    public MyInt(Integer myInt) {
        super();
        this.myIntValue= myInt;
    }

    public Integer getMyIntValue() {
        return myInt;
    }
}

class MyString extends MyInterface {
    private String myStringValue;

    public MyString (String myString) {
        super();
        this.myStringValue= myString;
    }

    public String getMyStringValue() {
        return myStringValue;
    }
}

假设您要表示以下 Json {"key": "myKey", "values":[12,"String1", 1, "String2"]},根据我们之前的模型和查询,它将表示如下:

{
   "data": {
       "filter": {
           "key": "myKey",
           "values" : [
               {
                   "myIntValue": 12
               },
               {
                   "myStringValue": "String1"
               },
               {
                   "myIntValue": 1
               },
               {
                   "myStringValue": "String2"
               }
           ]
       }
   }
}

最后,您可以拥有多个属性,每种属性一个,例如:

type Total {
    key : String
    valuesInt: [Int]
    valuesString: [String]
}

type Query {
    filter(key: String!) : Total
}