3

I'm trying to map a json object from my dynamodb table using DynamoDbMapper and with the latest aws android sdk: com.amazonaws:aws-android-sdk-ddb-mapper:2.13.0, I'm seeing this exception: "DynamoDBMappingException: Expected S in value...

The json object in my table has 3 attributes, 2 of which are string and the third is a list of complex objects. I've created an object using the @DynamoDbDocument annotation for the complex object and used the proper marshaling annotation but it doesn't seem to be unmarshaling the json object into a java object correctly. The complex object is a json object in this format:

{
  "allCitiesList": [
    {
      "city": "Auckland, New Zealand",
      "times": {
        "recTimes": [
          "Jan1",
          "Jan2"
        ]
      }
    }
}
public class CitiesDO {
    private String city;
    private String country;
    private List<AllCitiesObject> allCitiesList;
...get/setters for other fields...

    @DynamoDBMarshalling(marshallerClass = 
    AllCitiesJSONMarshaller.class)
    public List<AllCitiesObject> getAllCitiesList() {
        return allCitiesList;
    }

    public void setAllCitiesList(List<AllCitiesObject> allCitiesList) {
        this.allCitiesList = allCitiesList;
    }
}
@DynamoDBDocument
public class AllCitiesObject {
    @DynamoDBAttribute(attributeName = "allCitiesList")
    private String data;

    public AllCitiesObject(){}

    public String getData() {
        return data.toString();
    }

    public void setData(String data) {
        this.data = data;
    }
}

class AllCitiesJSONMarshaller extends JsonMarshaller<AllCitiesObject> {}

Have also tried this approach with a custom marshaller but no success:

public class MyCustomMarshaller implements DynamoDBMarshaller<List<AllCitiesObject>> {

    private static final ObjectMapper mapper = new ObjectMapper();
    private static final ObjectWriter writer = mapper.writer();

    @Override
    public String marshall(List<AllCitiesObject> obj) {

        try {
            return writer.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(
                    "Unable to marshall the instance of " + obj.getClass()
                            + "into a string", e);
        }
    }

    @Override
    public List<AllCitiesObject> unmarshall(Class<List<AllCitiesObject>> clazz, String json) {
        final CollectionType
                type =
                mapper.getTypeFactory().constructCollectionType(List.class, AllCitiesObject.class);
        try {
            return mapper.readValue(json, type);
        } catch (Exception e) {
            throw new RuntimeException("Unable to unmarshall the string " + json
                    + "into " + clazz, e);
        }
    }

}

The exception is: DynamoDBMappingException: Expected S in value {L: [{M: {times={M: {recTimes={L: [{S: Jan1,}, {S: Jan2,}

I'm having difficulty unmarshalling the json to a string although I think I have it set up correctly. Can anyone please help me understand what I'm missing and how to approach this issue? I would really appreciate your help!

salmank
  • 31
  • 1
  • 4

2 Answers2

0

DynamoDBMarshalling is deprecated, so I suggest using the newer DynamoDBTypeConverted annotation.

There are some useful notes on Mapping Arbitrary Data.

You can also see an example of mine in this answer

In summary, you create an AllCities plain java object. You then write a simple converter class which tells DynamoDB how to turn your AllCities object into a string to get into DynamoDB. Similarly, the converter class tells your application how to turn the string back into a Java object.

F_SO_K
  • 13,640
  • 5
  • 54
  • 83
  • Hi Stu, I really appreciate your help and quick response. I'm using the latest aws android sdk: com.amazonaws:aws-android-sdk-ddb-mapper:2.13.0, which doesn't have the newer DynamoDBTypeConverted annotation so I believe I'm stuck using the marshalling annotation unless I'm missing something or if there's any other work around. Again, thank you for time and help! – salmank May 22 '19 at 21:02
0

If anyone else is absolutely stuck on this issue with the ddbMapper, consider using the ddbClient to explicitly convert and map your DO object with your ddb table data. Due to time constraints, I'll come back to this and figure out the mapping issue at a later time and post the answer here in case it helps anyone else.

salmank
  • 31
  • 1
  • 4