Skip to content

Commit 3239ac7

Browse files
martinKindallzoewangg
authored andcommitted
EnumAttributeConverter: enums can be identified by toString() or name(). toString() is the default for backward compatibility (#3971)
Co-authored-by: Zoe Wang <[email protected]>
1 parent d7655f6 commit 3239ac7

File tree

5 files changed

+257
-86
lines changed

5 files changed

+257
-86
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"category": "Amazon DynamoDB",
3+
"contributor": "martinKindall",
4+
"type": "bugfix",
5+
"description": "Created static method EnumAttributeConverter::createWithNameAsKeys which creates a converter based on the Enum::name method to identify enums, rather than Enum::toString. This is preferable because Enum::name is final and cannot be overwritten, as opposed to Enum::toString. EnumAttributeConverter::create is kept as it is, for backward compatibility."
6+
}

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/DefaultAttributeConverterProvider.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
import software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.DocumentAttributeConverter;
4444
import software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.DoubleAttributeConverter;
4545
import software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.DurationAttributeConverter;
46-
import software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.EnumAttributeConverter;
4746
import software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.FloatAttributeConverter;
4847
import software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.InstantAsStringAttributeConverter;
4948
import software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.IntegerAttributeConverter;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.enhanced.dynamodb;
17+
18+
import java.util.Arrays;
19+
import java.util.Collections;
20+
import java.util.LinkedHashMap;
21+
import java.util.Map;
22+
import java.util.function.Function;
23+
import software.amazon.awssdk.annotations.SdkPublicApi;
24+
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
25+
import software.amazon.awssdk.utils.Validate;
26+
27+
/**
28+
* A converter between an {@link Enum} and {@link AttributeValue}.
29+
*
30+
* <p>
31+
* This stores values in DynamoDB as a string.
32+
*
33+
* <p>
34+
* Use EnumAttributeConverter::create in order to use Enum::toString as the enum identifier
35+
*
36+
* <p>
37+
* Use EnumAttributeConverter::createWithNameAsKeys in order to use Enum::name as the enum identifier
38+
*
39+
* <p>
40+
* This can be created via {@link #create(Class)}.
41+
*/
42+
@SdkPublicApi
43+
public final class EnumAttributeConverter<T extends Enum<T>> implements AttributeConverter<T> {
44+
45+
private final Class<T> enumClass;
46+
private final Map<String, T> enumValueMap;
47+
48+
private final Function<T, String> keyExtractor;
49+
50+
private EnumAttributeConverter(Class<T> enumClass, Function<T, String> keyExtractor) {
51+
this.enumClass = enumClass;
52+
this.keyExtractor = keyExtractor;
53+
54+
Map<String, T> mutableEnumValueMap = new LinkedHashMap<>();
55+
Arrays.stream(enumClass.getEnumConstants())
56+
.forEach(enumConstant -> mutableEnumValueMap.put(keyExtractor.apply(enumConstant), enumConstant));
57+
58+
this.enumValueMap = Collections.unmodifiableMap(mutableEnumValueMap);
59+
}
60+
61+
/**
62+
* Creates an EnumAttributeConverter for an {@link Enum}.
63+
*
64+
* <p>
65+
* Uses Enum::toString as the enum identifier.
66+
*
67+
* @param enumClass The enum class to be used
68+
* @return an EnumAttributeConverter
69+
* @param <T> the enum subclass
70+
*/
71+
public static <T extends Enum<T>> EnumAttributeConverter<T> create(Class<T> enumClass) {
72+
return new EnumAttributeConverter<>(enumClass, Enum::toString);
73+
}
74+
75+
/**
76+
* Creates an EnumAttributeConverter for an {@link Enum}.
77+
*
78+
* <p>
79+
* Uses Enum::name as the enum identifier.
80+
*
81+
* @param enumClass The enum class to be used
82+
* @return an EnumAttributeConverter
83+
* @param <T> the enum subclass
84+
*/
85+
public static <T extends Enum<T>> EnumAttributeConverter<T> createWithNameAsKeys(Class<T> enumClass) {
86+
return new EnumAttributeConverter<>(enumClass, Enum::name);
87+
}
88+
89+
/**
90+
* Returns the proper {@link AttributeValue} for the given enum type.
91+
*
92+
* @param input the enum type to be converted
93+
* @return AttributeValue
94+
*/
95+
@Override
96+
public AttributeValue transformFrom(T input) {
97+
return AttributeValue.builder().s(keyExtractor.apply(input)).build();
98+
}
99+
100+
/**
101+
* Returns the proper enum type for the given {@link AttributeValue} input.
102+
*
103+
* @param input the AttributeValue to be converted
104+
* @return an enum type
105+
*/
106+
@Override
107+
public T transformTo(AttributeValue input) {
108+
Validate.isTrue(input.s() != null, "Cannot convert non-string value to enum.");
109+
T returnValue = enumValueMap.get(input.s());
110+
111+
if (returnValue == null) {
112+
throw new IllegalArgumentException(String.format("Unable to convert string value '%s' to enum type '%s'",
113+
input.s(), enumClass));
114+
}
115+
116+
return returnValue;
117+
}
118+
119+
/**
120+
* Returns the {@link EnhancedType} of the converter.
121+
*
122+
* @return EnhancedType
123+
*/
124+
@Override
125+
public EnhancedType<T> type() {
126+
return EnhancedType.of(enumClass);
127+
}
128+
129+
/**
130+
* Returns the {@link AttributeValueType} of the converter.
131+
*
132+
* @return AttributeValueType
133+
*/
134+
@Override
135+
public AttributeValueType attributeValueType() {
136+
return AttributeValueType.S;
137+
}
138+
}

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/EnumAttributeConverter.java

Lines changed: 0 additions & 85 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.enhanced.dynamodb.converters.attribute;
17+
18+
import org.junit.jupiter.api.Test;
19+
import software.amazon.awssdk.enhanced.dynamodb.EnumAttributeConverter;
20+
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
21+
22+
import static org.assertj.core.api.Assertions.assertThat;
23+
24+
public class EnumAttributeConverterTest {
25+
26+
@Test
27+
public void transformFromDefault_returnsToString() {
28+
EnumAttributeConverter<Vehicle> vehicleConverter = EnumAttributeConverter.create(Vehicle.class);
29+
AttributeValue attribute = vehicleConverter.transformFrom(Vehicle.TRUCK);
30+
31+
assertThat(attribute.s()).isEqualTo("TRUCK");
32+
}
33+
34+
@Test
35+
public void transformToDefault_returnsEnum() {
36+
EnumAttributeConverter<Vehicle> vehicleConverter = EnumAttributeConverter.create(Vehicle.class);
37+
38+
Vehicle bike = vehicleConverter.transformTo(AttributeValue.fromS("BIKE"));
39+
40+
assertThat(bike).isEqualTo(Vehicle.BIKE);
41+
}
42+
43+
@Test
44+
public void transformFromDefault_returnsToString_2() {
45+
EnumAttributeConverter<Animal> animalConverter = EnumAttributeConverter.create(Animal.class);
46+
AttributeValue attribute = animalConverter.transformFrom(Animal.CAT);
47+
48+
assertThat(attribute.s()).isEqualTo("I am a Cat!");
49+
}
50+
51+
@Test
52+
public void transformToDefault_returnsEnum_2() {
53+
EnumAttributeConverter<Animal> animalConverter = EnumAttributeConverter.create(Animal.class);
54+
55+
Animal dog = animalConverter.transformTo(AttributeValue.fromS("I am a Dog!"));
56+
57+
assertThat(dog).isEqualTo(Animal.DOG);
58+
}
59+
60+
@Test
61+
public void transformFromWithNames_returnsName() {
62+
EnumAttributeConverter<Person> personConverter = EnumAttributeConverter.createWithNameAsKeys(Person.class);
63+
AttributeValue attribute = personConverter.transformFrom(Person.JANE);
64+
65+
assertThat(attribute.s()).isEqualTo("JANE");
66+
67+
assertThat(Person.JANE.toString()).isEqualTo("I am a cool person");
68+
}
69+
70+
@Test
71+
public void transformToWithNames_returnsEnum() {
72+
EnumAttributeConverter<Person> personConverter = EnumAttributeConverter.createWithNameAsKeys(Person.class);
73+
74+
Person john = personConverter.transformTo(AttributeValue.fromS("JOHN"));
75+
76+
assertThat(Person.JOHN.toString()).isEqualTo("I am a cool person");
77+
78+
assertThat(john).isEqualTo(Person.JOHN);
79+
}
80+
81+
private static enum Vehicle {
82+
CAR,
83+
BIKE,
84+
TRUCK
85+
}
86+
87+
private static enum Animal {
88+
DOG,
89+
CAT;
90+
91+
@Override
92+
public String toString() {
93+
switch (this) {
94+
case DOG:
95+
return "I am a Dog!";
96+
case CAT:
97+
return "I am a Cat!";
98+
default:
99+
return null;
100+
}
101+
}
102+
}
103+
104+
private static enum Person {
105+
JOHN,
106+
JANE;
107+
108+
@Override
109+
public String toString() {
110+
return "I am a cool person";
111+
}
112+
}
113+
}

0 commit comments

Comments
 (0)