0

I try to call my AWS Lambda function (serverless backend) with my Android mobile app client. The AWS lambda function returns an ArrayList of POJO objects (as JSON).

The problem is that the android client AWS Lambda(JSON)DataBinder does not deserialize to my ArrayList of POJOs. I get an ArrayList of LinkedTreeMap (see code at onPostExecute() below).

At the android client side I'm using Android AWS SDK: com.amazonaws:aws-android-sdk-core:2.6

Here is some code:

public void readSurveyList(String strUuid, int intLanguageID) {

    // Create an instance of CognitoCachingCredentialsProvider
    // You have to configure at least an AWS identity pool to get access to your lambda function
    CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
            this.getApplicationContext(),
            IDENTITY_POOL_ID,
            Regions.EU_CENTRAL_1);

    LambdaInvokerFactory factory = LambdaInvokerFactory.builder()
            .context(this.getApplicationContext())
            .region(Regions.EU_CENTRAL_1)
            .credentialsProvider(credentialsProvider)
            .build();

    // Create the Lambda proxy object with default Json data binder.
    myInterface = factory.build(MyInterface.class);

    //create a request object (depends on your lambda function)
    SurveyListRequest surveyListRequest = new SurveyListRequest(strUuid, intLanguageID);

    // Lambda function in async task with definiton of
    //      request object (-> SurveyListRequest)
    //      response object (-> ArrayList<SurveyListItem>>)
    new AsyncTask<SurveyListRequest, Void, ArrayList<SurveyListItem>>() {
        @Override
        protected ArrayList<SurveyListItem> doInBackground(SurveyListRequest... params) {

            try {
                return myInterface.ReadSurveyList(params[0]);
            } catch (LambdaFunctionException lfe) {
                Log.e("TAG", String.format("echo method failed: error [%s], details [%s].", lfe.getMessage(), lfe.getDetails()));
                return null;
            }
        }

        @Override
        protected void onPostExecute(ArrayList<SurveyListItem> surveyList) {

            // PROBLEM: here i get a ArrayList of LinkedTreeMap

        }
    }.execute(surveyListRequest);
}

Here is the code of my lambda function Interface:

public interface MyInterface {

    @LambdaFunction
    ArrayList<SurveyListItem> ReadSurveyList (SurveyListRequest surveyListRequest);
}

I would expect to get a list of my POJO objects. I found a lot of discussions about Gson and ArrayList type and solutions based on TypeToken (e.g. Gson TypeToken with dynamic ArrayList item type). Maybe same problem ...

Jörg
  • 59
  • 2

1 Answers1

0

I found a solution using a custom LambdaDataBinder. I have specified the type of my POJO-class "SurveyListItem" in deserialize function. The Gson uses the TypeToken definition and converts the JSON string correct to the list of POJOs (in my case "SurveyListItem" objects).

Here is the sourcecode of MyLambdaDataBinder:

public class MyLambdaDataBinder implements LambdaDataBinder {

    private final Gson gson;
    Type mType;

    //CUSTOMIZATION: pass typetoken via class constructor
    public MyLambdaDataBinder(Type type) {
        this.gson = new Gson();
        mType = type;
    }

    @Override
    public <T> T deserialize(byte[] content, Class<T> clazz) {
        if (content == null) {
            return null;
        }
        Reader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(content)));

        //CUSTOMIZATION: Original line of code: return gson.fromJson (reader, clazz);
        return gson.fromJson(reader, mType);
    }

    @Override
    public byte[] serialize(Object object) {
        return gson.toJson(object).getBytes(StringUtils.UTF8);
    }
}

Here is how to use the custom MyLambdaDataBinder. Use your POJO instead of "SurveyListItem":

myInterface = factory.build(LambdaInterface.class, new MyLambdaDataBinder(new TypeToken<ArrayList<SurveyListItem>>() {}.getType()));
Jörg
  • 59
  • 2