2

I have nested Object (composition) use to represent data that i want to store and using Dyanmodb enhanced client as part of AWS Java version 2 api. In the readme it explains how to flatten the objects. In the version one of the api was able to store list of objects as json documents in dyanmodb.

public class Customer{
  private String name;
  private List<GenericRecord> recordMetadata;
  //getters and setters for all attributes
}


public class GenericRecord {
  private String id;
  private String details;
  //getters and setters for all attributes
} 

Would like it to be stored as below not flattened for backward compatibility:

{
  "name": "ABC",
 "recordMetadata": [
  {
    "id":"123",
    "details":"hello"

   },
  {
    "id":"456",
    "details":"yellow"

   }
 ]

}

https://github.com/aws/aws-sdk-java-v2/blob/master/services-custom/dynamodb-enhanced/README.md

tsingh
  • 361
  • 1
  • 5
  • 17

2 Answers2

2

If I understood, you want to serialize the nested object to a String, just like the @DynamoDBTypeConvertedJson annotation did with the DynamoDBMapper in v1 of the AWS SDK for Java. There is nothing that comes out of the box to do this in v2 of the AWS SDK for Java. You'll have to write your own converter by hand as shown below.

But there's really no benefit to serializing it as a String, so you may consider just storing it as a nested document. It shouldn't require any changes to the code you posted. Storing it as a document does have benefits like being able to update a single nested field. You never know when a requirement may come along that requires this, and again, I'm not aware of any downside to storing it as a document.

Note: I don't think @DynamoDbFlatten will work in your case because it doesn't make sense to flatten a list.

class GenericRecordListConverter implements AttributeConverter<List<GenericRecord>> {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    public static GenericRecordListConverter create() {
        return new GenericRecordListConverter();
    }

    @Override
    public AttributeValue transformFrom(List<GenericRecord> input) {
        try {
            return AttributeValue.builder().s(MAPPER.writeValueAsString(input)).build();
        }
        catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<GenericRecord> transformTo(AttributeValue input) {
        try {
            return MAPPER.readValue(input.s(), new TypeReference<List<GenericRecord>>() {});
        }
        catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public EnhancedType<List<GenericRecord>> type() {
        return EnhancedType.listOf(GenericRecord.class);
    }

    @Override
    public AttributeValueType attributeValueType() {
        return AttributeValueType.S;
    }

}
David Good
  • 486
  • 5
  • 8
2

This is resolved, don't need converter see:

.addAttribute(EnhancedType.listOf(EnhancedType.documentOf(GenericRecord.class,TableSchema.fromClass(GenericRecord.class))),
                    a -> a.name("recordMetadata").getter(Customer::getRecordMetadata)
                            .setter(Customer::setRecordMetadata)  )

Official response:

https://github.com/aws/aws-sdk-java-v2/issues/2265

tsingh
  • 361
  • 1
  • 5
  • 17