【问题标题】:Return HashMap<String, Object> from GraphQL-Java从 GraphQL-Java 返回 HashMap<String, Object>
【发布时间】:2018-05-20 08:24:14
【问题描述】:

我尝试了几个变体,但没有运气在 GraphQL 中返回地图。所以我有以下两个对象:

public class Customer {

    private String name, age;
    // getters & setters
}

public class Person {

   private String type;
   private Map<String, Customer> customers;
   // getters & setters
}

我的架构如下所示:

type Customer {
   name: String!
   age:  String!
}

type Person {
  type: String!
  customers: [Customer!] // Here I tried all combination but had no luck, is there a Map type support for GQL?
}

谁能告诉我如何实现这一点,以便 GraphQL 神奇地处理这个或替代方法。

非常感谢!

【问题讨论】:

    标签: java graphql graphql-java


    【解决方案1】:

    GraphQL (Discussion on GitHub) 中没有地图类型。

    另一种方法是将customers 作为ListCustomers

    public class Person {
       private String type;
       private List<Customer> customers;
    }
    

    并在 Customer 类中包含地图的键

    public class Customer {
        private String key; // or another meaningful name
        private String name, age;
    }
    

    架构基本保持不变。

    type Customer {
       key: String! // or another meaningful name
       name: String!
       age: String!
    }
    
    type Person {
      type: String!
      customers: [Customer!]!
    }
    

    【讨论】:

      【解决方案2】:

      正如您自己所指出的,GraphQL 中没有地图类型,主要是因为地图基本上是无类型数据(或具有动态结构的数据),因此不能很好地转换为 GraphQL 期望的静态类型。不过,您有几个选择。

      1) 您可以更改值类型以使其包含键,然后放弃映射并改用列表。这是您在自己的答案中采用的方法。你已经举例说明了,这里不再赘述。

      2) 只要​​已知键和值 Java 类型(而不是例如 Object),您就可以将映射视为键值对列表。您可以创建一个类型来表示该对:

      type Person {
        type: String!
        customers: [CustomerEntry!]
      }
      
      type CustomerEntry {
        key: String!
        value: Customer!
      }
      

      不利的一面是,您现在有更难看的查询:

      {
         person {
           type
           customers {
             key
             value {
               name
             }
           }
         }
      }
      

      从好的方面来说,您可以保持类型安全和(大部分)语义。可以继续将这种方法嵌套到例如代表Map&lt;String, Map&lt;Long, Customer&gt;&gt;

      3) 如果您有一个完全未知的类型,即Object,唯一的选择是将其视为复数标量。在 JavaScript 中,这种方法称为JSON scalar,因为它归结为填充任意 JSON 结构并将其视为标量。相同的方法可以在 Java 中实现。 graphql-java 现在有一个extended scalars 的项目。这是他们的ObjectScalar(别名为JsonScalar)实现。

      现在,如果您想表示Map&lt;String, Object&gt; 之类的类型,您可以选择使用上面的键值对方法来表示它,只有值类型是 JSON 标量,或者您可以表示整个映射为 JSON 标量。

      事实上,您可以决定将 any 映射(嗯,实际上是任何类型,但这没用)表示为 JSON 标量。

      type MapEntry {
        key: String!
        value: [ObjectScalar!]
      }
      
      scalar ObjectScalar
      

      从好的方面来说,您现在可以准确地保持任何动态结构的形状。 不利的一面是,由于它是一个标量,因此无法进行子选择,而且您无法提前获取所有内容。

      【讨论】:

      • “主要是因为地图基本上是无类型数据”。我不同意。 IMO,地图的类型与数组的类型一样。
      • set/hashset怎么样?
      • @KokHowTeh 为什么 GraphQL 会这样做? Java 就是这样做的。
      • @yami 你需要一个条目列表,类似于List&lt;Map.Entry&lt;K,V&gt;&gt;。参见例如this 实现。
      • @yami 不是地图列表,而是条目列表。我真的不能再帮你了。
      【解决方案3】:

      以防万一 - 您始终可以将地图对象表示为 JSON 字符串(在我的情况下这很有帮助)。

      public class Person {
      
          private String type;
          private Map<String, Customer> customers;
          // getters & setters
      }
      

      type Person {
        type: String!
        customers: String!
      }
      

      之后不要忘记添加数据提取器以将其转换为 JSON。

      public DataFetcher<String> fetchCustomers() {
              return environment -> {
                  Person person = environment.getSource();
                  try {
                      ObjectMapper objectMapper = new ObjectMapper();
                      return objectMapper.writeValueAsString(person.getCustomers());
                  } catch (JsonProcessingException e) {
                      log.error("There was a problem fetching the person!");
                      throw new RuntimeException(e);
                  }
              };
          }
      

      它会返回:

      "person": {
          "type": "2",
          "customers": "{\"VIP\":{\"name\":\"John\",\"age\":\"19\"},\"Platinum VIP\":{\"name\":\"Peter\",\"age\":\"65\"}}"
        }
      

      之后,您可以像在客户端中使用典型的 JSON 字符串一样对客户进行操作。

      【讨论】:

        猜你喜欢
        • 2018-08-11
        • 1970-01-01
        • 2012-10-13
        • 1970-01-01
        • 2014-07-20
        • 1970-01-01
        • 1970-01-01
        • 2016-03-10
        • 1970-01-01
        相关资源
        最近更新 更多