0

I have an item I'd like to store in Dynamo:

public class Statement {
@DynamoDBTypeConverted(converter = ListLineItemConverter.class)
private List<LineItem> items;
}

and the definition of LineItem is the following:

public class LineItem {
private ZonedDateTime dateStart;
private ZonedDateTime dateEnd;
private long balance;

@DynamoDBTypeConverted(converter = ZonedDateTimeConverter.class)
public getDateStart() {...}

@DynamoDBTypeConverted(converter = ZonedDateTimeConverter.class)
public getDateEnd() {...} 
}

I've been using a known working converter for ZonedDateTime which is the following:

public class ZonedDateTimeConverter implements DynamoDBTypeConverter<String, ZonedDateTime> {
    public ZonedDateTimeConverter(){}

    @Override
    public String convert(final ZonedDateTime time) {
        return time.toString();
    }

    @Override
    public ZonedDateTime unconvert(final String stringValue) {
        return ZonedDateTime.parse(stringValue);
    }
}

And the converter works perfectly when it's annotated on a base class. But I have a custom type nested in a list of items and I can't seem to figure out how to get DynamoDB to correctly convert / unconvert a nested ZonedDateTime.

I even wrote a custom converter for List of LineItem without luck:

public class ListLineItemConverter implements DynamoDBTypeConverter<String, List<LineItem>> {

    private ObjectMapper objectMapper;

    public ListLineItemConverter() {
        objectMapper = new ObjectMapper();
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // THIS LINE OF CODE FIXED THE ISSUE FOR ME
        objectMapper.findAndRegisterModules();
        // THIS LINE OF CODE FIXED THE ISSUE FOR ME
    }

    @Override
    public String convert(List<LineItem> object) {
        try {
            String result = objectMapper.writeValueAsString(object);
            return objectMapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("bad json marshalling");
        }
    }

    @Override
    public List<LineItem> unconvert(String object) {
        try {
            return objectMapper.readValue(object, new TypeReference<List<LineItem>>() {});
        } catch (IOException e) {
            throw new RuntimeException("bad json unmarshalling");
        }
    }
}

There's no combination of annotations that I can seem to use to get this to work. I always get:

com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.time.ZonedDateTime: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)

EDIT: If I comment out the instances of ZonedDateTime from LineItem then the code works totally fine. So DynamoDB is having trouble reading the @DynamoDBTypeConverted annotation when it's buried 3 levels deep:

Statement.items.get[0].dateStart // annotations aren't working at this level

Statement.items.get[0].dateEnd // annotations aren't working at this level

fIwJlxSzApHEZIl
  • 11,861
  • 6
  • 62
  • 71

1 Answers1

1

Looks like there was an issue when using the Jackson parser on nested instances of ZonedDateTime and it not automatically picking it up.

I've switched to the newer version of Jackson and even included the JSR310 module to ensure that compatibility with marshaling / unmarshaling the newer java 8 time constructs was supported but alas.

Weirdly one line of code fixed it for me:

objectMapper.findAndRegisterModules();

taken from: https://stackoverflow.com/a/37499348/584947

Community
  • 1
  • 1
fIwJlxSzApHEZIl
  • 11,861
  • 6
  • 62
  • 71