amplify-android: [Flutter Support] Saving a list of strings is failing in DataStore

While saving a model which has a list of strings as a field such as stringList: [String], the modelSchema generated by flutter is as follows for that field

ModelField{name='stringList', javaClassForValue='class java.lang.String', targetType='String', isRequired=true, isArray=true, isEnum=false, isModel=false}

However when storing a value of [“VALUE_ONE”, “VALUE_TWO”], an exception is thrown from here since the value is of type Array. The exception stack trace is below

DataStoreException{message=, cause=null, recoverySuggestion=}
    at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.bindValueToStatement(SQLiteStorageAdapter.java:699)
    at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.bindStatementToValues(SQLiteStorageAdapter.java:670)
    at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.saveModel(SQLiteStorageAdapter.java:724)
    at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.lambda$save$3$SQLiteStorageAdapter(SQLiteStorageAdapter.java:303)
    at com.amplifyframework.datastore.storage.sqlite.-$$Lambda$SQLiteStorageAdapter$JhGtXoPGeJ7lbNvRHxROfLs-WmE.run(Unknown Source:12)

Originated from: https://github.com/aws-amplify/amplify-flutter/issues/241

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 22 (22 by maintainers)

Most upvoted comments

Alright. So I updated the generated Flutter models that have enum list fields to the modelSchemaDefinition above. I also had to fix some of the model serialization code for enum lists. This does appear to let me save the model to DataStore and it does appear to sync with the backend.

I am seeing some other odd behavior around the model _version numbers sent to AppSync. In one case I was seeing _version=1 on every update to the model. I think this is messing with a proper delta sync because my enum list just keeps getting bigger on every update.

In another case I was seeing _version=14 sent to AppSync the second time I saved a model. AppSync would reject this mutation since DynamoDB was still at _version=1.

Either of these could be something I’m doing wrong on the client. I’ll dig in more tomorrow.

Is this only for list of string or is there some combination I could try for list of enum?

ModelSchema generated for enums in flutter is actually very similar to the one with String. You can test with the following

modelSchemaDefinition.addField(ModelFieldDefinition.field(
    key: TestEnumModel.ENUMLIST,
    isArray: true,
    isRequired: true,
    ofType: ModelFieldType(ModelFieldTypeEnum.collection,
        ofModelName: describeEnum(ModelFieldTypeEnum.enumeration))));

Can someone try this to make sure?

I’ll try this in a couple of hour and report back.

I changed the generated code for the field to:

    modelSchemaDefinition.addField(ModelFieldDefinition.field(
        key: Todo.LIST_OF_STRINGS,
        isRequired: false,
        isArray: true,
        ofType: ModelFieldType(ModelFieldTypeEnum.collection, ofModelName: 'String')));

And that seems to work. Arrived at that conclusion after looking at this code.

Can someone try this to make sure?

So the isArray thing alone is not the issue here. It appears to be related to the type stored in the javaClassForValue property of the ModelField. It affects the execution path of this method.

When called from a flutter app, the javaClassForValue has the value String, which causes the converter to return whatever value is stored in the field (i.e. it assumes it’s a string).

When called from the unit test I’m using, it has the value List<String>. That throws an exception because you can’t create an instance of List<String>. Inside the catch block it gets treated as a custom type, which eventually becomes JSON-ified strings when saved to SQLite, which is why it works.

Looks like the Dart model that gets generated is not adding setting the isArray property to true.

    modelSchemaDefinition.addField(ModelFieldDefinition.field(
        key: Todo.LIST_OF_STRINGS,
        isRequired: false, 
        isArray: true, // This was not in the generated code
        ofType: ModelFieldType(ModelFieldTypeEnum.string)));