Graphql SPQR 自定义对象序列化/反序列化
Posted
技术标签:
【中文标题】Graphql SPQR 自定义对象序列化/反序列化【英文标题】:Graphql SPQR customize object serialization / deserialization 【发布时间】:2019-12-24 04:30:14 【问题描述】:我有以下具有自定义属性的数据模型:
class Foo
private Long id;
private Set<AdditionalAttribute> attributes;
class AdditionalAttribute
private Key key;
private String value;
class Key
private String name;
private Class<?> type;
我的模型生成这个 json:
"id":123, "attributes": ["key1":12345, "key2":"value2"]
我预期的 json 是:
"id":123, "key1":12345, "key2":"value2"
如何使用 graphql spqr 实现这样的序列化/反序列化?
仅供参考,目前我可以在 REST API 中使用 jackson(用于序列化的 BeanSerializerModifier 和用于反序列化的 @JsonAnySetter)如下:
// Serialization using BeanSerializerModifier
class FooModifier extends BeanSerializerModifier
@Override
public List<BeanPropertyWriter> changeProperties(
SerializationConfig config, BeanDescription beanDesc,
List<BeanPropertyWriter> beanProperties)
for (int i = 0; i < beanProperties.size(); i++)
BeanPropertyWriter writer = beanProperties.get(i);
if (Foo.class.isAssignableFrom(beanDesc.getBeanClass()) && "attributes".equals(writer.getName()))
beanProperties.set(i, new FooAttributesWriter(writer));
return beanProperties;
class FooAttributesWriter extends BeanPropertyWriter
public HasAttributesWriter(BeanPropertyWriter w)
super(w);
@Override
public void serializeAsField(Object bean, JsonGenerator gen,
SerializerProvider prov) throws Exception
if(Foo.class.isAssignableFrom(bean.getClass()))
Set<AdditionalAttribute> set = ((Foo) bean).getAttributes();
for (AdditionalAttribute a : set)
gen.writeStringField(a.getKey().getName(), a.getValue());
// Deserilization using @JsonAnySetter
class Foo
private Long id;
private Set<AdditionalAttribute> attributes;
// Deserialization of custom properties
@JsonAnySetter
public void set(String name, Object value)
attributes.add(new AdditionalAttribute(buildKey(name,value), value));
【问题讨论】:
【参考方案1】:非常感谢您抽出宝贵时间和建议的选项。 目前,我们已经找到了另一种方法(可能是选项 4 :))来生成与预期输出“相似”的 json(我们在生成的输出中丢失了类型信息,但我们有另一个逻辑可以帮助我们检索类型)。
这里是一个例子:
class Foo
private Long id;
private Set<AdditionalAttribute> attributes;
@GraphQLQuery
public String get(@GraphQLArgument(name = "key") String key)
for (AdditionalAttribute a : attributes)
if (a.getConfigurationKey().getKey().equalsIgnoreCase(key))
return a.getAttributeValue();
return null;
我们可以按如下方式子选择 Foo:
foo
id
key1: get(key: "key1")
key2: get(key: "key2")
这个返回
"id":123, "key1":"12345", "key2":"value2"
【讨论】:
【参考方案2】:这里的问题不是 JSON(反)序列化。使用 GraphQL,所有输入和输出的形状都由模式定义,并且模式通常不能具有动态部分(字段提前未知的对象类型)。因为您的 Set<AdditionalAttribute>
在运行时可以包含任何内容,这意味着您的 Foo
类型必须具有未知字段。这与 GraphQL 的设计方式大相径庭。
实现动态结构的唯一方法是拥有一个对象标量,它实际上是一个无法验证或从其中子选择的 JSON blob。您可以通过添加@GraphQLScalar
将Foo
变成这样的标量。那么所有输入都是有效的,"id":123, "key1":12345 "key2":"value2"
也是"whatever": "something"
。确保正确性将是您的逻辑工作。此外,如果您返回 Foo
,客户端将无法从中进行子选择。例如。 foo
可能,但 foo id
不会,因为架构将不再知道 id
字段是否存在。
回顾一下,你的选择是:
-
保持原样(动态内容是嵌套在
attributes
下的列表)
将Set<AdditionalAttribute>
转换为具有已知结构的类型(新类或EnumMap
),并将所有可能的键作为字段。这只有在键不是完全动态的情况下才有可能
使用@GraphQLScalar
使整个封闭对象成为对象标量
【讨论】:
以上是关于Graphql SPQR 自定义对象序列化/反序列化的主要内容,如果未能解决你的问题,请参考以下文章
C#中使用Newtonsoft.Json序列化和反序列化自定义类对象
java基础 序列化反序列化流 实现Serializable 接口 自动装载序列号到对象文本文件如修改不能反序列化对象文本,除非自定义long型常量 打印流