ragunathjawahar / android-saripaar

UI form validation library for Android
Apache License 2.0
3.22k stars 460 forks source link

Attempt to invoke virtual method 'void com.mobsandgeeks.saripaar.ValidationContext.setViewRulesMap(java.util.Map)' on a null object reference #187

Closed ajaysaini-sgvu closed 7 years ago

ajaysaini-sgvu commented 7 years ago

I am using this library https://github.com/ragunathjawahar/android-saripaar to apply validations on my input fields like non empty, email etc.

I have two input fields and this is how I am applying validations. It is crashing my application. I checked validator variable is not null

MainActivity.java

@NotEmpty
private TextInputLayout client_id_input_layout;

@NotEmpty
private TextInputLayout access_code_input_layout;

@Inject
Validator validator;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ....

    validator.setValidationListener(this);
}

@Override
public void onClick(View view) {
    if(isOnline())
        validator.validate();
    else
        Snackbar.make(mCoordinatorLayout, getString(R.string.network_error), Snackbar.LENGTH_LONG).show();
}

Validator.java

@Module
public class Validator {

    @Provides
    @Singleton
    com.mobsandgeeks.saripaar.Validator providesValidator(Application application) {
        return new com.mobsandgeeks.saripaar.Validator(application);
    }
}

StackTrace

Process: com.icici.iciciappathon, PID: 4555
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.mobsandgeeks.saripaar.ValidationContext.setViewRulesMap(java.util.Map)' on a null object reference
   at com.mobsandgeeks.saripaar.Validator.createRulesSafelyAndLazily(Validator.java:479)
   at com.mobsandgeeks.saripaar.Validator.validate(Validator.java:330)
   at com.mobsandgeeks.saripaar.Validator.validate(Validator.java:295)
   at com.icici.iciciappathon.login.AuthenticationActivity.onClick(AuthenticationActivity.java:102)
   at android.view.View.performClick(View.java:5609)
   at android.view.View$PerformClick.run(View.java:22259)
   at android.os.Handler.handleCallback(Handler.java:751)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:154)
   at android.app.ActivityThread.main(ActivityThread.java:6077)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
ragunathjawahar commented 7 years ago

Validator should accept the instance of the class within which the annotated view fields reside.

ajaysaini-sgvu commented 7 years ago

@ragunathjawahar How to pass activity instance to Validator and what would be method to invoke in case of if I pass activity ?

rjoncontract commented 7 years ago

@ajaysaini-sgvu Don't use DI, if you still want to do it. Use sub-components. But I would still stay away from them for this use case. The best way to do it would be to declare the Validator inside the class with Saripaar annotated fields.

ajaysaini-sgvu commented 7 years ago

@ragunathjawahar I am using Dagger2 using below approach -

@Module
public class Validator {
    @Provides
    com.mobsandgeeks.saripaar.Validator providesValidator(Application application) {
        return new com.mobsandgeeks.saripaar.Validator(application);
    }
}

@Singleton
@Component(modules = {AppModule.class, NetModule.class, Validator.class})
public interface NetComponent {
    void inject(AuthenticationActivity authenticationActivity);
    void inject(PaymentActivity paymentActivity);
}

Injecting like this in onCreate of an activity -

((AppApplication) getApplication()).getmNetComponent().inject(this);

Isn't correct to have correct Validator ?

rjoncontract commented 7 years ago

Validator's constructor takes in the instance of the declaring class. Not the context.

ajaysaini-sgvu commented 7 years ago

@rjoncontract @ragunathjawahar I have made changes in my dagger module and dagger component, nevertheless still facing same issue. Does your library work with DI ?

ValidationComponent .java

@Subcomponent(modules = {ValidatorModule.class})
public interface ValidationComponent {
    void inject(Activity activity);
}

NetComponent.java

@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface NetComponent {
    void inject(PaymentActivity paymentActivity);
    ValidationComponent validatorComponent(ValidatorModule validatorModule);
}

ValidatorModule.java

@Module
public class ValidatorModule {

    private final Activity activity;

    @Inject
    public ValidatorModule(Activity activity) {
        this.activity = activity;
    }

    @Provides
    Validator providesValidator() {
        return new com.mobsandgeeks.saripaar.Validator(activity);
    }
}

onCreate of my activity

 ((AppApplication) getApplication()).getmNetComponent()
                .validatorComponent(new ValidatorModule(this))
                .inject(AuthenticationActivity.this);

Error Logs

05-14 14:00:51.191 4647-4647/com.icici.iciciappathon E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.icici.iciciappathon, PID: 4647
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.icici.iciciappathon/com.icici.iciciappathon.login.AuthenticationActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.mobsandgeeks.saripaar.Validator.setValidationListener(com.mobsandgeeks.saripaar.Validator$ValidationListener)' on a null object reference
   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
   at android.app.ActivityThread.-wrap12(ActivityThread.java)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
   at android.os.Handler.dispatchMessage(Handler.java:102)
   at android.os.Looper.loop(Looper.java:154)
   at android.app.ActivityThread.main(ActivityThread.java:6077)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.mobsandgeeks.saripaar.Validator.setValidationListener(com.mobsandgeeks.saripaar.Validator$ValidationListener)' on a null object reference
   at com.icici.iciciappathon.login.AuthenticationActivity.onCreate(AuthenticationActivity.java:110)
   at android.app.Activity.performCreate(Activity.java:6664)
   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2599)
   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707) 
   at android.app.ActivityThread.-wrap12(ActivityThread.java) 
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460) 
   at android.os.Handler.dispatchMessage(Handler.java:102) 
   at android.os.Looper.loop(Looper.java:154) 
   at android.app.ActivityThread.main(ActivityThread.java:6077) 
   at java.lang.reflect.Method.invoke(Native Method) 
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 
ragunathjawahar commented 7 years ago

Looks like dagger isn't injecting dependencies. AFAIK, Dagger 2 doesn't handle base class injections (no straightforward way to accomplish it). Try changing your @Subcomponent to this,

@Subcomponent(modules = { ValidatorModule.class })
public interface ValidationComponent {
    void inject(AuthenticationActivity activity);
}
ajaysaini-sgvu commented 7 years ago

@ragunathjawahar It worked!! Perfect! Thanks a lot!

How it is different void inject(AuthenticationActivity activity); and void inject(Activity activity); ?

fabiomor commented 7 years ago

just faced the same problem, i used DI with dagger2 as well, but in my case the problem was simply that i didn't set any of the checks annotaion on my views, as soon as i set the first one, everything worked fine.