awslabs / aws-mobile-appsync-sdk-android

Android SDK for AWS AppSync.
https://docs.amplify.aws/sdk/api/graphql/q/platform/android/
Apache License 2.0
105 stars 58 forks source link

NullPointerException: Attempt to invoke virtual method 'org.json.JSONObject com.amazonaws.mobile.config.AWSConfiguration.optJsonObject(java.lang.String)' on a null object reference #382

Closed abbas-eno8 closed 2 years ago

abbas-eno8 commented 2 years ago

NullPointerException: 'Attempt to invoke virtual method org.json.JSONObject com.amazonaws.mobile.config.AWSConfiguration.optJsonObject(java.lang.String) on a null object reference'

I’m trying to migrate aws-mobile-appsync-sdk-android from 2.9.+ to 3.3.0 as per recommended by AWS for this AWS AppSync APIs v1 protocol (MQTT over WebSockets) will be disabled for all AppSync APIs in favor of v2 protocol (pure WebSockets) mentioned in below to query and receive mutations in real time. https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html

To Reproduce Steps to reproduce the behavior:

  1. For initializing
    if (mClient == null) {
    val regions = Regions.fromName(BuildConfig.AWS_REGION)
    val cognitoUserPool = CognitoUserPool(mContext.applicationContext, mAwsConfig.appSyncConfig?.poolId, mAwsConfig.appSyncConfig?.clientId, null, Regions.fromName(BuildConfig.AWS_REGION))
    val basicCognitoUserPoolsAuthProvider = BasicCognitoUserPoolsAuthProvider(cognitoUserPool)
    mClient = AWSAppSyncClient.builder()
            .context(mContext.applicationContext)
            .region(Regions.fromName(mAwsConfig.appSyncConfig?.region))
            .serverUrl(mAwsConfig.appSyncConfig?.apiUrl)
            .cognitoUserPoolsAuthProvider(basicCognitoUserPoolsAuthProvider)
            .s3ObjectManager(S3ObjectManagerImplementation(AmazonS3Client(AWSMobileClient.getInstance(), Region.getRegion(regions))))
            .build()
    }
  2. Using below snippet to create a subscription
    val subscription = AddedSkusBatchSubscription.builder().countkey(mPref.getCountKey()).domain(mPref.getCompanyName()).build()
    mAppSync?.mClient?.let {
    mSKUsWatcher = it.subscribe(subscription)
    }
  3. When pointer comes below line of code
    mSKUsWatcher?.execute(callback as AppSyncSubscriptionCall.Callback<AddedSkusBatchSubscription.Data>)
  4. It gives NullPointerException in SDK which will be found in below stack log
    2022-02-17 16:24:09.574 3286-3286/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: io.omnicounts.android, PID: 3286
    java.lang.NullPointerException: Attempt to invoke virtual method 'org.json.JSONObject com.amazonaws.mobile.config.AWSConfiguration.optJsonObject(java.lang.String)' on a null object reference
        at com.amazonaws.mobileconnectors.appsync.SubscriptionAuthorizer.getAuthorizationDetails(SubscriptionAuthorizer.java:76)
        at com.amazonaws.mobileconnectors.appsync.SubscriptionAuthorizer.getConnectionAuthorizationDetails(SubscriptionAuthorizer.java:65)
        at com.amazonaws.mobileconnectors.appsync.WebSocketConnectionManager.getConnectionRequestUrl(WebSocketConnectionManager.java:387)
        at com.amazonaws.mobileconnectors.appsync.WebSocketConnectionManager.createWebSocket(WebSocketConnectionManager.java:131)
        at com.amazonaws.mobileconnectors.appsync.WebSocketConnectionManager.requestSubscription(WebSocketConnectionManager.java:90)
        at com.amazonaws.mobileconnectors.appsync.AppSyncWebSocketSubscriptionCall.execute(AppSyncWebSocketSubscriptionCall.java:48)
        at io.omnicounts.android.services.remote.AWSSubscriptionHelper.startSubscription(AWSSubscriptionHelper.kt:35)
        at io.omnicounts.android.modules.welcome.interactor.SCGatheringInfoInteractor.startSubscription(SCGatheringInfoInteractor.kt:615)
        at io.omnicounts.android.modules.welcome.presenter.SCGatheringInfoPresenter.getSkus(SCGatheringInfoPresenter.kt:43)
        at io.omnicounts.android.modules.welcome.view.SCGatheringInfoActivity.getSkus(SCGatheringInfoActivity.kt:114)
        at io.omnicounts.android.modules.welcome.view.SCGatheringInfoActivity.updateProgress(SCGatheringInfoActivity.kt:160)
        at io.omnicounts.android.modules.welcome.presenter.SCGatheringInfoPresenter.onSkuSyncEnabledResponse$lambda-4(SCGatheringInfoPresenter.kt:102)
        at io.omnicounts.android.modules.welcome.presenter.SCGatheringInfoPresenter.$r8$lambda$BCZCrkBamx51omhJsl2asz4SrYM(Unknown Source:0)
        at io.omnicounts.android.modules.welcome.presenter.SCGatheringInfoPresenter$$ExternalSyntheticLambda1.run(Unknown Source:2)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:236)
        at android.app.ActivityThread.main(ActivityThread.java:8059)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)
    2022-02-17 16:24:09.583 3286-3286/? D/OOMEventManagerFK: checkEventAndDumpForJE: 0
    2022-02-17 16:24:10.212 3286-3286/? I/Process: Sending signal. PID: 3286 SIG: 9

Expected behaviour It should subscribe the subscription and execute the callback

Environment:

Device Information

Thanks for your support

div5yesh commented 2 years ago

It looks like the config you are using does not contain AuthMode key. Can you share your configuration with sensitive info removed?

iamfirdous8 commented 2 years ago

@div5yesh We(@abbas-eno8 and I) fixed this issue, by adding aws configuration via code, like below

val awsConfig = AWSConfiguration(getJSONObject())

val regions = Regions.fromName(BuildConfig.AWS_REGION)
val cognitoUserPool = CognitoUserPool(mContext.applicationContext, awsConfig)
val basicCognitoUserPoolsAuthProvider = BasicCognitoUserPoolsAuthProvider(cognitoUserPool)
mClient = AWSAppSyncClient.builder()
        .context(mContext.applicationContext)
        .awsConfiguration(awsConfig)
        .cognitoUserPoolsAuthProvider(basicCognitoUserPoolsAuthProvider)
        .s3ObjectManager(S3ObjectManagerImplementation(AmazonS3Client(AWSMobileClient.getInstance(), Region.getRegion(regions))))
        .build()

And here's how we get the JSONObject

private fun getJSONObject(): JSONObject {
    val jsonObject = JSONObject()

    // CognitoUserPool
    val default = JSONObject()
    default.apply {
        put("PoolId", mAwsConfig.appSyncConfig?.poolId)
        put("AppClientId", mAwsConfig.appSyncConfig?.clientId)
        put("Region", BuildConfig.AWS_REGION)
    }
    val cognitoUserPool = JSONObject()
    cognitoUserPool.put("Default", default)
    jsonObject.put("CognitoUserPool", cognitoUserPool)

    // AppSync
    val appSyncDefault = JSONObject()
    appSyncDefault.apply {
        put("ApiUrl", mAwsConfig.appSyncConfig?.apiUrl)
        put("Region", BuildConfig.AWS_REGION)
        put("AuthMode", "AMAZON_COGNITO_USER_POOLS")
    }
    val appSync = JSONObject()
    appSync.put("Default", appSyncDefault)
    jsonObject.put("AppSync", appSync)

    return jsonObject
}

So, this issue has been fixed, but after this, we've been facing another issue which has already been raised https://github.com/awslabs/aws-mobile-appsync-sdk-android/issues/350#issuecomment-1056756621

div5yesh commented 2 years ago

Closing as @iamfirdous8 got it working. Please watch #350 for further updates.