使用Java V2 Enhanced SDK查询DynamoDB时的数据校验问题
问题
使用Java V2 Enhanced SDK读取DynamoDB表时,代码可正常构建运行,但当部分属性返回错误类型时会触发异常。例如,应存储Long类型的属性返回空字符串("")或空值(<empty>),导致SDK抛出异常:
java.lang.NumberFormatException: For input string: "<empty>"
查询代码如下:
DynamoDbTable<MyRecord> myTable = enhancedClient.table(TABLE_NAME, MySchema); queryConditional = QueryConditional .keyEqualTo(Key.builder() .partitionValue(partKeyValue) .sortValue (sortKeyValue) .build()); List<T> results = myTable.query(r -> r.queryConditional(queryConditional)) .items() .stream() .collect(Collectors.toList());
Schema定义:
StaticTableSchema<MyRecord> MySchema = TableSchema.builder(MyRecord.class) .newItemSupplier(MyRecord::new) .addAttribute(Integer.class, a -> a.name("ID") .getter(MyRecord::getID) .setter(MyRecord::setID) .tags(primaryPartitionKey())) .addAttribute(String.class, a -> a.name("ClientID") .getter(MyRecord::getClientID) .setter(MyRecord::setClientID) .tags(primarySortKey())) ... .build();
需要解决这类类型不匹配导致的异常,推测可在TableSchema定义中添加数据校验逻辑,求具体实现方案。
解决方案
1. 自定义AttributeConverter处理类型转换异常
Enhanced SDK允许通过自定义AttributeConverter覆盖默认类型转换逻辑,在转换阶段捕获异常并处理非法值:
// 针对Long类型的安全转换器 public class SafeLongConverter implements AttributeConverter<Long> { @Override public AttributeValue transformFrom(Long input) { return input == null ? AttributeValue.builder().nul(true).build() : AttributeValue.builder().n(input.toString()).build(); } @Override public Long transformTo(AttributeValue input) { // 提前拦截空字符串、<empty>等非法值 String numStr = input.n(); if (numStr == null || numStr.isEmpty() || "<empty>".equals(numStr)) { return null; // 也可返回业务默认值如0,根据需求调整 } try { return Long.parseLong(numStr); } catch (NumberFormatException e) { // 记录异常日志,返回默认值或null return null; } } @Override public EnhancedType<Long> type() { return EnhancedType.of(Long.class); } @Override public AttributeValueType attributeValueType() { return AttributeValueType.N; } }
在Schema中绑定该转换器:
.addAttribute(Long.class, a -> a.name("TargetLongAttr") .getter(MyRecord::getTargetLongAttr) .setter(MyRecord::setTargetLongAttr) .converter(new SafeLongConverter())) // 为目标属性配置安全转换器
2. 全局注册转换器(批量处理同类型属性)
如果多个属性需要相同的安全转换逻辑,可实现AttributeConverterProvider全局注册转换器,避免逐个属性配置:
public class SafeConverterProvider implements AttributeConverterProvider { @Override public Optional<AttributeConverter<?>> converterFor(EnhancedType<?> type, Context context) { if (type.rawType().equals(Long.class)) { return Optional.of(new SafeLongConverter()); } // 可扩展添加Integer、Double等其他类型的安全转换器 return Optional.empty(); } }
创建Enhanced Client时注册该Provider:
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() .dynamoDbClient(dynamoDbClient) .attributeConverterProviders(new SafeConverterProvider()) .build();
3. 查询流中捕获异常(兜底方案)
如果不想修改转换器或Schema,可在查询结果流中捕获异常,过滤或标记无效记录:
List<T> results = myTable.query(r -> r.queryConditional(queryConditional)) .items() .stream() .filter(record -> { try { // 主动触发属性获取,暴露转换异常 record.getTargetLongAttr(); return true; } catch (RuntimeException e) { // 记录日志,跳过无效记录 log.warn("Invalid record with ID {}: {}", record.getID(), e.getMessage()); return false; } }) .collect(Collectors.toList());
内容的提问来源于stack exchange,提问作者Hephaestus
相关产品推荐
相关产品推荐

