AWS Lambda json deserialization with jackson annotations

后端 未结 5 1651
生来不讨喜
生来不讨喜 2021-01-07 22:43

I\'m calling an aws lambda with a json body. So the fields of the json are with different name from the ones in the POJO. So what I did is to add @JsonProperty on the fields

相关标签:
5条回答
  • 2021-01-07 23:06

    So I found a way to do this. You need to implement RequestStreamHandler which gives you input and output streams which you can work with:

    import com.amazonaws.services.lambda.runtime.RequestStreamHandler
    
    public class ChartHandler implements RequestStreamHandler {
        private ObjectMapper objectMapper = new ObjectMapper();
    
        @Override
        public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
            DeserializationClass deserializedInput = objectMapper.readValue(inputStream, DeserializationClass.class)
            objectMapper.writeValue(outputStream, deserializedInput); //write to the outputStream what you want to return
        }
    
    }
    

    Having the input and output streams makes you independent of the format and frameworks you use to parse it.

    0 讨论(0)
  • 2021-01-07 23:22

    It sounds like you have version mismatch between annotation types, and databind (ObjectMapper): both MUST be the same major version. Specifically, Jackson 1.x annotations work with Jackson 1.x databind; and 2.x with 2.x.

    Difference is visible via Java package: Jackson 1.x uses org.codehaus.jackson, whereas Jackson 2.x uses com.fasterxml.jackson. Make sure to import right annotations for ObjectMapper you use.

    0 讨论(0)
  • 2021-01-07 23:23

    create getter methods for the properties and put @JsonProperty on the getter methods.

    0 讨论(0)
  • 2021-01-07 23:26

    Take a look at this quote from AWS documentation:

    You shouldn't rely on any other features of serialization frameworks such as annotations. If you need to customize the serialization behavior, you can use the raw byte stream to use your own serialization.

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

    0 讨论(0)
  • 2021-01-07 23:26

    I had this same issue and needed MyCustomClass to be taken in and out of the Lambda Function correctly so that it can be passed through my State Machine in the Step Function without any hiccups.

    Building off what Hristo Angelov posted, I was able to get a solution that worked for me and I'm posting it hoping that it will help others that were stuck like I was:

    import java.io.InputStream;
    import java.io.OutputStream;
    
    import com.amazonaws.services.lambda.runtime.Context;
    import com.amazonaws.services.lambda.runtime.LambdaLogger;
    import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
    
    public class StaticSearchPagingLambdaFunctionHandler implements RequestStreamHandler {
    
        LambdaLogger logger = null;
        MyCustomClass myCustomClass = null;
    
        // Register the JavaTimeModule for LocalDate conversion
        ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
    
        @Override
        public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) {    
    
                myCustomClass = objectMapper.readValue(inputStream, MyCustomClass .class);
    
                // ...
                // Do stuff with myCustomClass
                // ...
    
                objectMapper.writeValue(outputStream, myCustomClass);
        }
    }
    

    Even though the JSON string will print out differently with the ObjectMapper writing to the OutPutStream, when the next lambda function takes it in while going through the Step Function, it will still get converted to LocalDate correctly.

    Make sure that in MyCustomClass your toString() method prints correctly. My toString() method looks like this:

    import java.time.LocalDate;
    
    import org.json.JSONObject;
    
    public class SimpleSearch {
    
        private LocalDate startDate;
        private LocalDate endDate;
    
        // ...
        // Getters and Setters for the LocalDate variables
        // ...
    
        @Override
        public String toString() {
            return new JSONObject(this).toString();
        }
    
        public SimpleSearch() {}
    }
    

    then your JSON printouts will always look like this when it gets sent to the lambda and not that other crazy Jackson format:

    {
        "startDate": "2018-11-01",
        "endDate": "2018-11-16"
    }
    

    Some of the Maven dependencies I used:

    <dependency>
        <groupId>org.json</groupId>
        <artifactId>json</artifactId>
        <version>20180813</version>
    </dependency>
    
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>2.9.7</version>
    </dependency>
    

    Hopefully AWS fixes the Jackson conversions to be reciprocal, to and from JSON, so that we wouldn't have to resort to these custom conversions anymore.

    0 讨论(0)
提交回复
热议问题