AWS无法反序列化START_OBECT之外的java.lang.String实例



我制作了一个Lambda函数,我想在API网关的帮助下通过URL访问它。

我已经设置好了,我还在API网关中创建了一个application/json主体映射模板,如下所示:

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

当我将输入参数的类型从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);
    }

这是Lambda反序列化过程中的错误消息。

API网关映射模板正在发送一个JSON对象,但处理程序需要一个String。从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

我尝试使用Object作为参数类型以及Pojo类,它在某些情况下有效,但当使用API网关URL从浏览器发出请求时,它失败了,并给出了上述错误。花了至少2-3个小时来找出正确的签名,在大多数情况下都有效,如下所示。然而,这是helloworld的例子,您显然会根据自己的需求自定义输入。

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–事件是任何JSON类型。运行时将文档的字节流传递给处理程序而不进行修改。您可以反序列化输入并将输出写入输出流。

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

错误消息试图说"由于input是一个字符串,我希望它以引用"开头。但是我看到的是{;。这就是为什么将input类型更改为ObjectMap<String,Object>MyPojo会让解析器感到高兴。

如果input真的应该是String,那么有效负载值本身必须以"开头。例如String payload = ""string input""

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

    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方法,您需要创建一个Model并将其添加到API定义的MethodRequest部分的请求主体中。模型的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函数的参数的名称。

我们可以使用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>

相关内容

  • 没有找到相关文章

最新更新