【问题标题】:Correctly moving around types with JSON::PullParser使用 JSON::PullParser 正确移动类型
【发布时间】:2020-02-25 13:29:21
【问题描述】:

在我创建的 Crystal 分片中,需要从不同的 API 端点提取数据。集合端点将响应如下数组:

json = %({
  "_embedded": [
    {"id":"item_1"},
    {"id":"item_2"}
  ]
})

为了解释数组并将其转换为对象数组,我准备了以下转换器:

struct ListConverter(T)
  def self.from_json(pull : JSON::PullParser)
    items = Array(T).new
    pull.read_array do
      items.push(Item.from_json(pull.read_raw))
    end
    items
  end
end

有两个抽象结构。一个用于数组中的项目,另一个用于列表本身,其中包括Enumerable

abstract struct Base
  include JSON::Serializable
end

abstract struct List(T) < Base
  include Enumerable(T)

  @[JSON::Field(key: "_embedded", converter: ListConverter(Item))]
  getter items : Array(T)

  def each(&block : T -> _)
  end
end

最后是实现:

struct Item < Base
  getter id : String?
end

struct ItemList < List(Item)
end

list = ItemList.from_json(json)

这一切都很好,除了一件事。列表转换器需要传递确切的项目类型:

@[JSON::Field(key: "_embedded", converter: ListConverter(Item))]

我希望能够做到这一点,但当然,这不起作用,因为T 没有在运行时定义(我认为):

@[JSON::Field(key: "_embedded", converter: ListConverter(T))]

所以现在我必须在每个继承自 List 的结构中定义以下行:

@[JSON::Field(key: "_embedded", converter: ListConverter(Item))]
getter items : Array(T)

避免不必要的重复的最佳方法是什么?

【问题讨论】:

  • 我不确定您的实际用例是否还有其他问题。但是在您在此处发布的示例中,您根本不需要自定义 ListConverterArray 已经涵盖了这一点。只需省略 converter: 配置就可以完美运行。
  • 谢谢,不知道它可以按原样转换数组。很高兴知道。虽然,在我的场景中,数组嵌套在一个对象内。像这样的东西:{ "_embedded": { "items": [{"id":"item_1"},{"id":"item_2"}] } }。并且密钥(items)根据T的名称而有所不同。
  • 这也应该有效。 JSON::Field 上有一个 root 属性用于此目的。例如,请参阅carc.in/#/r/8mhf
  • 更好!现在我不再需要转换器了。再次感谢! github.com/wout/mollie.cr/blob/master/src/mollie/list.cr#L3-L9

标签: json crystal-lang


【解决方案1】:

在快速步行之后,我想出了一个可行的解决方案。通过使用宏,可以捕获T,并使用宏将转换器传递给JSON::Field注解:

abstract struct List(T) < Base
  include Enumerable(T)

  macro list_converter
    ListConverter({{ T.id }})
  end

  @[JSON::Field(key: "_embedded", converter: list_converter)]
  getter items : Array(T)

  def each(&block : T -> _)
  end
end

不确定这是否是正确/最佳方法,但它可以按预期工作。

【讨论】:

    猜你喜欢
    • 2012-09-21
    • 2021-05-02
    • 2015-05-28
    • 2017-01-21
    • 2019-12-13
    • 2021-09-25
    • 2010-10-03
    相关资源
    最近更新 更多