Am I doing Throw correctly?

1

I'm typing a FireOut DAO that performs and handles Auth, Database, and Storage. But Firebase issues some exceptions depending on the scenario, password with less than 6 digits, email already registered, etc.

I'm trying to throw these exceptions forward using throw but it asks me to do a try, I do not understand why I'm passing the error to be handled further because it forces me to handle the error.

//-------------------- FirebaseAuth ------------------------------
    public void createAuth(User user) {       

       mFirebaseAuth = ConfigurationFirebase.getFirebaseAuth();
       mFirebaseAuth.createUserWithEmailAndPassword(user.getEmail(), user.getPassword()).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
           @Override
           public void onComplete(@NonNull Task<AuthResult> task) {
                //Fazer algo caso a criação do usuário tenha ocorrido com sucesso.
           }
       }).addOnFailureListener(new OnFailureListener() {
           @Override
           public void onFailure(@NonNull Exception e) {
                  if (e.getClass().equals(FirebaseAuthWeakPasswordException.class)) {

                      try {
                          throw new FirebaseAuthWeakPasswordException(e.getCause().toString(), e.getLocalizedMessage().toString(), e.getMessage().toString());
                      } catch (FirebaseAuthWeakPasswordException e1) {
                          e1.printStackTrace();
                      }

                  } else if (e.getClass().equals(FirebaseAuthUserCollisionException.class)) {

                      try {
                          throw new FirebaseAuthUserCollisionException(e.getCause().toString(), e.getLocalizedMessage().toString());
                      } catch (FirebaseAuthUserCollisionException e1) {
                          e1.printStackTrace();
                      }

                  }
           }
       });

    }
    
asked by anonymous 19.02.2018 / 23:20

1 answer

1

This will not work because the method you are calling is asynchronous. This exception would be thrown to another thread , in which the network call is occurring, and would not work anyway. This DAO pattern you are trying to do simply does not work on asynchronous paradigms without changes.

You did not specify the programming language or runtime environment, but if it is an environment where it is okay to catch the current thread while waiting for the result, you can use Tasks.await to do your code waits until finalization of Task resulting from createUserWithEmailAndPassword . Example:

public void createAuth(User user) throws FirebaseAuthWeakPasswordException {

    Task<AuthResult> createUserAccountTask = mFirebaseAuth.createUserWithEmailAndPassword(user.getEmail(), user.getPassword());
    try {
        // Nessa linha, a execução da thread atual vai congelar até a tarefa concluir (com sucesso ou erro)
        Tasks.await(createUserAccountTask);

        if (createUserAccountTask.isSuccessful()) {
            //Fazer algo caso a criação do usuário tenha ocorrido com sucesso.
        } else {
            Exception e = createUserAccountTask.getException();
            if (e.getClass().equals(FirebaseAuthWeakPasswordException.class)) {
                throw new FirebaseAuthWeakPasswordException(e.getCause().toString(), e.getLocalizedMessage().toString(), e.getMessage().toString());
            } else if (e.getClass().equals(FirebaseAuthUserCollisionException.class)) {
                throw new FirebaseAuthUserCollisionException(this.e.getCause().toString(), this.e.getLocalizedMessage().toString());
            }
        }

    } catch (ExecutionException e) {
        // faça alguma coisa aqui em caso de ExecutionException
    } catch (InterruptedException e) {
        // faça alguma coisa aqui caso a tarefa seja interrompida no meio
    }

}

However, be aware that this can freeze the user's screen if you run the main thread .

A common and simple approach to implement when it is not possible to block the execution of the current thread is to use the so called callbacks or listeners . You must require the caller to pass the role to you, in addition to the user and password, objects that explain what to do when the task completes. For example, you can define these interfaces:

@FunctionalInterface
interface UserCreationSuccessfulListener {
    void onUserCreated();
}

@FunctionalInterface
interface UserCreationFailedListener {
    void onFailedToCreateUser(Exception e);
}

And then you can change your function to look like this:

public void createAuth(User user, final UserCreationSuccessfulListener successListener, final UserCreationFailedListener failureListener) throws FirebaseAuthWeakPasswordException {

    mFirebaseAuth.createUserWithEmailAndPassword(user.getEmail(), user.getPassword())
            .addOnSuccessListener(new OnSuccessListener<AuthResult>() {
                @Override
                public void onSuccess(AuthResult authResult) {
                    successListener.onUserCreated();
                }
            }).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {

                    if (e.getClass().equals(FirebaseAuthWeakPasswordException.class)) {
                        failureListener.onFailedToCreateUser(
                                new FirebaseAuthWeakPasswordException(e.getCause().toString(), e.getLocalizedMessage(), e.getMessage())
                        );
                    } else if (e.getClass().equals(FirebaseAuthUserCollisionException.class)) {
                        failureListener.onFailedToCreateUser(new FirebaseAuthUserCollisionException(e.getCause().toString(), e.getLocalizedMessage()));
                    } else {
                        failureListener.onFailedToCreateUser(e);
                    }

                }
            }
            );

}

And use it like this:

createAuth(user, new UserCreationSuccessfulListener() {
    @Override
    public void onUserCreated() {
        // fazer algo aqui em caso de sucesso
    }
}, new UserCreationFailedListener() {
    @Override
    public void onFailedToCreateUser(Exception e) {
        // fazer algo aqui em caso de erro
    }
});

Or even better:

createAuth(user, () -> {
    // fazer algo aqui em caso de sucesso
}, (error) -> {
    // fazer algo aqui em caso de erro
});

There are other options. You can, for example, return the Task itself as the createUserWithEmailAndPassword and let the client code of your function turn around with the result. One problem is that this creates a dependency on the client code with the Google Play Services API.

    
20.02.2018 / 02:06