I use an AWS DynamoDB database to store data. I'm saving a "CommunityUser" object, which class looks as follows:
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 = ""
}
The class properties names do not match with AWS table fields names, so I was successfully using GSON SerializedName decorator to set the mapping like so:
class CommunityUser
{
@get:DynamoDBHashKey(attributeName = AWSTables.TableCommunityUser.user_id)
@SerializedName(value = "user_id")
var userId: String = ""
@get:DynamoDBAttribute(attributeName = AWSTables.TableCommunityUser.email)
@SerializedName(value = "email")
var email: String = ""
@get:DynamoDBAttribute(attributeName = AWSTables.TableCommunityUser.user)
@Json(name = "user")
var alias: String = ""
@get:DynamoDBAttribute(attributeName = AWSTables.TableCommunityUser.pass)
@SerializedName(value = "pass")
var password: String = ""
@get:DynamoDBAttribute(attributeName = AWSTables.TableCommunityUser.picture)
@SerializedName(value = "picture")
var picture: String = ""
}
But now I'm migrating from Gson to Moshi, and that's why in the first piece of code you see Json decorator instead of SerializedName, but the mapping is not working with moshi and on the contrary it's crashing.
This is where I try -for example- to update a user:
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
}
And mapper.save is crashing with the following exception:
Null or empty value for key: public final java.lang.String core.model.CommunityUser.getUserId()
Maybe I need to set up DynamoDB to work with Moshi? Not sure, but I need help to use Moshi with DynamoDB.
This is the class where I initialize AWS Mapper and connection:
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()
// initialize connection
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()
)
}
}
}
Gosh!! It was just a silly mistake!!
In "CommunityUser" class (the one in my case DynamoDB uses to map with database) I forgot the Moshi's @JsonClass(generateAdapter = true) decorator.
I'm using a custom Moshi adapter, which is faster than the built-in, so that decorator is needed in every class you will serialize/deserialize at any time.