user4695271
user4695271

Reputation:

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 {
  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.

Upvotes: 4

Views: 8012

Answers (3)

proofofwork
proofofwork

Reputation: 1

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" }
}

Upvotes: 0

Sam
Sam

Reputation: 31

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; }
}

Upvotes: 0

notionquest
notionquest

Reputation: 39196

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;

}

Upvotes: 0

Related Questions