AWS无法将java.lang.String实例反序列化为START_OBJECT。

36

我制作了一个AWS Lambda函数,现在我想通过API Gateway的帮助通过URL访问它。

我已经设置好了所有的内容,并创建了一个application/jsonbody映射模板在API Gateway中,如下所示:

{ 
    "input": "$input.params('input')",
}

然后我触发了一个看起来像这样的HTTP GET请求:

https://dmquh95ckh.execute-api.eu-west-1.amazonaws.com/prod/OtoTestFunction?input=test

我的Java处理程序类看起来像这样:

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)"
      ]
    }
  }
}

这是在调用您的Java函数之前还是之后发生的?您的“Input:”日志消息是否出现在日志中? - Mark B
7个回答

40

当我将输入参数的类型从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<String, Object>表示的纯字符串。 对于Map表示法,键是属性的名称,值是(1)如果是基本类型则为字符串,或者(2)如果有多个值,则为列表,或另一个Map<String, Object>或另一个JSON结构。 您可以使用以下方法恢复JSON表示:

    if(input instanceof String)
    {
        String lambdaInputJsonStr = (String)input;
    }
    else if(input instanceof Map)
    {
        String lambdaInputJsonStr = gson.toJson((Map)input);
    }

1
我曾经也陷入了同样的陷阱,在遵循https://github.com/awsdocs/aws-lambda-developer-guide/blob/main/sample-apps/java-basic/src/main/java/example/HandlerString.java时,过度使用了字符串。 - Big Pumpkin
4
这几乎就是我遇到的问题,最终使用了: implements RequestHandler<Map<String, Object>, String>而不是我复制的示例中的Map<String, String>。 - Matt
将数据类型从字符串更改为对象对我也起作用了。谢谢! - Shrinath
对我没用,我得到了“无法将java.lang.String反序列化为START_OBJECT令牌”的错误。 - Abel ANEIROS
这个可以工作。然而,解析 Object 类的对象将需要大量的工作。我已经在另一个答案中提供了一种改进方法,使用 AWS 提供的 Event 类。 - Anurag

10

这是Lambda反序列化期间出现的错误消息。

您的API Gateway映射模板正在发送JSON对象,但处理程序却期望一个字符串。要么从API Gateway发送原始字符串,要么更新处理程序以使用与您的模板输出对应的POJO。

例如:

public class MyPojo {
   private String input;
   public String getInput() { return input; }
   public void setInput(String input) { this.input = input; }
}

See: http://docs.aws.amazon.com/lambda/latest/dg/java-programming-model-req-resp.html


6
“从API Gateway发送原始字符串”是如何实现的?答案指的是哪个“模板输出”? - Harald

6

我尝试使用对象作为参数类型以及Pojo类,它在某些情况下可以正常工作,但是当通过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) {

    }
}

1

InputStream应该能够处理任何输入。

Reference: https://docs.aws.amazon.com/lambda/latest/dg/java-handler.html

InputStream – 事件可以是任何 JSON 类型。运行时将文档的字节流传递给处理程序,而不进行修改。您需要反序列化输入并将输出写入输出流。

public class Handler implements RequestHandler<InputStream, String> {
@Override
    public String handleRequest(InputStream event, Context context) {

1

我们可以使用AWS提供的事件类,如APIGatewayProxyRequestEvent、S3Event、SNSEvent等,而不是使用Object类。这样做可以节省很多精力,当您需要查看事件属性,如api查询参数、api方法等时。

您需要包含以下Maven依赖项:

    <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-lambda-java-events</artifactId>
        <version>3.11.1</version>
    </dependency>

0
错误提示消息的意思是:“由于input是一个字符串,因此我希望它以引号"开头。但我看到的却是一个{”。这就是为什么将input类型更改为ObjectMap<String,Object>MyPojo会使解析器满意。

如果input确实应该是一个字符串,则有效载荷值本身必须以"开头。例如:String payload = "\"string input\""


0

正如其他人所提到的,出现错误是因为无法将JSON请求转换为字符串对象。您可以使用自定义输入参数类来实现处理程序,例如:

    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类只是一个简单的POJO类。

为了调用API中的POST方法,你需要创建一个模型并将其添加到API定义的Method Request部分的请求体中。该模型的json定义需要与CustomGetEventInput类的定义相匹配。

例如

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 方法,您需要定义一个 URL 查询字符串,其中包含传递给 Lambda 函数的参数名称。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接