java - Graphql SPQR 自定义对象序列化/反序列化

标签 java graphql-java graphql-spqr

我有以下带有自定义属性的数据模型:

    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 实现这样的序列化/反序列化?

仅供引用,目前我可以使用 jackson 在 REST API 中执行此操作(用于序列化的 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));
        }
    }

最佳答案

这里的问题不是 JSON(反)序列化。使用 GraphQL,所有输入和输出的形状均由模式定义,并且模式通常不能具有动态部分(字段提前未知的对象类型)。因为你的Set<AdditionalAttribute>在运行时可以包含任何内容,这意味着您的 Foo类型必须有未知字段。这与 GraphQL 的设计方式完全相反。

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

回顾一下,您的选择是:

  1. 保持原样(动态内容是嵌套在 attributes 下的列表)
  2. 转动Set<AdditionalAttribute>转换为具有已知结构且所有可能的键作为字段的类型(新类或 EnumMap )。仅当 key 不是完全动态时这才有可能
  3. 使用@GraphQLScalar使整个封闭对象成为对象标量

关于java - Graphql SPQR 自定义对象序列化/反序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57548511/

相关文章:

java - Jetty 自动加载 JSP 支持,如何关闭?

java - Graphql 在 Postman 中使用变量作为文本发送 POST

java - graphql-spqr 中 Double 值的 NaN 模型

java - AssertValidName 抛出一个可能由库本身生成的名称

JavaFX 2.2 使用带有 FXML 的第二个窗口

java - Apache POI 异常

java - 为什么 Switch 会跳过一种情况并针对不同情况执行具有错误值的代码

spring - 带有 graphql-spring 的 LazyInitializationException

java - 动态生成 GraphQL schema 支持

java - 如何传递参数/变量进行查询或变异?