【问题标题】:Graphql SPQR customize object serialization / deserializationGraphql SPQR 自定义对象序列化/反序列化
【发布时间】: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));
        }
    }

【问题讨论】:

    标签: java graphql-java graphql-spqr


    【解决方案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&lt;AdditionalAttribute&gt; 在运行时可以包含任何内容,这意味着您的 Foo 类型必须具有未知字段。这与 GraphQL 的设计方式大相径庭。

      实现动态结构的唯一方法是拥有一个对象标量,它实际上是一个无法验证或从其中子选择的 JSON blob。您可以通过添加@GraphQLScalarFoo 变成这样的标量。那么所有输入都是有效的,{"id":123, "key1":12345 "key2":"value2"} 也是{"whatever": "something"}。确保正确性将是您的逻辑工作。此外,如果您返回 Foo,客户端将无法从中进行子选择。例如。 {foo} 可能,但 {foo { id }} 不会,因为架构将不再知道 id 字段是否存在。

      回顾一下,你的选择是:

      1. 保持原样(动态内容是嵌套在attributes 下的列表)
      2. Set&lt;AdditionalAttribute&gt; 转换为具有已知结构的类型(新类或EnumMap),并将所有可能的键作为字段。这只有在键不是完全动态的情况下才有可能
      3. 使用@GraphQLScalar 使整个封闭对象成为对象标量

      【讨论】:

        猜你喜欢
        • 2019-11-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-10
        • 1970-01-01
        相关资源
        最近更新 更多