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

时间:2019-12-02 17:07:42

标签: graphql-java

我有一个架构,其中json可以将Int和Strings的列表作为值。我想知道如何为我的方案定义一种解析器。

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

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

1 个答案:

答案 0 :(得分:1)

在GraphQL中没有通用对象(在Java中为 Object )的概念。实际上,定义的类型如下(如here所述):

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

您可以定义一个新的标量,但这意味着您必须定义自己如何对其进行序列化/反序列化和验证。它为没有太多价值的方式增加了更多的复杂性。而且,我觉得Graphql的 strong 类型完全丢失了。

我认为您最好的选择是使用Interfaces。使用接口并使用包装类型 ,您就可以为正在讨论的通用对象建模,并可以帮助您编写以下模式:

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字段,该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
}