1

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?

1 Answer 1

1

Yes, there is a better solution.
The root of your problem appear to be that you try to handle the exception at the wrong place, where you don't have the required information any more to roll back some actions that were taken.

If creating your Container object consists of multiple steps that can fail and that have externally visible or persistent effects that need to be rolled back if not all the steps succeed, then you should handle that in the logic that is creating the Container object.

For example:

public class InnerInnerClass {

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

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

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

            return new Container(s1, s2, s3);
        } catch (Exception)
        {
            // roll-back the effects from s2
            // re-throw the exception for further handling
        }
    } catch (Exception)
    {
        // roll-back the effects from s1
        // re-throw the exception for further handling
    }
  }
}

This way, OuterClass can deal with the failure to create the container without having to deal with the possibility that some steps in creating the container could have had an effect that needs to be rolled back, because that was already taken care of.

1
  • Thanks for the response! The issue is that an exception can also be thrown in InnerClass.createContainer(). That means we have to do the revert there as well, and in any other class that would throw an exception after InnerInnerClass.createContainer() is called. All of these would be called from OuterClass, so an advantage to having the exception handling there is that it would be in one place, and then callers would not have to worry about doing this reverting.
    – nmore
    May 2, 2016 at 19:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.