Search code examples
javaamazon-web-servicesaws-lambdaaws-api-gateway

AWS Can not deserialize instance of java.lang.String out of START_OBJECT


I have made a Lambda Function and I want to access it via URL with a help of the API Gateway.

I have set it all up, I have also created an application/json body mapping template in API Gateway looking like this:

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

And then I am triggering HTTP GET request that looks like this:

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

My Java handler class looks like this:

public class LambdaFunctionHandler implements RequestHandler<String, String> {

    @Override
    public String handleRequest(String input, Context context) {
        context.getLogger().log("Input: " + input);
        return "Test completed."+input;
    }
}

And this is the full error message:

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

Solution

  • It worked for me in all the scenarios when I change the type of input argument from String to 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;
      }
    }
    

    ************************** Added on 12 March 2021 ***************************

    After working on a couple of Lambda implementations, I realized that the input argument is nothing but a plain string representation of a JSON structure or a Map<String, Object> representation. For the map representation, Key is the name of the attribute, and the value is (1) a String if it is a primitive value or (2) a List if it has multiple values, is another Map<String, Object> or another JSON structure. You can recover the JSON representation with:

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