Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DataStore JSON exception on nullable arrays #3575

Closed
3 of 14 tasks
999Rub opened this issue Aug 17, 2023 · 6 comments
Closed
3 of 14 tasks

DataStore JSON exception on nullable arrays #3575

999Rub opened this issue Aug 17, 2023 · 6 comments
Assignees
Labels
bug Something is not working; the issue has reproducible steps and has been reproduced datastore Issues related to the DataStore Category pending-release Issues that have been addressed in main but have not been released

Comments

@999Rub
Copy link

999Rub commented Aug 17, 2023

Description

This bug report follows my two previous ones #2710 and #3472 .
The previous fixes fixed most of problems using custom type models within a classical model created using Amplify studio or via a custom data schema.

Nonetheless, a small bug is still alive when we use a custom type model as a nullable array.

See this field as exemple:
image

This field has the following properties:
image

The custom type model PreOxygenation is only composed of String fields (the issue does not comes from the custom type model itself).

When I try to save a model (and syncing it with the API) it occurs the following error:

E/amplify:aws-datastore(16302): Error ended observation of mutation outbox:
E/amplify:aws-datastore(16302): com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Not a JSON Array: null
E/amplify:aws-datastore(16302): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:397)
E/amplify:aws-datastore(16302): at com.google.gson.Gson.fromJson(Gson.java:1227)
E/amplify:aws-datastore(16302): at com.google.gson.Gson.fromJson(Gson.java:1137)
E/amplify:aws-datastore(16302): at com.google.gson.Gson.fromJson(Gson.java:1047)
E/amplify:aws-datastore(16302): at com.google.gson.Gson.fromJson(Gson.java:1014)
E/amplify:aws-datastore(16302): at com.amplifyframework.datastore.syncengine.GsonPendingMutationConverter.fromRecord(GsonPendingMutationConverter.java:72)
E/amplify:aws-datastore(16302): at com.amplifyframework.datastore.syncengine.PersistentMutationOutbox.lambda$load$15$com-amplifyframework-datastore-syncengine-PersistentMutationOutbox(PersistentMutationOutbox.java:261)
E/amplify:aws-datastore(16302): at com.amplifyframework.datastore.syncengine.PersistentMutationOutbox$$ExternalSyntheticLambda16.accept(Unknown Source:6)
E/amplify:aws-datastore(16302): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.lambda$query$4$com-amplifyframework-datastore-storage-sqlite-SQLiteStorageAdapter(SQLiteStorageAdapter.java:407)
E/amplify:aws-datastore(16302): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter$$ExternalSyntheticLambda0.run(Unknown Source:10)
E/amplify:aws-datastore(16302): at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:463)
E/amplify:aws-datastore(16302): at java.util.concurrent.FutureTask.run(FutureTask.java:264)
E/amplify:aws-datastore(16302): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
E/amplify:aws-datastore(16302): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
E/amplify:aws-datastore(16302): at java.lang.Thread.run(Thread.java:1012)
E/amplify:aws-datastore(16302): Caused by: java.lang.IllegalStateException: Not a JSON Array: null
E/amplify:aws-datastore(16302): at com.google.gson.JsonElement.getAsJsonArray(JsonElement.java:117)
E/amplify:aws-datastore(16302): at com.amplifyframework.datastore.appsync.SerializedModelAdapter.deserialize(SerializedModelAdapter.java:143)
E/amplify:aws-datastore(16302): at com.amplifyframework.datastore.appsync.SerializedModelAdapter.deserialize(SerializedModelAdapter.java:48)
E/amplify:aws-datastore(16302): at com.google.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:76)
E/amplify:aws-datastore(16302): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.readIntoField(ReflectiveTypeAdapterFactory.java:212)
E/amplify:aws-datastore(16302): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$FieldReflectionAdapter.readField(ReflectiveTypeAdapterFactory.java:433)
E/amplify:aws-datastore(16302): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:393)
E/amplify:aws-datastore(16302): ... 14 more

It seems this issue comes from the "allow null array" property, caused by the ser/deserialilzation engine wich does not handle null array with custom types.

I've tried the same operation but instead using null for my field

preOxygenation: null

I used an empty array

preOxygenation: []

This small update solved the issue without updating data schema.

This issue is easily counterable but it can waste precious time for future developers wich will face the same bug.

PS: I create this in amplify_flutter because the previous fix was here too and I don't know if the bug only occurs on Android.

Categories

  • Analytics
  • API (REST)
  • API (GraphQL)
  • Auth
  • Authenticator
  • DataStore
  • Notifications (Push)
  • Storage

Steps to Reproduce

  1. Create a classical model from Amplify studio
  2. Add a field wich use a custom type model
  3. Create the custom type model (you can use only one field)
  4. Set the field that use the custom type model as a nullable array (as in the exemple screenshot above)
  5. When you want to save your model in you flutter app, do not set the nullable array field (just instanciate the classical model)
  6. Then the issue occurs
  7. Then try the same operation but set an empty array [] for the nullable array field
  8. Then it will works.

Screenshots

No response

Platforms

  • iOS
  • Android
  • Web
  • macOS
  • Windows
  • Linux

Flutter Version

3.10.0

Amplify Flutter Version

1.3.2

Deployment Method

Amplify CLI

Schema

Classical model exemple:

type User @model @auth(rules: [{allow: owner}]) {
id: ID!
patientID: String!
name: String!
notes: [Note]
}

The notes field is a nullable array using a custom type Note that could be written like this in Dart: List<Note>?

This is a custom type exemple:

type Note{
content: String
date: String
}

For further details in Dart:

The shcemas exemple gives this:

User user = User(id: id, patientID: patientID, name: name, notes: null)

OR

User user = User(id: id, patientID: patientID, name: name) (without using notes fields because it is nullable)

Trying to save this will trigger the issue.

Now turn into this:

User user = User(id: id, patientID: patientID, name: name, notes: [] )

This will works fine.

@fjnoyp fjnoyp added datastore Issues related to the DataStore Category bug Something is not working; the issue has reproducible steps and has been reproduced labels Aug 17, 2023
@fjnoyp
Copy link
Contributor

fjnoyp commented Aug 17, 2023

Hi @999Rub thanks for sharing this issue and for providing a detailed explanation of what you did! To make sure we tested the same thing, can you please share you graphql schema here as well?

@fjnoyp fjnoyp added pending-triage This issue is in the backlog of issues to triage and removed bug Something is not working; the issue has reproducible steps and has been reproduced labels Aug 17, 2023
@fjnoyp fjnoyp self-assigned this Aug 17, 2023
@999Rub
Copy link
Author

999Rub commented Aug 17, 2023

Hi @fjnoyp , thanks for your reactivity. I've updated my original comment with further details about what it looks like in dart and add a small graphql shcema for a better undertsanding of this issue.

@cwomack cwomack added Investigating and removed pending-triage This issue is in the backlog of issues to triage labels Aug 17, 2023
@wojciechzahradnikdeviniti

I have the same problem.

E/amplify:flutter:datastore(15444): DataStoreException{message=Failed to start DataStore., cause=DataStoreException{message=Timed out while starting to observe storage changes., cause=com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Not a JSON Array: null, recoverySuggestion=There is a possibility that there is a bug if this error persists. Please take a look at 
E/amplify:flutter:datastore(15444): https://github.com/aws-amplify/amplify-android/issues to see if there are any existing issues that 
E/amplify:flutter:datastore(15444): match your scenario, and file an issue with the details of the bug if there isn't.}, recoverySuggestion=Retry.}
E/amplify:flutter:datastore(15444): 	at com.amplifyframework.datastore.AWSDataStorePlugin.lambda$start$12(AWSDataStorePlugin.java:331)
E/amplify:flutter:datastore(15444): 	at com.amplifyframework.datastore.AWSDataStorePlugin$$ExternalSyntheticLambda34.accept(Unknown Source:4)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.observers.CallbackCompletableObserver.onError(CallbackCompletableObserver.java:64)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.operators.completable.CompletableSubscribeOn$SubscribeOnObserver.onError(CompletableSubscribeOn.java:74)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.operators.completable.CompletableAndThenCompletable$NextObserver.onError(CompletableAndThenCompletable.java:104)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.operators.completable.CompletableAndThenCompletable$SourceObserver.onError(CompletableAndThenCompletable.java:62)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.operators.completable.CompletablePeek$CompletableObserverImplementation.onError(CompletablePeek.java:95)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.operators.completable.CompletableFromAction.subscribeActual(CompletableFromAction.java:40)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.core.Completable.subscribe(Completable.java:2850)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.operators.completable.CompletablePeek.subscribeActual(CompletablePeek.java:51)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.core.Completable.subscribe(Completable.java:2850)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.operators.completable.CompletableAndThenCompletable.subscribeActual(CompletableAndThenCompletable.java:35)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.core.Completable.subscribe(Completable.java:2850)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.operators.completable.CompletableAndThenCompletable$SourceObserver.onComplete(CompletableAndThenCompletable.java:67)
2
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.operators.completable.CompletablePeek$CompletableObserverImplementation.onComplete(CompletablePeek.java:115)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.operators.completable.CompletableSubscribeOn$SubscribeOnObserver.onComplete(CompletableSubscribeOn.java:79)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.operators.completable.CompletableTimeout$TimeOutObserver.onComplete(CompletableTimeout.java:87)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.operators.completable.CompletableFromAction.subscribeActual(CompletableFromAction.java:47)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.core.Completable.subscribe(Completable.java:2850)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.operators.completable.CompletableTimeout.subscribeActual(CompletableTimeout.java:53)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.core.Completable.subscribe(Completable.java:2850)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.operators.completable.CompletableSubscribeOn$SubscribeOnObserver.run(CompletableSubscribeOn.java:64)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.core.Scheduler$DisposeTask.run(Scheduler.java:614)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:65)
E/amplify:flutter:datastore(15444): 	at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:56)
E/amplify:flutter:datastore(15444): 	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
E/amplify:flutter:datastore(15444): 	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
E/amplify:flutter:datastore(15444): 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E/amplify:flutter:datastore(15444): 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/amplify:flutter:datastore(15444): 	at java.lang.Thread.run(Thread.java:920)
E/amplify:flutter:datastore(15444): Caused by: DataStoreException{message=Timed out while starting to observe storage changes., cause=com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Not a JSON Array: null, recoverySuggestion=There is a possibility that there is a bug if this error persists. Please take a look at 
E/amplify:flutter:datastore(15444): https://github.com/aws-amplify/amplify-android/issues to see if there are any existing issues that 

@fjnoyp
Copy link
Contributor

fjnoyp commented Aug 18, 2023

Hi @wojciechzahradnikdeviniti does setting an empty array when creating a model with a nullable custom model type array fix this error?

I want to make sure you have the same error as listed here.

We will investigate a fix for this JSON exception, but are aware that the interim solution is to just initialize with an empty array for now.

dnys1 pushed a commit to aws-amplify/amplify-android that referenced this issue Aug 18, 2023
Fixes aws-amplify/amplify-flutter#3575. When a custom type array is not required and `null` is returned from AppSync, deserialization will fail since `getAsJsonArray` will throw for `null` values.

This resolves the issue by checking if a field is `null` before attempting deserialization.
dnys1 pushed a commit to aws-amplify/amplify-android that referenced this issue Aug 18, 2023
Fixes aws-amplify/amplify-flutter#3575. When a custom type array is not required and `null` is returned from AppSync, deserialization will fail since `getAsJsonArray` will throw for `null` values.

This resolves the issue by checking if a field is `null` before attempting deserialization.
@fjnoyp fjnoyp added pending-release Issues that have been addressed in main but have not been released and removed Investigating labels Aug 21, 2023
@wojciechzahradnikdeviniti

Thanks - fixed in 1.4.0

@Jordan-Nelson
Copy link
Member

Closing as this was resolved in v1.4.0

@Jordan-Nelson Jordan-Nelson added bug Something is not working; the issue has reproducible steps and has been reproduced and removed Investigating labels Aug 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something is not working; the issue has reproducible steps and has been reproduced datastore Issues related to the DataStore Category pending-release Issues that have been addressed in main but have not been released
Projects
None yet
Development

No branches or pull requests

5 participants