Return 来自 GraphQL 的 HashMap<String, Object>-Java
Return HashMap<String, Object> from GraphQL-Java
我尝试了几个变体,但没有运气 return 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 神奇地处理这个或替代方法。
非常感谢!
GraphQL (Discussion on GitHub) 中没有地图类型。
另一种方法是将 customers
作为 Customer
s
的 List
public class Person {
private String type;
private List<Customer> customers;
}
并在 Customer
class
中包含地图的键
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!]!
}
正如您自己指出的那样,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<String, Map<Long, Customer>>
.
3) 如果您有一个完全未知的类型,即 Object
,唯一的选择是将其视为复数标量。在 JavaScript 中,这种方法称为 JSON scalar as it boils down to stuffing an arbitrary JSON structure in and treating it as a scalar. The same approach can be implemented in Java. graphql-java now has a project for extended scalars. Here's their ObjectScalar (aliased as JsonScalar) 实现。
现在,如果您想表示 Map<String, Object>
等类型,您可以选择使用上面的键值对方法来表示它,只有值类型是 JSON标量,或者您可以将整个地图表示为 JSON 标量。
事实上,您可以决定将 any 映射(好吧,实际上是任何类型,但这没有用)表示为 JSON 标量。
type MapEntry {
key: String!
value: [ObjectScalar!]
}
scalar ObjectScalar
从好的方面来说,您现在可以准确地保持任何动态结构的形状。
不利的一面是,由于它是一个标量,因此无法进行子选择,并且您无法提前获取所有内容,而无法提前了解其中的内容。
以防万一 - 您始终可以将地图对象表示为 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);
}
};
}
它会 return:
"person": {
"type": "2",
"customers": "{\"VIP\":{\"name\":\"John\",\"age\":\"19\"},\"Platinum VIP\":{\"name\":\"Peter\",\"age\":\"65\"}}"
}
之后,您可以像使用客户端中的典型 JSON 字符串一样与客户进行操作。
我尝试了几个变体,但没有运气 return 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 神奇地处理这个或替代方法。
非常感谢!
GraphQL (Discussion on GitHub) 中没有地图类型。
另一种方法是将 customers
作为 Customer
s
List
public class Person {
private String type;
private List<Customer> customers;
}
并在 Customer
class
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!]!
}
正如您自己指出的那样,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<String, Map<Long, Customer>>
.
3) 如果您有一个完全未知的类型,即 Object
,唯一的选择是将其视为复数标量。在 JavaScript 中,这种方法称为 JSON scalar as it boils down to stuffing an arbitrary JSON structure in and treating it as a scalar. The same approach can be implemented in Java. graphql-java now has a project for extended scalars. Here's their ObjectScalar (aliased as JsonScalar) 实现。
现在,如果您想表示 Map<String, Object>
等类型,您可以选择使用上面的键值对方法来表示它,只有值类型是 JSON标量,或者您可以将整个地图表示为 JSON 标量。
事实上,您可以决定将 any 映射(好吧,实际上是任何类型,但这没有用)表示为 JSON 标量。
type MapEntry {
key: String!
value: [ObjectScalar!]
}
scalar ObjectScalar
从好的方面来说,您现在可以准确地保持任何动态结构的形状。 不利的一面是,由于它是一个标量,因此无法进行子选择,并且您无法提前获取所有内容,而无法提前了解其中的内容。
以防万一 - 您始终可以将地图对象表示为 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);
}
};
}
它会 return:
"person": {
"type": "2",
"customers": "{\"VIP\":{\"name\":\"John\",\"age\":\"19\"},\"Platinum VIP\":{\"name\":\"Peter\",\"age\":\"65\"}}"
}
之后,您可以像使用客户端中的典型 JSON 字符串一样与客户进行操作。