Android AWS DynamoDB使用Moshi时mapper.save报错求助
Moshi与AWS DynamoDB配合时字段映射失效的解决方案
问题背景
使用AWS DynamoDB存储CommunityUser对象,此前用Gson的@SerializedName实现类属性与JSON字段的映射,切换到Moshi的@Json注解后,调用DynamoDBMapper.save时崩溃,报错信息:
Null or empty value for key: public final java.lang.String core.model.CommunityUser.getUserId()
涉及代码
CommunityUser类(Moshi注解版本)
class CommunityUser { @get:DynamoDBHashKey(attributeName = AWSTables.TableCommunityUser.user_id) @Json(name = "user_id") var userId: String = "" @get:DynamoDBAttribute(attributeName = AWSTables.TableCommunityUser.email) @Json(name = "email") var email: String = "" @get:DynamoDBAttribute(attributeName = AWSTables.TableCommunityUser.user) @Json(name = "user") var alias: String = "" @get:DynamoDBAttribute(attributeName = AWSTables.TableCommunityUser.pass) @Json(name = "pass") var password: String = "" @get:DynamoDBAttribute(attributeName = AWSTables.TableCommunityUser.picture) @Json(name = "picture") var picture: String = "" }
更新用户的核心代码
override fun updateUser(jsonUser: String): CommunityUserDTO? { val user: CommunityUser? var userDTO: CommunityUserDTO? = null val dynamoDBMapperConfig = AWSConnection.mapperConfig4Update try { user = AWSHelper.deserializeUser(jsonUser) AWSTestRepository.awsConnection.mapper.save(user, dynamoDBMapperConfig) userDTO = jsonUser.deserialize<CommunityUserDTO>() } catch (e: Exception) { e.logException() } return userDTO }
AWS连接与Mapper初始化代码
class AWSConnection { lateinit var mapper: DynamoDBMapper private set lateinit var ddbClient: AmazonDynamoDBClient private set companion object { private lateinit var poolId: String private val databaseRegion = Regions.xxx @JvmStatic val mapperConfig4Update: DynamoDBMapperConfig get() = DynamoDBMapperConfig.Builder() .withConsistentReads(DynamoDBMapperConfig.ConsistentReads.CONSISTENT) .withSaveBehavior(DynamoDBMapperConfig.SaveBehavior.UPDATE) .build() private fun initializeAWSIdentityPoolDynamoDBMapper(context: Context): DynamoDBMapper { val credentialsProvider = CognitoCachingCredentialsProvider( context, poolId, databaseRegion ) val ddbClient = com.amazonaws.regions.Region.getRegion(databaseRegion) .createClient( AmazonDynamoDBClient::class.java, credentialsProvider, ClientConfiguration() ) return DynamoDBMapper.builder().dynamoDBClient(ddbClient).build() } private fun initializeAWSIdentityPoolAmazonDynamoDBClient(context: Context): AmazonDynamoDBClient { val credentialsProvider = CognitoCachingCredentialsProvider( context, poolId, databaseRegion ) return com.amazonaws.regions.Region.getRegion(databaseRegion) .createClient( AmazonDynamoDBClient::class.java, credentialsProvider, ClientConfiguration() ) } } }
解决方案
1. 明确注解职责,分离映射逻辑
DynamoDB的注解(@DynamoDBHashKey、@DynamoDBAttribute)仅负责对象与DynamoDB表字段的映射,Moshi的@Json注解仅负责JSON与对象的序列化/反序列化,两者互不干扰,无需修改DynamoDB的配置适配Moshi。
2. 确保Moshi实例正确配置
Kotlin项目必须添加moshi-kotlin依赖,并在创建Moshi实例时加入KotlinJsonAdapterFactory,否则Kotlin类的注解可能无法生效:
// 正确初始化Moshi实例 val moshi = Moshi.Builder() .add(KotlinJsonAdapterFactory()) .build() // 修正deserializeUser方法 fun deserializeUser(json: String): CommunityUser? { val adapter = moshi.adapter(CommunityUser::class.java) return adapter.fromJson(json) }
3. 验证反序列化结果
在调用dynamoDBMapper.save前,检查user对象的userId值是否为空:
user = AWSHelper.deserializeUser(jsonUser) // 调试或打印验证userId if (user?.userId.isNullOrEmpty()) { throw IllegalArgumentException("JSON中缺少user_id字段或值为空") } AWSTestRepository.awsConnection.mapper.save(user, dynamoDBMapperConfig)
4. 检查JSON输入合法性
确认传入的jsonUser字符串中包含非空的user_id字段,例如:
{ "user_id": "12345", "email": "user@example.com", "user": "test_alias", "pass": "password123", "picture": "avatar_url" }
内容的提问来源于stack exchange,提问作者Diego Perez
相关产品推荐
相关产品推荐

