如何正确地序列化/反序列化复杂的Swift对象作为AWS Lambda有效负载?



我的用例是存储绘图数据。我在Swift中定义了一个Codable数据对象,就像这样:

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

(事实证明,像CGPoint这样的对象有一个非常好的Codable实现,正如你将在下面看到的)。在我的Java 8 Lambda函数中,我这样定义了对象:

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

要编码,在iOS端,我喜欢这样做:

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

,但在这种情况下,我得到一个NSInvalidArgumentException: Invalid type in JSON write。好的,没问题,我想,我将对对象进行编码:

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收到反序列化错误:

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

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

所以问题似乎在于a) SwiftJSONEncoder和/或String.init(data:),或者b)关于Jackson配置的一些东西,这是AWS Lambda环境的一部分。我不知道如何找出是哪一个,或者解决它的最佳方法是什么。

我可能会提交一个请求,让AWS iOS SDK接受一个可编码的对象作为有效载荷,但与此同时,有什么建议如何解决这个问题吗?我可以试试别的办法吗?提前感谢!

编辑如建议,这里是一个JSON的片段打印到我的XCode控制台:

{"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]...

找到这个答案后,我解决了这个问题,这导致我在iOS端使用以下代码:

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对象上调用这个之后,我有了一些可以分配作为有效负载的东西:

let payloadObject = drawingData.asDictionary()
request.payload = payloadObject
然后通过打印那个对象到XCode控制台,我能够准确地确定如何在Java中构造我的Lambda请求对象。

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

最新更新