Search code examples
javaandroidkotlindaggerdagger-hilt

Using dagger hilt + parse Server SDK: java.lang.IllegalArgumentException


currently, I am working on a project where I try to use both dagger (hilt) and parseServer SDK. The problem is that in my opinion it is impossible to use this combination in one project...

Here is my opinion on why I think it is impossible, at least in the way and knows how I would like it to be:

When using Parse SDK and creating a class, you have to annotate it with @ParseClasssName("YourDBClassName"). This custom class has to be registered in onCreate() with ParseObject.registerSubclass(YourClassName::class.java) before calling Parse.initialize....

Now comes my problem: When using dagger (hilt) and creating this customClass, it has to be injected with @Inject lateinit var YourClassName before calling onCreate(). But when you inject this customClass before calling the onCreate() parse throws an Error, because 1. It does not know that this class is a customClass and 2. the ParseObject has to be created within the onCreate() method.

To make it a bit more clear, here is my code and what I want to achieve:

Custom User Class

@ParseClassName("User")
data class User(var name: String, var passWord: String, var eMail: String) : ParseUser() {

    @Inject constructor(): this("","","")

    // Creates a new User
    fun signUpWithOutVerification() = apply {
        username = name
        setPassword(passWord)
        email = eMail
        signUpInBackground()
    }

    // logIn
    fun logIn() = logInInBackground(name, passWord) ?: Timber.e("logIn Error")

    // logOut
    fun logOut() = logOutInBackground() ?: Timber.e("logOut Error")

    // Update
    fun updateCredential(key: String, value: Any) = getCurrentUser().apply {
        put(key, value)
        saveInBackground()
    } ?: Timber.e("Update failed")

    // Delet and Logout
    fun deleteUser() = getCurrentUser().apply {
        deleteInBackground()
        logOut()
    } ?: Timber.e("Delete failed")

ApplicationModule

@Module
@InstallIn(ApplicationComponent::class)
object ApplicationModule {

    @Provides
    @Singleton
    fun provideUser() = User()

}

MainActivity

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject lateinit var user: User


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        ParseObject.registerSubclass(User::class.java)

        Parse.initialize(
            Parse.Configuration.Builder(this)
            .applicationId("YourAppKey")
            .clientKey("YourClientKey")
            .server("https://parseapi.back4app.com")
            .build()
        )

        Timber.plant(Timber.DebugTree())

        lateinit var userName: String
        lateinit var userPw: String

        btn_signup.setOnClickListener {
            userName = etName.text.toString()
            userPw = etPassword.text.toString()
            user.apply{
                name = userName
                passWord = userPw
                eMail = "$userName@email.com"
                signUpWithOutVerification()
            }

        }

MainApp

@HiltAndroidApp
class App : Application()

Current error stack

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.app, PID: 31532
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.app/com.example.app.ui.view.MainActivity}: java.lang.IllegalArgumentException: You must create this type of ParseObject using ParseObject.create() or the proper subclass.
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
     Caused by: java.lang.IllegalArgumentException: You must create this type of ParseObject using ParseObject.create() or the proper subclass.
        at com.parse.ParseObject.<init>(ParseObject.java:162)
        at com.parse.ParseObject.<init>(ParseObject.java:132)
        at com.parse.ParseUser.<init>(ParseUser.java:56)
        at com.example.app.data.model.User.<init>(User.kt:10)
        at com.example.app.data.model.User.<init>(User.kt:12)
        at com.example.app.di.modules.ApplicationModule.provideUser(ApplicationModule.kt:16)
        at com.example.app.di.modules.ApplicationModule_ProvideUserFactory.provideUser(ApplicationModule_ProvideUserFactory.java:27)
        at com.example.app.DaggerApp_HiltComponents_ApplicationC.getUser(DaggerApp_HiltComponents_ApplicationC.java:61)
        at com.example.app.DaggerApp_HiltComponents_ApplicationC.access$1000(DaggerApp_HiltComponents_ApplicationC.java:41)
        at com.example.app.DaggerApp_HiltComponents_ApplicationC$ActivityRetainedCImpl$ActivityCImpl.injectMainActivity2(DaggerApp_HiltComponents_ApplicationC.java:174)
        at com.example.app.DaggerApp_HiltComponents_ApplicationC$ActivityRetainedCImpl$ActivityCImpl.injectMainActivity(DaggerApp_HiltComponents_ApplicationC.java:155)
        at com.example.app.ui.view.Hilt_MainActivity.inject(Hilt_MainActivity.java:62)
        at com.example.app.ui.view.Hilt_MainActivity.onCreate(Hilt_MainActivity.java:37)
        at com.example.app.ui.view.MainActivity.onCreate(MainActivity.kt:22)
        at android.app.Activity.performCreate(Activity.java:7802)
        at android.app.Activity.performCreate(Activity.java:7791)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016) 
        at android.os.Handler.dispatchMessage(Handler.java:107) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7356) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 

Please Note!

  1. I never used dependency Injection before
  2. I am new to dagger (hilt)
  3. I am new to parse sdk

So it IS POSSIBLE that I just don't have the knowledge to write the code I want. What I want to do is, that dagger (hilt) creates the User + gets his Name etc...

I appreciate every help, thank you!


Solution

  • You should move the registerSubclass() code to your application class.

    Your application class:

    @HiltAndroidApp
    class App : Application() {
    
     override fun onCreate() {
            super.onCreate()
           
    ParseObject.registerSubclass(User::class.java)
    
            Parse.initialize(
                Parse.Configuration.Builder(this)
                .applicationId("YourAppKey")
                .clientKey("YourClientKey")
                .server("https://parseapi.back4app.com")
                .build()
            )
        }
    
      }
    

    In Manifest file:-

    <application
            android:name=".App"
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            ....