views:

52

answers:

1

I have a class that extends Application which has a lot of methods like:

public User getUser(String name);
public List<User> getFriends(User user);
public List<Game> getGames(User user);

which wraps a service class.

The catch here is that no method will work if I have no internet on the device. So for instance I am doing:

public User getUser(String name) {
        User ret = null;
        try {
            return myService.getUser(name);
        } catch (NoInternetException e) {
            NoInternetToast.show(this);
        }

    return ret;
}

Is there a way to wrap every call so I don't have to add the try catch on every method of my Application?

+3  A: 

Without using any third party libraries that might be available on Android, there is no simple way to wrap methods of a class. If you can extract your application functionality into an interface, you can use java.lang.reflect.Proxy to implement your interface - the proxy implementation is a single method that calls your real implementation method, and caches and handles the exception.

I can provide more details if factoring out the code into a separate class and interface is a workable approach for you.

EDIT: Here's the details:

You currently are using myService, which implements the methods. If you don't have one already, create an interface UserService that declares the service methods:

public interface UserService {
  User getUser(String name);
  List<User> getFriends(User user);
  List<Game> getGames(User user);
}

And declare this interface on your existing MyService class,

class MyService implements UserService {
     // .. existing methods unchanged 
     // interface implemented since methods were already present
}

To then avoid repetition, the exception handling is implemented as an InvocationHandler

class HandleNoInternet implements InvocationHandler {
   private final Object delegate;   // set fields from constructor args
   private final Application app;

   public HandleNoInternet(Application app, Object delegate) {
      this.app = app; 
      this.delegate = delegate;
   }
   public Object invoke(Object proxy, Method method, Object[] args) {
       try {
           // invoke the method on the delegate and handle the exception
           method.invoke(delegate, args);
       } catch (Exception ex) {
           if ( ex.getCause() instanceof NoInternetException ) {
             NoInternetToast.show(app);
           } else {
             throw new RuntimeException(ex);
           }
       }
   }
}

This is then used as a proxy, in your Application class:

InvocationHandler handler = new HandleNoInternet(this, myService);
UserService appUserService = (UserService)Proxy.newProxyInstance(
   getClass().getClassLoader(), new Class[] { UserService.class }, handler);

You then use the appUserService without needing to worry about catching the NoInternetException.

mdma
@mdma: Does it make sense to use a Proxy to achieve DRY?
Macarse
@Macarse - Very much so. In regular java, Proxying is the backbone of many AOP frameworks, and aspects are one way to avoid repeating yourself. In this case the aspect is consistent exception handling. With the proxy, you define the desired behaviour just once and apply it to all methods where you want consistent exception handling. Other than code-generation tools, I don't see any other alternative.
mdma
@mdma: cool. Can you give me some insight of how to apply it to my example?
Macarse
@mdma: Great. Thanks.I had to change something thought, I will edit your answer.
Macarse