AWS 无法反序列化 START_OBJECT 中 java.lang.String 的实例
AWS Can not deserialize instance of java.lang.String out of START_OBJECT
我创建了一个 Lambda 函数,我想在 API 网关的帮助下通过 URL 访问它。
我已经全部设置好,我还在 API 网关中创建了一个 application/json
body 映射模板,如下所示:
{
"input": "$input.params('input')",
}
然后我触发了如下所示的 HTTP GET 请求:
https://dmquh95ckh.execute-api.eu-west-1.amazonaws.com/prod/OtoTestFunction?input=test
我的 Java 处理程序 class 看起来像这样:
public class LambdaFunctionHandler implements RequestHandler<String, String> {
@Override
public String handleRequest(String input, Context context) {
context.getLogger().log("Input: " + input);
return "Test completed."+input;
}
}
这是完整的错误信息:
{
"errorMessage": "An error occurred during JSON parsing",
"errorType": "java.lang.RuntimeException",
"stackTrace": [],
"cause": {
"errorMessage": "com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token\n at [Source: lambdainternal.util.NativeMemoryAsInputStream@68c4039c; line: 1, column: 1]",
"errorType": "java.io.UncheckedIOException",
"stackTrace": [],
"cause": {
"errorMessage": "Can not deserialize instance of java.lang.String out of START_OBJECT token\n at [Source: lambdainternal.util.NativeMemoryAsInputStream@68c4039c; line: 1, column: 1]",
"errorType": "com.fasterxml.jackson.databind.JsonMappingException",
"stackTrace": [
"com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)",
"com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:835)",
"com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:59)",
"com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:12)",
"com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1441)",
"com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1047)"
]
}
}
}
这是 Lambda 反序列化期间的错误消息。
您的 API 网关映射模板正在发送一个 JSON 对象,但您的处理程序需要一个字符串。从 API 网关发送原始字符串,或更新您的处理程序以使用与您的模板输出对应的 POJO。
即
public class MyPojo {
private String input;
public String getInput() { return input; }
public void setInput(String input) { this.input = input; }
}
参见:
http://docs.aws.amazon.com/lambda/latest/dg/java-programming-model-req-resp.html
当我将输入参数的类型从 String 更改为 Object.
时,它在所有情况下都对我有用
public class LambdaFunctionHandler implements RequestHandler<Object, String> {
@Override
public String handleRequest(Object input, Context context) {
String data= input != null ? input.toString() : "{}";
context.getLogger().log("Input: " + data);
return "Test completed."+data;
}
}
************************** 添加于 2021 年 3 月 12 日 ************** *************
在研究了几个 Lambda 实现之后,我意识到输入参数只不过是 JSON 结构或 Map 表示的纯字符串表示。
对于地图表示,Key 是属性的名称,值是 (1) 如果它是原始值,则为 String 或 (2) 如果它有多个值,则为 List,是另一个 Map 或另一个JSON 结构。您可以使用以下方法恢复 JSON 表示:
if(input instanceof String)
{
String lambdaInputJsonStr = (String)input;
}
else if(input instanceof Map)
{
String lambdaInputJsonStr = gson.toJson((Map)input);
}
我尝试使用 Object 作为参数类型以及 Pojo class,它在某些情况下工作,但是当使用 API 网关 URL 从浏览器发出请求时,它失败了并且给出了准确的上述错误。至少花了 2-3 个小时来找出正确的签名,在大多数情况下都可以使用,如下所示。然而,这是针对 hello world 示例,您显然会根据您的要求自定义输入。
public class LambdaFunctionHandler implements RequestHandler<***Map<String,Object>,*** Customer> {
@Override
public Customer handleRequest(***Map<String,Object> input***, Context context) {
}
}
InputStream 应该能够处理任何输入。
参考:
https://docs.aws.amazon.com/lambda/latest/dg/java-handler.html
InputStream – The event is any JSON type. The runtime passes a byte stream of the document to the handler without modification. You deserialize the input and write output to an output stream.
public class Handler implements RequestHandler<InputStream, String> {
@Override
public String handleRequest(InputStream event, Context context) {
错误消息试图说“由于 input
是一个字符串,我希望它以引号 "
开头。但我看到的是 {
”。这就是为什么将 input
类型更改为 Object
、Map<String,Object>
或 MyPojo
让解析器满意的原因。
如果 input
确实应该是一个字符串,则负载值本身必须以 "
开头。例如,String payload = "\"string input\""
.
正如其他人所提到的,出现错误是因为 JSON 请求无法转换为 String 对象。您可以使用自定义输入参数 class 来实现您的处理程序,例如:
public class ZinusoftLambdaHandler implements
RequestHandler<CustomGetEventInput,String> {
public String handleRequest(CustomGetEventInput input, Context context) {
context.getLogger().log("Hello World from ZinusoftLambdaHandler :
"+input.getValue());
return "Response from lambda "+input.getValue();
}
}
您的 CustomGetEventInput class 只是一个简单的 POJO class。
为了调用 API 中的 POST 方法,您需要创建一个模型并将其添加到 API 定义的方法请求部分的请求正文中.模型的 json 定义需要与 CustomGetEventInput class.
的定义相匹配
例如
public class CustomEventInput {
private List<Integer> values;
public CustomEventInput() {
}
public CustomEventInput(List<Integer> input) {
values = input;
}
public List<Integer> getValues() {
return values;
}
public void setValues(List<Integer> values) {
this.values = values;
}
}
JSON 型号
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "CustomEventInput",
"type": "object",
"properties": {
"values": {
"type": "array",
"items": { "type": "integer" }
}
}
}
对于 GET 方法,您需要使用传递给 lambda 函数的参数名称定义一个 URL 查询字符串。
我创建了一个 Lambda 函数,我想在 API 网关的帮助下通过 URL 访问它。
我已经全部设置好,我还在 API 网关中创建了一个 application/json
body 映射模板,如下所示:
{
"input": "$input.params('input')",
}
然后我触发了如下所示的 HTTP GET 请求:
https://dmquh95ckh.execute-api.eu-west-1.amazonaws.com/prod/OtoTestFunction?input=test
我的 Java 处理程序 class 看起来像这样:
public class LambdaFunctionHandler implements RequestHandler<String, String> {
@Override
public String handleRequest(String input, Context context) {
context.getLogger().log("Input: " + input);
return "Test completed."+input;
}
}
这是完整的错误信息:
{
"errorMessage": "An error occurred during JSON parsing",
"errorType": "java.lang.RuntimeException",
"stackTrace": [],
"cause": {
"errorMessage": "com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token\n at [Source: lambdainternal.util.NativeMemoryAsInputStream@68c4039c; line: 1, column: 1]",
"errorType": "java.io.UncheckedIOException",
"stackTrace": [],
"cause": {
"errorMessage": "Can not deserialize instance of java.lang.String out of START_OBJECT token\n at [Source: lambdainternal.util.NativeMemoryAsInputStream@68c4039c; line: 1, column: 1]",
"errorType": "com.fasterxml.jackson.databind.JsonMappingException",
"stackTrace": [
"com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)",
"com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:835)",
"com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:59)",
"com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:12)",
"com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1441)",
"com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1047)"
]
}
}
}
这是 Lambda 反序列化期间的错误消息。
您的 API 网关映射模板正在发送一个 JSON 对象,但您的处理程序需要一个字符串。从 API 网关发送原始字符串,或更新您的处理程序以使用与您的模板输出对应的 POJO。
即
public class MyPojo {
private String input;
public String getInput() { return input; }
public void setInput(String input) { this.input = input; }
}
参见: http://docs.aws.amazon.com/lambda/latest/dg/java-programming-model-req-resp.html
当我将输入参数的类型从 String 更改为 Object.
时,它在所有情况下都对我有用public class LambdaFunctionHandler implements RequestHandler<Object, String> {
@Override
public String handleRequest(Object input, Context context) {
String data= input != null ? input.toString() : "{}";
context.getLogger().log("Input: " + data);
return "Test completed."+data;
}
}
************************** 添加于 2021 年 3 月 12 日 ************** *************
在研究了几个 Lambda 实现之后,我意识到输入参数只不过是 JSON 结构或 Map
if(input instanceof String)
{
String lambdaInputJsonStr = (String)input;
}
else if(input instanceof Map)
{
String lambdaInputJsonStr = gson.toJson((Map)input);
}
我尝试使用 Object 作为参数类型以及 Pojo class,它在某些情况下工作,但是当使用 API 网关 URL 从浏览器发出请求时,它失败了并且给出了准确的上述错误。至少花了 2-3 个小时来找出正确的签名,在大多数情况下都可以使用,如下所示。然而,这是针对 hello world 示例,您显然会根据您的要求自定义输入。
public class LambdaFunctionHandler implements RequestHandler<***Map<String,Object>,*** Customer> {
@Override
public Customer handleRequest(***Map<String,Object> input***, Context context) {
}
}
InputStream 应该能够处理任何输入。
参考: https://docs.aws.amazon.com/lambda/latest/dg/java-handler.html
InputStream – The event is any JSON type. The runtime passes a byte stream of the document to the handler without modification. You deserialize the input and write output to an output stream.
public class Handler implements RequestHandler<InputStream, String> {
@Override
public String handleRequest(InputStream event, Context context) {
错误消息试图说“由于 input
是一个字符串,我希望它以引号 "
开头。但我看到的是 {
”。这就是为什么将 input
类型更改为 Object
、Map<String,Object>
或 MyPojo
让解析器满意的原因。
如果 input
确实应该是一个字符串,则负载值本身必须以 "
开头。例如,String payload = "\"string input\""
.
正如其他人所提到的,出现错误是因为 JSON 请求无法转换为 String 对象。您可以使用自定义输入参数 class 来实现您的处理程序,例如:
public class ZinusoftLambdaHandler implements
RequestHandler<CustomGetEventInput,String> {
public String handleRequest(CustomGetEventInput input, Context context) {
context.getLogger().log("Hello World from ZinusoftLambdaHandler :
"+input.getValue());
return "Response from lambda "+input.getValue();
}
}
您的 CustomGetEventInput class 只是一个简单的 POJO class。
为了调用 API 中的 POST 方法,您需要创建一个模型并将其添加到 API 定义的方法请求部分的请求正文中.模型的 json 定义需要与 CustomGetEventInput class.
的定义相匹配例如
public class CustomEventInput {
private List<Integer> values;
public CustomEventInput() {
}
public CustomEventInput(List<Integer> input) {
values = input;
}
public List<Integer> getValues() {
return values;
}
public void setValues(List<Integer> values) {
this.values = values;
}
}
JSON 型号
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "CustomEventInput",
"type": "object",
"properties": {
"values": {
"type": "array",
"items": { "type": "integer" }
}
}
}
对于 GET 方法,您需要使用传递给 lambda 函数的参数名称定义一个 URL 查询字符串。