vendredi 29 avril 2016

How to use fields from an object after an exception is thrown and the object can't be fully created

The issue that I have is that I need information from an object that a method returns when it throws an exception. It is a little hard to describe so I have this java pseudo code example. I have a solution, but I don't like it (problems listed below), and was wondering if there was a better one:

public class OuterClass {

  InnerClass innerClass = new InnerClass();

  public void doOuterClass() {
    try {
      // class Container is a POJO with Strings s1, s2, and s3
      Container container = innerClass.createContainer();

      // more processing on the container that takes arg container
    } catch (Exception e) {
      // *Issue is here*: If s2 was calculated, it implies that an RPC was made,
      // which changed the state of a certain server. I need make a call using s1
      // to revert the state of that server. FYI, it is not easy to recalculate s1.
    }
  }
}

public class InnerClass {

  InnerInnerClass innerInnerClass = new InnerInnerClass();

  public Container createContainer() throws Exception {
    Container container = innerInnerClass.createContainer();

    // complex calls to various services that might throw Exception
    ...

    return container;
  }
}

public class InnerInnerClass {

  public Container createContainer() throws Exception {
    // complex calls to various services that might throw Exception
    String s1 = ...;

    // complex calls to various services that might throw Exception
    String s2 = ...;

    // complex calls to various services that might throw Exception
    String s3 = ...;

    return new Container(s1, s2, s3);
  }
}

What I tried to do is add Exception as a field in Container and made it mutable. As s1, s2, and s3 are calculated, it sets the values in the Container. There are a few problems with this though (non-exhaustive list):

  1. I have to surround each create method with a big try catch and set the exception on the Container when an exception is thrown. This makes it tricky for others adding new code.
  2. Container is now mutable.
  3. Container fields are marked as @Nullable, which means all code after innerClass.createContainer() should technically check for null since the object could technically be partially constructed. (however, if there is no exception we can assume that all items are not null, but this is again an assumption that has to be remembered.
  4. There are actually more exceptions thrown than just Exception, so to handle them I either have to rethrow the exception after innerClass.createContainer(), or use instanceof on the Exception, which is ugly.

In summary the solution that I tried is not maintainable and hard to follow. What do you think? Is there a better solution?

Aucun commentaire:

Enregistrer un commentaire