【问题标题】:AWS lambda java response does not support nested objects?AWS lambda java 响应不支持嵌套对象?
【发布时间】:2020-04-18 02:53:46
【问题描述】:

我是 Java 新手,所以这可能与 AWS lambda 完全无关。但是,lambda 对输入/输出对象如此随意,我认为这是罪魁祸首。

我正在构建我的第一个 lambda 函数并希望返回一个简单的 JSON 结构(本示例进一步简化):

{
  "document" : "1",
  "person" : { "name" : "John Doe" }
}

但是,当 lambda 序列化 JSON 时,它总是将“人”设置为空白对象!

{
  "document": "1",
  "person": {}
}

这是我的完整代码:

 - test1.java
package handler_test;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
public class test1 implements RequestHandler<String, ResponseClass> {
    @Override
    public ResponseClass handleRequest(String input, Context context) {
      return new ResponseClass();
    }
}

 - ResponseClass.java
package handler_test;
import org.json.JSONException;
import org.json.JSONObject;
public class ResponseClass {
    String document;
    JSONObject person;

    public String getdocument() {
        return "1";
    }

    public JSONObject getperson() {
        try {
            return new JSONObject("{ \"name\" : \"John Doe\" }");
        } catch (JSONException e1) {
            System.out.println("error creating jsonobject");
            return null;
        }
    }

    public ResponseClass() {
    }
}

我已经尝试了几十种变体,使用对象而不是 JSONObjects,将 getperson 输出转换为字符串(如果我想要字符串,它可以工作)等等。如果我存储值并将它们打印到记录器,没关系。但是一旦我尝试通过 lambda 返回它,它就会变成梨形。我已经梳理了网络,除了亚马逊的“问候”示例代码(仅包含两个字符串)之外,在 AWS-lambda java 响应对象上找不到更多内容。任何建议都非常感谢!

【问题讨论】:

  • 谢谢。这就是我提到的“问候”示例代码,它只返回一个简单的对象。 AWS 没有任何返回更复杂的样本。他们确实提到,如果开箱即用的序列化对您不起作用,您可以编写自己的 JSON 序列化,但不要说该怎么做!作为 java 和 lambda 的新手,我很茫然。 (坦率地说,在 JSON 对象中返回 JSON 对象似乎不是一个不寻常的请求,我应该使用自己的工具,尽管似乎没有其他人在 lambda 中这样做。)
  • 嘿@Gregg 你对这个问题有正确的解决方案吗?如果是,请在这里分享。我也想回答这个问题。

标签: java json amazon-web-services aws-lambda


【解决方案1】:

我使用流处理程序解决了这个问题,它不仅可以工作,而且您拥有更多的控制权和更少的代码!我使用 gson 进行 JSON 序列化/反序列化,使用 Apache IOUtils 将 inputteam 转换为字符串。因为我已经使用 Request 和 Response 类编写了它,所以我继续使用它们,尽管我能够摆脱所有 getter 和 setter 代码。

两个注意事项: 1.gson会输出Response类的所有非空属性,甚至 如果它们被声明为私有,那么如果有你不想的值 吐回一定要在最后一行之前将它们设置为空。 2.使用带有AWS插件的Eclipse IDE时,除非能找到RequestHandler,否则不会上传代码到AWS!因此,我有一个立即被覆盖的存根函数。

import com.google.gson.*;
import org.apache.commons.io.IOUtils;
import com.amazonaws.services.lambda.runtime.*;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;

public class Intel implements RequestStreamHandler, RequestHandler<Object, Object> {
    @Override
    public Object handleRequest(Object input, Context context) {
        return null;
    }

    @Override
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
        Request req = new Gson().fromJson(IOUtils.toString(inputStream, "UTF-8"), Request.class);
        Response resp = new ResponseClass();
            resp.id = 1;
            resp.person.name = req.name;
            et_home_phone(req.name);
        outputStream.write(new Gson().toJson(resp).getBytes(Charset.forName("UTF-8")));
    }

    private void get_home_phone(String name) {
        // call external API -- stub example!  Assumes only one phone returned
        // in the format { "number" : "123-456-7890", "type" = "home" }
        // gson magic assures they get copied to the keys of the same name
        HttpGet httpGet = new HttpGet(phoneURL + "/" + name));
        HttpResponse httpResponse = client.execute(httpGet);
        resp.phone[0] = new Gson().fromJson(IOUtils.toString(httpResponse .getEntity().getContent(), "UTF-8"), Response.Phone.class);
    }
}

public class Response {
    public class Person {
        String name;
    }
    public class Phone {
        String number;
        String type;
    }
    public Integer id;
    public Person person = new Person();
    public Phone[] phone = new Phone[5];
}

【讨论】:

  • 我认为您应该接受自己的答案。这是允许的 AFAIK。
  • 你真的应该接受你自己的答案。这是一个很好的解决方案。补充一点——你不需要实现RequestHandler&lt;&gt; 这样你就可以完全去掉第一个handleRequest 方法
【解决方案2】:

您可以跳过JSONObject 并为嵌套类使用 POJO。但是,在这里根据约定命名很重要。确保您的访问器方法使用驼峰式命名(get + 属性名称大写)。试试这个:

public class ResponseClass {
    String document;
    Person person;

    public String getDocument() {
        return "1";
    }

    public Person getPerson() {
        return person;
    }
}

class Person {
    String name;
    public String getName() {
        return name;
    }
}

【讨论】:

  • 不幸的是,这并没有创建嵌套对象,只是一个顶级键;例如: { "document": "1", "person": "john doe" } 如果我将 Person 类更改为返回 JSON 对象(这是我想要的),我会得到相同的结果:一个空的 "person" 对象。 { "document": "1", "person": {} }
  • @Gregg:面临类似问题。在 POJO 中定义默认构造函数将解决这个问题。
【解决方案3】:

来自文档:https://docs.aws.amazon.com/lambda/latest/dg/java-handler.html

“如果它是包装原始值的类型,则运行时返回该值的文本表示形式。”


因此,具有单个字符串属性的简单 person 类将返回如下内容:

{ "document": "1", "person": "john doe" }

向 person 类添加另一个字段,它将按需要工作:

class Person {
    String firstName;
    String lastName;
    ...
}

输出:

{ "document": "1", "person": { "firstName": "John", "lastName": "Doe" }}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-18
    • 1970-01-01
    • 1970-01-01
    • 2011-01-26
    • 1970-01-01
    • 2017-08-07
    • 2017-09-23
    • 1970-01-01
    相关资源
    最近更新 更多