Skip to content

Commit 6a44db3

Browse files
committed
Improve exception handling for missing converters
1 parent dfca7ef commit 6a44db3

21 files changed

Lines changed: 17394 additions & 25 deletions
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "feature",
3+
"category": "Amazon DynamoDB Enhanced Client",
4+
"contributor": "",
5+
"description": "Improve missing converter error handling in DynamoDB Enhanced Client"
6+
}

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

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.ZoneIdAttributeConverter;
7373
import software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.ZoneOffsetAttributeConverter;
7474
import software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.ZonedDateTimeAsStringAttributeConverter;
75+
import software.amazon.awssdk.utils.CollectionUtils;
7576
import software.amazon.awssdk.utils.Logger;
7677
import software.amazon.awssdk.utils.Validate;
7778

@@ -157,17 +158,21 @@ private <T> Optional<AttributeConverter<T>> findConverterInternal(EnhancedType<T
157158
return Optional.of(converter);
158159
}
159160

160-
if (type.rawClass().isAssignableFrom(Map.class)) {
161-
converter = createMapConverter(type);
162-
} else if (type.rawClass().isAssignableFrom(Set.class)) {
163-
converter = createSetConverter(type);
164-
} else if (type.rawClass().isAssignableFrom(List.class)) {
165-
EnhancedType<T> innerType = (EnhancedType<T>) type.rawClassParameters().get(0);
166-
AttributeConverter<?> innerConverter = findConverter(innerType)
167-
.orElseThrow(() -> new IllegalStateException("Converter not found for " + type));
168-
return Optional.of((AttributeConverter<T>) ListAttributeConverter.create(innerConverter));
169-
} else if (type.rawClass().isEnum()) {
170-
return Optional.of(EnumAttributeConverter.create(((EnhancedType<? extends Enum>) type).rawClass()));
161+
if (!Object.class.equals(type.rawClass())) {
162+
if (type.rawClass().isAssignableFrom(Map.class)) {
163+
requireTypeParameters(type);
164+
converter = createMapConverter(type);
165+
} else if (type.rawClass().isAssignableFrom(Set.class)) {
166+
requireTypeParameters(type);
167+
converter = createSetConverter(type);
168+
} else if (type.rawClass().isAssignableFrom(List.class)) {
169+
requireTypeParameters(type);
170+
EnhancedType<T> innerType = (EnhancedType<T>) type.rawClassParameters().get(0);
171+
AttributeConverter<?> innerConverter = converterFor(innerType);
172+
return Optional.of((AttributeConverter<T>) ListAttributeConverter.create(innerConverter));
173+
} else if (type.rawClass().isEnum()) {
174+
return Optional.of(EnumAttributeConverter.create(((EnhancedType<? extends Enum>) type).rawClass()));
175+
}
171176
}
172177

173178
if (type.tableSchema().isPresent()) {
@@ -186,23 +191,27 @@ private boolean shouldCache(Class<?> type) {
186191
return !type.isAnonymousClass();
187192
}
188193

194+
private static void requireTypeParameters(EnhancedType<?> type) {
195+
if (CollectionUtils.isNullOrEmpty(type.rawClassParameters())) {
196+
throw new IllegalStateException("Converter not found for " + type + ". Type parameters are required for this type.");
197+
}
198+
}
199+
189200
@SuppressWarnings("unchecked")
190201
private <T> AttributeConverter<T> createMapConverter(EnhancedType<T> type) {
191202
EnhancedType<?> keyType = type.rawClassParameters().get(0);
192203
EnhancedType<T> valueType = (EnhancedType<T>) type.rawClassParameters().get(1);
193204

194205
StringConverter<?> keyConverter = StringConverterProvider.defaultProvider().converterFor(keyType);
195-
AttributeConverter<?> valueConverter = findConverter(valueType)
196-
.orElseThrow(() -> new IllegalStateException("Converter not found for " + type));
206+
AttributeConverter<?> valueConverter = converterFor(valueType);
197207

198208
return (AttributeConverter<T>) MapAttributeConverter.mapConverter(keyConverter, valueConverter);
199209
}
200210

201211
@SuppressWarnings("unchecked")
202212
private <T> AttributeConverter<T> createSetConverter(EnhancedType<T> type) {
203213
EnhancedType<T> innerType = (EnhancedType<T>) type.rawClassParameters().get(0);
204-
AttributeConverter<?> innerConverter = findConverter(innerType)
205-
.orElseThrow(() -> new IllegalStateException("Converter not found for " + type));
214+
AttributeConverter<?> innerConverter = converterFor(innerType);
206215

207216
return (AttributeConverter<T>) SetAttributeConverter.setConverter(innerConverter);
208217
}

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/document/DefaultEnhancedDocument.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import software.amazon.awssdk.protocols.jsoncore.JsonNode;
4646
import software.amazon.awssdk.protocols.jsoncore.JsonNodeParser;
4747
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
48+
import software.amazon.awssdk.utils.CollectionUtils;
4849
import software.amazon.awssdk.utils.Lazy;
4950
import software.amazon.awssdk.utils.StringUtils;
5051
import software.amazon.awssdk.utils.Validate;
@@ -89,15 +90,22 @@ public static Builder builder() {
8990
public static <T> AttributeConverter<T> converterForClass(EnhancedType<T> type,
9091
ChainConverterProvider chainConverterProvider) {
9192

92-
if (type.rawClass().isAssignableFrom(List.class)) {
93-
return (AttributeConverter<T>) ListAttributeConverter
94-
.create(converterForClass(type.rawClassParameters().get(0), chainConverterProvider));
95-
}
96-
if (type.rawClass().isAssignableFrom(Map.class)) {
97-
return (AttributeConverter<T>) MapAttributeConverter.mapConverter(
98-
StringConverterProvider.defaultProvider().converterFor(type.rawClassParameters().get(0)),
99-
converterForClass(type.rawClassParameters().get(1), chainConverterProvider));
93+
if (!Object.class.equals(type.rawClass())) {
94+
if (type.rawClass().isAssignableFrom(List.class)) {
95+
requireTypeParameters(type);
96+
return (AttributeConverter<T>) ListAttributeConverter
97+
.create(converterForClass(type.rawClassParameters().get(0), chainConverterProvider));
98+
}
99+
if (type.rawClass().isAssignableFrom(Map.class)) {
100+
requireTypeParameters(type);
101+
return (AttributeConverter<T>) MapAttributeConverter.mapConverter(
102+
StringConverterProvider.defaultProvider().converterFor(type.rawClassParameters().get(0)),
103+
converterForClass(type.rawClassParameters().get(1), chainConverterProvider));
104+
}
100105
}
106+
// TODO: what about the case when type.rawClass() is Object or Unsupported type
107+
// and we have overridden the default converter provider with a custom one that can / cannot handle this type?
108+
// We should check for that case here.
101109
return Optional.ofNullable(chainConverterProvider.converterFor(type))
102110
.orElseThrow(() -> new IllegalStateException(
103111
"AttributeConverter not found for class " + type
@@ -496,4 +504,10 @@ private static void checkAndValidateClass(Class<?> type, boolean isPut) {
496504
String.format(VALIDATE_TYPE_ERROR, "Map", isPut ? "put" : "get", "Map"));
497505

498506
}
507+
508+
private static void requireTypeParameters(EnhancedType<?> type) {
509+
if (CollectionUtils.isNullOrEmpty(type.rawClassParameters())) {
510+
throw new IllegalStateException("Converter not found for " + type + ". Type parameters are required for this type.");
511+
}
512+
}
499513
}

0 commit comments

Comments
 (0)