Invoking API calls with parameters specified using JSON I have an instance of a Java class that I need to call some functions on, using the API exposed by another party. For each call, I need to both check for thrown exceptions, and check the value of the returned boolean. If the boolean is false, I need to read the errorMsg object to see what went wrong. In either error case, I need to throw an exception with a relevant method. Each method takes a different number of String arguments

I think there's a cleaner way to do this using reflection, but I can't figure out how to handle the different numbers of arguments. And there may be a totally different solution I've overlooked. Open to all suggestions. Any thoughts?

Here are two examples so you can see what I'm dealing with:

ClassProvidedWithExposedAPI s;

private void setHttp(JsonObject jo) throws Exception {
    boolean success = true;
    String errorString = null;
    ArrayList&lt;Message&gt; errorMsg = new ArrayList&lt;Message&gt;();
    try {
        JsonObject http = jo.getAsJsonObject("http");
        if (http != null &amp;&amp; !http.isJsonNull()) {
            success = s.setHttp(getJsonElementAsString(http, Http.ENABLED_ELEMENT),
                    getJsonElementAsString(http, Http.HTTP_PORT_ELEMENT),
                    getJsonElementAsString(http, Http.HTTPS_PORT_ELEMENT),
                    getJsonElementAsString(http, Http.TIMEOUT_ELEMENT),
                    getJsonElementAsString(http, Http.HTTP_REDIRECT_ELEMENT), errorMsg);
        }

    } catch (Exception e) {
        errorString = e.toString();
    } finally {
        if (!success) {
            if (errorString == null) {
                errorString = errorMsg.toString();
            }
            throw new Exception("Exception in setHttp: " + errorString);
        }
    }
}

private void setSsh(JsonObject jo) throws Exception {
    boolean success = true;
    String errorString = null;
    ArrayList&lt;Message&gt; errorMsg = new ArrayList&lt;Message&gt;();
    try {
        JsonObject ssh = jo.getAsJsonObject("ssh");
        if (ssh != null &amp;&amp; !ssh.isJsonNull()) {
            success = s.setSsh(getJsonElementAsString(ssh, Ssh.ENABLED_ELEMENT),
                    getJsonElementAsString(ssh, Ssh.SSH_PORT_ELEMENT),
                    getJsonElementAsString(ssh, Ssh.TIMEOUT_ELEMENT), errorMsg);
        }
    } catch (Exception e) {
        errorString = e.toString();
    } finally {
        if (!success) {
            if (errorString == null) {
                errorString = errorMsg.toString();
            }
            throw new Exception("Exception in setSsh: " + errorString);
        }
    }
}
Sounds like a simple use case for polymorphism:

interface JsonOperation {
    void run();
}

private void setHttp(JsonObject jo) {
    runAndHandleErrors(() -&gt; {
        // ...
    });
}

private void setSsl(JsonObject jo) {
    runAndHandleErrors(() -&gt; {
        // ...
    });
}

private void runAndHandleErrors(JsonOperation op) {
    try {
        op.run();
    } catch (Exception e) {
        // ...
    } finally {
        // ...
    }
}


Explanation: JsonOperation is an interface with one method so it is considered a functional interface, meaning a lambda can be considered an implementation of it. runAndHandleErrors takes a JsonOperation so whenever we call runAndHandleErrors with a lambda, the compiler infers the lambda to implement JsonOperation.

A lambda, like an anonymous inner class, captures final variables in enclosing blocks. That means that a lambda, like an anonymous inner class, can use these variables and sees the values of the variables that were assigned when the lambda / anonymous inner class was created. A lambda also captures variables that are effectively final, meaning their values are never changed whether or not they are declared as final.

When setHttp(x) is called, the following happens:


x is assigned to jo
an implementation of JsonOperation capturing jo is created (but not run)
runAndHandleErrors is called and the JsonOperation from step 2 is assigned to op
runAndHandleErrors calls op.run(), causing the JsonOperation to run
the JsonOperation runs, doing whatever it wants with jo - it sees the same value of jo as was assigned in step 2




However, since you posted to the Code Review Stack Exchange and not Programmers Stack Exchange, I'll critique your code:


catch Exception and throws Exception are code smells - to the greatest degree possible, catch and declare specific Exception types.
The logic regarding success and errorString is convoluted. You could instead separately throw an appropriate subclass of Exception in the try and catch blocks and get rid of the success and errorString variables. Your code reuse isn't actually helping because you need conditional logic in the finally block to account for both cases. Also, the thrown exception in the catch block should properly wrap the original exception by passing the latter directly into the former's constructor.
Make a helper method for getJsonElementAsString that takes a varargs array of attribute keys and returns a list of attributes. This method would make your code much terser.