Store Java Enum's String Value Instead of Enum Value Itself in Dynamodb
I'm Using Dynamodb and I Would Like to Store the Enum's String Values Instead of the Enum Itself. for Instance, I Have This Enum: Public Enum Source {...
I'm using DynamoDB and I would like to store the enum's String values instead of the enum itself.
For instance, I have this enum:
public enum Source {
BREACH("breach"),
LEAKAGE("leakage");
private final String desc;
Source(String desc) { this.desc = desc; }
public String desc() { return desc; }
}
...and this "entity":
@DynamoDBTable(tableName = "Alerts")
public final class Alert implements Serializable {
private static final long serialVersionUID = 4012517315640518044L;
@DynamoDBHashKey(attributeName = "AlertId") // Partition Key or Hash Attribute
private String alertId;
@DynamoDBTypeConvertedEnum
@DynamoDBAttribute(attributeName = "Source")
private Source type;
// Constructor(s), Getter(s), Setter(s), ToString, etc...
}
With the @DynamoDBTypeConvertedEnum annotation, the value that gets saved is BREACH, but I want breach.
{
"AlertId": { "S": "a083168d-cb23-4ec8-ab80-a1c16955c4b8" },
"Source": { "S": "BREACH" },
...
"CreatedAt": { "S": "2017-05-03T14:07:36.395Z" }
}
Any clues? I did try "converters" (not fully, I couldn't make it work though) but I think I have to end up doing one for each enum type since they are all different.
3 Answers
You can code the Alert class like this i.e. define the attribute as String and design the getter and setter to send/receive enum object (i.e. Source).
Alert class:-
@DynamoDBTable(tableName = "Alerts")
public final class Alert implements Serializable {
private static final long serialVersionUID = 4012517315640518044L;
private String alertId;
private String type;
@DynamoDBHashKey(attributeName = "AlertId")
public String getAlertId() {
return alertId;
}
@DynamoDBAttribute(attributeName = "Source")
public Source getType() {
if (type != null)
return Source.valueOf(type);
else
return null;
}
public void setAlertId(String alertId) {
this.alertId = alertId;
}
public void setType(Source type) {
this.type = type.desc();
}
}
Create Alert:-
Stores the value as expected on database table. The get item from DynamoDB table also works fine.
public Boolean createAlert(String alertId, Source source) {
DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(dynamoDBClient);
Alert alert = new Alert();
alert.setAlertId(alertId);
alert.setType(source);
dynamoDBMapper.save(alert);
return true;
}
Override toString() this should work.
public enum Source {
BREACH("breach"),
LEAKAGE("leakage");
private final String desc;
Source(String desc) { this.desc = desc; }
public String desc() { return desc; }
@Override
public String toString() { return desc; }
}
I solved it by defining a custom attribute converter. It works but I'm afraid you'd have to write converters for each enum.
There is already method for serializing desc().We can define a static method for deserializing toSource()
Source.java
public enum Source {
BREACH("breach"),
LEAKAGE("leakage");
private final String desc;
Source(String desc) {
this.desc = desc;
}
public String desc() {
return desc;
}
public static Source toSource(String value) {
return Arrays.stream(Source.values()).filter(et -> et.desc().equals(value)).findFirst().orElse(null);
}
}
We can then define a custom DynamoDBType converter:
SourceEnumDynamoDbConverter.java
public class SourceEnumDynamoDbConverter implements DynamoDBTypeConverter<String, Source> {
@Override
public String convert(Source source) {
return source.desc();
}
@Override
public Source unconvert(String sourceStr) {
return Source.toSource(sourceStr);
}
}
And finally annotate our Entity's Source property with this custom converter
Alert.java
@DynamoDBTable(tableName = "Alerts")
public final class Alert implements Serializable {
private static final long serialVersionUID = 4012517315640518044L;
@DynamoDBHashKey(attributeName = "AlertId") // Partition Key or Hash Attribute
private String alertId;
private Source type;
@DynamoDBTypeConverted(converter = TrialEnumDynamoDbConverter.class)
@DynamoDBAttribute(attributeName = "Source")
public Source getSource() {
return type;
}
public void setSource(Source type) {
this.type = type;
}
// Constructor(s), Getter(s), Setter(s), ToString, etc...
}
This way desc is stored and read from dynamodb resulting in
{
"AlertId": { "S": "a083168d-cb23-4ec8-ab80-a1c16955c4b8" },
"Source": { "S": "breach" },
...
"CreatedAt": { "S": "2017-05-03T14:07:36.395Z" }
}