DynamoDB查询时DynamoDBMappingException异常求助
问题现象
查询DynamoDB数据时触发以下映射异常,实体类已配置注解、Getter/Setter及转换器逻辑,问题持续未解决:
com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: POSTable[ProductIdentificationDetails]; could not unconvert attribute
Caused by: com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: could not invoke null on class with value Optional[ProductIdentificationDetails(identificationNumbers=[serialNumber2, serialNumber1, serialNumber3], capturedTime=Fri Apr 12 10:23:38 UTC 2024, userId=32886492417)] of type class java.util.Optional at com.amazonaws.services.dynamodbv2.datamodeling.StandardBeanProperties$MethodReflect.set(StandardBeanProperties.java:136) ~[AWSPersistenceJavaClient-1.12.x.jar:?]
at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperFieldModel.set(DynamoDBMapperFieldModel.java:111) ~[AWSPersistenceJavaClient-1.12.x.jar:?]
at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperFieldModel.unconvertAndSet(DynamoDBMapperFieldModel.java:164) ~[AWSPersistenceJavaClient-1.12.x.jar:?]
at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperTableModel.unconvert(DynamoDBMapperTableModel.java:267) ~[AWSPersistenceJavaClient-1.12.x.jar:?]
... 97 more
Caused by: java.lang.NullPointerException at com.amazonaws.services.dynamodbv2.datamodeling.StandardBeanProperties$MethodReflect.set(StandardBeanProperties.java:133) ~[AWSPersistenceJavaClient-1.12.x.jar:?]
at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperFieldModel.set(DynamoDBMapperFieldModel.java:111) ~[AWSPersistenceJavaClient-1.12.x.jar:?]
at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperFieldModel.unconvertAndSet(DynamoDBMapperFieldModel.java:164) ~[AWSPersistenceJavaClient-1.12.x.jar:?]
at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperTableModel.unconvert(DynamoDBMapperTableModel.java:267) ~[AWSPersistenceJavaClient-1.12.x.jar:?]
... 97 more
相关代码
实体类Getter/Setter
public void setProductIdentificationDetails(final ProductIdentificationDetails productIdentificationDetails) { this.productIdentificationDetails = Optional.ofNullable(productIdentificationDetails); } @DynamoDBMarshalling(marshallerClass = ProductIdentificationDetailsConverter.class) @DynamoDBAttribute(attributeName = "ProductIdentificationDetails") public Optional<ProductIdentificationDetails> getProductIdentificationDetails() { log.info("debug : " + this.productIdentificationDetails); return this.productIdentificationDetails; }
表类注解
@Builder @NoArgsConstructor @AllArgsConstructor (access = AccessLevel.PRIVATE) @Log4j @DynamoDBTable
转换器逻辑
@Log4j public class ProductIdentificationDetailsConverter implements DynamoDBMarshaller<Optional<ProductIdentificationDetails>> { @Override public String marshall(final Optional<ProductIdentificationDetails> object) { return object.isPresent() ? IonUtility.toString(object.get()) : null; } @Override public Optional<ProductIdentificationDetails> unmarshall(final Class<Optional<ProductIdentificationDetails>> clazz, final String serializedObject) { try { return (StringUtils.isNotEmpty(serializedObject) ? Optional.of(IonUtility.toObject(serializedObject, ProductIdentificationDetails.class)) : Optional.empty()); } catch (final IllegalArgumentException e) { throw new IllegalArgumentException("ProductIdentificationDetails De-serialization Failed", e); } } }
问题根源
DynamoDBMapper反序列化时,会根据Getter方法的返回类型(Optional<ProductIdentificationDetails>)寻找对应Setter方法,期望Setter参数类型与Getter返回类型一致。但当前Setter参数是ProductIdentificationDetails而非Optional<ProductIdentificationDetails>,导致Mapper无法找到匹配的Setter方法,反射调用时抛出空指针异常。
解决方案
修改Setter方法的参数类型为Optional<ProductIdentificationDetails>,确保与Getter返回类型一致:
public void setProductIdentificationDetails(final Optional<ProductIdentificationDetails> productIdentificationDetails) { this.productIdentificationDetails = productIdentificationDetails; }
如果需要保留原有业务逻辑(处理非Optional参数),可以重载Setter方法,同时保留符合Mapper要求的版本:
// 供DynamoDBMapper调用的Setter public void setProductIdentificationDetails(final Optional<ProductIdentificationDetails> productIdentificationDetails) { this.productIdentificationDetails = productIdentificationDetails; } // 业务代码使用的Setter public void setProductIdentificationDetails(final ProductIdentificationDetails productIdentificationDetails) { this.productIdentificationDetails = Optional.ofNullable(productIdentificationDetails); }
另外,检查Lombok的@Builder或@AllArgsConstructor配置,确保构造方法参数类型与实体类字段类型一致,避免Mapper实例化对象时出现类型不匹配问题。
内容的提问来源于stack exchange,提问作者Kancharla Aishwarya

