Handling Java Exceptions

If a Java method throws an exception, e.g. by using throw new Exception("...") and the exception is not caught by Java then it is passed on as a Prolog exception. The thrown term is a global reference to the Exception object. The following example code illustrates how to handle Java exceptions in Prolog:

     exception_example(JVM, ...) :-
        catch(
              %% Call Java method that may raise an exception
              jasper_call(JVM, ...),
              Excp,
              (
                ( is_java_exception(JVM, Excp)
                -> print_exception_info(JVM, Excp)
                ; throw(Excp)       % pass non-Java exceptions to caller
                )
              )
             ).
     
     is_java_exception(_JVM, Thing) :- var(Thing), !, fail.
     is_java_exception(_JVM, Thing) :-
        Thing = java_exception(_),      % misc error in Java/Prolog glue
        !.
     is_java_exception(JVM, Thing) :-
        jasper_is_object(JVM, Thing),
        jasper_is_instance_of(JVM, Thing, 'java/lang/Throwable').
     print_exception_info(_JVM, java_exception(Message)) :- !,
        format(user_error, '~NJasper exception: ~w~n', [Message]).
     print_exception_info(JVM, Excp) :-
        /*
        // Approximate Java code
        {
           String messageChars = excp.getMessage();
        }
        */
        jasper_call(JVM,
                    method('java/lang/Throwable', 'getMessage', [instance]),
                    get_message(+object('java/lang/Throwable'), [-chars]),
                    get_message(Excp, MessageChars)),
        /* // Approximate Java code
        {
           StringWriter stringWriter = new StringWriter();
           PrintWriter printWriter =  new PrintWriter(stringWriter);
           excp.printStackTrace(printWriter);
           printWriter.close();
           stackTraceChars = StringWriter.toString();
        }
        */
        jasper_new_object(JVM, 'java/io/StringWriter',
                          init, init, StringWriter),
        jasper_new_object(JVM, 'java/io/PrintWriter',
                          init(+object('java/io/Writer')),
                          init(StringWriter), PrintWriter),
        jasper_call(JVM,
                    method('java/lang/Throwable', 'printStackTrace', [instance]),
                    print_stack_trace(+object('java/lang/Throwable'),
                                      +object('java/io/PrintWriter')),
                    print_stack_trace(Excp, PrintWriter)),
        jasper_call(JVM,
                    method('java/io/PrintWriter','close',[instance]),
                    close(+object('java/io/PrintWriter')),
                    close(PrintWriter)),
        jasper_call(JVM,
                    method('java/io/StringWriter','toString',[instance]),
                    to_string(+object('java/io/StringWriter'),[-chars]),
                    to_string(StringWriter, StackTraceChars)),
        jasper_delete_local_ref(JVM, PrintWriter),
        jasper_delete_local_ref(JVM, StringWriter),
        %% ! exceptions are thrown as global references
        jasper_delete_global_ref(JVM, Excp),
        format(user_error, '~NJava Exception: ~s\nStackTrace: ~s~n',
               [MessageChars, StackTraceChars]).