46

I have written following Hello World Lambda which I am executing by uploading on AWS via AWS toolkit for Eclipse.

public class HelloWorldLambdaHandler implements RequestHandler<String, String> {
    public String handleRequest(String input, Context context) {
        System.out.println("Hello World! executed with input: " + input);
        return input;
    }
}

I am getting following error when executing above code. Any idea what I maybe doing wrong here? BTW Maven project which have this handler, doesn't have any other class and only dependency is aws-lambda-java-core version 1.1.0.

Skip uploading function code since no local change is found...
Invoking function...
==================== FUNCTION OUTPUT ====================
{"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@2f7c7260; 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@2f7c7260; 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)"]}}}
Hemant
  • 4,537
  • 8
  • 41
  • 43

6 Answers6

94

For some reason Amazon can't deserialize json to a String. You would think String would be as general as input parameter as you can get but rightly or wrongly it's not compatible.

To handle JSON you can either use a Map or a custom POJO.

public class HelloWorldLambdaHandler {
    public String handleRequest(Map<String,Object> input, Context context) {
        System.out.println(input);
        return "Hello";
    }
}
Lionel Port
  • 3,492
  • 23
  • 26
  • 2
    Indeed you are right - I replaced String with a "Person" class which doesn't have any property and it worked fine. – Hemant Mar 04 '16 at 02:22
  • 9
    This might be right, but why is it like that? Is there any explanation, since documentation itself suggests to use a String in their example. Can anybody from AWS explain that? – Ondrej Tokar May 10 '16 at 12:05
  • 5
    I agree that the documentation should be improved to explain that a handler input parameter declared as `String` only accepts a valid JSON-string (i.e. a Unicode sequence surrounded by quotation marks, e.g. `"foo"`) and not a string representation of a valid JSON object ( e.g. `{"foo": "bar"}`) – fspinnenhirn Jul 01 '16 at 02:15
  • The wording of the answer is rather strange. JSON is a String. You can't deserialize JSON to a String: it's already a string. – Shannon Jul 21 '17 at 15:14
  • Can anyone give an example of a pojo? I create a pojo and it still won't work. – EGHDK Aug 08 '17 at 00:15
  • Thank you! Wish they'd just use gson instead – Nathan Adams Oct 04 '18 at 22:26
  • 1
    String do work, just wrap your json in quotes and escape all the quotes in the json – sbnarra Oct 19 '18 at 13:53
  • Thanks, I had no use of input and hence this works for me to put a dummy parameter. This is so weird I need some json as input – Ajak6 Mar 13 '20 at 06:45
  • 1
    Having an input of `Map` and _not_ `Map` fixed it for me, even though I was sending in a JSON map of String to String... =/ – Matt Klein Apr 10 '20 at 19:00
  • The error message is trying to say that "Since `input` is a String, I am expecting it to start with a `"`. But I am seeing a `{` instead". That is why changing `input` type to `Object`, `Map` or `Person` made the parser happy. If `input` should truly be a String, the payload value itself must start with a `"`. For instance, `String payload = "\"string input\""`. – Big Pumpkin Jan 18 '21 at 17:37
16

Read the error from the stack trace. It says "Can not deserialize instance of java.lang.String out of START_OBJECT token". The "START_OBJECT" token is '{'.

The problem was simply that you need to pass an actual String as input, e.g., "A String". This is your json input. Not {}. {} is not a String. You don't need any braces, just a string (in quotes). On the other hand, {} is a valid Person object, so it worked once you changed it to handle a Person as the input.

Kelly Denehy
  • 207
  • 2
  • 5
  • 1
    @Cenxui This actually is the correct answer to the question: _"Any idea what @Hemnat is doing wrong when calling that particular lambda function with an empty JSON object (`{}`)"_ – fspinnenhirn Jul 01 '16 at 01:58
  • This is the correct answer - if you specify `"{}"` as your Lambda input, Lambda will try to parse it (even though your RequestHandler input type is String). If you specify `""` (empty string) instead, it works. – Luke May 03 '17 at 16:05
  • I tied to use string, and it didnot work. The above solution to of Map or person worked for me – user93796 Dec 20 '17 at 00:56
15

I tried with the following value in the test :

"TestInput"

instead of :

{ Input : "TestInput"}

and it seems to have worked fine.

Samuel Hulla
  • 6,617
  • 7
  • 36
  • 70
Anit Mohanty
  • 151
  • 1
  • 4
3

The complete working solution is

public class HelloWorldLambdaHandler implements RequestHandler<String, String> {
    public String handleRequest(String input, Context context) {
        System.out.println("Hello World! executed with input: " + input);
        return input;
    }
}

then input has to be in double quotes as a String - "Test Input"

kanaparthikiran
  • 523
  • 12
  • 15
0

The input window for the test configurator takes raw json, or strings.

  • If you pass raw json, AWS converts the json into a Map where the variable names are keys that map the respective values.
  • If you wrap the json in double quotes and delimit inner quotes, this is an acceptable Java string representation of a json object and can be parsed as usual.
Javageek
  • 21
  • 6
0

Workaround 1:

Instead of

{
  "key1": "value1",
  "key2": "value2",
  "key3": "value3"
}

use some String as input, as shown below

"anyString"

It'll work fine.

Workaround 2: please refer the answer of @Lionel Port.

Reason:

As @Lionel Port suggested, you must be having String as inputType in your handleRequest() method!

public String handleRequest(String input, Context context) {}

you can see here, input type is String and you're passing Json, that's why giving this error!

Demobilizer
  • 663
  • 9
  • 12