【问题标题】:AWS Lambda json deserialization with jackson annotations带有杰克逊注释的 AWS Lambda json 反序列化
【发布时间】:2017-05-19 17:26:55
【问题描述】:

我正在调用带有 json 主体的 aws lambda。因此 json 的字段与 POJO 中的字段名称不同。所以我所做的是在字段上添加@JsonProperty 来告诉杰克逊json 中的名称是什么。但由于某种原因,它似乎无法识别它们,并且所有字段都为空。如果我传递一个与 POJO 具有相同字段名称的 json,它就可以工作。这是我的课:

public class Event implements Identifiable {

    @JsonProperty("distinct_id")
    private String distinctId;

    @JsonProperty("user_id")
    private Integer userId;

    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    private LocalDateTime eventDateTime;

    //Here are the getters and setters
}

如果我通过了

{"distinct_id":"123", "user_id":123, "dt":"2017-01-04T08:45:04+00:00"} 

所有字段都是空的,并且具有 distinctId、userId、eventDateTime 它可以序列化,但它也无法识别我的自定义序列化器/反序列化器,但这实际上是同一个问题。

我的结论是,由于某种原因,aws jackson 没有使用注释,但它没有意义。

【问题讨论】:

  • 我也面临同样的问题。您可以在哪里使用它?
  • @Raja 我添加了答案

标签: java jackson aws-lambda


【解决方案1】:

为属性创建 getter 方法并将 @JsonProperty 放在 getter 方法上。

【讨论】:

  • 这不是问题。此注释也可以放置在字段上。如果我在我的代码中映射 json,它就可以工作。但我不想这样做,因为我想减少应用程序中的样板代码。
  • 我也在属性上使用它。我只是告诉你另一种方法。我正在使用@org.codehaus.jackson.annotate.JsonProperty,它可以工作。
  • 我试过了——它不起作用。由于某种原因,aws lambda 的 jackson 无法识别注释。
  • 我也遇到了 AWS Lambda 和 Jackson 的问题。我正在使用@JsonTypeInfo 进行继承:单元测试还可以,但是使用problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information 的lambda 失败。我正在尝试将 github.com/opendatalab-de/geojson-jackson 与 AWS Lambda 一起使用...
【解决方案2】:

听起来注释类型和数据绑定 (ObjectMapper) 之间的版本不匹配:两者必须是相同的主要版本。具体来说,Jackson 1.x 注释与 Jackson 1.x 数据绑定一起工作;和 2.x 和 2.x。

通过 Java 包可以看到差异:Jackson 1.x 使用 org.codehaus.jackson,而 Jackson 2.x 使用 com.fasterxml.jackson。确保为您使用的ObjectMapper 导入正确的注释。

【讨论】:

  • 我在类路径中只有 2.x 版本,并分别导入 2.x 注释(com.fasterxml.*)。我不确定 aws lambda 如何执行我提供的 jar,但我假设它们具有不同的类加载器和它们自己的依赖项。根据反序列化失败的堆栈跟踪,他们似乎也在使用杰克逊 2。所以它不能“识别”注解真的很奇怪。
  • @HristoAngelov 如果是这样,也许这不是这里的原因。我提到它是因为这是一个很常见的问题,尤其是当 IDE 可以同时提供 Jackson 1.x 和 2.x 类型时,如果两者都在类路径中(通常声明为传递依赖,因为 Hadoop 引入了 Jackson 1.x dep)跨度>
  • AWS Lambda 从什么版本开始序列化对象?
【解决方案3】:

所以我找到了一种方法来做到这一点。您需要实现 RequestStreamHandler ,它为您提供可以使用的输入和输出流:

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
    }

}

拥有输入和输出流使您独立于用于解析它的格式和框架。

【讨论】:

    【解决方案4】:

    看看 AWS 文档中的这句话:

    您不应依赖序列化框架的任何其他功能,例如注释。如果需要自定义序列化行为,可以使用原始字节流来使用自己的序列化。

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

    【讨论】:

    • 感谢您分享该评论。 java-programming-model-req-resp 的当前文档中没有引用,但它可能仍然是正确的
    【解决方案5】:

    我遇到了同样的问题,需要正确地将MyCustomClass 带入和带出Lambda Function,以便它可以在Step Function 中通过我的State Machine 而不会出现任何问题。

    Hristo Angelov 发布的内容的基础上,我能够获得一个适合我的解决方案,我发布它希望它能帮助像我一样被困住的其他人:

    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);
        }
    }
    

    尽管 JSON 字符串与 ObjectMapper 写入 OutPutStream 时打印输出不同,但当下一个 lambda 函数在通过 Step Function 时将其接收时,它仍会正确转换为 LocalDate .

    确保在MyCustomClass 中您的toString() 方法打印正确。我的toString() 方法如下所示:

    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() {}
    }
    

    那么当你的 JSON 打印输出被发送到 lambda 时,它总是看起来像这样,而不是其他疯狂的 Jackson 格式:

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

    我使用的一些 Maven 依赖项:

    <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>
    

    希望 AWS 将 Jackson 的转换修复为与 JSON 之间的相互转换,这样我们就不必再求助于这些自定义转换了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-07
      • 2015-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-18
      • 1970-01-01
      相关资源
      最近更新 更多