如何正确地将复杂的Swift对象序列化/反序列化为AWS Lambda负载? [英] How do I correctly serialize/deserialize a complex Swift object to as an AWS Lambda payload?

查看:59
本文介绍了如何正确地将复杂的Swift对象序列化/反序列化为AWS Lambda负载?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的用例是存储图形数据.我在Swift中定义了一个 Codable 数据对象,如下所示:

My use case is storing drawing data. I have defined a Codable data object in Swift, something like this:

class DrawingData : Codable {
  var startTime : Double?
  var pointsOverTime : [String : CGPoint] = [:]
  var templateLine : [CGPoint]
}

(事实证明,像 CGPoint 之类的对象具有非常好的 Codable 实现,如下所示).在我的Java 8 Lambda函数中,我以这种方式定义了对象:

(it turns out, objects like CGPoint have a very nice Codable implementation, as you will see below). In my Java 8 Lambda function, I have defined the object this way:

public class DrawingData {
  Double startTime;
  HashMap<String, Double[][]> pointsOverTime;
  Double[][] templateLine;
}

要在iOS端进行编码,我想这样做:

To encode, on the iOS side, I would love to just do this:

func sendToLambda(drawingData : DrawingData) {
  let request = AWSLambdaInvokerInvocationRequest()
  request.payload = drawingData
  ...

但是在这种情况下,我得到一个 NSInvalidArgumentException:JSON写入中的无效类型.好的,没问题,我想,我将对对象进行编码:

but in this case, I get an NSInvalidArgumentException: Invalid type in JSON write. OK, no problem, I thought, I will encode the object:

let encoder = JSONEncoder()
let data = try encoder.encode(drawingData)
let json = String(data: data, encoding: .utf8)

起初,我尝试了 request.payload = data ,但这给了我与上述相同的 NSInvalidArgumentException 错误.当我尝试 request.payload = json 时,它实际上将其发送到Lambda,但是随后我收到了来自Lambda的反序列化错误:

At first, I tried request.payload = data but this gives me the same NSInvalidArgumentException error as above. When I try request.payload = json it actually sends it to the Lambda, but then I receive a deserialization error from Lambda:

com.fasterxml.jackson.databind.JsonMappingException: 
Can not instantiate value of type [simple type, class com.(...).DrawingData] from String value ...

现在这才是真正吸引我的部分.我复制了String值(来自上面的错误),将转义的引号转换为引号,然后将确切的字符串粘贴为Lambda控制台中的测试对象,并且效果很好!(我还尝试使用 .replacingOccurrences(of:"\\\",with:" \")修改代码中的json字符串)-没有骰子).

Now here's the part that really gets me. I copy the String value (from the above error), convert escaped quotes to quotes, and paste the exact string as a test object in the Lambda console, and it works just fine! (I also tried modifying my json string in my code using .replacingOccurrences(of: "\\\"", with: "\"") - no dice).

所以看来问题出在a)Swift JSONEncoder 和/或 String.init(data:)或b)关于Jackson配置的问题是AWS Lambda环境的一部分.我不确定如何确定它是哪种,或者解决它的最佳方法是什么.

So it seems the problem lies either with a) the Swift JSONEncoder and/or String.init(data:) or else b) something about the Jackson configuration that is part of the AWS Lambda environment. I'm not sure how to figure out which one it is, or what the best way to fix it would be.

我可能会提交一个请求,要求AWS iOS SDK接受Codable对象作为有效负载,但与此同时,有什么建议可以解决此问题?我可以尝试其他替代方法吗?预先感谢!

I'll likely submit a request for the AWS iOS SDK to accept a Codable object as a payload, but in the meantime, any suggestions how to work around this? Any alternatives I could try? Thanks in advance!

编辑:根据建议,这是打印到我的XCode控制台上的JSON代码段:

Edit: as suggested, here is a snippet of the JSON as printed to my XCode console:

{\"startTime\":1612896264.1828671,
\"templateLine\":[[115.53672736136741,335.1095896791432],
[1055.5423897415162,193.17949493333694]],\"pointsOverTime\":
{\"363899.94621276855\":[880.5,145.5],\"209530.83038330078\":
[242,347.5],\"331470.9663391113\":[843,156.5],\"175115.10848999023\":
[187,369.5],\"156777.85873413086\":[173,373],\"209379.9114227295\":
[242,347.5],\"281613.826751709\":[698,197.5],\"265787.12463378906\":
[606.5,224],\"347551.8226623535\":[868.5,148.5],\"174979.92515563965\":
[187,369.5],\"0\":[172.5,373],\"156646.9669342041\":
[173,373],\"224991.7984008789\":[331,313]...

推荐答案

我在找到

I solved this after finding this answer, which led me to use the following code on the iOS side:

extension Encodable {
  func asDictionary() throws -> [String: Any] {
    let data = try JSONEncoder().encode(self)
    guard let dictionary = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] else {
      throw NSError()
    }
    return dictionary
  }
}

在我的 Codable 对象上调用它之后,我可以分配一些东西作为有效载荷:

After calling this on my Codable object, I had something I could assign as the payload:

let payloadObject = drawingData.asDictionary()
request.payload = payloadObject

然后通过将那个对象打印到XCode控制台,我能够确切地确定如何在Java中构造Lambda请求对象.

Then by printing that object to the XCode console, I was able to determine exactly how to structure my Lambda request object in Java.

另一种可能有用的方法是在我的Lambda函数中实现 RequestStreamHandler (而不是 RequestHandler ),然后使用GSON或类似方法手动反序列化.但是我很高兴能够利用 Codable 协议和POJO作为模型.

Another method that could have helped was to implement RequestStreamHandler (instead of RequestHandler) in my Lambda function, and just deserialize manually using GSON or something similar. But I'm really glad to be able to leverage the Codable protocol and POJOs as models.

这篇关于如何正确地将复杂的Swift对象序列化/反序列化为AWS Lambda负载?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆