You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 08:54:55